Database
Supported Databases
Section titled “Supported Databases”Parako.ID supports three database backends. Choose based on your deployment needs:
| Feature | SQLite | MongoDB | PostgreSQL |
|---|---|---|---|
| Setup complexity | Zero — file-based | Moderate | Moderate |
| ORM | Prisma | Mongoose | Prisma |
| Multi-tenancy | Not supported | Mongoose tenant plugin | Row-level security (RLS) |
| Clustering (PM2) | Single instance only | Multiple instances | Multiple instances |
| Best for | Development, small deployments | Production, multi-tenancy | Production, strict data integrity |
Set the database via the STORAGE_ADAPTER environment variable in .env:
STORAGE_ADAPTER=sqlite # DefaultSTORAGE_ADAPTER=mongodbSTORAGE_ADAPTER=postgresqlSQLite (Default)
Section titled “SQLite (Default)”SQLite requires no external database server. Data is stored in a single file.
Configuration
Section titled “Configuration”STORAGE_ADAPTER=sqliteSTORAGE_SQLITE_PATH=./data/parako.db# Generate Prisma client for SQLiteyarn db:generate
# Push schema to database (creates file if needed)yarn db:push
# Open Prisma Studio to inspect datayarn db:studioConstraints
Section titled “Constraints”- Single process only — You must set
PM2_INSTANCES=1in production. SQLite does not support concurrent writes from multiple processes. The application enforces this at startup and refuses to start if violated. - No multi-tenancy — Multi-tenancy requires MongoDB or PostgreSQL.
- WAL mode — Parako.ID enables Write-Ahead Logging (WAL) for better read concurrency.
Backups
Section titled “Backups”For continuous SQLite backups, see SQLite Backup with Litestream.
MongoDB
Section titled “MongoDB”MongoDB is the most battle-tested option, with full support for multi-tenancy via a global Mongoose tenant plugin.
Configuration
Section titled “Configuration”STORAGE_ADAPTER=mongodbSTORAGE_MONGODB_URI=mongodb://localhost:27017/parakoNo schema push is needed — Mongoose creates collections automatically on first use.
# Start the applicationyarn devMulti-Tenancy
Section titled “Multi-Tenancy”When MULTI_TENANCY_ENABLED=true, a global Mongoose plugin automatically scopes all queries by tenant_id. This provides transparent data isolation without changes to your query code.
Special tenants:
| Tenant | Purpose |
|---|---|
default | Used when no tenant is resolved |
_ops | Internal operations tenant |
_platforms | Platform administration (SaaS control plane) |
Collections
Section titled “Collections”Parako.ID creates these MongoDB collections:
Application data:
users— User accounts and profilesactivities— Audit log entriessettings— Application configuration (versioned)socialintegrations— Social login provider configurationstenants— Tenant registry (not tenant-scoped)jwks_keys— JWKS signing keystenant_settings_overrides— Per-tenant configuration overrides
OIDC adapter collections (created by node-oidc-provider, PascalCase names):
Session,Grant,Client,AccessToken,AuthorizationCode,RefreshToken,DeviceCode,ClientCredentials,InitialAccessToken,RegistrationAccessToken,Interaction,ReplayDetection,PushedAuthorizationRequest,BackchannelAuthenticationRequest
PostgreSQL
Section titled “PostgreSQL”PostgreSQL uses Prisma as its ORM and supports row-level security (RLS) for multi-tenancy.
Configuration
Section titled “Configuration”STORAGE_ADAPTER=postgresqlSTORAGE_POSTGRESQL_URL=postgresql://user:password@localhost:5432/parako# Generate Prisma client for PostgreSQLyarn db:generate:pg
# Run migrationsyarn db:migrate
# Deploy migrations (production, no prompts)yarn db:migrate:deploy
# Open Prisma Studioyarn db:studioTables
Section titled “Tables”Both PostgreSQL and SQLite use the same Prisma schema with these tables:
users— User accounts with MFA, WebAuthn, and recovery sub-tablesuser_mfa,user_mfa_totp,user_mfa_email_otp— MFA configurationuser_webauthn_credentials— WebAuthn/FIDO2 passkeysuser_recovery,user_backup_codes,user_security_questions— Account recoveryuser_notification_prefs— Notification preferencesactivities,activity_actors,activity_targets,activity_devices— Audit logsettings— Application configuration (versioned)social_integrations— Social login provider configurationstenants— Tenant registrytenant_settings_overrides— Per-tenant configuration overridesjwks_keys— JWKS signing keyssessions— Session storeoidc_store— OIDC tokens, grants, and interactions (single table for all OIDC models)
SSL Configuration
Section titled “SSL Configuration”For production PostgreSQL with SSL:
STORAGE_POSTGRESQL_URL=postgresql://user:password@host:5432/parako?sslmode=requireMulti-Tenancy
Section titled “Multi-Tenancy”PostgreSQL multi-tenancy uses a Prisma extension (src/db/extensions/tenant.extension.ts) that injects SET LOCAL app.tenant_id and automatically filters all queries by tenant_id. Row-level security (RLS) policies provide a belt-and-suspenders safety net at the database level. Each table includes a tenant_id column.
OIDC Storage Adapter
Section titled “OIDC Storage Adapter”The OIDC storage adapter controls where tokens, sessions, grants, and other OIDC artifacts are persisted. By default, it uses the same backend as your primary database, but you can separate them.
# Use Redis for OIDC storage while keeping MongoDB for application dataSTORAGE_ADAPTER=mongodbOIDC_STORAGE_ADAPTER=redisAvailable options:
| Adapter | Storage type | Best for |
|---|---|---|
sqlite | Persistent (file) | Development |
mongodb | Persistent | Production |
postgresql | Persistent | Production |
redis | Ephemeral (in-memory) | High-throughput, clustered deployments |
When using Redis for OIDC storage, configure the Redis connection:
REDIS_HOST=localhostREDIS_PORT=6379REDIS_PASSWORD=your_redis_passwordREDIS_DATABASE=0Redis provides faster token lookups at the cost of data loss on restart. This is acceptable for OIDC tokens since clients can re-authenticate, but you should use a persistent store if session continuity across restarts is important.
Repository Pattern
Section titled “Repository Pattern”Parako.ID abstracts database access through the repository pattern:
repositories/├── interfaces/ # Database-agnostic contracts│ ├── user.repository.interface.ts│ ├── activity.repository.interface.ts│ └── ...├── mongoose/ # MongoDB implementations│ ├── user.repository.ts│ └── ...└── prisma/ # SQLite/PostgreSQL implementations ├── user.repository.ts └── ...The application selects the correct repository implementation at startup based on STORAGE_ADAPTER. This means switching databases requires only changing the environment variable and running the appropriate setup commands — no application code changes.