feat(whatsapp,branding): WhatsApp demo-number wiring + Denya logo assets

WhatsApp demo path (relay #748):
- WHATSAPP_DEMO_TO config under the WhatsApp section (env-based, .env-only;
  .env.example keeps an empty placeholder; real numbers never enter source).
- build_demo_webhook_payload() in app/routers/whatsapp.py builds the Meta
  demo payload from it (fails closed when unset), so the webhook round trip
  logs from_number = demo number (surfaces in GET /api/whatsapp/mock-log) and
  the auto-reply targets the same number.
- tests/test_whatsapp_demo_number.py: default empty + never committed in
  tracked files, payload builder from/to, 200/403/401 gates unchanged.

Branding (logo-assets-v1, sha256-verified, same-origin app/static/branding):
- Login header uses h96 full lockup; logged-in topbar (base.html) uses h48 on
  a light chip (logo ink is ~2:1 vs the dark nav); favicons 32x32 + 16x16 in
  <head>. img-src 'self' data: blob: already allows /static/branding/*.
- tests/test_branding_assets.py: page placement + same-origin serving + CSP.
- AGENTS.md synced.
This commit is contained in:
root
2026-09-09 19:32:21 +00:00
parent f1428335ef
commit a6eb799efa
15 changed files with 330 additions and 13 deletions
+20
View File
@@ -73,6 +73,15 @@ read/write 500s. `ensure_legacy_schema` (app/main.py) adds the missing columns
and backfills+drops the obsolete NOT NULL `command` column idempotently at
startup — do not hand-edit legacy DBs, ship a self-heal there instead.
Demo WhatsApp round trip: `WHATSAPP_DEMO_TO` (E.164, .env-only — never commit
a real number; `.env.example` keeps an empty placeholder) is the expected
sender/recipient for the demo path.
`app/routers/whatsapp.py::build_demo_webhook_payload` builds a Meta webhook
payload from it (fails closed when unset), so posting it to
`POST /api/whatsapp/webhook` with the secret logs `from_number` = demo number
(visible via `GET /api/whatsapp/mock-log`) and the auto-reply targets the same
number. Covered by `tests/test_whatsapp_demo_number.py`.
### Pages (Sprint 3) — Jinja2 templates at `app/templates/`
| Method | Path | Auth | Description |
|--------|------|------|-------------|
@@ -108,6 +117,17 @@ Frontend: Alpine.js + Tailwind CSS vendored same-origin (no CDN) — see
`test_csp_script_src_allows_unsafe_eval_for_alpine` in
`tests/test_frontend_vendoring.py`.
### Branding (logo)
Official Denya Developers logo derivatives are committed under
`app/static/branding/` (Gitea release `logo-assets-v1`, sha256-verified
monochrome forest-green lockup; sourced from the Gitea release, never from
kagentz). Placement: login header uses `denya-logo-h96.png` (full lockup); the
logged-in topbar (base.html nav) uses `denya-logo-h48.png` on a light chip
(logo ink is only ~2:1 against the dark `#0d2b18` nav — keep a light chip
there); favicons 32x32+16x16 declared in `base.html <head>`.
`img-src 'self' data: blob:` already covers `/static/branding/*` — no CSP
change. Regression coverage: `tests/test_branding_assets.py`.
### Tickets (Sprint 2)
| Method | Path | Auth | Description |
|--------|------|------|-------------|