Data model

The key Prisma tables and what each one owns.

Every table below is tenant-scoped and RLS-protected unless noted otherwise. See Multi-tenancy for how that's enforced.

Auth

  • Tenant: the isolation boundary everything else hangs off. One project, in the language of Projects and roles.
  • User / Membership: bcrypt-authenticated operators. A user can hold one Membership per tenant, each with its own role (owner / manager / creator / moderator), so the same login can be Owner of one project and Creator on another. The JWT carries the role for whichever tenant it's currently scoped to; switching projects re-issues the token.

Accounts

  • SocialAccount: platform (x / telegram / discord / linkedin / instagram), connectionType (browser_session / bot_token / manual / oauth_api, the last one unimplemented), status (active / needs_reauth / disconnected), an AES-256-GCM encryptedSecret, daily post counters, riskAcknowledgedAt for browser-session accounts, and a bounded performanceSummary JSON aggregate.

Content strategy

  • BrandProfile: knowledge/voice, scoped to one account.
  • Topic / ConfigTopic: shared topic pool, rotated per config via lastUsedAt.
  • ContentConfig: the generation recipe. Model, topic strategy, schedule, requireApproval, similarity threshold, max regen attempts.
  • NewsKeyword, PromptTemplate: supporting config for live-news topics and prompt assembly.

Posts

  • Post: the status machine every draft moves through, draft → pending_approval → scheduled → posting → posted / failed, plus ready_to_copy for manual-posting accounts. Carries a contentHash for exact-duplicate blocking.
  • PostedSource: per-account tracker of which news URLs have already been used, so live-news topics don't cite the same source twice.

Cost and billing

  • CostEvent: one row per metered event (llm / web_search / platform_post).
  • CreditBalance / CreditLedger: the balance itself plus an append-only ledger. 1 credit equals $1.
  • IdempotencyKey: a generic (tenantId, key) intent/done ledger, used by publishing to guard against double-send on retry.

Reply Manage and Inbox

  • Mention: one row per X mention, unique on (accountId, platformPostId) so a mention is only ever drafted once no matter how many times it's re-scraped. status includes escalated alongside the usual draft/send states, with confidence (the model's self-reported score) and escalationReason (a named red-line topic, low_confidence, or classification_failed) recorded on the row.
  • ReplyConfig: per-account requireApproval and active toggles, plus the guardrail settings: confidenceThreshold (default 0.8) and redlineTopics (a string array, seeded with financial_advice / legal_advice / press_inquiry).
  • KnowledgeDocument / KnowledgeChunk: per-tenant documents split into retrievable chunks on blank lines. Retrieved via Postgres pg_trgm trigram similarity against a mention's body, the same extension DedupService already relies on, rather than a vector embeddings store: a real embeddings vendor would be a new external API credential for a v1 FAQ-style knowledge base where keyword/phrase matching against a few dozen documents is an honest substitute for semantic search.
  • DirectMessageThread / DirectMessage: scraped on demand when the inbox is opened, not on a background schedule. DirectMessageThread also carries category (general / lead / community) and an optional followUpAt reminder date, orthogonal to each other.

Analytics

  • AccountDailyMetrics: a daily rollup of engagement snapshots (likes, replies, reposts, impressions), unique on (accountId, date), keyed by the UTC day a snapshot was captured on rather than the day the underlying post went live. A single post contributes up to four snapshots spread across a week. This is what Analytics actually reads; the content score itself isn't stored, it's computed on read as a percentile rank of each day's engagement rate against the account's trailing 90-day window.
  • TopicPerformance: the persisted output of the loop's scoring. Average engagement rate and the resulting multiplier, per account per topic.
  • CompetitorAccount / CompetitorPost: tracked external handles and their scraped posts.

On this page