Skip to content

Civilian /v1/* tier, operator case CRUD, triage-driven Suggested cases panel#7

Open
hidden-salmon wants to merge 1 commit intoMichielMAnalytics:mainfrom
hidden-salmon:feat/civilian-tier-and-case-flow
Open

Civilian /v1/* tier, operator case CRUD, triage-driven Suggested cases panel#7
hidden-salmon wants to merge 1 commit intoMichielMAnalytics:mainfrom
hidden-salmon:feat/civilian-tier-and-case-flow

Conversation

@hidden-salmon
Copy link
Copy Markdown
Collaborator

Summary

End-to-end flow tying the SafeThread iOS app to the matching engine + dashboard.

  • Civilian API tier (/v1/*) — new server/api/civilian.py with register, message, sighting, alerts/active, and WS /v1/stream. Bearer-token auth = phone. Civilian app messages land orphan (no auto-Alert); only operators promote them to cases.
  • Operator case CRUDPOST /api/incidents and PATCH /api/incidents/{id} reuse the existing `incident_upserted` channel; iOS receives `ALERT_ISSUED` envelopes via WS /v1/stream and `upsertAlert` replaces cards in place.
  • Triage-driven "Suggested cases" panel — broader triage prompt covers all four case categories so distress messages classify as `sighting` instead of `noise`. Right-rail panel on the Messages tab groups orphan messages by shared co-mention token (e.g. `maryam · 3 msgs`); click → CreateCaseModal pre-filled.
  • Robustness — `get_or_create_default_ngo` helper means a fresh-volume DB never 503s; orphan messages persist across tab switches via the dashboard endpoint; WS re-fires after triage so the wire enriches in place.

Tested end-to-end against a clean Postgres volume + iOS simulator pointed at `localhost:8080`.

Test plan

  • `docker compose up -d` lands a clean DB; `/v1/register` auto-creates the default NGO on first request
  • iOS sim register → message → message lands as InboundMessage(channel='app', orphan)
  • Operator creates case from dashboard → iOS Alerts tab updates within ~1s via WS
  • Operator edits case description → iOS card replaces in place (same case_id, fresh issued_at)
  • "I NEED A MEDIC IN JPH" classifies as `sighting` 85% (was `noise` 95% under old prompt)
  • Two messages mentioning the same name surface in the right-rail Suggested cases panel as a single grouped entry

Notes

  • The "agent suggests" copy on the Suggested cases panel is honest about what it is: triage classification + frontend co-mention rule. Spinning up a real per-orphan agent loop (full `propose_case` tool surface) is documented as the next step in conversation but out of scope for this PR.
  • Photo/voice multipart uploads on `/v1/sighting` still fall back to the DTN mesh-queue path; JSON path works.

🤖 Generated with Claude Code

…s panel

End-to-end flow: SafeThread iOS app talks to the matching engine, NGO
operators create / edit cases, civilian messages flow into a curated
right-rail review queue rather than cluttering the case list.

Backend
- server/api/civilian.py (new) — POST /v1/register, /v1/message, /v1/sighting,
  GET /v1/alerts/active, WS /v1/stream. Bearer-token auth = phone. Civilian
  app messages land orphan (no auto-Alert); only operators turn them into
  cases. Wires into the existing eventbus + triage worker via new_inbound.
- server/api/incidents.py — POST /api/incidents (operator creates a case),
  PATCH /api/incidents/{id} (operator pushes update; same incident_upserted
  pipe forwards an ALERT_ISSUED to iOS for in-place card replacement).
- server/api/dashboard.py — recentDistress includes orphan messages with
  triage payload so the wire survives tab switches.
- server/api/ws.py — _compose_inbound_event includes triage; subscribes to
  new inbound_triaged channel so the wire enriches in-place after triage.
- server/workers/triage.py — publishes inbound_triaged after success.
- server/llm/triage_client.py — broader prompt covering all four case
  categories (missing_person / medical / resource_shortage / safety) so
  "I NEED A MEDIC" classifies as sighting, not noise.
- server/db/identity.py — get_or_create_default_ngo helper used by both
  /api/incidents and /v1/register so a fresh-volume DB never 503s.

Frontend
- web/src/components/CreateCaseModal.tsx (new) — case creation form with
  optional pre-fill defaults so the same component handles "blank" and
  "from-message" flows.
- web/src/components/EditCaseModal.tsx (new) — partial-update form for
  description / urgency / status; saving pushes an update to civilians.
- web/src/pages/CasesView.tsx — "+ Create case" button on the left rail,
  "Edit" affordance on the right-rail case profile.
- web/src/pages/MessagesView.tsx — triage classification pill + co-mention
  rule + new "Needs review" right-rail panel grouping orphan messages by
  shared name. "Now playing" + "What the agent can do" tucked under
  collapsible disclosures.
- web/src/lib/api.ts — createIncident, updateIncident helpers.
- web/src/lib/types.ts — TriageInfo + RecentDistressItem.triage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant