Files
apxtri/schema/mailboxes.json
T
2026-10-02 12:35:57 +00:00

229 lines
9.1 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "/schema/mailboxes",
"title": "Mailbox - External email account (multi-provider)",
"description": "A mailbox is an external email account (provider imap/pop3) attached to a tribe for synchronisation. Mailbox documents and their password secret live in the attached tribe namespace ({DATAPATH}/{tribe}/objects/mailboxes/itm and .../secrets). Synchronised mails are stored in the objects/mails collection of the same tribe. mailboxid stays globally unique across all tribes so a mailbox is resolvable by id. Passwords are never stored in the document: the password secret is stored separately at {DATAPATH}/{tribe}/objects/mailboxes/secrets/{mailboxid}.json (chmod 600). GRANULAR ACCESS: per-mailbox virtual profiles 'mail-{mailboxid}-reader' (read only) and 'mail-{mailboxid}-writer' (read + actions read/unread/trash) are added to the 'profils' array of the person document of the granted alias INSIDE the attached tribe. The model provides helpers setAccess/removeAccess to manage these profiles. APX3 BILLING: creating a mailbox requires the APX3 payment agreement and a declared weekly volume stored in the 'apx3' object. SYNC WATERMARK: a sync only fetches messages beyond the stored per-folder high-watermark 'syncCursor' instead of re-reading the N newest remote ids on every poll, and the 'syncing' marker prevents concurrent provider syncs when several users press sync at the same time.",
"type": "object",
"required": [
"mailboxid",
"provider",
"email",
"tribe"
],
"additionalProperties": false,
"apxid": "mailboxid",
"apxuniquekey": [
"mailboxid"
],
"apxidx": [
{
"name": "lst_mailboxid",
"type": "array",
"keyval": "mailboxid"
},
{
"name": "by_tribe",
"type": "distribution",
"keyval": "tribe"
},
{
"name": "by_status",
"type": "distribution",
"keyval": "status"
}
],
"apxaccessrights": {
"druids": {
"C": [],
"R": [],
"U": [],
"D": []
}
},
"properties": {
"mailboxid": {
"type": "string",
"description": "Unique slug identifier generated from label/email"
},
"provider": {
"type": "string",
"enum": ["imap", "pop3"],
"description": "Email provider: imap (password), pop3 (password)"
},
"connector": {
"type": "object",
"description": "Provider connection settings (public, never contains secrets). Passwords live in the secrets file.",
"properties": {
"host": { "type": "string", "description": "IMAP/POP3 server host" },
"port": { "type": "number", "description": "IMAP/POP3 server port (default 993/995)" },
"tls": { "type": "boolean", "default": true },
"user": { "type": "string", "description": "Login username (IMAP/POP3/SMTP)" },
"folder": { "type": "string", "description": "IMAP folder to poll (default INBOX)" },
"trashFolder": { "type": "string", "description": "IMAP folder receiving trashed messages" },
"sentFolder": { "type": "string", "description": "IMAP folder holding sent messages. Auto-detected ([Gmail]/Sent Mail on gmail.com hosts, Sent otherwise), overridable per mailbox. Corresponds to the app-side 'apxtriSent' folder." },
"deleteOnDownload": { "type": "boolean", "description": "POP3: delete remote message after download (also used by trash)" },
"rejectUnauthorized": { "type": "boolean", "default": true },
"smtp": {
"type": "object",
"description": "Outbound SMTP settings (nodemailer)",
"properties": {
"host": { "type": "string" },
"port": { "type": "number" },
"tls": { "type": "boolean", "default": true }
}
}
}
},
"connected": {
"type": "boolean",
"default": false,
"description": "True when the last live test succeeded"
},
"lastTest": {
"type": ["object", "null"],
"description": "Result of the last provider connection test",
"properties": {
"ok": { "type": "boolean" },
"latency": { "type": ["number", "null"] },
"smtp": { "type": ["string", "null"] },
"dt": { "type": ["string", "null"] },
"error": { "type": ["string", "null"] }
}
},
"lastError": {
"type": "string",
"description": "Last synchronisation error message (empty when last sync succeeded)"
},
"lastErrorAt": {
"type": ["string", "null"],
"description": "When the last sync error occurred"
},
"email": {
"type": "string",
"format": "email"
},
"label": {
"type": "string"
},
"tribe": {
"type": "string",
"description": "Tribe where the synchronised mails are stored and where reader/writer person profiles are managed"
},
"syncMode": {
"type": "string",
"enum": ["poll"],
"default": "poll"
},
"pollInterval": {
"type": "string",
"description": "Human interval like '3x/day' or a cron expression",
"default": "3x/day"
},
"pollIntervalMin": {
"type": "number",
"minimum": 1,
"default": 5,
"description": "Poll interval in minutes controlling the nextSync computation"
},
"nextSync": {
"type": ["string", "null"],
"description": "Time after which cron may poll this mailbox again (lastSync + pollIntervalMin)"
},
"syncCursor": {
"type": "object",
"description": "High-watermark cursor per synchronised folder so a sync only fetches messages never stored before, instead of re-reading the N newest remote ids on every poll. IMAP keys are folder names and store {uidValidity, lastUid, lastRemoteNum}; POP3 uses the single key 'pop3' and stores {lastRemoteNum}. uidValidity guards against a remote mailbox being re-created: when the server value changes the cursor is discarded and the folder is fully re-scanned.",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"uidValidity": { "type": ["number", "null"] },
"lastUid": { "type": ["number", "null"] },
"lastRemoteNum": { "type": ["number", "null"] },
"updatedAt": { "type": ["string", "null"] }
}
}
},
"syncing": {
"type": ["object", "null"],
"description": "Concurrency marker set while a synchronisation of this mailbox is running, so several users pressing sync at the same time cannot start concurrent provider syncs. Holds the alias that started it and the start date; null or absent when idle. A marker older than 10 minutes is treated as stale and ignored.",
"additionalProperties": false,
"properties": {
"alias": { "type": "string" },
"since": { "type": "string" },
"remote": { "type": "boolean" }
}
},
"downloadMode": {
"type": "string",
"enum": ["lazy", "eager"],
"default": "lazy",
"description": "lazy: attachments fetched on-demand at first click; eager: fetched during sync (for auto-read/OCR workflows)"
},
"counts": {
"type": "object",
"properties": {
"total": { "type": "number", "description": "Mails stored in the tribe for this mailbox" },
"unread": { "type": "number", "description": "Mails with status 'new' for this mailbox" }
}
},
"status": {
"type": "string",
"enum": ["active", "paused", "error"],
"default": "active"
},
"lastSync": {
"type": ["string", "null"],
"description": "Last successful synchronisation timestamp"
},
"history": {
"type": "array",
"items": {
"type": "object"
}
},
"availableTags": {
"type": "array",
"description": "Tags available for this mailbox, managed by druids. Each tag has a key (stored in mail.tags), label (display), and color (badge styling).",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"key": { "type": "string", "description": "Tag key stored in mail.tags" },
"label": { "type": "string", "description": "Display label" },
"color": { "type": "string", "enum": ["primary", "secondary", "accent", "success", "warning", "error", "info", "neutral"], "default": "primary", "description": "DaisyUI badge color" }
},
"required": ["key", "label"]
}
},
"apx3": {
"type": "object",
"additionalProperties": false,
"properties": {
"agree": {
"type": "boolean",
"description": "APX3 payment agreement accepted at creation"
},
"volumePerWeek": {
"type": "number",
"minimum": 1,
"description": "Declared weekly storage & traffic volume in GB used for APX3 billing"
},
"dtAgree": {
"type": "string",
"description": "ISO date when the agreement was accepted"
}
}
},
"owner": {
"type": "string",
"description": "Alias who created the mailbox"
},
"dt_create": {
"type": "string"
},
"dt_update": {
"type": "string"
}
}
}