feat: implement Story 1.1 — create and view diagrams

Add diagram/project DB schema, CRUD API, dashboard pages with grid/card/
empty state, create dialog with type selector, editor placeholder, and
26 schema validation tests. Includes code review fixes: soft-delete
filter on GET /:id, error handling, keyboard accessibility, type-safe
API response types, and error states on pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-22 23:54:50 +00:00
parent da3368fbdb
commit 392da385f4
20 changed files with 3785 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import {
integer,
jsonb,
pgEnum,
pgTable,
text,
timestamp,
} from "drizzle-orm/pg-core";
import { generateId } from "@turbostarter/shared/utils";
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
} from "../lib/zod";
import { user } from "./auth";
import type * as z from "zod";
export const diagramTypeEnum = pgEnum("diagram_type", [
"bpmn",
"er",
"orgchart",
"architecture",
"sequence",
"flowchart",
]);
export const project = pgTable("project", {
id: text().primaryKey().notNull().$defaultFn(generateId),
name: text().notNull(),
userId: text()
.references(() => user.id, { onDelete: "cascade" })
.notNull(),
sortOrder: integer().default(0),
createdAt: timestamp().defaultNow(),
updatedAt: timestamp().$onUpdate(() => new Date()),
});
export const diagram = pgTable("diagram", {
id: text().primaryKey().notNull().$defaultFn(generateId),
title: text().notNull(),
type: diagramTypeEnum().notNull(),
graphData: jsonb().$type<object>().default({}),
userId: text()
.references(() => user.id, { onDelete: "cascade" })
.notNull(),
projectId: text(),
lastAiMessage: text(),
deletedAt: timestamp(),
createdAt: timestamp().defaultNow(),
updatedAt: timestamp().$onUpdate(() => new Date()),
});
export const insertDiagramSchema = createInsertSchema(diagram);
export const selectDiagramSchema = createSelectSchema(diagram);
export const updateDiagramSchema = createUpdateSchema(diagram);
export type InsertDiagram = z.infer<typeof insertDiagramSchema>;
export type SelectDiagram = z.infer<typeof selectDiagramSchema>;
export type UpdateDiagram = z.infer<typeof updateDiagramSchema>;
export const insertProjectSchema = createInsertSchema(project);
export const selectProjectSchema = createSelectSchema(project);
export const updateProjectSchema = createUpdateSchema(project);
export type InsertProject = z.infer<typeof insertProjectSchema>;
export type SelectProject = z.infer<typeof selectProjectSchema>;
export type UpdateProject = z.infer<typeof updateProjectSchema>;

View File

@@ -2,6 +2,7 @@ import * as auth from "./auth";
import * as chat from "./chat";
import * as creditTransactions from "./credit-transaction";
import * as customers from "./customer";
import * as diagramModule from "./diagram";
import * as image from "./image";
import * as pdf from "./pdf";
@@ -27,6 +28,7 @@ export const schema = {
...auth,
...creditTransactions,
...customers,
...diagramModule,
...prefix(chat, "chat"),
...prefix(pdf, "pdf"),
...prefix(image, "image"),
@@ -36,6 +38,7 @@ export const schema = {
export * from "./auth";
export * from "./credit-transaction";
export * from "./customer";
export * from "./diagram";
// pgSchema-based modules (need explicit exports for drizzle-kit)
export * from "./chat";