Logical Architecture
The architecture of this package is designed to ensure consistency and eliminate typing issues between the application and the PostgreSQL engine. Every schema created here dictates the rules across the ecosystem.
Logical Modeling Flow
Section titled “Logical Modeling Flow”Creating and propagating a model in FRAME follows this deterministic pattern:
graph TD
A[Drizzle Schema] --> B(SQL Migrations)
A --> C(TypeScript Types)
A --> D(Zod Schemas / DTOs)
C --> E[Backend & Frontend]
D --> E
B --> F[(PostgreSQL)]
style A fill:#000000,stroke:#333,stroke-width:2px,color:#fff
Definition Conventions
Section titled “Definition Conventions”When structuring new models, we apply strict policies:
- Naming: Table names in lowercase snake_case.
- Better Auth Integration: The package includes native, extensible schemas required by the authentication framework (e.g.
users,sessions,accounts).
Model Creation Cycle
Section titled “Model Creation Cycle”- Define the Schema: Create the model declaration using Drizzle ORM syntax (column types, logical relations, indexes).
- Generate DTOs: Use complementary tools (such as
drizzle-zod) to automatically create Zod schemas (insert and select). - Export the Interface: Make the model, inferred types, and Zod validators available through the package
index.ts. - Automatic Migration: Run
drizzle-kitroutines to generate the equivalent SQL and write it into the migrations folder.
Contract Tests (Vitest)
Section titled “Contract Tests (Vitest)”Because this package has no dynamic state or network logic, its tests are direct and instrumental.
| Component | What we verify |
|---|---|
| Zod Schemas | That validation syntax catches illogical edge cases. |
| Pure Functions | Normalization logic or builders of partial SQL statements. |
| Generated DTOs | That type inference between Drizzle and TypeScript remains intact across refactors. |
Maintain standards using the local validation commands: vitest run for evaluation and vitest run --coverage for analytical metrics.
Tenant-owned models
Section titled “Tenant-owned models”Organization-owned product tables use organizationId as a required authorization boundary. A tenant-owned schema must include:
- a non-null foreign key to the Better Auth organization table;
- an index beginning with
organizationIdfor tenant-filtered queries; - relations from the organization to its owned records;
- tenant-safe composite foreign keys when one tenant-owned record references another.
For example, a cat references an owner by both ownerId and organizationId. PostgreSQL therefore rejects an owner relationship that crosses organization boundaries, even if application validation is bypassed.
Repository queries must still filter by organizationId; database constraints protect relationships but do not replace row-level query scoping.
Migration and seed requirements
Section titled “Migration and seed requirements”When converting existing data to tenant ownership:
- Add the organization column as nullable.
- Backfill it deterministically from an existing organization or parent relationship.
- Abort the migration if any rows remain unscoped.
- Make the column non-null and add foreign keys, composite constraints, and indexes.
- Update development seeds so parent records establish the organization identifier and dependent records inherit it.
The authorization boundary is defined in ADR 0003.