Site

The editable SQL lives in domain modules under database/schema/ and native integrations under database/overlays/. database/manifest.json defines exact assembly order. Run pnpm run db:schema:check after source edits. Init, local start/reset, bootstrap and audits assemble the complete core and CMS batches in memory; exported files are optional.

The same common sources assemble for Supabase or Neon and for Supabase Auth or Better Auth. Provider-native behavior is added only by explicit overlays. This fresh-installation workflow does not support upgrades of populated deployments. See SQL Sources & Installation for composition selection, domain ownership, manual installation and error mapping.

  1. Create a Supabase project

    Go to supabase.com and create a new project.

  2. Get your credentials

    Navigate to Settings > API and copy:

    • Project URL
    • Publishable key
    • Secret key
  3. Initialize the database

    Run pnpm run init for a fresh installation. For the manual SQL step, first run pnpm run db:schema:build and pnpm run db:schema:check-export, then execute the complete generated core file followed by the CMS file. Follow SQL Sources & Installation; source fragments must not be run individually.

Schema Overview

The database schema is organized into several functional areas. Click on each table to see detailed field information.

RLS follows the account-centric model: server-side Prisma transactions set the verified appUserId in app.actor_id, and policies scope reads and attributed writes through private.current_actor_id() plus Account memberships. This prevents one workspace member from forging another member's chat message or document ownership without coupling business SQL to a provider-native subject. Runtime, worker, maintenance and platform-administration credentials are distinct and least-privileged.

Data API Grants

Business persistence is not exposed through the Supabase Data API. The Supabase database overlay explicitly fences anon, authenticated, and service_role from common business tables and functions; the server uses the same shared Prisma capabilities as a Neon composition. Supabase-native Auth, Storage, and Realtime grants remain isolated in their own overlays.

RLS is not a substitute for Data API grants

When you add a new public object, keep common capabilities in its owning source and update the Supabase Data API deny overlay if required. Native client access must be an explicit, reviewed exception in a provider overlay. Fresh projects and resets must not depend on dashboard defaults.

Role Expected surface
anonNo common business-table or business-function privileges.
authenticatedNo common business-table or business-function privileges; authenticated product traffic uses the verified application actor through shared Prisma.
service_roleNo portable business-runtime bypass. It remains confined to explicit Supabase-native Auth or Storage administration.

For every new function, revoke default EXECUTE and grant only the owning portable capability. Do not add browser Data API access as a shortcut around a shared Prisma repository.

Users & Auth
Multi-Tenancy
Billing & Credits
AI & Chat
CMS
Jobs System

profiles User Profiles

Application-owned profile data keyed by the canonical private.app_users identity. It is created or revalidated by the explicit server-side application bootstrap after provider verification, never as an auth.users business trigger side effect.

Field Type Description
iduuid (PK)References private.app_users(id)
emailtextApplication profile email synchronized after provider verification
full_nametextFull display name
first_nametextFirst name (from onboarding)
last_nametextLast name (from onboarding)
birthdaydateOptional birthday
phonetextOptional phone number
avatar_urltextProfile picture URL (OAuth or upload)
is_adminbooleanPlatform super-admin flag
is_disabledbooleanAccount disabled by admin
onboarding_completedbooleanHas completed onboarding flow
newsletter_subscribedbooleanNewsletter subscription status
scheduled_deletion_attimestamptzGDPR deletion scheduled date
created_attimestamptzProfile creation timestamp
updated_attimestamptzLast update timestamp
Auto-Admin Assignment

The shared administrator check promotes an active, enabled user when their provider-verified email matches both the application identity and app_settings.admin_email. Promotion and audit commit together.

app_settings Application Settings

Global key-value settings for the application.

Field Type Description
keytext (PK)Setting key (e.g., 'admin_email')
valuetextSetting value
created_attimestamptzCreation timestamp
updated_attimestamptzLast update timestamp

accounts Accounts (Core)

The central entity of the system. All resources are attached to accounts, not users directly.

