v0.1.1
RustBox CI / rustbox (push) Canceled after 0s

This commit is contained in:
Mateusz Gruszczyński committed 2026-10-31 00:37:16 +01:00
1 parent ecc201ef50
commit 698e3c4a1b
124 files changed
+4593 -2721

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
# Database schemas and migrations
RustBox 0.1.1 has one database backend for the whole application:
```text
database_backend = sqlite | mysql | pgsql
session_backend = database | redis
```
When `session_backend = "database"`, sessions live in the same configured SQL database as the application data. `session_backend = "redis"` moves only session persistence to Redis; Redis Sentinel is a Redis discovery option and has no SQL schema.
## Layout
```text
migrations/
├── sqlite/
│ └── schema.sql
├── mysql/
│ └── schema.sql
└── pgsql/
└── schema.sql
```
Every `schema.sql` is the complete schema for that engine. It contains:
- global tables (`sessions`, `rustbox_accounts`), and
- the full account-data baseline at schema version 46.
Account data is isolated inside the selected physical database with a deterministic, collision-checked table prefix derived from the account hash. The `{{p}}` marker in the tenant part of each schema is replaced by RustBox at provisioning time. Sessions are global and therefore are not prefixed.
The SQLite baseline is structurally equivalent to the legacy V001-V046 migration chain. On first access, RustBox 0.1.1 imports an existing legacy `data_dir/<user_hash>/db.sqlite` at `PRAGMA user_version = 46` into the configured backend. Only after a successful import is the legacy file renamed to `db.sqlite.pre-0.1.1.bak`. Older legacy schemas must first be upgraded with RustBox 0.1.0.
## Future migrations
The next application schema change is **V047**. A schema-changing release must add the same logical migration for every supported SQL engine, for example:
```text
migrations/sqlite/V047__description.sql
migrations/mysql/V047__description.sql
migrations/pgsql/V047__description.sql
```
Tenant migration SQL uses `{{p}}` for account tables. Register each new migration in the corresponding migration array in `src/db/pool.rs` and keep the version numbers aligned across all three engines. Do not edit `schema.sql` alone for an upgrade that must work on existing installations; update both the baseline and the versioned migration.
Redis and Redis Sentinel do not use SQL migrations.
## Engine notes
- SQLite uses `data_dir/rustbox.sqlite` by default; `database_url` may point to another persistent SQLite file.
- MySQL requires `database_url` and targets MySQL 8.0.13 or newer.
- PostgreSQL requires `database_url`.
- MySQL/PostgreSQL are full application backends, not session-only databases.
-23
View File
@@ -1,23 +0,0 @@
CREATE TABLE IF NOT EXISTS sessions (
token VARCHAR(64) PRIMARY KEY,
account_id VARCHAR(64) NOT NULL UNIQUE,
browser_id VARCHAR(64) NOT NULL,
email VARCHAR(320) NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash VARCHAR(128) NOT NULL,
imap_host VARCHAR(255) NOT NULL,
imap_port BIGINT NOT NULL,
imap_tls BIGINT NOT NULL,
imap_tls_verify BIGINT NOT NULL,
smtp_host VARCHAR(255) NOT NULL,
smtp_port BIGINT NOT NULL,
smtp_tls BIGINT NOT NULL,
smtp_tls_verify BIGINT NOT NULL,
timeout_secs BIGINT NOT NULL,
created_at_unix BIGINT NOT NULL,
last_accessed_unix BIGINT NOT NULL,
user_agent VARCHAR(512) NOT NULL DEFAULT '',
INDEX idx_sessions_browser (browser_id),
INDEX idx_sessions_user (user_hash),
INDEX idx_sessions_expiry (last_accessed_unix, timeout_secs)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+424
View File
@@ -0,0 +1,424 @@
-- RustBox 0.1.1 MySQL schema.
-- One physical database contains global sessions plus isolated per-account tables.
-- Application tables are materialized by replacing {{p}} with a collision-checked prefix.
-- Baseline application schema version: 46. Future migrations start at V047.
-- RUSTBOX:GLOBAL-BEGIN
CREATE TABLE IF NOT EXISTS rustbox_accounts (
user_hash VARCHAR(128) PRIMARY KEY,
table_prefix VARCHAR(64) NOT NULL UNIQUE,
schema_version BIGINT NOT NULL DEFAULT 46,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS sessions (
token VARCHAR(64) PRIMARY KEY,
account_id VARCHAR(64) NOT NULL UNIQUE,
browser_id VARCHAR(64) NOT NULL,
email VARCHAR(320) NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash VARCHAR(128) NOT NULL,
imap_host VARCHAR(255) NOT NULL,
imap_port BIGINT NOT NULL,
imap_tls BIGINT NOT NULL,
imap_tls_verify BIGINT NOT NULL,
smtp_host VARCHAR(255) NOT NULL,
smtp_port BIGINT NOT NULL,
smtp_tls BIGINT NOT NULL,
smtp_tls_verify BIGINT NOT NULL,
timeout_secs BIGINT NOT NULL,
created_at_unix BIGINT NOT NULL,
last_accessed_unix BIGINT NOT NULL,
user_agent VARCHAR(512) NOT NULL DEFAULT '',
INDEX idx_sessions_browser (browser_id),
INDEX idx_sessions_user (user_hash),
INDEX idx_sessions_expiry (last_accessed_unix, timeout_secs)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- RUSTBOX:GLOBAL-END
-- RUSTBOX:TENANT-BEGIN
-- {{p}} is replaced at runtime with the account table prefix.
CREATE TABLE {{p}}calendar_events (
id VARCHAR(255) PRIMARY KEY,
title TEXT NOT NULL,
description LONGTEXT NOT NULL DEFAULT (''),
location TEXT NOT NULL DEFAULT (''),
start_time VARCHAR(255) NOT NULL,
end_time VARCHAR(255) NOT NULL,
all_day BIGINT NOT NULL DEFAULT 0,
recurrence_rule TEXT,
attendees LONGTEXT NOT NULL DEFAULT ('[]'),
organizer TEXT NOT NULL DEFAULT (''),
status TEXT NOT NULL DEFAULT ('confirmed'),
source TEXT NOT NULL DEFAULT ('manual'),
source_uid VARCHAR(255),
source_message_uid BIGINT,
source_message_folder TEXT,
meeting_url TEXT,
color TEXT,
reminder_minutes BIGINT,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}calendar_settings (
id BIGINT DEFAULT 1 PRIMARY KEY,
default_view TEXT NOT NULL DEFAULT ('month'),
week_starts_on BIGINT NOT NULL DEFAULT 0,
working_hours_start TEXT NOT NULL DEFAULT ('09:00'),
working_hours_end TEXT NOT NULL DEFAULT ('17:00'),
time_format TEXT NOT NULL DEFAULT ('12h'),
zoom_link TEXT NOT NULL DEFAULT (''),
teams_link TEXT NOT NULL DEFAULT (''),
meet_link TEXT NOT NULL DEFAULT (''),
caldav_url TEXT NOT NULL DEFAULT (''),
caldav_username TEXT NOT NULL DEFAULT (''),
caldav_password TEXT NOT NULL DEFAULT (''),
caldav_enabled BIGINT NOT NULL DEFAULT 0,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}contact_group_members (
group_id VARCHAR(255) NOT NULL,
contact_id VARCHAR(255) NOT NULL,
PRIMARY KEY (group_id, contact_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}contact_groups (
id VARCHAR(255) PRIMARY KEY,
name VARCHAR(512) NOT NULL,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
UNIQUE (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}contact_photos (
contact_id VARCHAR(255) PRIMARY KEY,
content_type TEXT NOT NULL,
data LONGBLOB NOT NULL,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}contacts (
id VARCHAR(255) PRIMARY KEY,
email VARCHAR(320) NOT NULL,
name VARCHAR(512) NOT NULL DEFAULT '',
company TEXT NOT NULL DEFAULT (''),
notes LONGTEXT NOT NULL DEFAULT (''),
is_favorite BIGINT NOT NULL DEFAULT 0,
last_contacted VARCHAR(64),
contact_count BIGINT NOT NULL DEFAULT 0,
source TEXT NOT NULL DEFAULT ('manual'),
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
phone TEXT NOT NULL DEFAULT (''),
job_title TEXT NOT NULL DEFAULT (''),
address TEXT NOT NULL DEFAULT (''),
website TEXT NOT NULL DEFAULT (''),
birthday TEXT NOT NULL DEFAULT (''),
emails_json LONGTEXT NOT NULL DEFAULT ('[]'),
phones_json LONGTEXT NOT NULL DEFAULT ('[]'),
addresses_json LONGTEXT NOT NULL DEFAULT ('[]')
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}display_preferences (
id BIGINT DEFAULT 1 PRIMARY KEY,
density TEXT NOT NULL DEFAULT ('comfortable'),
theme TEXT NOT NULL DEFAULT ('system'),
language TEXT NOT NULL DEFAULT ('en'),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
compose_format TEXT NOT NULL DEFAULT ('html'),
deep_index BIGINT NOT NULL DEFAULT 0,
animation_mode TEXT,
preview_pane TEXT NOT NULL DEFAULT ('right'),
ui_scale TEXT NOT NULL DEFAULT ('normal'),
color_preset TEXT NOT NULL DEFAULT ('sage'),
accent_color TEXT NOT NULL DEFAULT ('#6f9c86'),
font_family TEXT NOT NULL DEFAULT ('system'),
font_size BIGINT NOT NULL DEFAULT 13,
row_height BIGINT NOT NULL DEFAULT 58,
folder_pane_width BIGINT NOT NULL DEFAULT 228,
message_pane_width BIGINT NOT NULL DEFAULT 420,
border_radius BIGINT NOT NULL DEFAULT 4,
contrast TEXT NOT NULL DEFAULT ('normal'),
show_avatars BIGINT NOT NULL DEFAULT 1,
show_attachment_icons BIGINT NOT NULL DEFAULT 1,
show_flags BIGINT NOT NULL DEFAULT 1,
reduce_motion BIGINT NOT NULL DEFAULT 0,
date_format TEXT NOT NULL DEFAULT ('locale'),
time_format TEXT NOT NULL DEFAULT ('locale'),
background_color TEXT NOT NULL DEFAULT ('#121513'),
panel_color TEXT NOT NULL DEFAULT ('#181c19'),
text_color TEXT NOT NULL DEFAULT ('#edf0ec'),
compose_autosave_ms BIGINT NOT NULL DEFAULT 3000,
default_priority TEXT NOT NULL DEFAULT ('normal'),
request_mdn_default BIGINT NOT NULL DEFAULT 0,
attachment_reminder BIGINT NOT NULL DEFAULT 1,
icon_size BIGINT NOT NULL DEFAULT 18,
toolbar_density TEXT NOT NULL DEFAULT ('normal'),
sidebar_item_height BIGINT NOT NULL DEFAULT 29,
reader_max_width BIGINT NOT NULL DEFAULT 0,
composer_width BIGINT NOT NULL DEFAULT 900,
selection_color TEXT NOT NULL DEFAULT ('#28352e'),
unread_font_weight BIGINT NOT NULL DEFAULT 730,
unread_badge_style TEXT NOT NULL DEFAULT ('dot'),
compact_headers BIGINT NOT NULL DEFAULT 0,
show_borders BIGINT NOT NULL DEFAULT 1,
scrollbar_density TEXT NOT NULL DEFAULT ('thin'),
monochrome BIGINT NOT NULL DEFAULT 0,
folder_background TEXT NOT NULL DEFAULT (''),
message_background TEXT NOT NULL DEFAULT (''),
reader_background TEXT NOT NULL DEFAULT (''),
compose_font_family TEXT NOT NULL DEFAULT ('system'),
reply_position TEXT NOT NULL DEFAULT ('above'),
quote_style TEXT NOT NULL DEFAULT ('standard'),
forward_mode TEXT NOT NULL DEFAULT ('inline'),
spellcheck_enabled BIGINT NOT NULL DEFAULT 1,
interface_skin TEXT NOT NULL DEFAULT ('rustbox'),
preset_scale_unlocked BIGINT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}draft_attachments (
id VARCHAR(255) PRIMARY KEY,
draft_id VARCHAR(255) NOT NULL,
filename TEXT NOT NULL,
content_type TEXT NOT NULL,
size BIGINT NOT NULL,
file_path TEXT NOT NULL,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}drafts (
id VARCHAR(255) PRIMARY KEY,
to_addresses LONGTEXT NOT NULL DEFAULT (''),
cc_addresses LONGTEXT NOT NULL DEFAULT (''),
bcc_addresses LONGTEXT NOT NULL DEFAULT (''),
subject TEXT NOT NULL DEFAULT (''),
text_body LONGTEXT NOT NULL DEFAULT (''),
html_body LONGTEXT,
in_reply_to TEXT,
references_header LONGTEXT,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
request_mdn BIGINT NOT NULL DEFAULT 0,
priority TEXT NOT NULL DEFAULT ('normal'),
compose_format TEXT NOT NULL DEFAULT ('html'),
remote_folder TEXT,
remote_uid BIGINT,
remote_uid_validity BIGINT,
pgp_mode TEXT NOT NULL DEFAULT ('none'),
pgp_inline BIGINT NOT NULL DEFAULT 0,
pgp_attach_public_key BIGINT NOT NULL DEFAULT 0,
pgp_attach_recipient_keys BIGINT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}folder_preferences (
folder_name VARCHAR(512) PRIMARY KEY,
flagged_on_top BIGINT,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}folders (
name VARCHAR(512) PRIMARY KEY,
delimiter TEXT,
parent TEXT,
flags TEXT NOT NULL DEFAULT (''),
is_subscribed BIGINT NOT NULL DEFAULT 1,
total_count BIGINT NOT NULL DEFAULT 0,
unread_count BIGINT NOT NULL DEFAULT 0,
uid_validity BIGINT NOT NULL DEFAULT 0,
highest_modseq BIGINT NOT NULL DEFAULT 0,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
messages_updated_at VARCHAR(64)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}identities (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
display_name TEXT NOT NULL DEFAULT (''),
email TEXT NOT NULL,
signature_html LONGTEXT NOT NULL DEFAULT (''),
is_default BIGINT NOT NULL DEFAULT 0,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
reply_to TEXT NOT NULL DEFAULT (''),
bcc TEXT NOT NULL DEFAULT (''),
organization TEXT NOT NULL DEFAULT (''),
signature_text LONGTEXT NOT NULL DEFAULT (''),
signature_new BIGINT NOT NULL DEFAULT 1,
signature_reply BIGINT NOT NULL DEFAULT 1,
signature_forward BIGINT NOT NULL DEFAULT 1,
signature_position TEXT NOT NULL DEFAULT ('above'),
pgp_fingerprint TEXT,
pgp_sign_default BIGINT NOT NULL DEFAULT 0,
pgp_encrypt_default BIGINT NOT NULL DEFAULT 0,
pgp_inline_default BIGINT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}known_addresses (
email VARCHAR(320) NOT NULL PRIMARY KEY,
name VARCHAR(512) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}mail_preferences (
id BIGINT PRIMARY KEY,
messages_per_page BIGINT NOT NULL DEFAULT 50,
mark_read_delay_ms BIGINT NOT NULL DEFAULT 0,
remote_images TEXT NOT NULL DEFAULT ('ask'),
preferred_body TEXT NOT NULL DEFAULT ('auto'),
thread_mode TEXT NOT NULL DEFAULT ('threaded'),
collapse_quotes BIGINT NOT NULL DEFAULT 1,
show_snippets BIGINT NOT NULL DEFAULT 1,
default_sort TEXT NOT NULL DEFAULT ('date_desc'),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
flagged_on_top BIGINT NOT NULL DEFAULT 0,
sync_imap_keywords BIGINT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}meeting_templates (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name TEXT NOT NULL,
url_template TEXT NOT NULL,
icon TEXT NOT NULL DEFAULT (''),
is_default BIGINT NOT NULL DEFAULT 0,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}message_tags (
tag_id VARCHAR(128) NOT NULL,
message_uid BIGINT NOT NULL,
message_folder VARCHAR(512) NOT NULL,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
PRIMARY KEY (tag_id, message_uid, message_folder)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}messages (
uid BIGINT NOT NULL,
folder VARCHAR(512) NOT NULL,
message_id VARCHAR(255),
in_reply_to VARCHAR(255),
subject TEXT NOT NULL DEFAULT (''),
from_address TEXT NOT NULL DEFAULT (''),
from_name TEXT NOT NULL DEFAULT (''),
to_addresses LONGTEXT NOT NULL DEFAULT (''),
cc_addresses LONGTEXT NOT NULL DEFAULT (''),
date TEXT NOT NULL,
flags TEXT NOT NULL DEFAULT (''),
size BIGINT NOT NULL DEFAULT 0,
has_attachments BIGINT NOT NULL DEFAULT 0,
snippet TEXT NOT NULL DEFAULT (''),
body_cached BIGINT NOT NULL DEFAULT 0,
body_html LONGTEXT,
body_text LONGTEXT,
references_header LONGTEXT,
date_epoch BIGINT NOT NULL DEFAULT 0,
attachments_json LONGTEXT,
raw_headers LONGTEXT,
reaction TEXT,
email_theme BIGINT,
PRIMARY KEY (uid, folder)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}notification_preferences (
id BIGINT DEFAULT 1 PRIMARY KEY,
enabled BIGINT NOT NULL DEFAULT 1,
sound BIGINT NOT NULL DEFAULT 0,
folders TEXT NOT NULL DEFAULT ('["INBOX"]'),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
dnd_enabled BIGINT NOT NULL DEFAULT 0,
dnd_start TEXT NOT NULL DEFAULT ('22:00'),
dnd_end TEXT NOT NULL DEFAULT ('07:00')
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}pgp_keys (
fingerprint VARCHAR(255) PRIMARY KEY,
key_id TEXT NOT NULL,
email TEXT NOT NULL DEFAULT (''),
user_id TEXT NOT NULL DEFAULT (''),
public_key_armor LONGTEXT NOT NULL,
secret_key_path TEXT,
has_secret BIGINT NOT NULL DEFAULT 0,
trust TEXT NOT NULL DEFAULT ('unknown'),
source TEXT NOT NULL DEFAULT ('import'),
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}pgp_preferences (
id BIGINT PRIMARY KEY,
wkd_enabled BIGINT NOT NULL DEFAULT 1,
hkp_enabled BIGINT NOT NULL DEFAULT 0,
require_trusted_encryption BIGINT NOT NULL DEFAULT 0,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}response_templates (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(512) NOT NULL,
body TEXT NOT NULL DEFAULT (''),
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
format TEXT NOT NULL DEFAULT ('text'),
UNIQUE (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}saved_searches (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(512) NOT NULL,
query_string LONGTEXT NOT NULL,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}special_folders (
role VARCHAR(255) PRIMARY KEY,
folder_name TEXT NOT NULL,
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}tags (
id VARCHAR(128) PRIMARY KEY,
name VARCHAR(512) NOT NULL,
color TEXT NOT NULL DEFAULT ('#6b7280'),
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)),
imap_keyword VARCHAR(255) NOT NULL DEFAULT '',
UNIQUE (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}trusted_senders (
email VARCHAR(320) PRIMARY KEY,
created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE {{p}}user_meta (
key VARCHAR(255) PRIMARY KEY,
value TEXT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE {{p}}contact_group_members ADD CONSTRAINT {{p}}fk_contact_group_members_0 FOREIGN KEY (contact_id) REFERENCES {{p}}contacts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}contact_group_members ADD CONSTRAINT {{p}}fk_contact_group_members_1 FOREIGN KEY (group_id) REFERENCES {{p}}contact_groups (id) ON DELETE CASCADE;
ALTER TABLE {{p}}contact_photos ADD CONSTRAINT {{p}}fk_contact_photos_0 FOREIGN KEY (contact_id) REFERENCES {{p}}contacts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}draft_attachments ADD CONSTRAINT {{p}}fk_draft_attachments_0 FOREIGN KEY (draft_id) REFERENCES {{p}}drafts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}folder_preferences ADD CONSTRAINT {{p}}fk_folder_preferences_0 FOREIGN KEY (folder_name) REFERENCES {{p}}folders (name) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE {{p}}message_tags ADD CONSTRAINT {{p}}fk_message_tags_0 FOREIGN KEY (message_uid, message_folder) REFERENCES {{p}}messages (uid, folder) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE {{p}}message_tags ADD CONSTRAINT {{p}}fk_message_tags_1 FOREIGN KEY (tag_id) REFERENCES {{p}}tags (id) ON DELETE CASCADE;
ALTER TABLE {{p}}messages ADD CONSTRAINT {{p}}fk_messages_0 FOREIGN KEY (folder) REFERENCES {{p}}folders (name) ON DELETE CASCADE;
CREATE INDEX {{p}}idx_calendar_events_source_uid ON {{p}}calendar_events (source_uid);
CREATE INDEX {{p}}idx_calendar_events_time ON {{p}}calendar_events (start_time, end_time);
CREATE INDEX {{p}}idx_cgm_contact_id ON {{p}}contact_group_members (contact_id);
CREATE INDEX {{p}}idx_contacts_contact_count ON {{p}}contacts (contact_count DESC);
CREATE UNIQUE INDEX {{p}}idx_contacts_email ON {{p}}contacts (email);
CREATE INDEX {{p}}idx_contacts_last_contacted ON {{p}}contacts (last_contacted DESC);
CREATE INDEX {{p}}idx_contacts_name ON {{p}}contacts (name);
CREATE INDEX {{p}}idx_known_addresses_name ON {{p}}known_addresses (name);
CREATE INDEX {{p}}idx_message_tags_message ON {{p}}message_tags (message_uid, message_folder);
CREATE INDEX {{p}}idx_message_tags_tag ON {{p}}message_tags (tag_id);
CREATE INDEX {{p}}idx_messages_folder_date ON {{p}}messages (folder, date_epoch DESC);
CREATE INDEX {{p}}idx_messages_in_reply_to ON {{p}}messages (in_reply_to);
CREATE INDEX {{p}}idx_messages_message_id ON {{p}}messages (message_id);
CREATE INDEX {{p}}idx_pgp_keys_email ON {{p}}pgp_keys (email);
CREATE UNIQUE INDEX {{p}}idx_saved_searches_name ON {{p}}saved_searches (name);
-- RUSTBOX:TENANT-END
-23
View File
@@ -1,23 +0,0 @@
CREATE TABLE IF NOT EXISTS sessions (
token VARCHAR(64) PRIMARY KEY,
account_id VARCHAR(64) NOT NULL UNIQUE,
browser_id VARCHAR(64) NOT NULL,
email VARCHAR(320) NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash VARCHAR(128) NOT NULL,
imap_host VARCHAR(255) NOT NULL,
imap_port BIGINT NOT NULL,
imap_tls BIGINT NOT NULL,
imap_tls_verify BIGINT NOT NULL,
smtp_host VARCHAR(255) NOT NULL,
smtp_port BIGINT NOT NULL,
smtp_tls BIGINT NOT NULL,
smtp_tls_verify BIGINT NOT NULL,
timeout_secs BIGINT NOT NULL,
created_at_unix BIGINT NOT NULL,
last_accessed_unix BIGINT NOT NULL,
user_agent VARCHAR(512) NOT NULL DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_sessions_browser ON sessions(browser_id);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_hash);
CREATE INDEX IF NOT EXISTS idx_sessions_expiry ON sessions(last_accessed_unix, timeout_secs);
+425
View File
@@ -0,0 +1,425 @@
-- RustBox 0.1.1 PostgreSQL schema.
-- One physical database contains global sessions plus isolated per-account tables.
-- Application tables are materialized by replacing {{p}} with a collision-checked prefix.
-- Baseline application schema version: 46. Future migrations start at V047.
-- RUSTBOX:GLOBAL-BEGIN
CREATE TABLE IF NOT EXISTS rustbox_accounts (
user_hash VARCHAR(128) PRIMARY KEY,
table_prefix VARCHAR(64) NOT NULL UNIQUE,
schema_version BIGINT NOT NULL DEFAULT 46,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE IF NOT EXISTS sessions (
token VARCHAR(64) PRIMARY KEY,
account_id VARCHAR(64) NOT NULL UNIQUE,
browser_id VARCHAR(64) NOT NULL,
email VARCHAR(320) NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash VARCHAR(128) NOT NULL,
imap_host VARCHAR(255) NOT NULL,
imap_port BIGINT NOT NULL,
imap_tls BIGINT NOT NULL,
imap_tls_verify BIGINT NOT NULL,
smtp_host VARCHAR(255) NOT NULL,
smtp_port BIGINT NOT NULL,
smtp_tls BIGINT NOT NULL,
smtp_tls_verify BIGINT NOT NULL,
timeout_secs BIGINT NOT NULL,
created_at_unix BIGINT NOT NULL,
last_accessed_unix BIGINT NOT NULL,
user_agent VARCHAR(512) NOT NULL DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_sessions_browser ON sessions(browser_id);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_hash);
CREATE INDEX IF NOT EXISTS idx_sessions_expiry ON sessions(last_accessed_unix, timeout_secs);
-- RUSTBOX:GLOBAL-END
-- RUSTBOX:TENANT-BEGIN
-- {{p}} is replaced at runtime with the account table prefix.
CREATE TABLE {{p}}calendar_events (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
location TEXT NOT NULL DEFAULT '',
start_time TEXT NOT NULL,
end_time TEXT NOT NULL,
all_day BIGINT NOT NULL DEFAULT 0,
recurrence_rule TEXT,
attendees TEXT NOT NULL DEFAULT '[]',
organizer TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'confirmed',
source TEXT NOT NULL DEFAULT 'manual',
source_uid TEXT,
source_message_uid BIGINT,
source_message_folder TEXT,
meeting_url TEXT,
color TEXT,
reminder_minutes BIGINT,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}calendar_settings (
id BIGINT DEFAULT 1 PRIMARY KEY,
default_view TEXT NOT NULL DEFAULT 'month',
week_starts_on BIGINT NOT NULL DEFAULT 0,
working_hours_start TEXT NOT NULL DEFAULT '09:00',
working_hours_end TEXT NOT NULL DEFAULT '17:00',
time_format TEXT NOT NULL DEFAULT '12h',
zoom_link TEXT NOT NULL DEFAULT '',
teams_link TEXT NOT NULL DEFAULT '',
meet_link TEXT NOT NULL DEFAULT '',
caldav_url TEXT NOT NULL DEFAULT '',
caldav_username TEXT NOT NULL DEFAULT '',
caldav_password TEXT NOT NULL DEFAULT '',
caldav_enabled BIGINT NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}contact_group_members (
group_id TEXT NOT NULL,
contact_id TEXT NOT NULL,
PRIMARY KEY (group_id, contact_id)
);
CREATE TABLE {{p}}contact_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
UNIQUE (name)
);
CREATE TABLE {{p}}contact_photos (
contact_id TEXT PRIMARY KEY,
content_type TEXT NOT NULL,
data BYTEA NOT NULL,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}contacts (
id TEXT PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
company TEXT NOT NULL DEFAULT '',
notes TEXT NOT NULL DEFAULT '',
is_favorite BIGINT NOT NULL DEFAULT 0,
last_contacted TEXT,
contact_count BIGINT NOT NULL DEFAULT 0,
source TEXT NOT NULL DEFAULT 'manual',
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
phone TEXT NOT NULL DEFAULT '',
job_title TEXT NOT NULL DEFAULT '',
address TEXT NOT NULL DEFAULT '',
website TEXT NOT NULL DEFAULT '',
birthday TEXT NOT NULL DEFAULT '',
emails_json TEXT NOT NULL DEFAULT '[]',
phones_json TEXT NOT NULL DEFAULT '[]',
addresses_json TEXT NOT NULL DEFAULT '[]'
);
CREATE TABLE {{p}}display_preferences (
id BIGINT DEFAULT 1 PRIMARY KEY,
density TEXT NOT NULL DEFAULT 'comfortable',
theme TEXT NOT NULL DEFAULT 'system',
language TEXT NOT NULL DEFAULT 'en',
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
compose_format TEXT NOT NULL DEFAULT 'html',
deep_index BIGINT NOT NULL DEFAULT 0,
animation_mode TEXT,
preview_pane TEXT NOT NULL DEFAULT 'right',
ui_scale TEXT NOT NULL DEFAULT 'normal',
color_preset TEXT NOT NULL DEFAULT 'sage',
accent_color TEXT NOT NULL DEFAULT '#6f9c86',
font_family TEXT NOT NULL DEFAULT 'system',
font_size BIGINT NOT NULL DEFAULT 13,
row_height BIGINT NOT NULL DEFAULT 58,
folder_pane_width BIGINT NOT NULL DEFAULT 228,
message_pane_width BIGINT NOT NULL DEFAULT 420,
border_radius BIGINT NOT NULL DEFAULT 4,
contrast TEXT NOT NULL DEFAULT 'normal',
show_avatars BIGINT NOT NULL DEFAULT 1,
show_attachment_icons BIGINT NOT NULL DEFAULT 1,
show_flags BIGINT NOT NULL DEFAULT 1,
reduce_motion BIGINT NOT NULL DEFAULT 0,
date_format TEXT NOT NULL DEFAULT 'locale',
time_format TEXT NOT NULL DEFAULT 'locale',
background_color TEXT NOT NULL DEFAULT '#121513',
panel_color TEXT NOT NULL DEFAULT '#181c19',
text_color TEXT NOT NULL DEFAULT '#edf0ec',
compose_autosave_ms BIGINT NOT NULL DEFAULT 3000,
default_priority TEXT NOT NULL DEFAULT 'normal',
request_mdn_default BIGINT NOT NULL DEFAULT 0,
attachment_reminder BIGINT NOT NULL DEFAULT 1,
icon_size BIGINT NOT NULL DEFAULT 18,
toolbar_density TEXT NOT NULL DEFAULT 'normal',
sidebar_item_height BIGINT NOT NULL DEFAULT 29,
reader_max_width BIGINT NOT NULL DEFAULT 0,
composer_width BIGINT NOT NULL DEFAULT 900,
selection_color TEXT NOT NULL DEFAULT '#28352e',
unread_font_weight BIGINT NOT NULL DEFAULT 730,
unread_badge_style TEXT NOT NULL DEFAULT 'dot',
compact_headers BIGINT NOT NULL DEFAULT 0,
show_borders BIGINT NOT NULL DEFAULT 1,
scrollbar_density TEXT NOT NULL DEFAULT 'thin',
monochrome BIGINT NOT NULL DEFAULT 0,
folder_background TEXT NOT NULL DEFAULT '',
message_background TEXT NOT NULL DEFAULT '',
reader_background TEXT NOT NULL DEFAULT '',
compose_font_family TEXT NOT NULL DEFAULT 'system',
reply_position TEXT NOT NULL DEFAULT 'above',
quote_style TEXT NOT NULL DEFAULT 'standard',
forward_mode TEXT NOT NULL DEFAULT 'inline',
spellcheck_enabled BIGINT NOT NULL DEFAULT 1,
interface_skin TEXT NOT NULL DEFAULT 'rustbox',
preset_scale_unlocked BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE {{p}}draft_attachments (
id TEXT PRIMARY KEY,
draft_id TEXT NOT NULL,
filename TEXT NOT NULL,
content_type TEXT NOT NULL,
size BIGINT NOT NULL,
file_path TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}drafts (
id TEXT PRIMARY KEY,
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
bcc_addresses TEXT NOT NULL DEFAULT '',
subject TEXT NOT NULL DEFAULT '',
text_body TEXT NOT NULL DEFAULT '',
html_body TEXT,
in_reply_to TEXT,
references_header TEXT,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
request_mdn BIGINT NOT NULL DEFAULT 0,
priority TEXT NOT NULL DEFAULT 'normal',
compose_format TEXT NOT NULL DEFAULT 'html',
remote_folder TEXT,
remote_uid BIGINT,
remote_uid_validity BIGINT,
pgp_mode TEXT NOT NULL DEFAULT 'none',
pgp_inline BIGINT NOT NULL DEFAULT 0,
pgp_attach_public_key BIGINT NOT NULL DEFAULT 0,
pgp_attach_recipient_keys BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE {{p}}folder_preferences (
folder_name TEXT PRIMARY KEY,
flagged_on_top BIGINT,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}folders (
name TEXT PRIMARY KEY,
delimiter TEXT,
parent TEXT,
flags TEXT NOT NULL DEFAULT '',
is_subscribed BIGINT NOT NULL DEFAULT 1,
total_count BIGINT NOT NULL DEFAULT 0,
unread_count BIGINT NOT NULL DEFAULT 0,
uid_validity BIGINT NOT NULL DEFAULT 0,
highest_modseq BIGINT NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
messages_updated_at TEXT
);
CREATE TABLE {{p}}identities (
id BIGSERIAL PRIMARY KEY,
display_name TEXT NOT NULL DEFAULT '',
email TEXT NOT NULL,
signature_html TEXT NOT NULL DEFAULT '',
is_default BIGINT NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
reply_to TEXT NOT NULL DEFAULT '',
bcc TEXT NOT NULL DEFAULT '',
organization TEXT NOT NULL DEFAULT '',
signature_text TEXT NOT NULL DEFAULT '',
signature_new BIGINT NOT NULL DEFAULT 1,
signature_reply BIGINT NOT NULL DEFAULT 1,
signature_forward BIGINT NOT NULL DEFAULT 1,
signature_position TEXT NOT NULL DEFAULT 'above',
pgp_fingerprint TEXT,
pgp_sign_default BIGINT NOT NULL DEFAULT 0,
pgp_encrypt_default BIGINT NOT NULL DEFAULT 0,
pgp_inline_default BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE {{p}}known_addresses (
email TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL DEFAULT ''
);
CREATE TABLE {{p}}mail_preferences (
id BIGINT PRIMARY KEY,
messages_per_page BIGINT NOT NULL DEFAULT 50,
mark_read_delay_ms BIGINT NOT NULL DEFAULT 0,
remote_images TEXT NOT NULL DEFAULT 'ask',
preferred_body TEXT NOT NULL DEFAULT 'auto',
thread_mode TEXT NOT NULL DEFAULT 'threaded',
collapse_quotes BIGINT NOT NULL DEFAULT 1,
show_snippets BIGINT NOT NULL DEFAULT 1,
default_sort TEXT NOT NULL DEFAULT 'date_desc',
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
flagged_on_top BIGINT NOT NULL DEFAULT 0,
sync_imap_keywords BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE {{p}}meeting_templates (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
url_template TEXT NOT NULL,
icon TEXT NOT NULL DEFAULT '',
is_default BIGINT NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}message_tags (
tag_id TEXT NOT NULL,
message_uid BIGINT NOT NULL,
message_folder TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
PRIMARY KEY (tag_id, message_uid, message_folder)
);
CREATE TABLE {{p}}messages (
uid BIGINT NOT NULL,
folder TEXT NOT NULL,
message_id TEXT,
in_reply_to TEXT,
subject TEXT NOT NULL DEFAULT '',
from_address TEXT NOT NULL DEFAULT '',
from_name TEXT NOT NULL DEFAULT '',
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
date TEXT NOT NULL,
flags TEXT NOT NULL DEFAULT '',
size BIGINT NOT NULL DEFAULT 0,
has_attachments BIGINT NOT NULL DEFAULT 0,
snippet TEXT NOT NULL DEFAULT '',
body_cached BIGINT NOT NULL DEFAULT 0,
body_html TEXT,
body_text TEXT,
references_header TEXT,
date_epoch BIGINT NOT NULL DEFAULT 0,
attachments_json TEXT,
raw_headers TEXT,
reaction TEXT,
email_theme BIGINT,
PRIMARY KEY (uid, folder)
);
CREATE TABLE {{p}}notification_preferences (
id BIGINT DEFAULT 1 PRIMARY KEY,
enabled BIGINT NOT NULL DEFAULT 1,
sound BIGINT NOT NULL DEFAULT 0,
folders TEXT NOT NULL DEFAULT '["INBOX"]',
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
dnd_enabled BIGINT NOT NULL DEFAULT 0,
dnd_start TEXT NOT NULL DEFAULT '22:00',
dnd_end TEXT NOT NULL DEFAULT '07:00'
);
CREATE TABLE {{p}}pgp_keys (
fingerprint TEXT PRIMARY KEY,
key_id TEXT NOT NULL,
email TEXT NOT NULL DEFAULT '',
user_id TEXT NOT NULL DEFAULT '',
public_key_armor TEXT NOT NULL,
secret_key_path TEXT,
has_secret BIGINT NOT NULL DEFAULT 0,
trust TEXT NOT NULL DEFAULT 'unknown',
source TEXT NOT NULL DEFAULT 'import',
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}pgp_preferences (
id BIGINT PRIMARY KEY,
wkd_enabled BIGINT NOT NULL DEFAULT 1,
hkp_enabled BIGINT NOT NULL DEFAULT 0,
require_trusted_encryption BIGINT NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}response_templates (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
body TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
format TEXT NOT NULL DEFAULT 'text',
UNIQUE (name)
);
CREATE TABLE {{p}}saved_searches (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
query_string TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}special_folders (
role TEXT PRIMARY KEY,
folder_name TEXT NOT NULL,
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}tags (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
color TEXT NOT NULL DEFAULT '#6b7280',
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text),
imap_keyword TEXT NOT NULL DEFAULT '',
UNIQUE (name)
);
CREATE TABLE {{p}}trusted_senders (
email TEXT PRIMARY KEY,
created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text)
);
CREATE TABLE {{p}}user_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
ALTER TABLE {{p}}contact_group_members ADD CONSTRAINT {{p}}fk_contact_group_members_0 FOREIGN KEY (contact_id) REFERENCES {{p}}contacts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}contact_group_members ADD CONSTRAINT {{p}}fk_contact_group_members_1 FOREIGN KEY (group_id) REFERENCES {{p}}contact_groups (id) ON DELETE CASCADE;
ALTER TABLE {{p}}contact_photos ADD CONSTRAINT {{p}}fk_contact_photos_0 FOREIGN KEY (contact_id) REFERENCES {{p}}contacts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}draft_attachments ADD CONSTRAINT {{p}}fk_draft_attachments_0 FOREIGN KEY (draft_id) REFERENCES {{p}}drafts (id) ON DELETE CASCADE;
ALTER TABLE {{p}}folder_preferences ADD CONSTRAINT {{p}}fk_folder_preferences_0 FOREIGN KEY (folder_name) REFERENCES {{p}}folders (name) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE {{p}}message_tags ADD CONSTRAINT {{p}}fk_message_tags_0 FOREIGN KEY (message_uid, message_folder) REFERENCES {{p}}messages (uid, folder) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE {{p}}message_tags ADD CONSTRAINT {{p}}fk_message_tags_1 FOREIGN KEY (tag_id) REFERENCES {{p}}tags (id) ON DELETE CASCADE;
ALTER TABLE {{p}}messages ADD CONSTRAINT {{p}}fk_messages_0 FOREIGN KEY (folder) REFERENCES {{p}}folders (name) ON DELETE CASCADE;
CREATE INDEX {{p}}idx_calendar_events_source_uid ON {{p}}calendar_events (source_uid);
CREATE INDEX {{p}}idx_calendar_events_time ON {{p}}calendar_events (start_time, end_time);
CREATE INDEX {{p}}idx_cgm_contact_id ON {{p}}contact_group_members (contact_id);
CREATE INDEX {{p}}idx_contacts_contact_count ON {{p}}contacts (contact_count DESC);
CREATE UNIQUE INDEX {{p}}idx_contacts_email ON {{p}}contacts (email);
CREATE INDEX {{p}}idx_contacts_last_contacted ON {{p}}contacts (last_contacted DESC);
CREATE INDEX {{p}}idx_contacts_name ON {{p}}contacts (name);
CREATE INDEX {{p}}idx_known_addresses_name ON {{p}}known_addresses (name);
CREATE INDEX {{p}}idx_message_tags_message ON {{p}}message_tags (message_uid, message_folder);
CREATE INDEX {{p}}idx_message_tags_tag ON {{p}}message_tags (tag_id);
CREATE INDEX {{p}}idx_messages_folder_date ON {{p}}messages (folder, date_epoch DESC);
CREATE INDEX {{p}}idx_messages_in_reply_to ON {{p}}messages (in_reply_to);
CREATE INDEX {{p}}idx_messages_message_id ON {{p}}messages (message_id);
CREATE INDEX {{p}}idx_pgp_keys_email ON {{p}}pgp_keys (lower(email));
CREATE UNIQUE INDEX {{p}}idx_saved_searches_name ON {{p}}saved_searches (name);
CREATE UNIQUE INDEX {{p}}idx_tags_imap_keyword ON {{p}}tags (imap_keyword) WHERE imap_keyword <> '';
-- RUSTBOX:TENANT-END
@@ -1,6 +0,0 @@
CREATE TABLE IF NOT EXISTS user_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT OR IGNORE INTO user_meta (key, value) VALUES ('schema_version', '1');
@@ -1,41 +0,0 @@
-- Folder cache: stores the IMAP folder hierarchy
CREATE TABLE IF NOT EXISTS folders (
name TEXT PRIMARY KEY,
delimiter TEXT,
parent TEXT,
flags TEXT NOT NULL DEFAULT '',
is_subscribed INTEGER NOT NULL DEFAULT 1,
total_count INTEGER NOT NULL DEFAULT 0,
unread_count INTEGER NOT NULL DEFAULT 0,
uid_validity INTEGER NOT NULL DEFAULT 0,
highest_modseq INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Message header cache: stores synced email headers per folder
CREATE TABLE IF NOT EXISTS messages (
uid INTEGER NOT NULL,
folder TEXT NOT NULL,
message_id TEXT,
in_reply_to TEXT,
subject TEXT NOT NULL DEFAULT '',
from_address TEXT NOT NULL DEFAULT '',
from_name TEXT NOT NULL DEFAULT '',
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
date TEXT NOT NULL,
flags TEXT NOT NULL DEFAULT '',
size INTEGER NOT NULL DEFAULT 0,
has_attachments INTEGER NOT NULL DEFAULT 0,
snippet TEXT NOT NULL DEFAULT '',
body_cached INTEGER NOT NULL DEFAULT 0,
body_html TEXT,
body_text TEXT,
references_header TEXT,
PRIMARY KEY (uid, folder),
FOREIGN KEY (folder) REFERENCES folders(name) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_messages_folder_date ON messages(folder, date DESC);
CREATE INDEX IF NOT EXISTS idx_messages_message_id ON messages(message_id);
CREATE INDEX IF NOT EXISTS idx_messages_in_reply_to ON messages(in_reply_to);
@@ -1,6 +0,0 @@
-- Add a sortable integer timestamp column for proper date ordering.
ALTER TABLE messages ADD COLUMN date_epoch INTEGER NOT NULL DEFAULT 0;
-- Rebuild index to use the new column for sorting.
DROP INDEX IF EXISTS idx_messages_folder_date;
CREATE INDEX idx_messages_folder_date ON messages(folder, date_epoch DESC);
@@ -1,3 +0,0 @@
-- Separate timestamp for when a folder's messages were last synced from IMAP,
-- distinct from `updated_at` which tracks when the folder list was last synced.
ALTER TABLE folders ADD COLUMN messages_updated_at TEXT;
@@ -1,24 +0,0 @@
CREATE TABLE IF NOT EXISTS drafts (
id TEXT PRIMARY KEY,
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
bcc_addresses TEXT NOT NULL DEFAULT '',
subject TEXT NOT NULL DEFAULT '',
text_body TEXT NOT NULL DEFAULT '',
html_body TEXT,
in_reply_to TEXT,
references_header TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS draft_attachments (
id TEXT PRIMARY KEY,
draft_id TEXT NOT NULL,
filename TEXT NOT NULL,
content_type TEXT NOT NULL,
size INTEGER NOT NULL,
file_path TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (draft_id) REFERENCES drafts(id) ON DELETE CASCADE
);
@@ -1,3 +0,0 @@
-- Cache attachment metadata and raw headers alongside the message body.
ALTER TABLE messages ADD COLUMN attachments_json TEXT;
ALTER TABLE messages ADD COLUMN raw_headers TEXT;
-18
View File
@@ -1,18 +0,0 @@
CREATE TABLE IF NOT EXISTS contacts (
id TEXT PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
company TEXT NOT NULL DEFAULT '',
notes TEXT NOT NULL DEFAULT '',
is_favorite INTEGER NOT NULL DEFAULT 0,
last_contacted TEXT,
contact_count INTEGER NOT NULL DEFAULT 0,
source TEXT NOT NULL DEFAULT 'manual',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_contacts_email ON contacts(email);
CREATE INDEX IF NOT EXISTS idx_contacts_name ON contacts(name);
CREATE INDEX IF NOT EXISTS idx_contacts_last_contacted ON contacts(last_contacted DESC);
CREATE INDEX IF NOT EXISTS idx_contacts_contact_count ON contacts(contact_count DESC);
-9
View File
@@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS identities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
display_name TEXT NOT NULL DEFAULT '',
email TEXT NOT NULL,
signature_html TEXT NOT NULL DEFAULT '',
is_default INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS notification_preferences (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
enabled INTEGER NOT NULL DEFAULT 1,
sound INTEGER NOT NULL DEFAULT 0,
folders TEXT NOT NULL DEFAULT '["INBOX"]',
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
INSERT OR IGNORE INTO notification_preferences (id) VALUES (1);
@@ -1,16 +0,0 @@
CREATE TABLE IF NOT EXISTS contact_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS contact_group_members (
group_id TEXT NOT NULL,
contact_id TEXT NOT NULL,
PRIMARY KEY (group_id, contact_id),
FOREIGN KEY (group_id) REFERENCES contact_groups(id) ON DELETE CASCADE,
FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_cgm_contact_id ON contact_group_members(contact_id);
@@ -1 +0,0 @@
ALTER TABLE messages ADD COLUMN reaction TEXT;
-20
View File
@@ -1,20 +0,0 @@
CREATE TABLE IF NOT EXISTS tags (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
color TEXT NOT NULL DEFAULT '#6b7280',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS message_tags (
tag_id TEXT NOT NULL,
message_uid INTEGER NOT NULL,
message_folder TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (tag_id, message_uid, message_folder),
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE,
FOREIGN KEY (message_uid, message_folder) REFERENCES messages(uid, folder) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_message_tags_message ON message_tags(message_uid, message_folder);
CREATE INDEX IF NOT EXISTS idx_message_tags_tag ON message_tags(tag_id);
@@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS display_preferences (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
density TEXT NOT NULL DEFAULT 'comfortable',
theme TEXT NOT NULL DEFAULT 'system',
language TEXT NOT NULL DEFAULT 'en',
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN compose_format TEXT NOT NULL DEFAULT 'html';
-1
View File
@@ -1 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN deep_index BOOLEAN NOT NULL DEFAULT 0;
-51
View File
@@ -1,51 +0,0 @@
CREATE TABLE calendar_events (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
location TEXT NOT NULL DEFAULT '',
start_time TEXT NOT NULL,
end_time TEXT NOT NULL,
all_day INTEGER NOT NULL DEFAULT 0,
recurrence_rule TEXT,
attendees TEXT NOT NULL DEFAULT '[]',
organizer TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'confirmed',
source TEXT NOT NULL DEFAULT 'manual',
source_uid TEXT,
source_message_uid INTEGER,
source_message_folder TEXT,
meeting_url TEXT,
color TEXT,
reminder_minutes INTEGER,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_calendar_events_time ON calendar_events(start_time, end_time);
CREATE INDEX idx_calendar_events_source_uid ON calendar_events(source_uid);
CREATE TABLE calendar_settings (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
default_view TEXT NOT NULL DEFAULT 'month',
week_starts_on INTEGER NOT NULL DEFAULT 0,
working_hours_start TEXT NOT NULL DEFAULT '09:00',
working_hours_end TEXT NOT NULL DEFAULT '17:00',
time_format TEXT NOT NULL DEFAULT '12h',
zoom_link TEXT NOT NULL DEFAULT '',
teams_link TEXT NOT NULL DEFAULT '',
meet_link TEXT NOT NULL DEFAULT '',
caldav_url TEXT NOT NULL DEFAULT '',
caldav_username TEXT NOT NULL DEFAULT '',
caldav_password TEXT NOT NULL DEFAULT '',
caldav_enabled INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE meeting_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
url_template TEXT NOT NULL,
icon TEXT NOT NULL DEFAULT '',
is_default INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1,4 +0,0 @@
-- Add email_theme column to messages table
-- NULL = not yet detected (only relevant when body_html exists)
-- 0 = Light, 1 = Dark, 2 = Transparent
ALTER TABLE messages ADD COLUMN email_theme INTEGER;
@@ -1,2 +0,0 @@
ALTER TABLE display_preferences
ADD COLUMN animation_mode TEXT NULL;
@@ -1,34 +0,0 @@
-- Denormalized table of known email addresses extracted from message headers.
-- Avoids expensive json_each() scanning of to_addresses/cc_addresses columns.
CREATE TABLE IF NOT EXISTS known_addresses (
email TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
PRIMARY KEY (email)
);
CREATE INDEX IF NOT EXISTS idx_known_addresses_name ON known_addresses(name);
-- Backfill from existing messages: from_address
INSERT INTO known_addresses (email, name)
SELECT from_address, COALESCE(from_name, '')
FROM messages
WHERE from_address != ''
ON CONFLICT(email) DO UPDATE SET name = excluded.name WHERE excluded.name != '';
-- Backfill from existing messages: to_addresses (JSON array)
INSERT INTO known_addresses (email, name)
SELECT value->>'address', COALESCE(value->>'name', '')
FROM messages, json_each(to_addresses)
WHERE json_valid(to_addresses)
AND value->>'address' IS NOT NULL
AND value->>'address' != ''
ON CONFLICT(email) DO UPDATE SET name = excluded.name WHERE excluded.name != '';
-- Backfill from existing messages: cc_addresses (JSON array)
INSERT INTO known_addresses (email, name)
SELECT value->>'address', COALESCE(value->>'name', '')
FROM messages, json_each(cc_addresses)
WHERE json_valid(cc_addresses)
AND value->>'address' IS NOT NULL
AND value->>'address' != ''
ON CONFLICT(email) DO UPDATE SET name = excluded.name WHERE excluded.name != '';
@@ -1,17 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN preview_pane TEXT NOT NULL DEFAULT 'right';
ALTER TABLE display_preferences ADD COLUMN ui_scale TEXT NOT NULL DEFAULT 'normal';
ALTER TABLE display_preferences ADD COLUMN color_preset TEXT NOT NULL DEFAULT 'sage';
ALTER TABLE display_preferences ADD COLUMN accent_color TEXT NOT NULL DEFAULT '#6f9c86';
ALTER TABLE display_preferences ADD COLUMN font_family TEXT NOT NULL DEFAULT 'system';
ALTER TABLE display_preferences ADD COLUMN font_size INTEGER NOT NULL DEFAULT 13;
ALTER TABLE display_preferences ADD COLUMN row_height INTEGER NOT NULL DEFAULT 58;
ALTER TABLE display_preferences ADD COLUMN folder_pane_width INTEGER NOT NULL DEFAULT 228;
ALTER TABLE display_preferences ADD COLUMN message_pane_width INTEGER NOT NULL DEFAULT 420;
ALTER TABLE display_preferences ADD COLUMN border_radius INTEGER NOT NULL DEFAULT 4;
ALTER TABLE display_preferences ADD COLUMN contrast TEXT NOT NULL DEFAULT 'normal';
ALTER TABLE display_preferences ADD COLUMN show_avatars INTEGER NOT NULL DEFAULT 1;
ALTER TABLE display_preferences ADD COLUMN show_attachment_icons INTEGER NOT NULL DEFAULT 1;
ALTER TABLE display_preferences ADD COLUMN show_flags INTEGER NOT NULL DEFAULT 1;
ALTER TABLE display_preferences ADD COLUMN reduce_motion INTEGER NOT NULL DEFAULT 0;
ALTER TABLE display_preferences ADD COLUMN date_format TEXT NOT NULL DEFAULT 'locale';
ALTER TABLE display_preferences ADD COLUMN time_format TEXT NOT NULL DEFAULT 'locale';
@@ -1,5 +0,0 @@
CREATE TABLE IF NOT EXISTS special_folders (
role TEXT PRIMARY KEY CHECK(role IN ('sent','drafts','trash','junk','archive')),
folder_name TEXT NOT NULL,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1,8 +0,0 @@
ALTER TABLE identities ADD COLUMN reply_to TEXT NOT NULL DEFAULT '';
ALTER TABLE identities ADD COLUMN bcc TEXT NOT NULL DEFAULT '';
ALTER TABLE identities ADD COLUMN organization TEXT NOT NULL DEFAULT '';
ALTER TABLE identities ADD COLUMN signature_text TEXT NOT NULL DEFAULT '';
ALTER TABLE identities ADD COLUMN signature_new INTEGER NOT NULL DEFAULT 1;
ALTER TABLE identities ADD COLUMN signature_reply INTEGER NOT NULL DEFAULT 1;
ALTER TABLE identities ADD COLUMN signature_forward INTEGER NOT NULL DEFAULT 1;
ALTER TABLE identities ADD COLUMN signature_position TEXT NOT NULL DEFAULT 'above';
@@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS saved_searches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
query_string TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_saved_searches_name ON saved_searches(name COLLATE NOCASE);
@@ -1,3 +0,0 @@
ALTER TABLE notification_preferences ADD COLUMN dnd_enabled INTEGER NOT NULL DEFAULT 0;
ALTER TABLE notification_preferences ADD COLUMN dnd_start TEXT NOT NULL DEFAULT '22:00';
ALTER TABLE notification_preferences ADD COLUMN dnd_end TEXT NOT NULL DEFAULT '07:00';
@@ -1,3 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN background_color TEXT NOT NULL DEFAULT '#121513';
ALTER TABLE display_preferences ADD COLUMN panel_color TEXT NOT NULL DEFAULT '#181c19';
ALTER TABLE display_preferences ADD COLUMN text_color TEXT NOT NULL DEFAULT '#edf0ec';
@@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS mail_preferences (
id INTEGER PRIMARY KEY CHECK (id = 1),
messages_per_page INTEGER NOT NULL DEFAULT 50,
mark_read_delay_ms INTEGER NOT NULL DEFAULT 0,
remote_images TEXT NOT NULL DEFAULT 'ask',
preferred_body TEXT NOT NULL DEFAULT 'auto',
thread_mode TEXT NOT NULL DEFAULT 'threaded',
collapse_quotes INTEGER NOT NULL DEFAULT 1,
show_snippets INTEGER NOT NULL DEFAULT 1,
default_sort TEXT NOT NULL DEFAULT 'date_desc',
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
INSERT OR IGNORE INTO mail_preferences (id) VALUES (1);
@@ -1,13 +0,0 @@
ALTER TABLE contacts ADD COLUMN phone TEXT NOT NULL DEFAULT '';
ALTER TABLE contacts ADD COLUMN job_title TEXT NOT NULL DEFAULT '';
ALTER TABLE contacts ADD COLUMN address TEXT NOT NULL DEFAULT '';
ALTER TABLE contacts ADD COLUMN website TEXT NOT NULL DEFAULT '';
ALTER TABLE contacts ADD COLUMN birthday TEXT NOT NULL DEFAULT '';
CREATE TABLE IF NOT EXISTS contact_photos (
contact_id TEXT PRIMARY KEY,
content_type TEXT NOT NULL,
data BLOB NOT NULL,
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE
);
@@ -1,3 +0,0 @@
ALTER TABLE contacts ADD COLUMN emails_json TEXT NOT NULL DEFAULT '[]';
ALTER TABLE contacts ADD COLUMN phones_json TEXT NOT NULL DEFAULT '[]';
ALTER TABLE contacts ADD COLUMN addresses_json TEXT NOT NULL DEFAULT '[]';
@@ -1,2 +0,0 @@
ALTER TABLE drafts ADD COLUMN request_mdn INTEGER NOT NULL DEFAULT 0;
ALTER TABLE drafts ADD COLUMN priority TEXT NOT NULL DEFAULT 'normal';
@@ -1,7 +0,0 @@
ALTER TABLE mail_preferences ADD COLUMN flagged_on_top INTEGER NOT NULL DEFAULT 0;
CREATE TABLE IF NOT EXISTS folder_preferences (
folder_name TEXT PRIMARY KEY REFERENCES folders(name) ON UPDATE CASCADE ON DELETE CASCADE,
flagged_on_top INTEGER CHECK(flagged_on_top IN (0, 1) OR flagged_on_top IS NULL),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1,4 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN compose_autosave_ms INTEGER NOT NULL DEFAULT 3000;
ALTER TABLE display_preferences ADD COLUMN default_priority TEXT NOT NULL DEFAULT 'normal';
ALTER TABLE display_preferences ADD COLUMN request_mdn_default INTEGER NOT NULL DEFAULT 0;
ALTER TABLE display_preferences ADD COLUMN attachment_reminder INTEGER NOT NULL DEFAULT 1;
@@ -1,15 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN icon_size INTEGER NOT NULL DEFAULT 18;
ALTER TABLE display_preferences ADD COLUMN toolbar_density TEXT NOT NULL DEFAULT 'normal';
ALTER TABLE display_preferences ADD COLUMN sidebar_item_height INTEGER NOT NULL DEFAULT 29;
ALTER TABLE display_preferences ADD COLUMN reader_max_width INTEGER NOT NULL DEFAULT 0;
ALTER TABLE display_preferences ADD COLUMN composer_width INTEGER NOT NULL DEFAULT 900;
ALTER TABLE display_preferences ADD COLUMN selection_color TEXT NOT NULL DEFAULT '#28352e';
ALTER TABLE display_preferences ADD COLUMN unread_font_weight INTEGER NOT NULL DEFAULT 730;
ALTER TABLE display_preferences ADD COLUMN unread_badge_style TEXT NOT NULL DEFAULT 'dot';
ALTER TABLE display_preferences ADD COLUMN compact_headers INTEGER NOT NULL DEFAULT 0;
ALTER TABLE display_preferences ADD COLUMN show_borders INTEGER NOT NULL DEFAULT 1;
ALTER TABLE display_preferences ADD COLUMN scrollbar_density TEXT NOT NULL DEFAULT 'thin';
ALTER TABLE display_preferences ADD COLUMN monochrome INTEGER NOT NULL DEFAULT 0;
ALTER TABLE display_preferences ADD COLUMN folder_background TEXT NOT NULL DEFAULT '';
ALTER TABLE display_preferences ADD COLUMN message_background TEXT NOT NULL DEFAULT '';
ALTER TABLE display_preferences ADD COLUMN reader_background TEXT NOT NULL DEFAULT '';
@@ -1 +0,0 @@
ALTER TABLE drafts ADD COLUMN compose_format TEXT NOT NULL DEFAULT 'html';
@@ -1,4 +0,0 @@
ALTER TABLE mail_preferences ADD COLUMN sync_imap_keywords INTEGER NOT NULL DEFAULT 0;
ALTER TABLE tags ADD COLUMN imap_keyword TEXT NOT NULL DEFAULT '';
UPDATE tags SET imap_keyword = 'RustBox-' || replace(id, '-', '') WHERE imap_keyword = '';
CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_imap_keyword ON tags(imap_keyword) WHERE imap_keyword <> '';
@@ -1,5 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN compose_font_family TEXT NOT NULL DEFAULT 'system';
ALTER TABLE display_preferences ADD COLUMN reply_position TEXT NOT NULL DEFAULT 'above';
ALTER TABLE display_preferences ADD COLUMN quote_style TEXT NOT NULL DEFAULT 'standard';
ALTER TABLE display_preferences ADD COLUMN forward_mode TEXT NOT NULL DEFAULT 'inline';
ALTER TABLE display_preferences ADD COLUMN spellcheck_enabled INTEGER NOT NULL DEFAULT 1;
@@ -1,3 +0,0 @@
ALTER TABLE drafts ADD COLUMN remote_folder TEXT;
ALTER TABLE drafts ADD COLUMN remote_uid INTEGER;
ALTER TABLE drafts ADD COLUMN remote_uid_validity INTEGER;
@@ -1,24 +0,0 @@
-- OpenPGP keyring metadata. Secret key material is stored outside SQLite.
CREATE TABLE IF NOT EXISTS pgp_keys (
fingerprint TEXT PRIMARY KEY,
key_id TEXT NOT NULL,
email TEXT NOT NULL DEFAULT '',
user_id TEXT NOT NULL DEFAULT '',
public_key_armor TEXT NOT NULL,
secret_key_path TEXT,
has_secret INTEGER NOT NULL DEFAULT 0,
trust TEXT NOT NULL DEFAULT 'unknown',
source TEXT NOT NULL DEFAULT 'import',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_pgp_keys_email ON pgp_keys(lower(email));
CREATE TABLE IF NOT EXISTS pgp_preferences (
id INTEGER PRIMARY KEY CHECK (id = 1),
wkd_enabled INTEGER NOT NULL DEFAULT 1,
hkp_enabled INTEGER NOT NULL DEFAULT 0,
require_trusted_encryption INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
INSERT OR IGNORE INTO pgp_preferences (id) VALUES (1);
@@ -1,4 +0,0 @@
ALTER TABLE identities ADD COLUMN pgp_fingerprint TEXT;
ALTER TABLE identities ADD COLUMN pgp_sign_default INTEGER NOT NULL DEFAULT 0;
ALTER TABLE identities ADD COLUMN pgp_encrypt_default INTEGER NOT NULL DEFAULT 0;
ALTER TABLE identities ADD COLUMN pgp_inline_default INTEGER NOT NULL DEFAULT 0;
@@ -1,2 +0,0 @@
ALTER TABLE drafts ADD COLUMN pgp_mode TEXT NOT NULL DEFAULT 'none';
ALTER TABLE drafts ADD COLUMN pgp_inline INTEGER NOT NULL DEFAULT 0;
@@ -1 +0,0 @@
ALTER TABLE drafts ADD COLUMN pgp_attach_public_key INTEGER NOT NULL DEFAULT 0;
@@ -1 +0,0 @@
ALTER TABLE drafts ADD COLUMN pgp_attach_recipient_keys INTEGER NOT NULL DEFAULT 0;
@@ -1,4 +0,0 @@
CREATE TABLE IF NOT EXISTS trusted_senders (
email TEXT PRIMARY KEY COLLATE NOCASE,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS response_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL COLLATE NOCASE UNIQUE,
body TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -1 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN interface_skin TEXT NOT NULL DEFAULT 'rustbox';
@@ -1 +0,0 @@
ALTER TABLE response_templates ADD COLUMN format TEXT NOT NULL DEFAULT 'text';
@@ -1 +0,0 @@
ALTER TABLE display_preferences ADD COLUMN preset_scale_unlocked INTEGER NOT NULL DEFAULT 0;
-23
View File
@@ -1,23 +0,0 @@
CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY NOT NULL,
account_id TEXT NOT NULL UNIQUE,
browser_id TEXT NOT NULL,
email TEXT NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash TEXT NOT NULL,
imap_host TEXT NOT NULL,
imap_port INTEGER NOT NULL,
imap_tls INTEGER NOT NULL,
imap_tls_verify INTEGER NOT NULL,
smtp_host TEXT NOT NULL,
smtp_port INTEGER NOT NULL,
smtp_tls INTEGER NOT NULL,
smtp_tls_verify INTEGER NOT NULL,
timeout_secs INTEGER NOT NULL,
created_at_unix INTEGER NOT NULL,
last_accessed_unix INTEGER NOT NULL,
user_agent TEXT NOT NULL DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_sessions_browser ON sessions(browser_id);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_hash);
CREATE INDEX IF NOT EXISTS idx_sessions_expiry ON sessions(last_accessed_unix, timeout_secs);
+344
View File
@@ -0,0 +1,344 @@
-- RustBox 0.1.1 SQLite schema.
-- One physical database contains global sessions plus isolated per-account tables.
-- Application tables are materialized from the tenant section by replacing {{p}}.
-- Baseline application schema version: 46. Future migrations start at V047.
-- RUSTBOX:GLOBAL-BEGIN
CREATE TABLE IF NOT EXISTS rustbox_accounts (
user_hash TEXT PRIMARY KEY NOT NULL,
table_prefix TEXT NOT NULL UNIQUE,
schema_version INTEGER NOT NULL DEFAULT 46,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY NOT NULL,
account_id TEXT NOT NULL UNIQUE,
browser_id TEXT NOT NULL,
email TEXT NOT NULL,
password_ciphertext TEXT NOT NULL,
user_hash TEXT NOT NULL,
imap_host TEXT NOT NULL,
imap_port INTEGER NOT NULL,
imap_tls INTEGER NOT NULL,
imap_tls_verify INTEGER NOT NULL,
smtp_host TEXT NOT NULL,
smtp_port INTEGER NOT NULL,
smtp_tls INTEGER NOT NULL,
smtp_tls_verify INTEGER NOT NULL,
timeout_secs INTEGER NOT NULL,
created_at_unix INTEGER NOT NULL,
last_accessed_unix INTEGER NOT NULL,
user_agent TEXT NOT NULL DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_sessions_browser ON sessions(browser_id);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_hash);
CREATE INDEX IF NOT EXISTS idx_sessions_expiry ON sessions(last_accessed_unix, timeout_secs);
-- RUSTBOX:GLOBAL-END
-- RUSTBOX:TENANT-BEGIN
-- {{p}} is replaced at runtime with a collision-checked per-account table prefix.
CREATE TABLE {{p}}calendar_events (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
location TEXT NOT NULL DEFAULT '',
start_time TEXT NOT NULL,
end_time TEXT NOT NULL,
all_day INTEGER NOT NULL DEFAULT 0,
recurrence_rule TEXT,
attendees TEXT NOT NULL DEFAULT '[]',
organizer TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'confirmed',
source TEXT NOT NULL DEFAULT 'manual',
source_uid TEXT,
source_message_uid INTEGER,
source_message_folder TEXT,
meeting_url TEXT,
color TEXT,
reminder_minutes INTEGER,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}calendar_settings (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
default_view TEXT NOT NULL DEFAULT 'month',
week_starts_on INTEGER NOT NULL DEFAULT 0,
working_hours_start TEXT NOT NULL DEFAULT '09:00',
working_hours_end TEXT NOT NULL DEFAULT '17:00',
time_format TEXT NOT NULL DEFAULT '12h',
zoom_link TEXT NOT NULL DEFAULT '',
teams_link TEXT NOT NULL DEFAULT '',
meet_link TEXT NOT NULL DEFAULT '',
caldav_url TEXT NOT NULL DEFAULT '',
caldav_username TEXT NOT NULL DEFAULT '',
caldav_password TEXT NOT NULL DEFAULT '',
caldav_enabled INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}contact_group_members (
group_id TEXT NOT NULL,
contact_id TEXT NOT NULL,
PRIMARY KEY (group_id, contact_id),
FOREIGN KEY (group_id) REFERENCES {{p}}contact_groups(id) ON DELETE CASCADE,
FOREIGN KEY (contact_id) REFERENCES {{p}}contacts(id) ON DELETE CASCADE
);
CREATE TABLE {{p}}contact_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}contact_photos (
contact_id TEXT PRIMARY KEY,
content_type TEXT NOT NULL,
data BLOB NOT NULL,
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (contact_id) REFERENCES {{p}}contacts(id) ON DELETE CASCADE
);
CREATE TABLE {{p}}contacts (
id TEXT PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
company TEXT NOT NULL DEFAULT '',
notes TEXT NOT NULL DEFAULT '',
is_favorite INTEGER NOT NULL DEFAULT 0,
last_contacted TEXT,
contact_count INTEGER NOT NULL DEFAULT 0,
source TEXT NOT NULL DEFAULT 'manual',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
phone TEXT NOT NULL DEFAULT '', job_title TEXT NOT NULL DEFAULT '', address TEXT NOT NULL DEFAULT '', website TEXT NOT NULL DEFAULT '', birthday TEXT NOT NULL DEFAULT '', emails_json TEXT NOT NULL DEFAULT '[]', phones_json TEXT NOT NULL DEFAULT '[]', addresses_json TEXT NOT NULL DEFAULT '[]');
CREATE TABLE {{p}}display_preferences (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
density TEXT NOT NULL DEFAULT 'comfortable',
theme TEXT NOT NULL DEFAULT 'system',
language TEXT NOT NULL DEFAULT 'en',
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
compose_format TEXT NOT NULL DEFAULT 'html', deep_index BOOLEAN NOT NULL DEFAULT 0, animation_mode TEXT NULL, preview_pane TEXT NOT NULL DEFAULT 'right', ui_scale TEXT NOT NULL DEFAULT 'normal', color_preset TEXT NOT NULL DEFAULT 'sage', accent_color TEXT NOT NULL DEFAULT '#6f9c86', font_family TEXT NOT NULL DEFAULT 'system', font_size INTEGER NOT NULL DEFAULT 13, row_height INTEGER NOT NULL DEFAULT 58, folder_pane_width INTEGER NOT NULL DEFAULT 228, message_pane_width INTEGER NOT NULL DEFAULT 420, border_radius INTEGER NOT NULL DEFAULT 4, contrast TEXT NOT NULL DEFAULT 'normal', show_avatars INTEGER NOT NULL DEFAULT 1, show_attachment_icons INTEGER NOT NULL DEFAULT 1, show_flags INTEGER NOT NULL DEFAULT 1, reduce_motion INTEGER NOT NULL DEFAULT 0, date_format TEXT NOT NULL DEFAULT 'locale', time_format TEXT NOT NULL DEFAULT 'locale', background_color TEXT NOT NULL DEFAULT '#121513', panel_color TEXT NOT NULL DEFAULT '#181c19', text_color TEXT NOT NULL DEFAULT '#edf0ec', compose_autosave_ms INTEGER NOT NULL DEFAULT 3000, default_priority TEXT NOT NULL DEFAULT 'normal', request_mdn_default INTEGER NOT NULL DEFAULT 0, attachment_reminder INTEGER NOT NULL DEFAULT 1, icon_size INTEGER NOT NULL DEFAULT 18, toolbar_density TEXT NOT NULL DEFAULT 'normal', sidebar_item_height INTEGER NOT NULL DEFAULT 29, reader_max_width INTEGER NOT NULL DEFAULT 0, composer_width INTEGER NOT NULL DEFAULT 900, selection_color TEXT NOT NULL DEFAULT '#28352e', unread_font_weight INTEGER NOT NULL DEFAULT 730, unread_badge_style TEXT NOT NULL DEFAULT 'dot', compact_headers INTEGER NOT NULL DEFAULT 0, show_borders INTEGER NOT NULL DEFAULT 1, scrollbar_density TEXT NOT NULL DEFAULT 'thin', monochrome INTEGER NOT NULL DEFAULT 0, folder_background TEXT NOT NULL DEFAULT '', message_background TEXT NOT NULL DEFAULT '', reader_background TEXT NOT NULL DEFAULT '', compose_font_family TEXT NOT NULL DEFAULT 'system', reply_position TEXT NOT NULL DEFAULT 'above', quote_style TEXT NOT NULL DEFAULT 'standard', forward_mode TEXT NOT NULL DEFAULT 'inline', spellcheck_enabled INTEGER NOT NULL DEFAULT 1, interface_skin TEXT NOT NULL DEFAULT 'rustbox', preset_scale_unlocked INTEGER NOT NULL DEFAULT 0);
CREATE TABLE {{p}}draft_attachments (
id TEXT PRIMARY KEY,
draft_id TEXT NOT NULL,
filename TEXT NOT NULL,
content_type TEXT NOT NULL,
size INTEGER NOT NULL,
file_path TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (draft_id) REFERENCES {{p}}drafts(id) ON DELETE CASCADE
);
CREATE TABLE {{p}}drafts (
id TEXT PRIMARY KEY,
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
bcc_addresses TEXT NOT NULL DEFAULT '',
subject TEXT NOT NULL DEFAULT '',
text_body TEXT NOT NULL DEFAULT '',
html_body TEXT,
in_reply_to TEXT,
references_header TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
request_mdn INTEGER NOT NULL DEFAULT 0, priority TEXT NOT NULL DEFAULT 'normal', compose_format TEXT NOT NULL DEFAULT 'html', remote_folder TEXT, remote_uid INTEGER, remote_uid_validity INTEGER, pgp_mode TEXT NOT NULL DEFAULT 'none', pgp_inline INTEGER NOT NULL DEFAULT 0, pgp_attach_public_key INTEGER NOT NULL DEFAULT 0, pgp_attach_recipient_keys INTEGER NOT NULL DEFAULT 0);
CREATE TABLE {{p}}folder_preferences (
folder_name TEXT PRIMARY KEY REFERENCES {{p}}folders(name) ON UPDATE CASCADE ON DELETE CASCADE,
flagged_on_top INTEGER CHECK(flagged_on_top IN (0, 1) OR flagged_on_top IS NULL),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}folders (
name TEXT PRIMARY KEY,
delimiter TEXT,
parent TEXT,
flags TEXT NOT NULL DEFAULT '',
is_subscribed INTEGER NOT NULL DEFAULT 1,
total_count INTEGER NOT NULL DEFAULT 0,
unread_count INTEGER NOT NULL DEFAULT 0,
uid_validity INTEGER NOT NULL DEFAULT 0,
highest_modseq INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
messages_updated_at TEXT);
CREATE TABLE {{p}}identities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
display_name TEXT NOT NULL DEFAULT '',
email TEXT NOT NULL,
signature_html TEXT NOT NULL DEFAULT '',
is_default INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
reply_to TEXT NOT NULL DEFAULT '', bcc TEXT NOT NULL DEFAULT '', organization TEXT NOT NULL DEFAULT '', signature_text TEXT NOT NULL DEFAULT '', signature_new INTEGER NOT NULL DEFAULT 1, signature_reply INTEGER NOT NULL DEFAULT 1, signature_forward INTEGER NOT NULL DEFAULT 1, signature_position TEXT NOT NULL DEFAULT 'above', pgp_fingerprint TEXT, pgp_sign_default INTEGER NOT NULL DEFAULT 0, pgp_encrypt_default INTEGER NOT NULL DEFAULT 0, pgp_inline_default INTEGER NOT NULL DEFAULT 0);
CREATE TABLE {{p}}known_addresses (
email TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
PRIMARY KEY (email)
);
CREATE TABLE {{p}}mail_preferences (
id INTEGER PRIMARY KEY CHECK (id = 1),
messages_per_page INTEGER NOT NULL DEFAULT 50,
mark_read_delay_ms INTEGER NOT NULL DEFAULT 0,
remote_images TEXT NOT NULL DEFAULT 'ask',
preferred_body TEXT NOT NULL DEFAULT 'auto',
thread_mode TEXT NOT NULL DEFAULT 'threaded',
collapse_quotes INTEGER NOT NULL DEFAULT 1,
show_snippets INTEGER NOT NULL DEFAULT 1,
default_sort TEXT NOT NULL DEFAULT 'date_desc',
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
flagged_on_top INTEGER NOT NULL DEFAULT 0, sync_imap_keywords INTEGER NOT NULL DEFAULT 0);
CREATE TABLE {{p}}meeting_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
url_template TEXT NOT NULL,
icon TEXT NOT NULL DEFAULT '',
is_default INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}message_tags (
tag_id TEXT NOT NULL,
message_uid INTEGER NOT NULL,
message_folder TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (tag_id, message_uid, message_folder),
FOREIGN KEY (tag_id) REFERENCES {{p}}tags(id) ON DELETE CASCADE,
FOREIGN KEY (message_uid, message_folder) REFERENCES {{p}}messages(uid, folder) ON DELETE CASCADE
);
CREATE TABLE {{p}}messages (
uid INTEGER NOT NULL,
folder TEXT NOT NULL,
message_id TEXT,
in_reply_to TEXT,
subject TEXT NOT NULL DEFAULT '',
from_address TEXT NOT NULL DEFAULT '',
from_name TEXT NOT NULL DEFAULT '',
to_addresses TEXT NOT NULL DEFAULT '',
cc_addresses TEXT NOT NULL DEFAULT '',
date TEXT NOT NULL,
flags TEXT NOT NULL DEFAULT '',
size INTEGER NOT NULL DEFAULT 0,
has_attachments INTEGER NOT NULL DEFAULT 0,
snippet TEXT NOT NULL DEFAULT '',
body_cached INTEGER NOT NULL DEFAULT 0,
body_html TEXT,
body_text TEXT,
references_header TEXT, date_epoch INTEGER NOT NULL DEFAULT 0, attachments_json TEXT, raw_headers TEXT, reaction TEXT, email_theme INTEGER,
PRIMARY KEY (uid, folder),
FOREIGN KEY (folder) REFERENCES {{p}}folders(name) ON DELETE CASCADE
);
CREATE TABLE {{p}}notification_preferences (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
enabled INTEGER NOT NULL DEFAULT 1,
sound INTEGER NOT NULL DEFAULT 0,
folders TEXT NOT NULL DEFAULT '["INBOX"]',
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
dnd_enabled INTEGER NOT NULL DEFAULT 0, dnd_start TEXT NOT NULL DEFAULT '22:00', dnd_end TEXT NOT NULL DEFAULT '07:00');
CREATE TABLE {{p}}pgp_keys (
fingerprint TEXT PRIMARY KEY,
key_id TEXT NOT NULL,
email TEXT NOT NULL DEFAULT '',
user_id TEXT NOT NULL DEFAULT '',
public_key_armor TEXT NOT NULL,
secret_key_path TEXT,
has_secret INTEGER NOT NULL DEFAULT 0,
trust TEXT NOT NULL DEFAULT 'unknown',
source TEXT NOT NULL DEFAULT 'import',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}pgp_preferences (
id INTEGER PRIMARY KEY CHECK (id = 1),
wkd_enabled INTEGER NOT NULL DEFAULT 1,
hkp_enabled INTEGER NOT NULL DEFAULT 0,
require_trusted_encryption INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}response_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL COLLATE NOCASE UNIQUE,
body TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
format TEXT NOT NULL DEFAULT 'text');
CREATE TABLE {{p}}saved_searches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
query_string TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}special_folders (
role TEXT PRIMARY KEY CHECK(role IN ('sent','drafts','trash','junk','archive')),
folder_name TEXT NOT NULL,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}tags (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
color TEXT NOT NULL DEFAULT '#6b7280',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
imap_keyword TEXT NOT NULL DEFAULT '');
CREATE TABLE {{p}}trusted_senders (
email TEXT PRIMARY KEY COLLATE NOCASE,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE {{p}}user_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE INDEX {{p}}idx_calendar_events_source_uid ON {{p}}calendar_events(source_uid);
CREATE INDEX {{p}}idx_calendar_events_time ON {{p}}calendar_events(start_time, end_time);
CREATE INDEX {{p}}idx_cgm_contact_id ON {{p}}contact_group_members(contact_id);
CREATE INDEX {{p}}idx_contacts_contact_count ON {{p}}contacts(contact_count DESC);
CREATE UNIQUE INDEX {{p}}idx_contacts_email ON {{p}}contacts(email);
CREATE INDEX {{p}}idx_contacts_last_contacted ON {{p}}contacts(last_contacted DESC);
CREATE INDEX {{p}}idx_contacts_name ON {{p}}contacts(name);
CREATE INDEX {{p}}idx_known_addresses_name ON {{p}}known_addresses(name);
CREATE INDEX {{p}}idx_message_tags_message ON {{p}}message_tags(message_uid, message_folder);
CREATE INDEX {{p}}idx_message_tags_tag ON {{p}}message_tags(tag_id);
CREATE INDEX {{p}}idx_messages_folder_date ON {{p}}messages(folder, date_epoch DESC);
CREATE INDEX {{p}}idx_messages_in_reply_to ON {{p}}messages(in_reply_to);
CREATE INDEX {{p}}idx_messages_message_id ON {{p}}messages(message_id);
CREATE INDEX {{p}}idx_pgp_keys_email ON {{p}}pgp_keys(lower(email));
CREATE UNIQUE INDEX {{p}}idx_saved_searches_name ON {{p}}saved_searches(name COLLATE NOCASE);
CREATE UNIQUE INDEX {{p}}idx_tags_imap_keyword ON {{p}}tags(imap_keyword) WHERE imap_keyword <> '';
-- RUSTBOX:TENANT-END