Core Tables
users
Extends Supabaseauth.users table to store additional user information.
Primary key. References
auth.users(id) with CASCADE deleteUser’s email address (redundant with auth.users but useful for queries)
User’s display name
Timestamp when user record was created
Timestamp of last update (auto-updated by trigger)
update_users_updated_at: Automatically updatesupdated_atbefore each updateon_auth_user_created: Automatically creates user record when auth.users entry is created
transactions
Stores all financial transactions extracted from emails or manually added by users.Primary key, auto-generated
References
users(id). Owner of this transactionReferences
user_oauth_tokens(id) with CASCADE delete. The Gmail account that received the transaction email (NULL for manual transactions)Email address of the sender (merchant, bank, etc.)
Gmail message ID. Ensures each email only creates one transaction
Transaction amount. Supports values from -99,999,999,999,999.99 to 99,999,999,999,999.99
Currency code (e.g., ‘USD’, ‘EUR’, ‘GBP’)
Type of transaction. Must be ‘income’ or ‘expense’
Description of the transaction
Date when the transaction occurred
Name of the merchant or entity
Transaction category. Must be one of: ‘salary’, ‘entertainment’, ‘investment’, ‘food’, ‘transport’, ‘services’, ‘health’, ‘education’, ‘housing’, ‘clothing’, ‘other’
AI extraction confidence score (0.00 to 1.00)
Timestamp when transaction was created
Timestamp of last update (auto-updated by trigger)
idx_transactions_user_idonuser_ididx_transactions_source_message_idonsource_message_ididx_transactions_dateontransaction_dateidx_transactions_typeontransaction_typeidx_transactions_categoryoncategoryidx_transactions_created_atoncreated_atidx_transactions_user_oauth_token_idonuser_oauth_token_id
transactions_source_message_id_key: UNIQUE onsource_message_idtransactions_category_check: CHECK category in allowed valuescheck_amount_range: CHECK amount within valid range
REPLICA IDENTITY FULL
user_oauth_tokens
Stores encrypted OAuth tokens for Gmail API access.Primary key, auto-generated
References
users(id) with CASCADE deleteDEPRECATED: Use
access_token_encrypted insteadEncrypted OAuth access token (using pgcrypto)
DEPRECATED: Use
refresh_token_encrypted insteadEncrypted OAuth refresh token (using pgcrypto)
OAuth token type
Token expiration timestamp
OAuth scopes granted
Gmail address associated with these tokens
Whether this token is currently active
Timestamp when token was created
Timestamp of last update (auto-updated by trigger)
idx_user_oauth_tokens_user_idonuser_id
- UNIQUE on
(user_id, gmail_email)
gmail_watches
Tracks active Gmail API push notification watches.Primary key, auto-generated
References
users(id) with CASCADE deleteGmail address being watched
Gmail API watch ID
Google Cloud Pub/Sub topic name
Gmail labels being watched (e.g., [‘INBOX’])
When this watch expires
Alternative expiration field
Last processed Gmail history ID
Whether this watch is active
Alternative active status field
Timestamp when watch was created
Timestamp of last update (auto-updated by trigger)
idx_gmail_watches_user_idonuser_ididx_gmail_watches_watch_idonwatch_id
- UNIQUE on
(user_id, gmail_email) - UNIQUE on
watch_id
pubsub_subscriptions
Manages Google Cloud Pub/Sub subscription configurations.Primary key, auto-generated
References
users(id) with CASCADE deletePub/Sub subscription name
Pub/Sub topic name
Webhook URL for push notifications
Message acknowledgment deadline
Whether this subscription is active
Timestamp when subscription was created
Timestamp of last update (auto-updated by trigger)
idx_pubsub_subscriptions_user_idonuser_ididx_pubsub_subscriptions_subscription_nameonsubscription_name
- UNIQUE on
subscription_name - UNIQUE on
(user_id, topic_name)
Processing Tables
seeds
Tracks email import jobs (“seed” operations) that fetch historical transactions from Gmail.Primary key, auto-generated
References
users(id) with CASCADE deleteReferences
user_oauth_tokens(id) with CASCADE deleteStatus enum: ‘pending’, ‘processing’, ‘completed’, or ‘failed’
Error details if status is ‘failed’
Last processed email index for resumable operations
Array of Gmail message IDs to process
Total number of emails retrieved from Gmail
Number of new transactions found and inserted
Number of emails skipped (already processed or not in INBOX)
Number of emails sent to AI for analysis
Timestamp when seed job was created
Timestamp of last update (auto-updated by trigger)
idx_seeds_user_idonuser_ididx_seeds_statusonstatusidx_seeds_user_oauth_token_idonuser_oauth_token_id
Simple tracking of seed status to prevent duplicate seeds. Seed status: pending (in progress), completed, or failed.
discarded_emails
Caches emails that were analyzed but don’t contain transactions. Prevents re-processing and saves AI costs.Primary key, auto-generated
References
user_oauth_tokens(id) with CASCADE deleteGmail message ID of the discarded email
Why the email was discarded (e.g., “No transaction found”, “Promotional email”)
Timestamp when email was discarded
idx_discarded_emails_lookupon(user_oauth_token_id, message_id)idx_discarded_emails_tokenonuser_oauth_token_ididx_discarded_emails_discarded_atondiscarded_at DESC
- UNIQUE on
(user_oauth_token_id, message_id)
Stores emails that were analyzed but did not contain transactions. Prevents re-processing the same emails in future seed jobs, saving time and AI costs.
Notification Tables
notification_categories
Defines categories for grouping notification types.Primary key, auto-generated
Unique category identifier (e.g., ‘system’)
Internationalization key for category label
Whether this category is active
Timestamp when category was created
Timestamp of last update (auto-updated by trigger)
notification_types
Defines specific types of notifications that can be sent to users.Primary key, auto-generated
References
notification_categories(id) with RESTRICT deleteUnique notification type identifier
Internationalization key for type label
Internationalization key for description
Internationalization key for notification title
Internationalization key for notification body
Default importance level: ‘low’, ‘normal’, ‘high’, or ‘critical’
Whether this notification type is active
Timestamp when type was created
Timestamp of last update (auto-updated by trigger)
seed_completed_with_transactions: Seed job completed with new transactions foundseed_completed_no_new: Seed job completed with no new transactionsseed_failed: Seed job failedgmail_reconnect_required: Gmail connection needs re-authenticationgmail_watch_expiring: Gmail watch is about to expiregmail_watch_renew_failed: Failed to renew Gmail watchgmail_sync_error: Error during Gmail synchronization
user_notification_preferences
Stores user preferences for each notification type.Primary key, auto-generated
References
users(id) with CASCADE deleteReferences
notification_types(id) with CASCADE deleteWhether user wants to receive this notification type
Whether notifications are temporarily muted
When to unmute notifications (if muted)
Timestamp when preference was created
Timestamp of last update (auto-updated by trigger)
idx_user_notification_preferences_lookupon(user_id, notification_type_id)idx_user_notification_preferences_stateon(user_id, is_enabled, is_muted)
user_notification_preferences_unique: UNIQUE on(user_id, notification_type_id)
notifications
Stores individual notification messages sent to users.Primary key, auto-generated
References
users(id) with CASCADE deleteReferences
notification_types(id) with RESTRICT deleteInternationalization key for notification title
Internationalization key for notification body
Parameters for internationalization template
Additional notification metadata
Timestamp when notification was read (NULL if unread)
Whether notification is archived
Whether notification is muted
Importance level: ‘low’, ‘normal’, ‘high’, or ‘critical’
App route/path for notification action
Icon identifier for notification
URL for avatar image
Unique key for deduplication
Timestamp when notification was created
Timestamp of last update (auto-updated by trigger)
idx_notifications_user_created_aton(user_id, created_at DESC)idx_notifications_user_read_aton(user_id, read_at)idx_notifications_user_archivedon(user_id, is_archived)idx_notifications_user_mutedon(user_id, is_muted)idx_notifications_user_importanceon(user_id, importance)idx_notifications_dedupeon(user_id, notification_type_id, dedupe_key)WHEREdedupe_key IS NOT NULL
supabase_realtime publication