Field Type Description
iduuid (PK)Unique account identifier
typeenum'personal' | 'workspace'
nametextAccount display name
slugtext (unique)URL-friendly identifier (workspaces only)
owner_user_iduuid (FK)References private.app_users(id)
credits_balanceintegerCurrent credit balance
max_membersintegerAdditional administrative member ceiling (null = commercial limit only)
billing_emailtextProvider-owned billing contact
created_attimestamptzCreation timestamp
updated_attimestamptzLast update timestamp

billing_customers Provider Customer Registry

Service-only mapping between an Account and each payment provider customer, isolated by test/live environment.

Field Type Description
iduuid (PK)Unique registry identifier
account_iduuid (FK)References accounts(id); cascades on deletion
providerenumStripe, Lemon Squeezy, or Paddle
livemodebooleanSeparates test and production identities
external_customer_idtextProvider-owned customer identifier

roles Dynamic Roles

Role definitions with permissions. System roles (owner, admin, member) are protected.

Field Type Description
iduuid (PK)Unique role identifier
nametextDisplay name (e.g., "Administrator")
slugtext (unique)Identifier slug (e.g., "admin")
descriptiontextRole description
permissionsjsonbJSONB array of permission strings (default [])
is_systembooleanProtected system role (cannot delete)
colortextBadge color (e.g., "blue", "amber")
icontextIcon name (e.g., "crown", "shield")
display_orderintegerSort order for display
created_attimestamptzCreation timestamp
updated_attimestamptzLast update timestamp

Available Permissions: account:update, account:delete, billing:view, billing:manage, members:view, members:invite, members:remove, members:update_role, api_keys:view, api_keys:create, api_keys:delete, ai:use. Roles store these as a JSONB array of strings; is_system roles (owner/admin/member) cannot be deleted.

memberships User-Account Relationships

Links users to accounts with their assigned role. Unique constraint: (account_id, user_id)

Field Type Description
iduuid (PK)Unique membership identifier
account_iduuid (FK)References accounts(id)
user_iduuid (FK)References profiles(id)
roleenumLegacy: 'owner' | 'admin' | 'member'
role_slugtext (FK)References roles(slug) - dynamic roles
created_attimestamptzMembership creation
updated_attimestamptzLast update

invitations Workspace Invitations

Pending invitations to join a workspace. Expire after 7 days by default.

Field Type Description
iduuid (PK)Unique invitation identifier
account_iduuid (FK)References accounts(id)
emailtextInvitee email address
role_slugtext (FK)Role to assign on acceptance
invited_byuuid (FK)References profiles(id)
tokentext (unique)Secure invitation token
statusenum'pending' | 'accepted' | 'expired' | 'revoked'
expires_attimestamptzExpiration (default: 7 days)
created_attimestamptzCreation timestamp

subscriptions Provider-neutral Subscriptions

Stores the normalized current and historical subscription state for Stripe, Lemon Squeezy, Paddle, and internal free plans.

Field Type Description
iduuid (PK)Local subscription ID
account_iduuid (FK)References accounts(id)
billing_customer_iduuid (FK, nullable)Matching provider customer identity; null only for internal plans
providerbilling_providerinternal, stripe, lemon_squeezy, or paddle
livemodebooleanSeparates sandbox/test identities from production identities
external_subscription_idtext (nullable)Provider subscription identifier; unique per provider and environment
external_price_idtext (nullable)Validated provider catalogue binding snapshot
plan_idtextPlan ID from config/pricing.ts
statusbilling_subscription_statusNormalized lifecycle state shared by every provider
provider_statustext (nullable)Sanitized provider-native state for service diagnostics
currencytextValidated ISO 4217 currency
billing_intervaltextmonthly or yearly
current_period_starttimestamptzBilling period start
current_period_endtimestamptzBilling period end
trial_start / trial_endtimestamptzNormalized trial bounds
cancel_at_period_endbooleanWill cancel at period end
cancel_attimestamptzScheduled cancellation timestamp
canceled_attimestamptzCancellation timestamp
paused_at / resumed_attimestamptzPause/resume audit timestamps
billing_holdbooleanInternal risk or debt hold, paired with a stable reason code
superseded_attimestamptzNull only for the account's unique current subscription
last_provider_occurred_attimestamptzProvider event ordering guard
last_provider_event_idtextDeterministic event tie-breaker, service-only
created_attimestamptzCreation timestamp
updated_attimestamptzLast update timestamp
Plans are in Code, Not Database

