docs: close unified ingest public docs gaps

This commit is contained in:
Andrey Avtomonov 2026-05-13 19:38:05 +02:00
parent 7309fbde94
commit 644bf58c37
10 changed files with 50 additions and 14 deletions

View file

@ -17,6 +17,7 @@
"!**/dist/**",
"!**/coverage/**",
"!**/.next/**",
"!**/.source/**",
"!**/node_modules/**",
"!**/*.gen.ts",
"!**/*.generated.ts"

View file

@ -9,6 +9,7 @@ import { notFound, redirect } from "next/navigation";
import defaultMdxComponents from "fumadocs-ui/mdx";
import { CodeBlock } from "@/components/code-block";
import { DocsPageActions } from "@/components/docs-page-actions";
import { readDocsPageMarkdown } from "@/lib/docs-markdown";
const docsIndexPath = "/docs/getting-started/introduction";
const docsIndexSlug = ["getting-started", "introduction"] as const;
@ -33,6 +34,7 @@ export default async function Page(props: {
if (!page) notFound();
const MDX = page.data.body;
const mdxSource = await readDocsPageMarkdown(page.slugs);
const hero = isHeroPage(params.slug);
@ -44,7 +46,7 @@ export default async function Page(props: {
<DocsTitle>{page.data.title}</DocsTitle>
<DocsPageActions
markdownUrl={`${page.url}.md`}
mdxSource={page.data.content}
mdxSource={mdxSource}
/>
</div>
<DocsDescription>{page.data.description}</DocsDescription>

View file

@ -1,5 +1,5 @@
import "./global.css";
import { RootProvider } from "fumadocs-ui/provider";
import { RootProvider } from "fumadocs-ui/provider/next";
import { Outfit, Inter, Geist_Mono } from "next/font/google";
import type { ReactNode } from "react";
import type { Metadata } from "next";

View file

@ -1,18 +1,16 @@
"use client";
import {
type ComponentPropsWithoutRef,
type ReactNode,
type ReactElement,
isValidElement,
} from "react";
import { CopyButton } from "./copy-button";
type Props = {
children?: ReactNode;
className?: string;
type Props = ComponentPropsWithoutRef<"pre"> & {
title?: string;
// rehype-pretty-code adds data attributes such as data-language; capture them via index signature
[key: string]: unknown;
"data-language"?: string;
};
const TERMINAL_LANGS = new Set(["bash", "sh", "shell", "zsh"]);

View file

@ -134,13 +134,13 @@ my-project/
│ └── data-quality-notes.md
├── raw-sources/
│ └── warehouse/
│ └── live-database/ # Scan artifacts and reports
│ └── database-ingest/ # Schema ingest artifacts and reports
└── .ktx/
├── db.sqlite # Local state (git-ignored)
└── cache/ # Runtime cache (git-ignored)
```
Semantic sources and wiki pages are committed to git. The SQLite database holds ephemeral state — scan results, embedding indexes, session logs — and is git-ignored. If you delete it, KTX rebuilds it on the next run.
Semantic sources and wiki pages are committed to git. The SQLite database holds ephemeral state — schema ingest results, embedding indexes, session logs — and is git-ignored. If you delete it, KTX rebuilds it on the next run.
This means your analytics context travels with your code. You can fork it, branch it, review it in a PR, and merge it with the same tools you use for dbt models. There's no sync problem between a remote server and your local state. There's no migration to run. The files are the source of truth.

View file

@ -0,0 +1,33 @@
import { readFile } from "node:fs/promises";
import { join } from "node:path";
export async function readDocsPageMarkdown(slugs: string[]) {
if (
slugs.length === 0 ||
slugs.some((segment) => segment.includes("/") || segment.includes(".."))
) {
throw new Error(`Invalid docs page slug: ${slugs.join("/")}`);
}
const docsRoot = join(process.cwd(), "content/docs");
const directPath = join(docsRoot, `${slugs.join("/")}.mdx`);
try {
return await readFile(directPath, "utf8");
} catch (error) {
if (!isNotFoundError(error)) {
throw error;
}
}
return readFile(join(docsRoot, slugs.join("/"), "index.mdx"), "utf8");
}
function isNotFoundError(error: unknown) {
return (
typeof error === "object" &&
error !== null &&
"code" in error &&
error.code === "ENOENT"
);
}

View file

@ -1,4 +1,5 @@
import { source } from "@/lib/source";
import { readDocsPageMarkdown } from "@/lib/docs-markdown";
const siteOrigin = "https://docs.kaelio.com/ktx";
@ -102,7 +103,7 @@ function toLlmDocsPage(page: ReturnType<typeof source.getPages>[number]) {
url: page.url,
markdownUrl: `${page.url}.md`,
slug: page.slugs,
getMarkdown: async () => normalizeMarkdown(page.data.content),
getMarkdown: async () => normalizeMarkdown(await readDocsPageMarkdown(page.slugs)),
} satisfies LlmDocsPage;
}

View file

@ -1,4 +1,4 @@
import { docs } from "@/.source";
import { docs } from "@/.source/server";
import { loader } from "fumadocs-core/source";
export const source = loader({

View file

@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View file

@ -15,7 +15,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
@ -33,7 +33,8 @@
"**/*.tsx",
".source/**/*.ts",
"next-env.d.ts",
".next/types/**/*.ts"
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"