Database Schema
Nenyax uses PostgreSQL with SQLAlchemy ORM and Alembic migrations.Dual User Table Design
Nenyax maintains two separate user-related tables. This is intentional:
Why two tables? The
users table acts as an auth-agnostic abstraction layer. If the auth provider changes (e.g., switching from Better Auth to Auth.js or a custom solution), only the sync logic needs updating — all business data, foreign keys, and queries remain untouched.
How they sync: When a user signs up via Better Auth and makes their first API request, the backend automatically creates a corresponding users row by reading from Better Auth’s "user" table. This auto-creation happens in verify_session_token() in backend/app/dependencies.py.
Organization auto-creation follows the same pattern: Better Auth manages the "organization" table, and the backend auto-creates a corresponding organizations row on first access (see _auto_create_org_from_ba() in dependencies.py).
Tables
instance_settings
Encrypted API key store (instance-level, not per-user). Managed via API Keys in the dashboard.users
Backend user records, auto-created from Better Auth on first authenticated request.agents
Voice agent configurations.
The
config JSON column stores the complete agent configuration:
voice_sessions
Call session records.transcripts
Per-message conversation logs.usage_events
Granular cost tracking events logged by the agent worker.agent_files
Files uploaded for custom agents, stored in MinIO.agent_file_versions
Version history for custom agent files.agent_containers
Docker container tracking for custom agents.coding_agent_conversations
Chat conversations with the coding agent (per agent, per user).coding_agent_messages
Individual messages within coding agent conversations.organizations
Multi-tenancy: top-level tenant for resource scoping. Auto-created from Better Auth’s"organization" table on first access.
org_members
Organization membership with roles.org_api_keys
Per-organization encrypted API key storage.user_api_keys
Per-user encrypted API key storage (legacy, migrating to org_api_keys).Migrations
Database migrations are managed by Alembic and run automatically on backend startup:Fresh Deployment Notes
On a fresh deployment, the backend runsalembic upgrade head on startup to create all tables. If migrations fail, the backend will not start — check the logs for migration errors.
Startup order matters: In Docker Compose, PostgreSQL must be healthy before the backend starts. The frontend can start independently since Better Auth tables are created via autoMigrate() in the frontend’s auth.ts.
Better Auth Tables
Better Auth manages its own tables ("user", "session", "account", "verification", "organization", "member", "invitation"). These are created automatically by the frontend’s auth configuration. Do not modify these tables via Alembic — they are owned by Better Auth.