The plan_id references plans defined in config/pricing.ts. Plan details (price, features, credits) are NOT stored in the database.

payments One-Time Payments

Provider-neutral financial proofs for subscriptions, credit packs, and licenses. Every row belongs to an Account; provider identifiers and financial details are service-only while members receive a restricted safe projection.

Field Type Description
iduuid (PK)Payment identifier
account_iduuid (FK)References accounts(id)
subscription_iduuid (FK, nullable)Required for purchase_kind='subscription'; references subscriptions(id)
checkout_attempt_iduuid (FK, nullable)Optional link to the initiating checkout attempt
providerenum'internal' | 'stripe' | 'lemon_squeezy' | 'paddle'
livemodebooleanSeparates test and live financial identities
purchase_kindenum'subscription' | 'credit_pack' | 'license'
offer_idtextStable configured plan, credit-pack, or license identifier
statusenum'pending' | 'paid' | 'failed' | 'partially_refunded' | 'refunded' | 'disputed' | 'reversed'
amount_centsbigintGross amount in minor currency units
tax_amount_centsbigintTax included in the provider proof
discount_amount_centsbigintDiscount reported by the provider
refunded_amount_centsbigintCumulative refunded amount
provider_fee_centsbigint (nullable)Provider fee when reconciliation supplies it
merchant_net_centsbigint (nullable)Merchant net amount when reconciliation supplies it
currencytextUppercase ISO currency code
external_checkout_idtext (nullable)Provider checkout identifier; unique per provider and mode
external_transaction_idtext (nullable)Provider transaction or payment-intent identifier; unique per provider and mode
external_invoice_idtext (nullable)Subscription invoice identifier; unique per provider and mode
external_payment_idtext (nullable)Additional provider payment identifier; unique per provider and mode
payment_proof_keytext (unique)Canonical test/live-scoped financial idempotency proof
provider_period_starttimestamptz (nullable)Provider entitlement-period start
provider_period_endtimestamptz (nullable)Provider entitlement-period end
paid_attimestamptz (nullable)Required for paid or post-payment states
metadatajsonbBounded internal reconciliation and entitlement pointers
created_at / updated_attimestamptzRecord lifecycle timestamps

licenses One-Time Licenses

Records of license purchases for one-time payment access (alternative to subscriptions).

Field Type Description
iduuid (PK)License identifier
account_iduuid (FK)References accounts(id) (ON DELETE CASCADE)
product_idtextProduct ID from config/pricing.ts
license_typeenum'lifetime' | 'yearly' | 'monthly' | 'custom'
statusenum'active' | 'expired' | 'revoked'
payment_iduuid (unique FK)Provider-neutral normalized payment. The composite (payment_id, account_id) foreign key keeps payment and license ownership aligned; amount, currency, provider, environment, and external transaction identity live on payments.
purchased_byuuid (FK)References private.app_users(id) — application actor who initiated the purchase
starts_attimestamptzLicense start date (default now())
expires_attimestamptzExpiration date (NULL for lifetime)
featuresjsonbFeature flags snapshot at purchase (e.g., {"api_access": true})
credits_includedintegerOne-time credits granted on purchase
credits_grantedbooleanWhether the one-time credits have been added
limitsjsonbResource limits snapshot (e.g., {"projects": 10})
metadatajsonbAdditional license data
created_attimestamptzPurchase timestamp
updated_attimestamptzLast update timestamp
Billing Models

Configure via billingModel in config/app.ts: 'subscription' | 'one_time' | 'hybrid'. Hybrid mode allows both subscriptions and licenses.

credit_transactions Credit Ledger

Audit trail of all credit changes. Immutable.

Field Type Description
iduuid (PK)Transaction identifier
account_iduuid (FK)References accounts(id)
amountintegerChange amount (+ = add, - = deduct)
balance_afterintegerBalance after transaction
reasontextHuman-readable reason
sourceenum (credit_source)'subscription_refill' | 'one_time_purchase' | 'admin_adjustment' | 'ai_usage' | 'refund' | 'bonus' | 'license_purchase' | 'referral'. Plus webhook audit-trail values used for zero-amount ledger rows: 'payment_method_added', 'payment_method_removed', 'payment_failed', 'dispute_created', 'dispute_closed', 'checkout_expired', 'async_payment_failed', 'trial_ending', 'payment_action_required'.
metadatajsonbAdditional transaction data
created_attimestamptzTransaction timestamp

