@zooly/app-db is the database access package for the main application. This package manages all database interactions using Drizzle ORM and enforces multi-tenant data access patterns.
NOTE - this package should never be imported in a client package.
@zooly/app-dbpackages/dbWe use Drizzle ORM for database access for several important reasons:
pgvector, which is crucial for applications that need vector similarity search and AI/ML featuresThese features make Drizzle the ideal choice for our use case, providing both type safety and the flexibility needed for complex database operations.
accountId parameteraccess package within the db packageThe package follows a strict access pattern:
packages/db/
├── src/
│ ├── access/ # Access functions (enforce tenant filtering)
│ │ ├── stripePayments.ts # Payment CRUD operations
│ │ ├── payOut.ts # Payout operations
│ │ ├── paymentShareTracking.ts # Revenue distribution tracking
│ │ ├── accountPayoutRoutes.ts # Payout route configuration
│ │ ├── accountPaymentSettings.ts # Payment settings
│ │ ├── paymentSystemLogs.ts # Audit logging
│ │ ├── ppu.ts # Purchase code management
│ │ └── accountAgents.ts # Agent relationships
│ ├── schema/ # Database schema definitions
│ │ ├── paymentEnums.ts # Payment-related enums
│ │ ├── stripePayments.ts # Payment transaction records
│ │ ├── payOut.ts # Payout records
│ │ ├── paymentShareTracking.ts # Revenue distribution tracking
│ │ └── ... # Other schemas
│ ├── db.ts # Database connection (not exported)
│ └── index.ts # Public API (only exports access functions)
Critical Design Principle: The raw database schema and database object are never exported from the db package. Instead, all database access is exclusively handled through access functions.
This design pattern serves two critical purposes:
Clean Separation: By keeping the database connection and schema definitions internal to the package, we maintain a clean separation of concerns. Other packages cannot directly access the database, ensuring all interactions go through the intended access layer.
Multi-Tenant Enforcement: Access functions require an accountId parameter and automatically apply tenant filtering. This ensures that all queries are multi-tenant aware by design—it's impossible to bypass tenant filtering when using the access functions.
The build will fail if you attempt to use an access function without providing the required accountId parameter, making multi-tenant support a compile-time guarantee rather than a runtime check.
See Multi-tenant Design in the introduction for more details on how this pattern is enforced across the platform.
All database operations are performed through access functions that:
accountId parameteraccountId is missing@zooly/types for shared typesDrizzle uses migrations to manage database schema changes. Here's how to work with them:
After making changes to your schema files in src/schema/, generate migration files:
npm run db:generate
This command:
After making changes to your schema files in packages/db/src/schema/, generate migration files:
cd packages/db
npm run db:generate
# or
set -a && source ../../../.env.local && npm run db:generate
This command:
packages/db/drizzle/Important: Migration SQL files are committed to git so they can be applied during production deployments.
For local development, apply migrations manually:
cd packages/db
npm run db:migrate:deploy
# or
set -a && source ../../../.env.local && npm run db:migrate:deploy
This will:
drizzle.__drizzle_migrations tableImportant: db:push should only be used in development. In production, always use db:generate followed by db:migrate to maintain proper migration history and version control.
Critical: Never develop against the remote server database. Running db:generate or db:migrate against a remote production or shared database can break it for other developers or users.
Always use a local database instance for development. See Database Setup for instructions on setting up a local database.
db:generate - Generate migration files from schema changesdb:migrate - Apply pending migrations to the databasedb:push - Push schema changes directly (development only)db:studio - Open Drizzle Studio for database inspection