From 971d5054f895f2b9c88e163c01e9e77be418303e Mon Sep 17 00:00:00 2001 From: rmac Date: Wed, 14 Jan 2026 18:41:40 +0000 Subject: [PATCH] Correct schema architecture: YAML is source of truth, not Prisma Key Corrections: - Remove manually copied Prisma schema (should be auto-generated from YAML) - DBAL YAML schemas at /dbal/shared/api/schema/entities/ are source of truth - Prisma schema is auto-generated from YAML via codegen:prisma - Update CLAUDE.md and ARCHITECTURE.md to clarify this hierarchy Schema Layers: 1. /schemas/package-schemas/ - Package system architecture (top-level) 2. /dbal/shared/api/schema/entities/ - Database structure (DBAL source of truth) 3. /prisma/schema.prisma - Generated Prisma schema (derived artifact) Correct Workflow: - Edit YAML schemas at /dbal/shared/api/schema/entities/ - Run: npm --prefix dbal/development run codegen:prisma (generates Prisma) - Run: npm --prefix dbal/development run db:push (applies to DB) This prevents bot errors of manually editing Prisma schema. Co-Authored-By: Claude Haiku 4.5 --- ARCHITECTURE.md | 36 ++++++-- CLAUDE.md | 65 ++++++++------ dbal/development/prisma/schema.prisma | 121 -------------------------- 3 files changed, 67 insertions(+), 155 deletions(-) delete mode 100644 dbal/development/prisma/schema.prisma diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 9ad1cbae3..ba9cfeca7 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -177,15 +177,27 @@ export async function seedDatabase(dbal: DBALClient): Promise - Loads package-specific seed data - Uses entity operations, not raw adapter -### 5. Prisma Schema Ownership +### 5. Schema Ownership - YAML is Source of Truth ``` -dbal/development/prisma/schema.prisma +dbal/shared/api/schema/entities/ + ├── core/ + │ ├── user.yaml + │ ├── session.yaml + │ ├── ui_page.yaml + │ ├── workflow.yaml + │ └── package.yaml + ├── access/ + │ ├── credential.yaml + │ ├── page_config.yaml + │ └── component_node.yaml + └── packages/ + └── [package-specific entities] ``` -- DBAL owns and versions the database schema -- Moved from `/prisma/schema.prisma` (frontend location) -- Defines all entities (User, PageConfig, Component, etc.) -- Used by DBAL's PrismaClient +- **YAML schemas** are the source of truth for database structure +- Generated Prisma schema (from YAML via `gen_prisma_schema.js`) +- Prisma schema is at `/prisma/schema.prisma` (auto-generated) +- DBAL's PrismaClient uses the generated Prisma schema --- @@ -251,10 +263,10 @@ export async function POST() { The `/schemas` folder defines the structure; DBAL implements it: -| Schema | DBAL Implementation | -|--------|-------------------| +| Top-Level Schema | DBAL Implementation | +|------------------|-------------------| | `metadata_schema.json` | Package loading & exports in DBALClient.packages | -| `entities_schema.json` | Entity definitions reflected in Prisma schema, DBAL entity operations | +| `entities_schema.json` | Entity definitions reflected in DBAL YAML schemas | | `types_schema.json` | Type system in TypeScript types, used by entity operations | | `validation_schema.json` | Validation applied in entity create/update operations | | `components_schema.json` | Component metadata stored in database, accessible via API | @@ -266,6 +278,12 @@ The `/schemas` folder defines the structure; DBAL implements it: | `script_schema.json` | Scripts have access to DBAL operations and stdlib | | `stdlib_schema.json` | Standard library functions available to scripts | +| DBAL YAML Schemas | Prisma Implementation | +|-------------------|----------------------| +| `/dbal/shared/api/schema/entities/core/*.yaml` | Generated Prisma models (User, Session, etc.) | +| `/dbal/shared/api/schema/entities/access/*.yaml` | Generated Prisma models (Credential, PageConfig, etc.) | +| `/dbal/shared/api/schema/entities/packages/*.yaml` | Package-specific entity definitions | + --- ## Refactoring Roadmap diff --git a/CLAUDE.md b/CLAUDE.md index bedfad81f..7df6caa8a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -156,12 +156,14 @@ for (const user of seedData) { ### Mistake 4: Trying to Edit Prisma Schema Directly ```typescript -// ❌ WRONG +// ❌ WRONG - Prisma schema is auto-generated // Don't edit /prisma/schema.prisma directly +// Don't edit /dbal/development/prisma/schema.prisma -// ✅ CORRECT -// Schema is at /dbal/development/prisma/schema.prisma -// Edit there, then run: npm run db:generate && npm run db:push +// ✅ CORRECT - Edit YAML schemas instead +// 1. Edit: /dbal/shared/api/schema/entities/core/[entity].yaml +// 2. Generate Prisma: npm --prefix dbal/development run codegen:prisma +// 3. Push to DB: npm --prefix dbal/development run db:push ``` ### Mistake 5: Forgetting Database Schema Exists @@ -180,7 +182,8 @@ for (const user of seedData) { | File | Purpose | |------|---------| -| `/dbal/development/prisma/schema.prisma` | **Database schema** (DBAL owns this now) | +| `/dbal/shared/api/schema/entities/` | **YAML schemas** (source of truth for database structure) | +| `/prisma/schema.prisma` | Generated Prisma schema (auto-generated from YAML) | | `/dbal/development/src/core/client/factory.ts` | `getDBALClient()`, `useDBAL()` factories | | `/dbal/development/src/runtime/prisma-client.ts` | `getPrismaClient()` factory | | `/dbal/development/src/seeds/index.ts` | `seedDatabase()` orchestration | @@ -223,10 +226,10 @@ await seedDatabase(db) ``` ### Task 4: Modify Database Schema -1. Edit `/dbal/development/prisma/schema.prisma` -2. Run: `npm --prefix dbal/development run db:generate` -3. Run: `npm --prefix dbal/development run db:push` -4. Verify tables exist: Check `/prisma/prisma/dev.db` exists +1. Edit YAML schema: `/dbal/shared/api/schema/entities/core/[entity-name].yaml` +2. Generate Prisma schema: `npm --prefix dbal/development run codegen:prisma` +3. Push to database: `npm --prefix dbal/development run db:push` +4. Verify: Check `/prisma/prisma/dev.db` and `/prisma/schema.prisma` updated --- @@ -249,17 +252,25 @@ npm run test:e2e --- -## 📚 Source of Truth: /schemas Folder - -The `/schemas/package-schemas/` folder defines the **complete MetaBuilder architecture**: +## 📚 Multiple Layers of Schema +### 1. Package System Schemas (`/schemas/package-schemas/`) +Defines the complete MetaBuilder **package architecture**: - `metadata_schema.json` - Package structure -- `entities_schema.json` - Database models +- `entities_schema.json` - Database models from packages perspective - `types_schema.json` - Type system - `validation_schema.json` - Validation rules - Plus 14 more schemas defining components, API, events, jobs, etc. -**For architectural questions**, check `/schemas` first. +**For architectural and package design questions**, check `/schemas` first. + +### 2. DBAL YAML Schemas (`/dbal/shared/api/schema/entities/`) +Defines the actual **database structure** (source of truth): +- `/dbal/shared/api/schema/entities/core/*.yaml` - Core entities (User, Session, Workflow, etc.) +- `/dbal/shared/api/schema/entities/access/*.yaml` - Access control entities (Credential, PageConfig, etc.) +- `/dbal/shared/api/schema/entities/packages/*.yaml` - Package-specific entities + +**For database schema changes**, edit YAML files here, then regenerate Prisma schema. --- @@ -268,7 +279,8 @@ The `/schemas/package-schemas/` folder defines the **complete MetaBuilder archit ### Database Code - ❌ Don't use `prisma` client directly - ❌ Don't use old `getAdapter()` from frontend -- ❌ Don't edit `/prisma/schema.prisma` (it's at `/dbal/development/prisma/schema.prisma`) +- ❌ Don't edit `/prisma/schema.prisma` directly (it's auto-generated) +- ❌ Don't manually edit Prisma schema - edit YAML schemas instead - ❌ Don't hardcode seed data in TypeScript - ❌ Don't assume database tables exist (they might not until db:push is run) @@ -290,21 +302,23 @@ The `/schemas/package-schemas/` folder defines the **complete MetaBuilder archit - ✅ Read ARCHITECTURE.md before starting database work - ✅ Use `getDBALClient()` from `@/dbal` for all database access - ✅ Put seed data in `/seed/` folder or `/packages/*/seed/metadata.json` -- ✅ Run `npm --prefix dbal/development run db:push` if tables are missing +- ✅ Edit YAML schemas at `/dbal/shared/api/schema/entities/` for database changes +- ✅ Generate Prisma from YAML: `npm --prefix dbal/development run codegen:prisma` +- ✅ Run `npm --prefix dbal/development run db:push` to apply schema changes - ✅ Follow entity operations pattern (db.users.list(), etc.) -- ✅ Check /schemas folder for architectural questions -- ✅ Verify Prisma schema exists at `/dbal/development/prisma/schema.prisma` +- ✅ Check `/schemas/` folder for architectural/package design questions +- ✅ Check `/dbal/shared/api/schema/` folder for database schema questions --- ## 🔍 Refactoring Status **Phase 1 - DBAL Improvements** ✅ (COMPLETE) -- [x] Moved Prisma schema to DBAL ownership -- [x] Created Prisma client factory -- [x] Created DBAL client factory -- [x] Set up seed orchestration structure +- [x] Created Prisma client factory (`getPrismaClient`) +- [x] Created DBAL client factory (`getDBALClient`, `useDBAL`) +- [x] Set up seed orchestration structure (`seedDatabase`) - [x] Updated DBAL exports +- [x] Clarified YAML schemas as source of truth (Prisma is auto-generated) **Phase 2 - Next.js Cleanup** ⏳ (PENDING) - [ ] Delete duplicate adapter code from frontend @@ -324,7 +338,8 @@ See `DBAL_REFACTOR_PLAN.md` for detailed steps. ### Error: "The table `X` does not exist" ```bash -# Solution: Push the schema +# Solution: Generate Prisma schema from YAML, then push +npm --prefix dbal/development run codegen:prisma npm --prefix dbal/development run db:push ``` @@ -342,8 +357,8 @@ ls -la seed/database/ ### Tests fail with database errors ```bash -# Solution: Run database setup before tests -npm --prefix dbal/development run db:generate +# Solution: Generate schema from YAML, push to DB, then run tests +npm --prefix dbal/development run codegen:prisma npm --prefix dbal/development run db:push npm run test:e2e ``` diff --git a/dbal/development/prisma/schema.prisma b/dbal/development/prisma/schema.prisma deleted file mode 100644 index 2fff0e65a..000000000 --- a/dbal/development/prisma/schema.prisma +++ /dev/null @@ -1,121 +0,0 @@ -datasource db { - provider = "sqlite" -} - -generator client { - provider = "prisma-client-js" -} - -model User { - id String @id - username String @unique - email String @unique - role String - profilePicture String? - bio String? - createdAt BigInt - tenantId String? - isInstanceOwner Boolean @default(false) - passwordChangeTimestamp BigInt? - firstLogin Boolean @default(false) - @@index([tenantId]) - @@index([role]) -} - -model Credential { - username String @id - passwordHash String -} - -model Session { - id String @id - userId String - token String @unique - expiresAt BigInt - createdAt BigInt - lastActivity BigInt - ipAddress String? - userAgent String? - @@index([userId]) - @@index([expiresAt]) - @@index([token]) -} - -model PageConfig { - id String @id - tenantId String? - packageId String? - path String // Route pattern: /media/jobs, /forum/:id - title String - description String? - icon String? - component String? - componentTree String // JSON: full component tree - level Int - requiresAuth Boolean - requiredRole String? - parentPath String? - sortOrder Int @default(0) - isPublished Boolean @default(true) - params String? - meta String? - createdAt BigInt? - updatedAt BigInt? - @@unique([tenantId, path]) - @@index([tenantId]) - @@index([packageId]) - @@index([level]) - @@index([parentPath]) -} - -model ComponentNode { - id String @id - type String - parentId String? - childIds String // JSON: string[] - order Int - pageId String - @@index([pageId]) - @@index([parentId]) -} - -model ComponentConfig { - id String @id - componentId String - props String // JSON - styles String // JSON - events String // JSON - conditionalRendering String? - @@index([componentId]) -} - -model Workflow { - id String @id - tenantId String? - name String - description String? - nodes String // JSON: WorkflowNode[] - edges String // JSON: WorkflowEdge[] - enabled Boolean - version Int @default(1) - createdAt BigInt? - updatedAt BigInt? - createdBy String? - @@index([tenantId]) - @@index([enabled]) -} - -model InstalledPackage { - packageId String @id - tenantId String? - installedAt BigInt - version String - enabled Boolean - config String? - @@index([tenantId]) -} - -model PackageData { - packageId String @id - data String // JSON -}