Skip to content

Database Schema

MysticX uses PostgreSQL 18 with Prisma 7 as the ORM. The schema has 40+ models organized into logical domains.

Core Models

User

Central user record.

FieldTypeDescription
idStringPrimary key
nameStringDisplay name
emailStringEmail (unique)
emailVerifiedBooleanEmail verification status
imageString?Avatar URL
creditsIntCurrent credit balance
tierSubscriptionTierFREE, GOLD, or DIAMOND
roleString?'admin' for admin users, null for regular users
timezoneString?IANA timezone
stripeCustomerIdString?Stripe customer ID
subscriptionProviderString?'stripe', 'apple', 'google', or null
subscriptionIntervalString?'week', 'month', 'year', or null
inviteCodeString?Unique referral code
invitedByUserIdString?ID of user who invited this user
activeCardSkinIdString?Currently equipped card skin
activeTarotReaderIdString?Currently selected reader
bannedBoolean?Account ban status
banReasonString?Reason for ban
banExpiresDateTime?Ban expiry (null = permanent)
deletedAtDateTime?Soft-delete timestamp (null = active)ntly selected reader
bannedBoolean?Account ban status
banReasonString?Reason for ban
banExpiresDateTime?Ban expiry (null = permanent)
deletedAtDateTime?Soft-delete timestamp (null = active)

Session / Account / Verification

Standard Better Auth tables for session management, OAuth accounts, and email verification tokens.

UserProfile

Optional personal profile used to enrich AI readings.

FieldTypeDescription
pronounsString?User's pronouns (max 20 chars)
birthdayDate?Birthday (date only, no time)
zodiacSignString?Zodiac sign; auto-computed from birthday if null
relationshipString?Relationship status
bioString?Short bio (max 200 chars)
occupationString?Occupation (max 100 chars)

Reading Models

TarotReading

Core reading record.

FieldTypeDescription
idStringPrimary key
userIdString?Owner (null for guest readings)
guestTokenString?Guest identifier
readerIdStringAI reader persona used
spreadIdStringSpread type used
questionStringUser's question
selectedCardsJsonArray of card indices and reversed status
localeStringReading locale
statusReadingStatusACTIVE (live reading) or PRECREATED (pre-created during card selection, not yet claimed)
ipAddressString?Client IP
timezoneString?Client timezone
locationString?Approximate location derived from IP

Chat

One chat per reading for follow-up conversations.

Message

Individual messages in a chat.

FieldTypeDescription
roleStringuser, assistant, system
typeStringMessage type
contentStringMessage body
statusMessageStatusPENDING, STREAMING, COMPLETED, FAILED
tokensCountInt?Token count for billing
feedbackRatingFeedbackRating?THUMBS_UP or THUMBS_DOWN (null = no reaction)
feedbackReasonString?Text reason when THUMBS_DOWN

AiApiCall

Telemetry for every AI model call.

FieldTypeDescription
callTypeAiCallTypeINITIAL_READING, FOLLOW_UP, DRAW_CARD, SPREAD_SUGGEST
modelStringModel identifier
statusAiCallStatusSUCCESS, FAILED, TIMEOUT
totalTokensInt?Combined token count
durationMsIntTotal call duration
timeToFirstTokenMsInt?Time to first streamed token
inputTokensInt?Input token count
outputTokensInt?Output token count
totalTokensInt?Combined token count
errorMessageString?Error details if failed

Tarot Content Models

TarotCard

78-card deck with localized names and meanings.

FieldTypeDescription
cardIndexInt0–77 index
suitString'major', 'wands', 'cups', 'swords', 'pentacles'
rankString'0'–'21' for major, 'ace'–'king' for minor
nameJsonTLocalizedString
imageUrlStringCard face image
descriptionJsonTLocalizedString
meaningUpJsonUpright meaning (localized)
meaningRevJsonReversed meaning (localized)
keywordsUpJsonUpright keywords
keywordsRevJsonReversed keywords
yesNoUpVerdictYesNoVerdictYES, NO, or MAYBE for upright
yesNoUpStrengthInt?Strength 1–10
yesNoUpMeaningJson?TLocalizedString for upright meaning
yesNoRevVerdictYesNoVerdictYES, NO, or MAYBE for reversed
yesNoRevStrengthInt?Strength 1–10
yesNoRevMeaningJson?TLocalizedString for reversed meaning

TarotSpread

Spread definitions with positions.