chat_sessions Chat Sessions

Conversation sessions with optional agent assignment.

Field Type Description
iduuid (PK)Session identifier
account_iduuid (FK)References accounts(id)
user_iduuid (FK)References profiles(id)
titletextSession title (auto-generated or user-defined)
agent_idtextDefault agent for this session (e.g., 'chat')
created_attimestamptzSession creation
updated_attimestamptzLast activity timestamp

chat_messages Chat Messages

Individual messages within a session.

Field Type Description
iduuid (PK)Message identifier
session_iduuid (FK)References chat_sessions(id)
account_iduuid (FK)References accounts(id)
roleenum'user' | 'assistant' | 'system'
contenttextMessage content
tokens_usedintegerTokens consumed by this message
agent_idtextAgent that generated response
model_idtextResolved LLM model used (e.g., 'gpt-5.6-terra')
created_attimestamptzMessage timestamp

ai_requests AI Request Logs

Detailed logging of all AI API calls for observability and cost tracking.

Field Type Description
iduuid (PK)Request identifier
account_iduuid (FK)References accounts(id)
user_iduuid (FK)References profiles(id) (who made the request)
agent_typetextAgent used (e.g., 'chat', 'code-assistant')
modeltextResolved LLM model (e.g., 'gpt-5.6-luna')
input_tokensintegerInput tokens consumed
output_tokensintegerOutput tokens generated
total_tokensintegerComputed: input + output (generated)
cost_centsnumericCalculated cost in cents
latency_msintegerResponse time in milliseconds
statustext'success' | 'error'
error_messagetextError details (if status is 'error')
metadatajsonbAdditional request metadata
created_attimestamptzRequest timestamp

cms_pages CMS Pages

Multi-locale content pages. All locales stored in JSONB fields per row.

Canonical CMS locale keys are the BCP 47 ids from i18n/config.ts (fr-FR, en-US, en-CA, fr-CH). The app still reads legacy language-only keys (fr, en) through localized helpers for backwards compatibility, while admin writes and schema seeds normalize content back to the configured BCP 47 keys.

Field Type Description
iduuid (PK)Page identifier
slugtext (unique)URL slug (e.g., 'about', 'blog/my-post')
titlejsonb{"fr-FR": "...", "fr-CH": "...", "en-US": "...", "en-CA": "..."}
contentjsonbHTML/Markdown content per locale
excerptjsonbShort description (for blog posts)
featured_imagetextFeatured image URL
category_iduuid (FK)Blog category reference (ON DELETE SET NULL)
publishedjsonbPublished status per locale
seo_titlejsonbSEO title override
seo_descriptionjsonbMeta description
seo_noindexjsonbNoindex flag per locale
created_attimestamptzCreation timestamp
updated_attimestamptzLast update

cms_blocks CMS Blocks

Reusable content snippets (promo bars, banners, etc.).

Field Type Description
iduuid (PK)Block identifier
keytext (unique)Block key (e.g., 'promo_bar')
contentjsonbBlock content per locale
created_attimestamptzCreation timestamp
updated_attimestamptzLast update

blog_categories Blog Categories

Multi-locale blog categories with color coding and display ordering.

Field Type Description
iduuid (PK)Category identifier
slugtext (unique)URL-safe identifier
namejsonbMulti-locale name {"fr-FR": "...", "fr-CH": "...", "en-US": "...", "en-CA": "..."}
descriptionjsonbMulti-locale description
colortextBadge color (slate, amber, blue, green, red, purple, pink, indigo, teal, orange)
display_orderintegerSort order for display
created_attimestamptzCreation timestamp
updated_attimestamptzLast update

blog_tags Blog Tags

Multi-locale blog tags for content labeling.

Field Type Description
iduuid (PK)Tag identifier
slugtext (unique)URL-safe identifier
namejsonbMulti-locale name {"fr-FR": "...", "fr-CH": "...", "en-US": "...", "en-CA": "..."}
created_attimestamptzCreation timestamp
updated_attimestamptzLast update

