User guide
Database
On this page
SQLite, default ~/.invoiceguard/invoiceguard.db (override with $INVOICEGUARD_DB). Both the CLI and the dashboard read and write these tables — column names and types are frozen; additive migrations only.
CREATE TABLE clients(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
phone TEXT,
created_at TEXT NOT NULL
);
CREATE TABLE projects(
id INTEGER PRIMARY KEY,
client_id INTEGER NOT NULL REFERENCES clients(id),
title TEXT NOT NULL,
amount_cents INTEGER NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
deposit_pct REAL NOT NULL DEFAULT 50.0,
late_fee_pct REAL NOT NULL DEFAULT 1.5,
late_fee_grace_days INTEGER NOT NULL DEFAULT 15,
contract_md TEXT NOT NULL,
contract_ack INTEGER NOT NULL DEFAULT 0,
contract_ack_at TEXT,
created_at TEXT NOT NULL
);
CREATE TABLE invoices(
id INTEGER PRIMARY KEY,
project_id INTEGER NOT NULL REFERENCES projects(id),
kind TEXT NOT NULL,
amount_cents INTEGER NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
status TEXT NOT NULL DEFAULT 'draft',
stripe_url TEXT,
stripe_session_id TEXT,
due_date TEXT,
sent_at TEXT,
paid_at TEXT,
created_at TEXT NOT NULL
);
CREATE TABLE dunning_events(
id INTEGER PRIMARY KEY,
invoice_id INTEGER NOT NULL REFERENCES invoices(id),
stage TEXT NOT NULL,
sent_at TEXT NOT NULL
);
CREATE TABLE payments(
id INTEGER PRIMARY KEY,
invoice_id INTEGER NOT NULL REFERENCES invoices(id),
amount_cents INTEGER NOT NULL CHECK (amount_cents > 0),
method TEXT NOT NULL DEFAULT 'manual',
note TEXT,
paid_at TEXT NOT NULL
);
CREATE TABLE signatures(
id INTEGER PRIMARY KEY,
project_id INTEGER NOT NULL REFERENCES projects(id),
token TEXT NOT NULL UNIQUE,
status TEXT NOT NULL DEFAULT 'pending',
signer_name TEXT,
signature_image TEXT,
contract_hash TEXT,
signed_at TEXT,
created_at TEXT NOT NULL
);
CREATE TABLE message_events(
id INTEGER PRIMARY KEY,
invoice_id INTEGER NOT NULL REFERENCES invoices(id),
channel TEXT NOT NULL DEFAULT 'sms',
stage TEXT NOT NULL,
to_addr TEXT NOT NULL,
provider_sid TEXT,
sent_at TEXT NOT NULL
);
Enumerations
- Invoice kinds:
deposit | milestone | final - Invoice statuses:
draft | sent | partially-paid | paid | overdue | void(partially-paidadded in v0.2.0) - Dunning stages:
day1 | day7 | day15
Notes
- Money is stored as integer cents (
amount_cents) — no float rounding bugs. - Timestamps are ISO-8601 UTC strings.
- The dashboard's
web/db.pymodule is the second implementation of this schema used by the web app; both follow the same frozen contract. seed_demo.py(in the repo) seeds a demo database where every sample name carries a(demo)suffix so demo data can never be mistaken for real clients.- The
paymentstable (v0.2.0) is the ledger: everyrecord-payment,mark-paid, and Stripe webhook writes rows here. Databases created before v0.2.0 get a labeled backfill row for invoices already markedpaid, so outstanding balances stay truthful without any manual migration. clients.phoneand themessage_eventstable (v0.5.0) support SMS/WhatsApp escalation. Existing databases gain both automatically on first open (additive migration, same pattern as the payments backfill).