| Field | Type | DescTotal number of cards drawn (includes any system-drawn cards) | | userSelectionCount | Int | How many cards the user manually picks | | positions | Json | Position definitions (order, name, description, isMainCard) | | layoutImageUrl | String? | Small image showing the spread layout | | sortOrder | Int | Admin-reorderable display ordering | slug | String | URL slug (e.g., celtic-cross) | | name | Json | TLocalizedString | | description | Json | TLocalizedString | | cardsCount | Int | Total number of cards drawn (includes any system-drawn cards) | | userSelectionCount | Int | How many cards the user manually picks | | positions | Json | Position definitions (order, name, description, isMainCard) | | layoutImageUrl | String? | Small image showing the spread layout | | sortOrder | Int | Admin-reorderable display ordering | isDefault | Boolean | Whether this is the default reader | | isActive | Boolean | Soft-delete flag (hidden when false) | | name | Json | TLocalizedString | | avatarUrl | String? | Avatar image URL | | coverImageUrl | String? | Background cover image URL | | bio | Json | Short bio shown in reader selection (TLocalizedString) | | description | Json | Detailed backstory (TLocalizedString) | | specialties | Json | TLocalized<string[]> — reader's specialty tags | | introAudioUrls | Json? | Partial<TLocalizedString> — per-locale intro audio URLs | | voiceIds | Json? | Partial<TLocalizedString> — MiniMax voice IDs per locale | | systemPrompt | String | AI system prompt (English only, not user-facing) | | temperature | Float | Model temperature (0.0–1.0) | | topP | Float | Top-P sampling parameter | | thinkingLevel | ThinkingLevel | AI thinking intensity | | unlockPrice | Int | Credit cost to unlock (0 = free) | | sortOrder | Int | UI display order

FieldTypeDescription
slugStringURL slug
isDefaultBooleanWhether this is the default reader
isActiveBooleanSoft-delete flag (hidden when false)
nameJsonTLocalizedString
avatarUrlString?Avatar image URL
coverImageUrlString?Background cover image URL
bioJsonShort bio shown in reader selection (TLocalizedString)
descriptionJsonDetailed backstory (TLocalizedString)
specialtiesJsonTLocalized<string[]> — reader's specialty tags
introAudioUrlsJson?Partial<TLocalizedString> — per-locale intro audio URLs
voiceIdsJson?Partial<TLocalizedString> — MiniMax voice IDs per locale
systemPromptStringAI system prompt (English only, not user-facing)
temperatureFloatModel temperature (0.0–1.0)
topPFloatTop-P sampling parameter
thinkingLevelThinkingLevelAI thinking intensity
unlockPriceIntCredit cost to unlock (0 = free)
sortOrderIntUI display order

TarotQuestionCategory / TarotQuestion / SpreadQuestion / SpreadInspiration

Question catalog and inspiration content for spread selection.

  • TarotQuestionCategory — Categories (Love, Career, Healing, Decision) with icons, localized labels, and sort order.
  • TarotQuestion — Individual questions per category with depth level (STRAIGHTFORWARD, LIGHT, MEDIUM, DEEP) and sort order.
  • SpreadQuestion — Per-spread prompt questions shown in the hero section during spread selection.
  • SpreadInspiration — Short mystical sentences shown on the loading screen after card reveal; one pool per spread.

Commerce Models

Subscription

See enum values below | | description | String?cord linked to user.

FieldTypeDescription
planStringGOLD or DIAMOND
stripeSubscriptionIdStringStripe sub ID
statusStringactive, canceled, past_due, etc.
periodStartDateTimeCurrent period start
periodEndDateTimeCurrent period end

CreditTransaction

Audit log for every credit change.

FieldTypeDescription
userIdStringUser
amountIntPositive (credit) or negative (debit)
typeCreditTransactionTypeSee enum values below
descriptionString?Human-readable description

Personalization Models

UserMemory

AI memory facts per user.

FieldTypeDescription
factsJsonArray of up to 5 English-language fact strings
translationsJsonOn-demand locale translations of facts

WeeklyGuidanceof markdown content |

| status | GuidanceStatus | GENERATING, READY, FAILED | | themes | Json | Extracted theme strings | | themeTranslations | Json | Cached locale translations of themes | | readingCount | Int | Number of r

FieldTypeDescription
contentStringMarkdown guidance content
translationsJsonLocalized versions
statusGuidanceStatusGENERATING, READY, FAILED
weekStart / weekEndDateTimeCovered period
autoGeneratedBooleanTrue for Diamond auto-generation

SoulJourney

Personal evolution document.

FieldTypeDescription
contentStringMarkdown journey content
translationsJsonLocalized versions of markdown content
statusGuidanceStatusGENERATING, READY, FAILED
themesJsonExtracted theme strings
themeTranslationsJsonCached locale translations of themes
readingCountIntNumber of readings analyzed

CardOfDayEntry

Daily card draws.

FieldTypeDescription
cardIndexIntDrawn card
isReversedBooleanCard orientation
keywordsString[]Array of keyword strings
emotionalWeatherStringAI-generated mood paragraph
actionsString[]Recommended actions (3 items)
questionsString[]Exploration prompts (3 items)
resonanceCountIntUser resonance tracking
creditsIntCredits awarded

Engagement Models

Referral

Tracks invitation relationships.

