Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

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.

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

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).
  1. Define the Schema: Create the model declaration using Drizzle ORM syntax (column types, logical relations, indexes).
  2. Generate DTOs: Use complementary tools (such as drizzle-zod) to automatically create Zod schemas (insert and select).
  3. Export the Interface: Make the model, inferred types, and Zod validators available through the package index.ts.
  4. Automatic Migration: Run drizzle-kit routines to generate the equivalent SQL and write it into the migrations folder.

Because this package has no dynamic state or network logic, its tests are direct and instrumental.

ComponentWhat we verify
Zod SchemasThat validation syntax catches illogical edge cases.
Pure FunctionsNormalization logic or builders of partial SQL statements.
Generated DTOsThat 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.

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 organizationId for 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.

When converting existing data to tenant ownership:

  1. Add the organization column as nullable.
  2. Backfill it deterministically from an existing organization or parent relationship.
  3. Abort the migration if any rows remain unscoped.
  4. Make the column non-null and add foreign keys, composite constraints, and indexes.
  5. Update development seeds so parent records establish the organization identifier and dependent records inherit it.

The authorization boundary is defined in ADR 0003.