Flask + SQLite, in de Van Emous-huisstijl (tokens uit het design system, GSAP-effecten volgens de motion-regels, uit bij prefers-reduced-motion). - Leads en contactpersonen: status, toewijzen, verwachte waarde, omzetten naar klant, tijdlijn, bestanden, taken/opvolging - Relaties (zoals accounts in EspoCRM): klantbundels (huishouden/familie) en partners met type (leverancier, aannemer, ...); leveranciers van producten worden automatisch partners - API voor formulieren (POST /api/leads) met dubbele-leaddetectie, bestanden en configurator-ontwerpen (house-design JSON) - Import van CSV/JSON (leads, relaties, producten) met kolomkoppeling; configurator-formaat - Producten met SKU als vaste sleutel, mutatiehistorie, POST /api/products, CSV-export; offerteregels houden hun eigen prijs - Offertes met btw per tarief en afdrukversie (PDF via de browser) - Inbox via IMAP/SMTP, gekoppeld aan contacten - Gebruikers (beheerder/medewerker) en klantportaal (offertes accepteren, bestanden, berichten) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
161 lines
4.9 KiB
SQL
161 lines
4.9 KiB
SQL
CREATE TABLE IF NOT EXISTS settings (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
email TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
|
password_hash TEXT NOT NULL,
|
|
role TEXT NOT NULL DEFAULT 'user',
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
-- Relaties (zoals accounts in EspoCRM): klantbundels (huishouden, familie, bedrijf) en partners
|
|
-- (leverancier, aannemer, ...). Contactpersonen hangen eronder met een rol.
|
|
CREATE TABLE IF NOT EXISTS relations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
kind TEXT NOT NULL DEFAULT 'klant',
|
|
type TEXT DEFAULT '',
|
|
name TEXT NOT NULL,
|
|
email TEXT DEFAULT '',
|
|
phone TEXT DEFAULT '',
|
|
website TEXT DEFAULT '',
|
|
address TEXT DEFAULT '',
|
|
postcode TEXT DEFAULT '',
|
|
city TEXT DEFAULT '',
|
|
kvk TEXT DEFAULT '',
|
|
notes TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_relations_name ON relations(kind, name COLLATE NOCASE);
|
|
|
|
CREATE TABLE IF NOT EXISTS contacts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL DEFAULT '',
|
|
email TEXT DEFAULT '',
|
|
phone TEXT DEFAULT '',
|
|
company TEXT DEFAULT '',
|
|
address TEXT DEFAULT '',
|
|
postcode TEXT DEFAULT '',
|
|
city TEXT DEFAULT '',
|
|
type TEXT NOT NULL DEFAULT 'lead',
|
|
status TEXT NOT NULL DEFAULT 'nieuw',
|
|
source TEXT DEFAULT '',
|
|
value REAL NOT NULL DEFAULT 0,
|
|
assigned_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
relation_id INTEGER REFERENCES relations(id) ON DELETE SET NULL,
|
|
relation_role TEXT DEFAULT '',
|
|
portal_token TEXT,
|
|
portal_password_hash TEXT,
|
|
portal_last_login TEXT,
|
|
notes TEXT DEFAULT '',
|
|
extra TEXT DEFAULT '{}',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_contacts_email ON contacts(email COLLATE NOCASE);
|
|
|
|
CREATE TABLE IF NOT EXISTS activities (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
contact_id INTEGER NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
|
type TEXT NOT NULL,
|
|
body TEXT DEFAULT '',
|
|
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS files (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
contact_id INTEGER REFERENCES contacts(id) ON DELETE CASCADE,
|
|
stored TEXT NOT NULL,
|
|
original TEXT NOT NULL,
|
|
mime TEXT DEFAULT '',
|
|
size INTEGER DEFAULT 0,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS products (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
sku TEXT DEFAULT '',
|
|
description TEXT DEFAULT '',
|
|
unit TEXT DEFAULT 'stuk',
|
|
supplier TEXT DEFAULT '',
|
|
supplier_id INTEGER REFERENCES relations(id) ON DELETE SET NULL,
|
|
price REAL NOT NULL DEFAULT 0,
|
|
vat REAL NOT NULL DEFAULT 21,
|
|
image TEXT DEFAULT '',
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT
|
|
);
|
|
|
|
-- Elke wijziging aan een product (handmatig, import of API), zodat prijsmutaties terug te zien zijn.
|
|
CREATE TABLE IF NOT EXISTS product_history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
|
field TEXT NOT NULL,
|
|
old_value TEXT,
|
|
new_value TEXT,
|
|
source TEXT DEFAULT '',
|
|
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_product_history ON product_history(product_id, created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS quotes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
number TEXT UNIQUE NOT NULL,
|
|
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
|
|
status TEXT NOT NULL DEFAULT 'concept',
|
|
title TEXT DEFAULT '',
|
|
date TEXT NOT NULL,
|
|
valid_until TEXT,
|
|
intro TEXT DEFAULT '',
|
|
notes TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS quote_lines (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
quote_id INTEGER NOT NULL REFERENCES quotes(id) ON DELETE CASCADE,
|
|
position INTEGER NOT NULL DEFAULT 0,
|
|
product_id INTEGER,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
qty REAL NOT NULL DEFAULT 1,
|
|
unit TEXT DEFAULT '',
|
|
price REAL NOT NULL DEFAULT 0,
|
|
vat REAL NOT NULL DEFAULT 21
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS emails (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
uid TEXT UNIQUE,
|
|
message_id TEXT DEFAULT '',
|
|
direction TEXT NOT NULL DEFAULT 'in',
|
|
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
|
|
from_name TEXT DEFAULT '',
|
|
from_addr TEXT DEFAULT '',
|
|
to_addr TEXT DEFAULT '',
|
|
subject TEXT DEFAULT '',
|
|
body TEXT DEFAULT '',
|
|
date TEXT NOT NULL,
|
|
is_read INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_emails_from ON emails(from_addr);
|
|
|
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
contact_id INTEGER REFERENCES contacts(id) ON DELETE CASCADE,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
title TEXT NOT NULL,
|
|
due_date TEXT,
|
|
done INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL
|
|
);
|