FieldTypeDescription
inviterUserIdStringWho invited
inviteeUserIdStringWho was invited
statusReferralStatusREGISTERED, QUALIFIED, REWARDED

ReferralMilestoneReward

Milestone bonus tracking (3, 10, 25 referrals).

Notification

In-app notification records.

FieldTypeDescription
categoryNotificationCategoryREADING, ACCOUNT, SOCIAL, SYSTEM
typeNotificationTypeSpecific notification type enum
targetUrlString?Deep link URL
metadataJson?Optional payload
isReadBooleanRead status

UserFeedback

User-submitted feedback with screenshot URLs.

Content Models

BlogPost / BlogCategory / BlogTag / BlogAuthor / BlogPostTag

Full blog system with categories, tags, and author profiles. All content fields use TLocalizedString JSON format.

Marketplace Models

CardSkin / UserCardSkin

Card back designs and user ownership records.

UserTarotReader

Reader unlock records (which readers a user has purchased). filteredCount | Int | How many passed pre-filter (non-gibberish) | | categories | Json | Category distribution map | | topKeywords | Json | Top keywords per category | | wordCloud | Json | Word cloud data array | | samplesByKeyword | Json | Sample questions per keyword | | trendData | Json | Monthly trend data | | summary | String? | AI-generated narrative | | actionItems | Json | Recommended actions list | | tokensUsed | Int | AI tokens consumed | | durationMs | Int | Total wall-clock time for analysis | | triggeredBy | String? | Admin user ID who triggered | | completedAt | DateTime? | When analysis complet

Links Telegram accounts to MysticX user accounts (1:1 per user).

InsightSnapshot

Admin-triggered AI analysis snapshots of user question patterns.

FieldTypeDescription
statusInsightSnapshotStatusPENDING, RUNNING, DONE, FAILED
sampledCountIntHow many were sampled
filteredCountIntHow many passed pre-filter (non-gibberish)
categoriesJsonCategory distribution map
topKeywordsJsonTop keywords per category
wordCloudJsonWord cloud data array
samplesByKeywordJsonSample questions per keyword
trendDataJsonMonthly trend data
summaryString?AI-generated narrative
actionItemsJsonRecommended actions list
tokensUsedIntAI tokens consumed
durationMsIntTotal wall-clock time for analysis
triggeredByString?Admin user ID who triggered
completedAtDateTime?When analysis completed

DeletedEmail

Tombstone table that prevents re-registration bonus abuse. Stores emails of deleted accounts permanently (no FK to User — must survive hard deletes).

Key Enums

EnumValues
SubscriptionTierFREE, GOLD, DIAMOND
CreditTransactionTypeREGISTRATION_BONUS, REFERRAL_INVITER_REWARD, REFERRAL_INVITEE_BONUS, REFERRAL_MILESTONE_BONUS, DAILY_CLAIM, CARD_OF_DAY_CLAIM, READING_DEDUCTION, FOLLOWUP_DEDUCTION, SPREAD_SUGGEST_DEDUCTION, SUBSCRIPTION_GRANT, ONE_TIME_PURCHASE, ADMIN_ADJUSTMENT, WEEKLY_GUIDANCE_DEDUCTION, SOUL_JOURNEY_DEDUCTION, READER_UNLOCK_DEDUCTION, CARD_SKIN_UNLOCK_DEDUCTION
ReadingStatusACTIVE, PRECREATED
MessageStatusPENDING, STREAMING, COMPLETED, FAILED
FeedbackRatingTHUMBS_UP, THUMBS_DOWN
GuidanceStatusGENERATING, READY, FAILED
ReferralStatusREGISTERED, QUALIFIED, REWARDED
FeedbackStatusPENDING, REVIEWED, RESOLVED
FeedbackMoodAMAZING, GOOD, OKAY, BAD, TERRIBLE
BlogPostStatusDRAFT, PUBLISHED, SCHEDULED, ARCHIVED
NotificationCategoryREADING, ACCOUNT, SOCIAL, SYSTEM
NotificationTypeWEEKLY_GUIDANCE_GENERATED, SOUL_JOURNEY_GENERATED, SUBSCRIPTION_CHANGED, REFERRAL_REWARD_EARNED, REFERRAL_MILESTONE_REACHED, SYSTEM_MAINTENANCE, SYSTEM_PRODUCT_CHANGE
AiCallTypeINITIAL_READING, FOLLOW_UP, DRAW_CARD, SPREAD_SUGGEST
AiCallStatusSUCCESS, FAILED, TIMEOUT
ThinkingLevelMINIMAL, LOW, MEDIUM, HIGH
YesNoVerdictYES, NO, MAYBE
QuestionLevelSTRAIGHTFORWARD, LIGHT, MEDIUM, DEEP
InsightSnapshotStatusPENDING, RUNNING, DONE, FAILED

Internal documentation for MysticX team