Add credentials store to the CRM, docs cleanup, deploy pipeline TODO

Adds a `credentials` entity to the back office (never mirrored to
Sheets, gated by the CRM token even to read) so client logins like
the auto-generated Easy!Appointments provider password can be viewed
and copied from the dashboard instead of getting lost — the actual
cause of the happynails password going missing. Onboarding now saves
that generated password instead of discarding it. Also adds
Documentation.md, brings README/TODO in line with the current
Postgres-first architecture, and tidies the backlog.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 14:13:34 +02:00
parent 8eba724428
commit 94ae2d578d
9 changed files with 183 additions and 27 deletions
+16 -1
View File
@@ -86,6 +86,20 @@ CREATE TABLE IF NOT EXISTS invoices (
updated_at timestamptz NOT NULL DEFAULT now()
);
-- Per-client login credentials (e.g. the auto-generated Easy!Appointments
-- provider login). Deliberately NOT mirrored to Sheets — see db.py TABLES
-- ("mirror": False) — so secrets never leave Postgres.
CREATE TABLE IF NOT EXISTS credentials (
cred_id text PRIMARY KEY,
client_id text,
label text,
username text,
secret text,
notes text,
created_at timestamptz,
updated_at timestamptz NOT NULL DEFAULT now()
);
-- keep updated_at fresh on row changes
CREATE OR REPLACE FUNCTION touch_updated_at() RETURNS trigger AS $$
BEGIN NEW.updated_at = now(); RETURN NEW; END;
@@ -94,7 +108,7 @@ $$ LANGUAGE plpgsql;
DO $$
DECLARE t text;
BEGIN
FOREACH t IN ARRAY ARRAY['clients','leads','projects','bookings','invoices'] LOOP
FOREACH t IN ARRAY ARRAY['clients','leads','projects','bookings','invoices','credentials'] LOOP
EXECUTE format(
'CREATE TRIGGER %I_touch BEFORE UPDATE ON %I FOR EACH ROW EXECUTE FUNCTION touch_updated_at()',
t, t);
@@ -104,3 +118,4 @@ END $$;
CREATE INDEX IF NOT EXISTS leads_received_idx ON leads (received_at DESC);
CREATE INDEX IF NOT EXISTS clients_status_idx ON clients (status);
CREATE INDEX IF NOT EXISTS activity_ts_idx ON activity_log (ts DESC);
CREATE INDEX IF NOT EXISTS credentials_client_idx ON credentials (client_id);