who_need_help/README.md

190 lines
6.9 KiB
Markdown

# Who Need Help
Who Need Help is a working mutual-aid MVP for urgent, local, voluntary help.
The first supported scenario is pickup and delivery of a legal medicine that
has already been purchased or reserved.
It is not an emergency or medical service, does not prescribe or sell medicine,
and does not process payments. A helper may publish an optional external
thank-you link; money goes directly between users outside the platform.
## What is implemented
- Phoenix 1.8 LiveView application with email magic-link/password auth and 18+
self-attestation.
- Data-driven, translated category tree with validated per-category fields,
community proposals/votes, and human approve/reject/merge tools.
- Request lifecycle: `open → matched → in_progress → completed`, plus cancel
and expiry paths.
- PostgreSQL/PostGIS locations, MapLibre map, private matched chat, Phoenix
PubSub/Presence, and optional foreground-only location sharing.
- Handover code plus both-party confirmation before verified completion.
- Double-blind reviews, public trust summaries, and a helper leaderboard that
prioritizes unique location-supported and handover-verified counterparts
before raw totals.
- Bidirectional discovery blocks, scoped reports, account/request/category
moderation, abuse-signal review, and audited moderator access to only the
conversation linked by a report.
- Optional GPS evidence derived from browser accuracy envelopes. Raw current
positions are deleted on stop, terminal match state, or participant block.
- PostgreSQL-backed cross-replica action-limit policies configured by the
operator. No unapproved numeric thresholds are enabled by default.
- Public manual social links, always marked unverified in this MVP.
- EN/UK/RU UI foundation and installable PWA metadata/service worker.
- Native Android WebView client with the same authenticated LiveView, map,
private chat, and foreground geolocation flows. The reproducible Docker
target currently exports a debug APK; production signing and store
publication are not configured.
- Local, advisory Codex category review through the user's ChatGPT-authenticated
Codex CLI. It receives a PII-free export and never writes to the database.
- One immutable release image with `web`, `worker`, and one-shot `migrate`
roles.
- Docker Compose and Helm/kind deployment paths with 2 web and 2 worker
replicas by default.
OAuth social verification, public coffee/cinema/hiking activities, background
tracking, platform payments, production Android signing/store publication,
iOS, automatic punitive fraud decisions, and jurisdiction-specific
public-launch policies are deliberately not claimed as complete.
## Fast start with Docker Compose
Prerequisite: Docker with the Compose plugin.
```bash
./scripts/compose-up.sh
```
Open:
- app: <http://localhost:4010>
- local email inbox: <http://localhost:8027>
Compose starts Traefik, PostGIS, Mailpit, a migration runner, 2 web replicas,
and 2 Oban worker replicas. It waits for readiness and verifies a PubSub message
broadcast from a different BEAM node. Registration emails appear in Mailpit.
Inspect the exact state:
```bash
docker compose -p who_need_help ps -a
docker compose -p who_need_help logs -f web worker
./scripts/verify-realtime-cluster.sh compose
```
Local defaults are intentionally limited to local development. Copy
`.env.example` to `.env` and replace every secret before any public deployment.
Generate independent values with `mix phx.gen.secret`; do not reuse the session
secret as the BEAM cookie or handover secret. External Helm deployments must
set `app.host`, `app.scheme`, and `app.urlPort` to the public URL used in email
links, and must set `app.mapTileUrl` to a tile service whose policy and capacity
fit the deployment.
Rotate all local application secrets and the existing local PostgreSQL role
without printing the generated values:
```bash
./scripts/rotate-local-secrets.sh
docker compose up -d --wait
```
This preserves the named PostgreSQL volume, but invalidates existing browser
sessions and changes handover codes for active local requests.
## Tests
The reproducible test command builds a dedicated test target and uses the
project's PostGIS service:
```bash
./scripts/test.sh
```
It creates/updates only the project-scoped `who_need_help_test` database.
## First administrator
Register and confirm the first account, then explicitly bootstrap it:
```bash
./scripts/bootstrap-admin.sh you@example.com --confirm
```
This succeeds only while no administrator exists and writes an audit event.
After bootstrap, an administrator can manage roles in `/moderation`; the last
administrator cannot demote themselves. For kind, append `kind`:
```bash
./scripts/bootstrap-admin.sh you@example.com --confirm kind
```
## Optional shared action limits
`RATE_LIMIT_POLICIES_JSON` configures atomic PostgreSQL counters shared by every
web replica. Its shape is:
```json
{"action_name":{"limit":"POSITIVE_INTEGER","window_seconds":"POSITIVE_INTEGER"}}
```
The strings above describe the required types and are not a runnable policy.
Keep `{}` until numeric limits have been approved from policy and observed
traffic. Supported actions are listed in `docs/trust-safety.md`.
## Local Kubernetes verification
The kind script downloads checksum-verified kubectl, Helm, and kind binaries
into `.tools/`, creates a project-owned cluster, loads the local image, and
installs the Helm chart, waits for both Deployments, and verifies cross-node
PubSub:
```bash
./scripts/kind-up.sh
```
Open:
- app: <http://localhost:4011>
- Mailpit: <http://localhost:8028>
The script refuses to modify a pre-existing cluster named `who-need-help`
unless the project ownership marker exists.
For an external cluster, provide a real PostgreSQL/PostGIS service and a
pre-created Secret through `existingSecret`. The chart intentionally has no
invented CPU/RAM limits or HPA thresholds; measure this application in the
target environment before setting them.
## Local Codex category review
Export the redacted proposals from a running release:
```bash
docker compose -p who_need_help exec -T web \
/app/bin/who_need_help eval \
'WhoNeedHelp.CatalogModeration.export_open_proposals() |> IO.puts()' \
> proposals.json
```
Then run the advisory review:
```bash
./scripts/codex-review-categories.sh proposals.json recommendations.json
```
The script exits unless `codex login status` is exactly
`Logged in using ChatGPT`. It uses no OpenAI API key, no usage-based API billing,
and no fallback provider. Recommendations require a human moderator action.
## Design documentation
- [Product specification](docs/product-spec.md)
- [Architecture](docs/architecture.md)
- [Trust and safety](docs/trust-safety.md)
- [Implementation verification and known limits](docs/verification.md)
- [PostgreSQL/PostGIS ADR](docs/decisions/0001-postgresql-postgis-over-spacetimedb.md)
Exact dependency versions are locked in `mix.lock`,
`assets/package-lock.json`, the Dockerfile, Compose file, and tool bootstrap
script.