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:
root
2026-08-26 02:26:33 -04:00
parent 7a5603b495
commit 7a62b0b340
46 changed files with 11004 additions and 35 deletions
+15 -3
View File
@@ -11,6 +11,7 @@ from pydantic import ValidationError
from . import auth as authmod
from . import db
from . import dreemail
from . import analysis
from .db import get_conn, new_uuid, next_sequence_number, utcnow_iso
from .models import IntakeRequest
@@ -93,10 +94,12 @@ async def intake(request: Request):
claim_id = new_uuid()
claim_number = next_sequence_number(conn, "DRE")
conn.execute(
"INSERT INTO claims (id, claim_number, client_id, debtor_id, amount_cents, currency, status, tier, description, client_reference, invoice_date, date_assigned, date_resolved, twentycrm_id, created_at, updated_at) "
"VALUES (?, ?, ?, ?, ?, 'USD', 'NEW', 'TIER_1', ?, ?, ?, NULL, NULL, NULL, ?, ?)",
"INSERT INTO claims (id, claim_number, client_id, debtor_id, amount_cents, currency, status, tier, description, client_reference, invoice_date, date_assigned, date_resolved, no_other_agency_at, no_prior_action_at, twentycrm_id, created_at, updated_at) "
"VALUES (?, ?, ?, ?, ?, 'USD', 'NEW', 'TIER_1', ?, ?, ?, NULL, NULL, ?, ?, NULL, ?, ?)",
(claim_id, claim_number, client_id, debtor_id, claim_in.amount_cents,
claim_in.description, claim_in.client_reference, claim_in.invoice_date, now, now),
claim_in.description, claim_in.client_reference, claim_in.invoice_date,
now if req.no_other_agency_accepted else None,
now if req.no_prior_action_accepted else None, now, now),
)
conn.execute(
"INSERT INTO audit_log (id, entity_type, entity_id, action, old_value, new_value, actor, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
@@ -114,6 +117,15 @@ async def intake(request: Request):
"INSERT INTO audit_log (id, entity_type, entity_id, action, actor, created_at) VALUES (?, ?, ?, ?, ?, ?)",
(new_uuid(), "note", note_id, "note_add", "system", now),
)
# Auto-run AI analysis on submission (score + recommended tier + approval=PENDING).
# Deterministic rules engine; no external call. Best-effort: a failure must not
# block intake, so we guard and let the claim persist without a score if it errors.
try:
analysis.analyze_and_store(conn, claim_id, actor="system")
except Exception as exc: # noqa: BLE001
logger.error("auto-analysis failed for claim %s: %s", claim_number, exc)
conn.commit()
# Best-effort team notification