v0.0.5: gedeelde mailboxen (info@, facturen@, nieuwsbrief@, persoonlijk) met eigen IMAP/SMTP, afzender, rol en toegang per gebruiker; inbox per mailbox en versturen vanuit een gekozen mailbox; routines (jobs.py: types met @jobs.register, interval, instellingen, logboek, slot tegen dubbel draaien; app.py scheduler/tick) voor e-mail ophalen, nieuwsbrieven versturen en opschonen; meldingen (bel, bureaubladmelding); nieuwsbrieven met segmenten, testmail, inplannen en versturen per batch over één verbinding, afmeldlink met List-Unsubscribe en bounceverwerking; oude mailinstellingen worden de eerste mailbox
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8f6e1ab443
commit
cad838f1f4
+106
@@ -198,3 +198,109 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_events_href ON events(user_id, href);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_events_uid ON events(user_id, uid);
|
||||
CREATE INDEX IF NOT EXISTS idx_events_start ON events(starts_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_events_contact ON events(contact_id);
|
||||
|
||||
-- Mailboxen: elk een eigen IMAP/SMTP-account (info@, facturen@, nieuwsbrief@, persoonlijk). purpose = rol
|
||||
-- (MAILBOX_PURPOSES in app.py); toegang via mailbox_users, zonder regels is de mailbox gedeeld met iedereen.
|
||||
CREATE TABLE IF NOT EXISTS mailboxes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
purpose TEXT NOT NULL DEFAULT 'inbox',
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
notify INTEGER NOT NULL DEFAULT 1,
|
||||
imap_host TEXT DEFAULT '', imap_port TEXT DEFAULT '', imap_security TEXT DEFAULT '', imap_user TEXT DEFAULT '',
|
||||
imap_pass TEXT DEFAULT '', imap_folder TEXT DEFAULT '', imap_days TEXT DEFAULT '',
|
||||
smtp_host TEXT DEFAULT '', smtp_port TEXT DEFAULT '', smtp_security TEXT DEFAULT '', smtp_user TEXT DEFAULT '',
|
||||
smtp_pass TEXT DEFAULT '', smtp_sent_folder TEXT DEFAULT '', smtp_from TEXT DEFAULT '',
|
||||
signature TEXT DEFAULT '',
|
||||
last_sync TEXT,
|
||||
last_error TEXT DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS mailbox_users (
|
||||
mailbox_id INTEGER NOT NULL REFERENCES mailboxes(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (mailbox_id, user_id)
|
||||
);
|
||||
|
||||
-- Meldingen per gebruiker (bel in de bovenbalk); url = waar de melding heen leidt.
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
kind TEXT DEFAULT '',
|
||||
title TEXT NOT NULL,
|
||||
body TEXT DEFAULT '',
|
||||
url TEXT DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
read_at TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_id, read_at);
|
||||
|
||||
-- Routines (jobs.py): een type met eigen instellingen (config, JSON) en een interval in minuten.
|
||||
-- running_since = slot tegen dubbel draaien.
|
||||
CREATE TABLE IF NOT EXISTS jobs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
kind TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
interval_minutes INTEGER NOT NULL DEFAULT 60,
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
next_run TEXT,
|
||||
last_run TEXT,
|
||||
last_status TEXT DEFAULT '',
|
||||
last_message TEXT DEFAULT '',
|
||||
running_since TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS job_runs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
job_id INTEGER NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
||||
started_at TEXT NOT NULL,
|
||||
finished_at TEXT,
|
||||
status TEXT NOT NULL,
|
||||
message TEXT DEFAULT '',
|
||||
manual INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_job_runs_job ON job_runs(job_id, started_at);
|
||||
|
||||
-- Segmenten: een opgeslagen selectie van contacten (filters als JSON, zie segment_where in app.py).
|
||||
CREATE TABLE IF NOT EXISTS segments (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
filters TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Nieuwsbrieven (bulkmail): bij het inplannen worden de ontvangers uit het segment vastgelegd; de routine
|
||||
-- "Nieuwsbrieven versturen" verstuurt ze per batch. base_url = adres van de CRM voor de afmeldlink.
|
||||
CREATE TABLE IF NOT EXISTS campaigns (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
mailbox_id INTEGER REFERENCES mailboxes(id) ON DELETE SET NULL,
|
||||
segment_id INTEGER REFERENCES segments(id) ON DELETE SET NULL,
|
||||
subject TEXT DEFAULT '',
|
||||
body TEXT DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'concept',
|
||||
scheduled_at TEXT,
|
||||
started_at TEXT,
|
||||
finished_at TEXT,
|
||||
base_url TEXT DEFAULT '',
|
||||
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS campaign_recipients (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
campaign_id INTEGER NOT NULL REFERENCES campaigns(id) ON DELETE CASCADE,
|
||||
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
|
||||
email TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'wacht',
|
||||
error TEXT DEFAULT '',
|
||||
sent_at TEXT,
|
||||
UNIQUE (campaign_id, email)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_campaign_recipients ON campaign_recipients(campaign_id, status);
|
||||
|
||||
Reference in New Issue
Block a user