SparkBiz — Database Entity Relationship Diagram

All 30 tables and their foreign-key relationships, colour-coded by module. To keep the diagram readable, TENANTS shows its conceptually distinct columns only — its 12 repetitive per-module document-numbering columns (invoice_number_* / variation_number_* / esign_number_*, each a prefix/padding/start/year_mode group, plus a shared fy_start_month) are omitted here and fully listed in database-guide.html, which is the exhaustive column-by-column reference. Last regenerated 2026-08-27, updated 2026-08-31 (E-Sign templates, auto-suppression, platform settings), updated 2026-09-04 (Payslip module removed), updated 2026-09-14 (Invoice partial payments — new INVOICE_PAYMENTS table), updated 2026-09-30 (email footer — new FOOTER_LOGOS table + TENANTS email_footer_* columns) against backend/db/database.py.

Core / Multi-tenant
Invoice module
Variations module
E-Sign module
Auth / Security
Shared / cross-module
Admin
erDiagram %% ── CORE / MULTI-TENANT ──────────────────────────────────────────────── TENANTS { string id PK string business_name string abn string email UK string phone text address string website text logo_url string brand_color string ui_theme string email_footer_logo_layout string email_footer_note string timezone string bsb string account_number string account_name string payid string bpay_biller string bpay_ref string plan datetime plan_expires_at datetime trial_invoice_until datetime trial_variation_until datetime trial_esign_until boolean has_invoice boolean has_variation boolean has_esign string stripe_customer_id string stripe_subscription_id string invoice_line_item_mode string invoice_gst_mode string variation_gst_mode string variation_line_item_mode text admin_notes boolean is_active datetime suspended_at datetime created_at } USERS { string id PK string tenant_id FK string email UK string hashed_password string full_name boolean is_active boolean is_admin boolean is_verified string email_send_method text gmail_access_token text gmail_refresh_token datetime gmail_token_expiry string gmail_connected_email text microsoft_access_token text microsoft_refresh_token datetime microsoft_token_expiry string microsoft_connected_email string smtp_host integer smtp_port string smtp_username text smtp_password_enc string smtp_from_name datetime created_at } TENANTS ||--o{ USERS : "has" %% ── INVOICE MODULE ────────────────────────────────────────────────────── CLIENTS { string id PK string tenant_id FK string name string email string phone text address string company text notes boolean is_active datetime created_at } INVOICES { string id PK string tenant_id FK string client_id FK string invoice_number string status datetime issue_date datetime due_date numeric subtotal numeric gst_amount numeric total_amount string line_item_mode string gst_mode string email_subject string cc_emails text notes text pdf_url datetime sent_at datetime viewed_at datetime paid_at numeric paid_amount datetime created_at datetime updated_at } INVOICE_LINE_ITEMS { string id PK string invoice_id FK string description numeric quantity numeric unit_price numeric amount } INVOICE_PAYMENTS { string id PK string invoice_id FK numeric amount datetime paid_at string note datetime created_at } BANK_TRANSACTIONS { string id PK string tenant_id FK datetime transaction_date text description numeric amount string bank_reference string source string matched_invoice_id FK integer match_confidence boolean is_confirmed datetime created_at } TENANTS ||--o{ CLIENTS : "has" TENANTS ||--o{ INVOICES : "has" TENANTS ||--o{ BANK_TRANSACTIONS : "has" CLIENTS ||--o{ INVOICES : "billed via" INVOICES ||--o{ INVOICE_LINE_ITEMS : "contains" INVOICES ||--o{ INVOICE_PAYMENTS : "settled by" INVOICES ||--o| BANK_TRANSACTIONS : "matched by" %% ── VARIATIONS MODULE ─────────────────────────────────────────────────── PROJECTS { string id PK string tenant_id FK string project_name text address string homeowner_name string homeowner_email string homeowner_phone string builder_reference string status boolean is_active datetime created_at } VARIATIONS { string id PK string project_id FK string tenant_id FK string variation_number text description numeric original_price numeric new_price numeric price_difference numeric new_price_gst string status string approval_token UK datetime token_expires_at text notes boolean hide_price string gst_mode string line_item_mode string email_subject string cc_emails datetime sent_at datetime created_at datetime updated_at } VARIATION_LINE_ITEMS { string id PK string variation_id FK string description numeric quantity numeric unit_price_before numeric unit_price_after numeric total_before numeric total_after } VARIATION_APPROVALS { string id PK string variation_id FK "unique" string decision datetime approved_at string ip_address text user_agent string homeowner_name text decline_reason } VARIATION_ATTACHMENTS { string id PK string variation_id FK string filename string content_type string s3_key datetime uploaded_at } TENANTS ||--o{ PROJECTS : "has" PROJECTS ||--o{ VARIATIONS : "has" VARIATIONS ||--o| VARIATION_APPROVALS : "has one" VARIATIONS ||--o{ VARIATION_ATTACHMENTS : "has" VARIATIONS ||--o{ VARIATION_LINE_ITEMS : "contains (optional)" %% ── E-SIGN MODULE ─────────────────────────────────────────────────────── ESIGN_DOCUMENTS { string id PK string tenant_id FK string created_by_user_id FK string document_number string title string original_filename string source_pdf_key integer page_count string status string final_pdf_key text decline_reason string email_subject datetime sent_at datetime completed_at datetime declined_at datetime cancelled_at datetime created_at datetime updated_at } ESIGN_RECIPIENTS { string id PK string document_id FK string name string email string role "signer or cc" integer sort_order string color_hex string status string access_token UK datetime token_expires_at datetime viewed_at datetime completed_at datetime declined_at string ip_address text user_agent text decline_reason datetime consented_at integer group_number datetime activated_at datetime created_at } ESIGN_FIELDS { string id PK string document_id FK string recipient_id FK string field_type integer page_number float x float y float width float height boolean required string radio_group boolean group_exclusive text value_text datetime filled_at datetime created_at } ESIGN_TEMPLATES { string id PK string tenant_id FK string created_by_user_id FK string name text description string original_filename string source_pdf_key integer page_count string default_email_subject datetime created_at datetime updated_at } ESIGN_TEMPLATE_ROLES { string id PK string template_id FK string label string role "signer or cc" string color_hex integer sort_order integer group_number } ESIGN_TEMPLATE_FIELDS { string id PK string template_id FK string template_role_id FK string field_type integer page_number float x float y float width float height boolean required string radio_group boolean group_exclusive } TENANTS ||--o{ ESIGN_DOCUMENTS : "has" USERS ||--o{ ESIGN_DOCUMENTS : "created by" ESIGN_DOCUMENTS ||--o{ ESIGN_RECIPIENTS : "has" ESIGN_DOCUMENTS ||--o{ ESIGN_FIELDS : "has" ESIGN_RECIPIENTS ||--o{ ESIGN_FIELDS : "owns" TENANTS ||--o{ ESIGN_TEMPLATES : "has" USERS ||--o{ ESIGN_TEMPLATES : "created by" ESIGN_TEMPLATES ||--o{ ESIGN_TEMPLATE_ROLES : "has" ESIGN_TEMPLATES ||--o{ ESIGN_TEMPLATE_FIELDS : "has" ESIGN_TEMPLATE_ROLES ||--o{ ESIGN_TEMPLATE_FIELDS : "owns" %% ── AUTH / SECURITY ───────────────────────────────────────────────────── PASSWORD_RESET_TOKENS { string id PK string user_id FK string token UK datetime expires_at boolean used datetime created_at } EMAIL_VERIFICATION_TOKENS { string id PK string user_id FK string token UK datetime expires_at boolean used datetime created_at } USERS ||--o{ PASSWORD_RESET_TOKENS : "requests" USERS ||--o{ EMAIL_VERIFICATION_TOKENS : "requests" %% ── SHARED / CROSS-MODULE ─────────────────────────────────────────────── ITEM_DESCRIPTIONS { string id PK string tenant_id FK string module string description datetime created_at } FOOTER_LOGOS { string id PK string tenant_id FK text image_data int sort_order datetime created_at } EMAIL_SUBJECT_OVERRIDES { string id PK string tenant_id FK string email_type string subject_template datetime created_at datetime updated_at } REQUEST_TEMPLATES { string id PK string tenant_id FK string name string subject text body datetime created_at datetime updated_at } REQUEST_LOGS { string id PK string tenant_id FK string module string recipient_id "no FK — Client/Project" string recipient_name string recipient_email string template_name string subject datetime sent_at } EMAIL_SEND_LOG { string id PK string tenant_id FK string module string recipient string subject string provider boolean success text error datetime sent_at } SES_EVENTS { string id PK string event_type string bounce_type string bounce_subtype string complaint_feedback_type string recipient string source_email string tenant_id FK "nullable, best-effort match" string module text raw_payload datetime received_at } SUPPRESSED_EMAILS { string id PK string tenant_id FK string email "stored lower-cased" string reason "hard_bounce / complaint / repeated_soft_bounce" string module boolean is_active integer soft_bounce_count string ses_event_id "no FK — snapshot" text detail datetime created_at datetime updated_at datetime cleared_at string cleared_by } TENANTS ||--o{ ITEM_DESCRIPTIONS : "has" TENANTS ||--o{ EMAIL_SUBJECT_OVERRIDES : "has" TENANTS ||--o{ FOOTER_LOGOS : "has" TENANTS ||--o{ REQUEST_TEMPLATES : "has" TENANTS ||--o{ REQUEST_LOGS : "has" TENANTS ||--o{ EMAIL_SEND_LOG : "has" TENANTS |o--o{ SES_EVENTS : "resolved (optional)" TENANTS ||--o{ SUPPRESSED_EMAILS : "has" %% ── ADMIN ──────────────────────────────────────────────────────────────── ADMIN_AUDIT_LOG { string id PK string admin_user_id "no FK — snapshotted" string admin_email string action string tenant_id "no FK — snapshotted" string tenant_business_name text detail datetime created_at } PLATFORM_SETTINGS { string key PK text value datetime updated_at }
Module access rules — four independent boolean flags on TENANTS are authoritative (plan is display-only, not an access gate):
has_invoice → Clients + Invoices + Invoice Line Items + Bank Reconcile  |  has_variation → Projects + Variations + Variation Line Items + Approvals + Attachments  |  has_esign → E-Sign Documents + Recipients + Fields + Templates (+ Template Roles / Template Fields) (standalone module, not part of the original 3-module bundle definition but included when a tenant buys "bundle")

Not gated by a module flag — ITEM_DESCRIPTIONS/EMAIL_SUBJECT_OVERRIDES are shared utilities scoped by their own module/email_type column rather than a separate access flag; FOOTER_LOGOS feeds the signature on every customer email, whatever the module; REQUEST_TEMPLATES/REQUEST_LOGS (E-Request) are available to any tenant with at least one of Invoice/Variation active; EMAIL_SEND_LOG/SES_EVENTS/ADMIN_AUDIT_LOG/PLATFORM_SETTINGS are infra/admin-only, not tenant-facing at all. SUPPRESSED_EMAILS is populated automatically from SES bounce/complaint events and blocks further sends to that address, but each tenant can view and clear their own entries (badges on the Customers / Projects tabs + a re-enable flow).