8.0 KiB
8.0 KiB
Who Need Help — local hardening completion plan
This plan deliberately excludes buying a domain, renting another server, and
real third-party credentials. The existing local Docker/kind environments and
the temporary whoneedhelp.imalto.site staging origin are sufficient for every
item below unless the evidence column explicitly describes a local mock.
| Area | Observed baseline | Local completion evidence |
|---|---|---|
| Browser E2E | Manual headed-Chrome scenarios exist; no committed browser suite | A fresh uniquely named Compose project runs two-user urgent help, Activity, moderation, privacy, and error paths; traces are retained on failure; its exact volume is removed |
| Android UI | Two JVM unit-test files; no androidTest source set |
Emulator instrumentation covers deep links, permissions, foreground tracking, notification Stop, lifecycle, and network failure |
| CI and quality | No tracked CI workflow or static/security analysis dependencies | The same containerized gates pass locally and are represented in a validated CI workflow |
| Localization and accessibility | Completed locally: product copy and custom validation messages are extracted; EN/UK/RU catalogs and localized category descriptions/structured values are implemented | 508 default and 40 error messages are current; RU/UK have no empty/fuzzy entries; 163 backend tests and all 8 browser specs pass, including locale persistence, keyboard, axe, themes, responsive widths, and reconnect |
| Database scale | Core discovery/chat/moderation lists call unbounded Repo.all() |
Cursor-bounded queries pass behavior tests and measured EXPLAIN ANALYZE checks on an isolated generated dataset |
| Load and resilience | Public/readiness/heartbeat k6 profile exists | Authenticated writes, chat, tracking, reconnect, rolling replacement, and worker retry profiles pass without touching staging data |
| Observability | Completed locally: protected per-process metrics feed a pinned Prometheus/Grafana/Alertmanager profile | All 3 direct web targets are up before/after the drill; a verified replica stop delivers firing and resolved webhooks; Grafana datasource/dashboard and an empty DB-count diff are retained |
| Backup | Validated local custom-format dump and restore drill exist | An encrypted artifact is uploaded to local S3-compatible MinIO and restored into a fresh database; corruption and interrupted-upload checks fail closed |
| External boundaries | Mailpit and a fake GitHub strategy cover parts of SMTP/OAuth | Local protocol-level SMTP/OAuth mocks and the applicable push adapter boundary cover success, rejection, retry, replay, and timeout |
| Final regression | 163 Phoenix tests plus reproducible browser and Android device suites | Browser, Android, API, DB, WebSocket, backup, monitoring, failure, cleanup, docs, and clean Git are verified from the final commits |
The goal remains open while any row lacks reproducible local evidence.
Verified progress
- The isolated browser harness now generates independent local secrets, starts two web and two worker replicas behind Traefik, and removes only its uniquely named Compose project and PostGIS volume.
- The browser suite passes public/authentication boundaries and the complete two-user medicine flow: Mailpit confirmation, category-driven request, matching, bidirectional realtime chat, handover verification, bilateral completion, and double-blind review reveal.
- A separate browser scenario passes Activity creation, participant approval, bidirectional private group chat, a report scoped to the selected message, block/unblock, inherited location privacy, manual social-link removal, category-proposal rejection, report resolution, account restriction, and enforcement of that restriction. Its administrator is created in the isolated database through the existing audited one-time bootstrap command.
- Browser console errors, page errors, and unexpected failed requests are test failures. Playwright traces, screenshots, video, JSON/HTML reports, and Compose logs are retained in ignored output on failure.
- The browser gate also passes axe checks on the home, safety, login, and
registration pages in both light and dark themes, keyboard skip navigation,
and 360/768/1440-pixel overflow checks. Its local raster-tile endpoint exists
only in the E2E-compiled image, and map scenarios wait for MapLibre
idlebefore navigation. - A forced LiveSocket transport loss while Chromium is offline exposes the reconnect alert, and restoring the network clears it and reconnects the authenticated LiveView.
- The isolated API 37 Android suite passes five device tests: missing and granted location permission, same-origin deep-link routing across Activity recreation, native foreground location upload, notification Stop with remote cleanup, and a disconnected Stop request with visible retry state. It uses an in-process loopback fixture, runs its emulator without external networking, retains diagnostics on failure, and removes its exact container and image.
- The containerized
scripts/quality.shgate passes ShellCheck, Hadolint, actionlint, all Compose renders, Helm lint, a Trivy scan of tracked source and the rendered Kubernetes manifest, compiler/xref/Credo/Sobelow/Dialyzer/Hex checks, 163 Phoenix tests, both npm audits, and a Trivy scan of the production release image. It creates random one-run database credentials and removes its exact volume, networks, images, and source snapshot. - The checked-in GitHub Actions workflow runs the same isolated backend/security gate, browser E2E suite, and Android unit/lint/APK build. The workflow itself passes actionlint and uses a commit-pinned checkout action without persisted credentials.
- The hardened local kind manifests also passed a runtime rollout: PostGIS, Mailpit, both web replicas, and both worker replicas became Ready as non-root containers with read-only root filesystems, dropped capabilities, and RuntimeDefault seccomp where configured. The cross-node PubSub probe passed.
- EN/UK/RU extraction and catalogs are now complete for current product UI and custom validation messages. Locale selection persists for public pages and authenticated LiveViews; category descriptions and structured values follow that browser locale. The localization browser specs run in the same isolated two-web/two-worker gate as the accessibility checks.
- The isolated three-web/two-worker load profile now uses real password login, authenticated LiveView joins, tracking start, HTTP position writes, private chat writes, and explicit tracking stop. A measured 30-second run completed all 1,880 authenticated chains and 240 heartbeat sockets with no functional failure, retained no current positions after stop, passed cross-node PubSub and readiness, and restored every tracked table count after exact fixture cleanup.
- The same isolated profile now passes deliberate web/worker BEAM crashes, sequential replacement of every replica, exact five-node cluster/PubSub checks, and an Oban job that records one failure before succeeding on its second attempt. A 743-sample readiness probe observed no final HTTP failure and the probe job/domain fixtures were absent afterward.
- The project-owned kind cluster also passes a full web/worker rolling restart: all four pod UIDs changed, all replacements became Ready with zero restarts, the four-node cluster/PubSub probe passed, and database counts were unchanged. The local single-node NodePort needed three reconnect attempts across 305 ultimately successful samples; this is recorded rather than presented as raw transport continuity.
- The isolated observability profile scrapes all three web containers by direct
target with a file-based Bearer credential, provisions a four-panel Grafana
dashboard, and routes the
up == 0rule through Alertmanager. The canonical drill observed both firing and resolved webhooks for the exact stopped replica, restored all three targets, and left database counts unchanged. - The remaining rows above are still pending; this document is not a completion claim for the entire hardening goal.