Skip to content

Database

ERD Schema


Indexes

TableIndexTypeUsage
archived_mailssearch_vectorGINFull-text search
archived_mailsgmail_account_idBTreeFilter by account
archived_mailssenderBTreeFilter by sender
archived_mailsdate DESCBTreeSort by date
archived_mailssize_bytes DESCBTreeSort by size
archived_attachmentsarchived_mail_idBTreeJoin emails ↔ attachments
jobsgmail_account_idBTreeFilter jobs by account
jobsstatusBTreeFilter by status
jobscreated_at DESCBTreeSort by date
jobsuser_idBTreeFilter jobs by user
usersgoogle_id (partial)UniqueGoogle SSO lookup
audit_logsuser_id + created_atBTreeLogs by user
audit_logsaction + created_atBTreeFilter by action
webhooksuser_idBTreeFilter by user
notification_preferencesuser_idUniqueOne row per user
tracking_pixelsgmail_account_idBTreeFilter by account
tracking_pixels(gmail_account_id, gmail_message_id)UniqueScan deduplication
pii_findingsgmail_account_idBTreeFilter by account
pii_findingsarchived_mail_idBTreeJoin emails ↔ PII
retention_policiesuser_idBTreeFilter by user
gmail_api_usage(gmail_account_id, recorded_at)BTreeQuota stats by account
gmail_api_usagerecorded_atBTreeOld data cleanup
storage_configsuser_idUniqueOne config per user
archived_mails(gmail_account_id, deleted_at)BTree (partial)Trash listing (WHERE deleted_at IS NOT NULL)

The search_vector field is automatically updated via a PostgreSQL trigger on each insert/update on archived_mails:

sql
-- Poids de recherche :
-- A (le plus fort) : sujet
-- B : expéditeur
-- C : snippet (extrait du corps)
NEW.search_vector :=
  setweight(to_tsvector('french', COALESCE(NEW.subject, '')), 'A') ||
  setweight(to_tsvector('french', COALESCE(NEW.sender, '')), 'B') ||
  setweight(to_tsvector('french', COALESCE(NEW.snippet, '')), 'C');

Search query example:

sql
SELECT *, ts_rank(search_vector, query) AS rank
FROM archived_mails, to_tsquery('french', 'facture & 2024') query
WHERE gmail_account_id = $1
  AND search_vector @@ query
ORDER BY rank DESC, date DESC;

JSONB — Rules Format

conditions (array)

json
[
  { "field": "from", "operator": "contains", "value": "newsletter@" },
  { "field": "subject", "operator": "contains", "value": "promotion" }
]

Supported fields: from, to, subject, has_attachment, size_gt (bytes)

Operators: contains, equals, not_contains, gt, lt

action (object)

json
{ "type": "trash" }
{ "type": "label", "labelId": "Label_123" }
{ "type": "archive" }
{ "type": "archive_nas" }