blog_post_tags Blog Post Tags (Join Table)

Many-to-many relationship between blog posts and tags.

Field Type Description
iduuid (PK)Row identifier
page_iduuid (FK)References cms_pages (ON DELETE CASCADE)
tag_iduuid (FK)References blog_tags (ON DELETE CASCADE)
created_attimestamptzCreation timestamp

jobs Job Definitions

Background job configurations for scheduled and manual tasks.

Field Type Description
iduuid (PK)Job identifier
nametext (unique)Job name
descriptiontextJob description
executorenum'edge' | 'internal'
function_nametextHandler function name
cron_expressiontextCron schedule (e.g., '0 3 * * *')
is_enabledbooleanJob enabled status
notify_on_failurebooleanEmail admin when job fails
timeout_secondsintegerExecution timeout
max_retriesintegerMax retry attempts
last_run_attimestamptzLast execution time
last_run_statusenumLast run result
run_countintegerTotal run count
success_countintegerSuccessful runs
failure_countintegerFailed runs
configjsonbJob-specific configuration

job_runs Job Execution History

Records of job executions with output and error logging.

Field Type Description
iduuid (PK)Run identifier
job_iduuid (FK)References jobs(id)
statusenum'pending' | 'running' | 'success' | 'failed'
triggered_byenum'cron' | 'manual' | 'webhook' | 'api'
started_attimestamptzExecution start
completed_attimestamptzExecution end
duration_msintegerExecution duration
outputjsonbJob output/result
errortextError message if failed

api_keys B2B API Keys

Hashed API keys for programmatic access.

Field Type Description
iduuid (PK)Key identifier
account_iduuid (FK)References accounts(id)
nametextKey display name
key_prefixtextVisible prefix (e.g., 'sk_live_abc...')
key_hashtextHashed key value
scopestext[]Permitted API scopes
last_used_attimestamptzLast usage timestamp
expires_attimestamptzExpiration date (optional)
is_activebooleanKey active status

user_consents GDPR Consents

User consent records for GDPR compliance. Logged-in consent changes are written server-side via POST /api/user/consents so IP/user-agent capture, CSRF checks, rate limiting, and the append-only evidence capability stay out of browser code.

Field Type Description
iduuid (PK)Consent identifier
user_iduuid (FK)References private.app_users(id)
typeenum'marketing' | 'analytics' | 'necessary'
acceptedbooleanConsent status
ip_addressinetIP when consent given
accepted_attimestamptzConsent timestamp

account_deletion_requests GDPR Deletion Queue

Pending account deletion requests with 30-day grace period.

Field Type Description
iduuid (PK)Request identifier
account_iduuid (FK)References accounts(id)
requested_byuuid (FK)References private.app_users(id)
statusenum'pending' | 'processing' | 'completed' | 'cancelled' | 'failed'
scheduled_fortimestamptzDeletion date (default: now + 30 days)
completed_attimestamptzActual deletion timestamp
cascade_membersbooleanWhen true, the deletion job also erases every member's application identity and asks the selected Auth adapter to delete each provider subject. It is set only by the personal-account deletion workflow for the owner's B2B cascade. A column-lock trigger keeps it immutable outside the dedicated deletion capability; a member or ordinary runtime request cannot force another member's deletion.
processor_statusjsonbPer-processor and per-payment-resource deletion proof, including mutation_started, provider_unknown, and verified checkpoints.
processor_errorsjsonbRedacted processor failures that blocked completion.
error_messagetextShort redacted summary when the request is marked failed.
retry_countintegerNumber of failed processor attempts.
processing_lease_tokenuuidCurrent worker fencing token; populated only while status='processing'.
processing_lease_expires_attimestamptzLease deadline renewed by fenced checkpoints; an expired request may be reclaimed with a new token.

admin_logs Admin Audit Logs

Admin action audit trail for compliance and debugging.

Field Type Description
iduuid (PK)Log entry identifier
admin_user_iduuid (FK)Admin who performed action
actiontextAction performed (e.g., 'user.disable')
target_typetextEntity type (e.g., 'user', 'subscription')
target_iduuidAffected entity ID
detailsjsonbAction details and changes
ip_addressinetAdmin IP address
created_attimestamptzAction timestamp

