feat: revamp to dynamic database-first architecture and cleanup phase docs
CI / typecheck + build (turbo) (push) Canceled after 0s

- Migrate document fetching and CRUD to be PostgreSQL-authoritative
- Remove static section enums and add dynamic listSections query
- Support custom sections and metadata across API, MCP, and Web UI
- Add /api/sections endpoint and update Header, Sidebar, and Forms
- Remove obsolete phase planning docs and modernize README/AGENTS
This commit is contained in:
asepharyana
2026-08-21 11:35:42 +07:00
parent a937e8f51b
commit a9b67385c3
37 changed files with 720 additions and 2515 deletions
+6 -11
View File
@@ -8,14 +8,6 @@ import type {
DocumentMeta,
} from "@mcpedia/types";
const SECTIONS: DocSection[] = ["docs", "writeups", "research", "notes"];
const VALID_TYPES: DocType[] = [
"documentation",
"writeup",
"research",
"note",
];
// Standard frontmatter keys that are rendered explicitly in the UI template.
// Any other key in frontmatter becomes a dynamic "extra field" badge.
@@ -41,13 +33,16 @@ export function parseFile(absPath: string, relPath: string): ParsedFile {
const raw = readFileSync(absPath, "utf8");
const { data, content } = matter(raw);
const parts = relPath.split("/");
const derivedSection = parts.length > 1 ? parts[0] : "docs";
const section: DocSection =
(SECTIONS.find((s) => relPath.startsWith(s + "/")) as DocSection | undefined) ??
"docs";
typeof data.section === "string" && data.section.trim() !== ""
? data.section.trim()
: derivedSection;
const slug = relPath.replace(/\.mdx?$/, "");
const type = (VALID_TYPES.includes(data.type) ? data.type : "documentation") as DocType;
const type = (typeof data.type === "string" && data.type.trim() !== "" ? data.type.trim() : "documentation") as DocType;
const status = (data.status === "draft" ? "draft" : "published") as DocStatus;
const tags: string[] = Array.isArray(data.tags)
+12 -5
View File
@@ -57,13 +57,20 @@ test("parseFile: section derived from top-level dir", () => {
expect(writeDoc("notes/baz.md", "---\ntitle: C\n---\nbody").meta.section).toBe("notes");
});
test("parseFile: invalid type/status fall back to defaults", () => {
const { meta } = writeDoc(
test("parseFile: dynamic type and status with defaults", () => {
const { meta: m1 } = writeDoc(
"docs/x.md",
"---\ntitle: X\ntype: bogus\nstatus: bogus\n---\n",
"---\ntitle: X\ntype: custom-type\nstatus: draft\n---\n",
);
expect(meta.type).toBe("documentation");
expect(meta.status).toBe("published");
expect(m1.type).toBe("custom-type");
expect(m1.status).toBe("draft");
const { meta: m2 } = writeDoc(
"docs/y.md",
"---\ntitle: Y\n---\n",
);
expect(m2.type).toBe("documentation");
expect(m2.status).toBe("published");
});
test("parseFile: missing optional fields get sane defaults", () => {