Database Models
SQLAlchemy models live in app/models/ and inherit from a common Base. PostgreSQL is the backing store; migrations are managed with Alembic (alembic/).
Base Model
Every model inherits from Base, which provides:
id: UUID primary key (customGUIDtype wrapping PostgreSQL’suuid)nano_id: short human-readable unique identifiercreated_at/updated_at: timestamps,updated_atrefreshed on modificationdeleted_at: soft-delete marker withsoft_delete()/restore()helpers (see Soft Deletion)
UUID primary keys are used instead of sequential integers for security and distribution in a multi-tenant environment.
Core Models
- User —
email(unique),name,is_active,is_verified(admin/Polyphemus access gate),organization_id, anduser_settings(JSONB preferences, see User Settings). - Organization — a tenant in the multi-tenant architecture:
name,slug,is_active, plus domain and subscription fields. - Prompt — the input text sent to a model:
content,expected_response, and FKs to behavior, category, topic, and source. - Test — pairs a
Prompt(prompt_id) with metadata:priority,test_type_id,status_id, and owner/assignee. A test’s text comes from its linked prompt, not from its own columns. - TestSet — a named collection of tests (many-to-many with
Test):name,description,status_id. - Model — an AI model configuration:
name,model_name(provider identifier),model_type,endpoint, andprovider_type(FK to a type lookup). API keys are stored encrypted.
Relationships
- One-to-many: Organization → Users, User → Tests, Category → Prompts.
- Many-to-many: Test ↔ TestSet (via an association table), and any model using
TagsMixin↔ Tag (polymorphic, viaTaggedItem).
Mixins
Common behavior is composed from mixins in app/models/mixins.py:
OrganizationMixin/UserOwnedMixin— addorganization_id/user_idFKs for tenancy and ownership.ProjectMixin— nullableproject_id;NULLmeans org-wide (visible in every project).TagsMixin,CommentsMixin,FilesMixin,TasksMixin— polymorphic relationships keyed onentity_type+entity_id.EmbeddableMixin— vector-embedding and full-text search support; subclasses implementto_searchable_text().
Multi-tenancy
Models with org-scoped data carry an organization_id. Tenant filtering is applied automatically by SQLAlchemy event listeners and enforced at the database level with row-level security (PostgreSQL policies keyed on the app.current_organization / app.current_user session variables). See Multi-tenancy.