in_app_notifications In-App Notifications

User notifications with read status tracking. Column-lock trigger restricts user updates to the read column only.

Field Type Description
iduuid (PK)Notification identifier
user_iduuid (FK)References profiles(id)
account_iduuid (FK)NOT NULL — References accounts(id) (ON DELETE CASCADE)
typeenum'info' | 'success' | 'warning' | 'error' | 'system'
titletextNotification title (max 200 chars)
messagetextNotification body (max 1000 chars)
linktextOptional relative URL for navigation
readbooleanRead status (default: false)
created_attimestamptzCreation timestamp

changelog_entries Changelog Entries

Public changelog with multi-locale JSONB content. Supports versioning and type badges.

Field Type Description
iduuid (PK)Entry identifier
versiontextVersion label (e.g., '1.2.0')
typeenum'feature' | 'improvement' | 'fix' | 'breaking' | 'security'
titlejsonbMulti-locale title ({ "fr-FR": "...", "fr-CH": "...", "en-US": "...", "en-CA": "..." })
contentjsonbMulti-locale markdown content
publishedbooleanPublish status (global, not per-locale)
published_attimestamptzPublication date (for ordering)
created_attimestamptzCreation timestamp
updated_attimestamptzLast update timestamp

documents RAG Documents

Uploaded documents for RAG chat. Tracks processing status, file metadata, and chunk count.

Field Type Description
iduuid (PK)Document identifier
account_iduuid (FK)References accounts(id)
user_iduuid (FK)References profiles(id) (uploader)
nametextOriginal filename
storage_pathtextOpaque UUID-based object key for the selected Storage adapter
file_typetextFile type
file_sizeintegerFile size in bytes
statusenum'pending' | 'processing' | 'ready' | 'error'
chunk_countintegerNumber of generated chunks
error_messagetextProcessing error details
created_attimestamptzUpload timestamp

document_chunks Document Chunks (Vector)

Text chunks with vector embeddings for similarity search. Uses pgvector vector(1536) with HNSW index. Embedding model is configurable in config/ai.ts (default: text-embedding-3-small).

Field Type Description
iduuid (PK)Chunk identifier
document_iduuid (FK)References documents(id) (CASCADE delete)
contenttextChunk text content
embeddingvector(1536)Embedding vector (model configurable via embeddingConfig.defaultModel)
chunk_indexintegerPosition within document
metadatajsonbChunk metadata (source, chunk index, total, embedding_model)
created_attimestamptzCreation timestamp

Database Functions

The schema includes several PostgreSQL functions for common operations.

Trigger Functions

Supabase Auth does not install an auth.users bootstrap trigger. Verified callbacks explicitly and idempotently finalize the provider principal into the canonical application identity before profile, Account, membership or consent work.

Function Trigger Description
update_job_stats() job_runs_update_stats Updates job statistics after each run completes.

Credit Functions

Function Parameters Description
add_credits() p_account_id uuid, p_amount integer, p_source credit_source, p_reason text default null, p_metadata jsonb default '{}'::jsonb Atomically adds credits to an account, writes the matching credit_transactions ledger row, and returns the new balance. Executable only by the bounded portable ledger capabilities; Data API roles have no access.
decrement_credits() p_account_id uuid, p_amount integer, p_reason text default null, p_metadata jsonb default '{}'::jsonb, p_source credit_source default 'ai_usage' Atomically deducts credits, writes the ledger row, and returns the new balance. Raises a CHECK (credits_balance >= 0) violation when the result would go negative — wrap calls in try/catch. Executable only by the bounded portable ledger capabilities.

These functions ensure atomic credit operations. Never update the credits_balance column directly; always use these RPC functions to maintain data integrity and the audit trail.

Utility Functions

