Backend Aug 22-25: AI analysis, welcome-packet templating, LetterStream, DocuSeal, staff RBAC + tier gate
- analysis.py: deterministic claim scorer + /analyze /approve /letter /advance-tier endpoints (auto-runs on intake) - packet.py + packet_fields.json: welcome-packet templating engine (6 onboarding docs, field catalog) - letterstream.py + letters.py: certified-mail send pipeline + letter lifecycle (webhook verified) - docuseal.py: DocuSeal signing integration - staff.py/models.py/schema.sql/auth.py: approval actor from staff key, tier gate (APPROVED+ACTIVE+onboarding docs), onboarding_docs table - frontend/: dependency-free static portal (intake, magic-link login/verify, dashboard) - landing-mockups/: 4 design-stance mockups + favicons - legal/: aup/privacy/sms-terms/terms HTML - docs/: letter-queue scope, letterstream API contract, 6 welcome-packet templates - review-dre-landing-2026-08-21.md: 3-variant landing feedback sprint - compliance/DRE_Compliance_Manual.md: updated Source synced from deployed /opt/dre-portal/app/ (was 4 days ahead of git).
This commit is contained in:
@@ -50,6 +50,24 @@ CREATE TABLE IF NOT EXISTS claims (
|
||||
invoice_date TEXT, -- ISO date
|
||||
date_assigned TEXT, -- set when moved out of NEW
|
||||
date_resolved TEXT, -- set on SETTLED/CLOSED/WRITE_OFF
|
||||
-- Client signed representations at intake (added via db._migrate on existing DBs)
|
||||
no_other_agency_at TEXT, -- confirmed no other agency/attorney engaged
|
||||
no_prior_action_at TEXT, -- confirmed no prior litigation/judgment/bankruptcy
|
||||
-- AI analysis + approval (added via db._migrate on existing DBs)
|
||||
analysis_score INTEGER, -- 0-100, NULL until analyzed
|
||||
analysis_summary TEXT, -- plain-English narrative
|
||||
analysis_components TEXT, -- JSON breakdown of component scores
|
||||
analysis_at TEXT, -- ISO timestamp of analysis
|
||||
recommended_tier TEXT, -- AI-recommended starting tier
|
||||
approval_status TEXT NOT NULL DEFAULT 'NONE'
|
||||
CHECK (approval_status IN ('NONE','PENDING','APPROVED','REJECTED')),
|
||||
approval_decision_by TEXT, -- staff name who approved/rejected
|
||||
approval_decision_at TEXT,
|
||||
-- AI-recommended letter (staff-customizable)
|
||||
letter_subject TEXT,
|
||||
letter_body TEXT,
|
||||
letter_tier TEXT, -- tier the letter was generated for
|
||||
letter_updated_at TEXT,
|
||||
twentycrm_id TEXT, -- nullable
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
@@ -137,3 +155,80 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
version TEXT PRIMARY KEY,
|
||||
applied_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Welcome-packet field overrides: client's final value per profile field,
|
||||
-- merged over pre-populated submission values at render time.
|
||||
CREATE TABLE IF NOT EXISTS packet_field_overrides (
|
||||
id TEXT PRIMARY KEY,
|
||||
claim_id TEXT NOT NULL REFERENCES claims(id) ON DELETE CASCADE,
|
||||
profile_key TEXT NOT NULL,
|
||||
value TEXT,
|
||||
updated_by TEXT NOT NULL DEFAULT 'CLIENT' CHECK (updated_by IN ('CLIENT','STAFF')),
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(claim_id, profile_key)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_packet_overrides_claim ON packet_field_overrides(claim_id);
|
||||
|
||||
-- Onboarding paperwork receipt tracking. One row per welcome-packet document
|
||||
-- per claim; staff mark each doc "received" once the client returns it.
|
||||
CREATE TABLE IF NOT EXISTS onboarding_docs (
|
||||
id TEXT PRIMARY KEY,
|
||||
claim_id TEXT NOT NULL REFERENCES claims(id) ON DELETE CASCADE,
|
||||
doc_key TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN ('PENDING','RECEIVED')),
|
||||
received_by TEXT,
|
||||
received_at TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
UNIQUE(claim_id, doc_key)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_onboarding_claim ON onboarding_docs(claim_id);
|
||||
|
||||
-- Physical mail queue (LetterStream). Lifecycle: DRAFT -> APPROVED -> PREAUTH -> SENT
|
||||
-- (+ REJECTED / CANCELLED / ERROR). One row per mailed letter.
|
||||
CREATE TABLE IF NOT EXISTS letters (
|
||||
id TEXT PRIMARY KEY, -- uuid4
|
||||
claim_id TEXT NOT NULL REFERENCES claims(id) ON DELETE CASCADE,
|
||||
letter_type TEXT NOT NULL DEFAULT 'demand',
|
||||
subject TEXT,
|
||||
body TEXT, -- rendered letter body snapshot
|
||||
recipient_json TEXT NOT NULL, -- structured {name,name2,addr1,addr2,city,state,zip}
|
||||
sender_json TEXT NOT NULL, -- structured {name,addr1,addr2,city,state,zip}
|
||||
mailtype TEXT NOT NULL DEFAULT 'firstclass',
|
||||
status TEXT NOT NULL DEFAULT 'DRAFT'
|
||||
CHECK (status IN ('DRAFT','APPROVED','PREAUTH','SENT','REJECTED','CANCELLED','ERROR')),
|
||||
job_id TEXT, -- LetterStream unique job name
|
||||
batch_id TEXT, -- LetterStream batch id
|
||||
doc_id TEXT, -- LetterStream doc id
|
||||
tracking_no TEXT, -- USPS tracking (certified mail)
|
||||
cost_cents INTEGER, -- pricing from preauth/response
|
||||
authcode TEXT, -- preauth authcode (release via doauth)
|
||||
pages INTEGER,
|
||||
pdf_path TEXT, -- rendered PDF on disk
|
||||
error TEXT,
|
||||
note TEXT, -- reject/cancel reason (terminal states)
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
sent_at TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_letters_claim ON letters(claim_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_letters_status ON letters(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_letters_doc ON letters(doc_id);
|
||||
|
||||
-- LetterStream tracking scan events (pushed via callback every 4h).
|
||||
CREATE TABLE IF NOT EXISTS letter_events (
|
||||
id TEXT PRIMARY KEY,
|
||||
letter_id TEXT NOT NULL REFERENCES letters(id) ON DELETE CASCADE,
|
||||
scan_code TEXT,
|
||||
scan_status TEXT,
|
||||
scan_date TEXT,
|
||||
scan_zip TEXT,
|
||||
scan_facility TEXT,
|
||||
tracking_id TEXT,
|
||||
batch_id TEXT,
|
||||
job_id TEXT,
|
||||
doc_id TEXT,
|
||||
raw_json TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_letter_events_letter ON letter_events(letter_id);
|
||||
|
||||
Reference in New Issue
Block a user