Commit graph

4 commits

Author SHA1 Message Date
969101600d
db: scope invoices to owner, add void + snapshot columns
- owner_id (FK users, ON DELETE RESTRICT) + index on (owner_id, created_at DESC)
- client_id (nullable FK clients, ON DELETE RESTRICT) for client back-references
- issuer_snapshot jsonb + snapshot_version: invoices freeze the issuer's
  legal-entity fields at issue time so historical PDFs render unchanged when
  the user later edits their profile
- voided_at + voided_reason: soft-void instead of delete, since invoices
  are retained indefinitely
- swap unique(number) for unique(owner_id, number): numbers are now per-user,
  not global

DROP CONSTRAINT uses IF EXISTS so the migration is resilient to the
auto-generated constraint name differing across Postgres versions.
2026-05-26 19:09:33 +03:00
4e68a74ef5
db: issuer_profiles + clients migration
issuer_profiles is one row per user with all the legal-entity fields
that previously lived in the ISSUER constant — legal name, tax id,
reg number, bank details — plus per-user defaults (invoice prefix,
currency, due days, notes). On invoice creation these get snapshotted
onto the invoice row so historical PDFs render unchanged when the
user later edits their profile.

clients is per-user, case-insensitive unique on (owner_id, email).
Partial index on active clients for the dropdown. Soft-archive only;
ON DELETE RESTRICT to honor the indefinite-retention rule.
2026-05-26 19:08:55 +03:00
331917522c
db: users + password_tokens migration
Adds users (citext email, nullable password_hash so a user can be
invited before claiming) and password_tokens (hashed one-shot tokens
for initial-set and reset, with purpose + TTL + used_at).

Token raw values live only in the email body; the DB stores SHA256
of the token so a DB leak doesn't grant account access.
2026-05-26 19:07:55 +03:00
3fdb0f36b3
db: connection helper and invoices migration
DB.connect! opens a single Sequel connection from DATABASE_URL; DB.migrate!
runs Sequel migrations from db/migrations/.

The first migration creates the invoices table: uuid PK, unique invoice
number, client + currency fields, JSONB for line items, GEL conversion rate
captured at issue time, paid_at for the status toggle, pdf_key for the
MinIO object.
2026-05-26 17:43:18 +03:00