feat: add architecture docs, fix code issues from review, add analyze_lint script

Architecture docs (docs/architecture/):
- overview.md: package purpose, exports, terminology, design decisions, gaps
- metagraph.md: core graph model, schema types, SchemaBuilder, validation
- sqlite-host.md: SQLite tables, common columns, relations, concurrency model
- encrypted-data.md: encrypted data as a node type, AES-256-GCM crypto utility design

Code fixes from architecture review:
- Remove ConfigSchema duplication in graphTypes.ts (import GraphConfig from types.ts)
- Add missing SelectNodeSchema/SelectNode to nodes.ts
- Fix InsertEdge.key to be Optional (match nullable DB column)
- Replace TypeScript enums with as const objects (GRAPH_STATUS, GRAPH_BASE_TYPE)
- Add verbatim-module-syntax to lint exclusions (TypeBox false positive)
- Add @std/flags and @std/path to deno.json imports

Infrastructure:
- Add scripts/analyze_lint.ts from @ade for grouped lint analysis
- Add deno task lint:analyze
- Update AGENTS.md with architecture doc references, enum convention, crypto todo
This commit is contained in:
2026-05-28 13:18:56 +00:00
parent 351fc98ec1
commit b0298663dc
13 changed files with 1311 additions and 37 deletions

View File

@@ -51,20 +51,28 @@ export const GraphSchema: TSchema = Type.Object({
export type GraphSchema = Static<typeof GraphSchema>;
export enum EnumGraphStatus {
Active = "active",
Archived = "archived",
Draft = "draft",
}
export const GRAPH_STATUS = {
Active: "active",
Archived: "archived",
Draft: "draft",
} as const;
export type GraphStatus = Static<typeof GraphStatus>;
export const GraphStatus: TSchema = Type.Enum(EnumGraphStatus);
export type GraphStatus = (typeof GRAPH_STATUS)[keyof typeof GRAPH_STATUS];
export const GraphStatus: TSchema = Type.Union([
Type.Literal(GRAPH_STATUS.Active),
Type.Literal(GRAPH_STATUS.Archived),
Type.Literal(GRAPH_STATUS.Draft),
]);
export enum EnumGraphBaseType {
Directed = "directed",
Undirected = "undirected",
Mixed = "mixed",
}
export const GRAPH_BASE_TYPE = {
Directed: "directed",
Undirected: "undirected",
Mixed: "mixed",
} as const;
export type GraphBaseType = Static<typeof GraphBaseType>;
export const GraphBaseType: TSchema = Type.Enum(EnumGraphBaseType);
export type GraphBaseType = (typeof GRAPH_BASE_TYPE)[keyof typeof GRAPH_BASE_TYPE];
export const GraphBaseType: TSchema = Type.Union([
Type.Literal(GRAPH_BASE_TYPE.Directed),
Type.Literal(GRAPH_BASE_TYPE.Undirected),
Type.Literal(GRAPH_BASE_TYPE.Mixed),
]);

View File

@@ -37,7 +37,7 @@ export const SelectEdge = createSelectSchema(edges, {
export type SelectEdge = Static<typeof SelectEdge>;
export const InsertEdge = createInsertSchema(edges, {
key: Type.String({ minLength: 1 }),
key: Type.Optional(Type.String({ minLength: 1 })),
attributes: AttributesSchema,
});

View File

@@ -2,23 +2,15 @@ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import { createInsertSchema, createSelectSchema } from "@alkdev/drizzlebox";
import { Type, type Static } from "@alkdev/typebox";
import { commonCols } from "./common.ts";
import { GraphConfig } from "../../graphs/types.ts";
const ConfigSchema = Type.Object({
type: Type.Union([
Type.Literal("directed"),
Type.Literal("undirected"),
Type.Literal("mixed"),
], { default: "mixed" }),
multi: Type.Boolean({ default: true }),
allowSelfLoops: Type.Boolean({ default: true }),
});
type GraphConfigType = Static<typeof GraphConfig>;
export const graphTypes = sqliteTable("graph_types", {
...commonCols,
name: text("name").notNull().unique(),
description: text("description").default(""),
config: text("config", { mode: "json" }).$type<Static<typeof ConfigSchema>>().notNull(),
config: text("config", { mode: "json" }).$type<GraphConfigType>().notNull(),
version: integer("version").notNull().default(1),
});

View File

@@ -3,7 +3,7 @@ import { createInsertSchema, createSelectSchema } from "@alkdev/drizzlebox";
import { Type, type Static } from "@alkdev/typebox";
import { commonCols } from "./common.ts";
import { graphTypes } from "./graphTypes.ts";
import { EnumGraphStatus } from "../../graphs/types.ts";
import { GRAPH_STATUS } from "../../graphs/types.ts";
export const graphs = sqliteTable("graphs", {
...commonCols,
@@ -26,9 +26,9 @@ export type SelectGraph = Static<typeof SelectGraph>;
export const InsertGraph = createInsertSchema(graphs, {
name: Type.String({ minLength: 2 }),
status: Type.Optional(Type.Union([
Type.Literal(EnumGraphStatus.Active),
Type.Literal(EnumGraphStatus.Archived),
Type.Literal(EnumGraphStatus.Draft),
Type.Literal(GRAPH_STATUS.Active),
Type.Literal(GRAPH_STATUS.Archived),
Type.Literal(GRAPH_STATUS.Draft),
])),
});

View File

@@ -2,8 +2,8 @@ export { graphs } from "./graphs.ts";
export type { SelectGraph, InsertGraph } from "./graphs.ts";
export { SelectGraph as SelectGraphSchema, InsertGraph as InsertGraphSchema } from "./graphs.ts";
export { nodes } from "./nodes.ts";
export type { InsertNode } from "./nodes.ts";
export { InsertNodeSchema } from "./nodes.ts";
export type { SelectNode, InsertNode } from "./nodes.ts";
export { SelectNodeSchema, InsertNodeSchema } from "./nodes.ts";
export { edges } from "./edges.ts";
export type { SelectEdge, InsertEdge } from "./edges.ts";
export { SelectEdge as SelectEdgeSchema, InsertEdge as InsertEdgeSchema } from "./edges.ts";

View File

@@ -1,5 +1,5 @@
import { sqliteTable, text, unique } from "drizzle-orm/sqlite-core";
import { createInsertSchema } from "@alkdev/drizzlebox";
import { createInsertSchema, createSelectSchema } from "@alkdev/drizzlebox";
import { Type, type Static } from "@alkdev/typebox";
import { commonCols } from "./common.ts";
import { graphs } from "./graphs.ts";
@@ -15,6 +15,15 @@ export const nodes = sqliteTable("nodes", {
graphKeyIdx: unique().on(table.graphId, table.key),
}));
export const SelectNodeSchema = createSelectSchema(nodes, {
attributes: AttributesSchema,
metadata: Type.Object({}, { additionalProperties: true }),
createdAt: Type.Date(),
updatedAt: Type.Date(),
});
export type SelectNode = Static<typeof SelectNodeSchema>;
export const InsertNodeSchema = createInsertSchema(nodes, {
key: Type.String({ minLength: 1 }),
attributes: AttributesSchema,