Function Returns Description
get_user_accounts(user_uuid) setof accounts Returns all accounts a user belongs to
is_account_member(account_uuid, user_uuid) boolean Check if user belongs to an account
get_user_role_slug(account_uuid, user_uuid) text Get user's role in an account
user_has_permission(account_id, permission) boolean Check if current user has a specific permission
user_belongs_to_account(account_id) boolean RLS helper - check membership (security definer)
user_is_account_admin(account_id) boolean RLS helper - check if owner/admin (security definer)
has_valid_license(p_account_id) boolean True if the account has any active, non-expired license. SECURITY INVOKER, callable from authenticated context.
get_active_license(p_account_id) setof licenses Returns the current active license row (if any) for the account.
mark_expired_licenses() integer Batch-marks expires_at < now() licenses as 'expired'. Called by the check-license-expiration daily job. Returns row count.
grant_license_credits(p_license_id) integer Grants the license's credits_included via add_credits (source 'license_purchase') and flips credits_granted = true. Idempotent on the boolean flag and restricted to the license worker capability.
generate_referral_code(p_account_id, p_length, p_alphabet) text Idempotent: returns the existing active code for the account, or generates a new one with collision-retry through the actor-scoped referral runtime.
apply_referral_code(...) uuid Attribution entry point — runs self-referral / same-owner / one-per-lifetime / IP rate-limit guards and inserts the referrals row. Its optional historical-payment reconciliation flag is enabled only by trusted cookie attribution, never by manual code application. Actor and worker entry points use separate portable capabilities.
qualify_referral(p_referral_id, p_trigger, p_referrer_credits, p_referred_credits, p_qualifying_payment_id) void Calls add_credits on both sides with source='referral'. Paid triggers require a positive, non-fully-refunded normalized payment belonging to the referred Account; subscription rewards additionally require purchase_kind='subscription'. Restricted to the referral worker capability.
qualify_referral_for_account(p_referred_account_id, p_trigger, p_referrer_credits, p_referred_credits, p_qualifying_payment_id) uuid / null Account-locked webhook entry point. Qualifies a pending referral with the exact payment and returns the referrer Account id for targeted cache invalidation. Restricted to the billing/referral worker capability.
reverse_referral_for_payment(p_payment_id, p_reason) uuid / null Reverses only the reward whose qualifying_payment_id matches the supplied payment, then returns the referrer Account id. Restricted to the billing/referral worker capability.
reverse_referral(p_referral_id, p_reason) void Per-side guarded decrement_credits — an insufficient balance on one side doesn't abort the other (details written to metadata). Restricted to the referral worker capability.
purge_error_logs(p_retention_days) integer Deletes error_logs rows older than the supplied retention window. Called by the daily purge-error-logs job through the isolated maintenance credential.
+ 12 affiliate RPCs — Application workflow, link creation, click recording, attribution, conversion ledger, reversal, hold-period maturation, and aggregate stats. Actor, public-attribution, worker and platform-admin operations use separate portable capabilities. See .claude/rules/affiliates.md for the full registry.

Entity Relationships

Provider principal (provider + issuer + subject) │ explicit identity resolution ▼ private.app_users ◄── 1:N ── private.auth_identities │ explicit application bootstrap ▼ profiles │ │ 1:N ▼ memberships ◄─── N:1 ───► accounts │ │ │ N:1 ├── 1:N ──► subscriptions ▼ ├── 1:N ──► payments roles ├── 1:N ──► licenses ├── 1:N ──► credit_transactions ├── 1:N ──► chat_sessions ──► chat_messages ├── 1:N ──► ai_requests ├── 1:N ──► documents ──► document_chunks ├── 1:N ──► api_keys ├── 1:N ──► invitations ├── 1:N ──► in_app_notifications ├── 1:N ──► referral_codes / referrals └── 1:N ──► affiliate_* (8 tables, see below)

Other domain tables grouped by ownership:

  • Standalone (global): app_settings, admin_logs, error_logs, pending_emails, jobs / job_runs / job_handlers.
  • User-scoped: user_consents, user_access_logs, push_subscriptions, notification_preferences, notification_log, account_deletion_requests.
  • CMS & content: cms_pages, cms_blocks, blog_categories, blog_tags, blog_post_tags, changelog_entries.
  • Referrals: referral_codes, referrals (account-scoped via the referrer).
  • Affiliates (8 tables): affiliate_tiers, affiliate_applications, affiliates, affiliate_links, affiliate_clicks (write-only attribution capability), affiliate_attributions, affiliate_conversions, affiliate_payouts. All account-scoped through the affiliate row.