HelPhone is a React + Vite community emergency response application built on Stellar. It combines wallet-gated help requests, Soroban smart contracts, local ZK privacy proofs, WebAuthn Passkeys, and automated contract storage state backups.
Someone is in trouble and needs help from nearby people — but broadcasting "I'm hurt, here is my exact address and my name" to a public blockchain is dangerous. HelPhone fixes that:
- Emergency. A person taps Get help and picks what happened (lost, fallen, medical, danger…).
- Identity protected. Their name and contact never leave the browser. Only a pseudonymous
Private request #Nis written on-chain. - Location proven, not revealed. The exact GPS coordinate is used as a private witness. A Noir ZK proof is generated locally to prove "I am inside this zone" without disclosing where. Only a coarse ~1 km point and a 3 km proof box go on-chain.
- Stellar verifies. The proof fingerprint (nullifier) and transaction hash are recorded on Soroban testnet, visible in the live
ZK PRIVACY CHECKPOINTpanel. - Double-claim blocked. The nullifier is
Poseidon2(secret_id, campaign_id)— one claim per user per campaign, so the same proof can't be replayed.
Privacy here is real, not theater: see anonymizeLocation (coarsens coordinates) and createRequest(..., '', '', ...) in handleSubmit (empty name/contact on-chain).
- CLI Exporter:
scripts/export-contract-state.shextracts complete contract storage dumps usingstellar contract inspector JSON-RPC queries. - Node.js/TypeScript Exporter:
server/indexer/exporter.tsindexes storage entries into versioned JSON snapshots (./snapshots/snapshot-<ledgerSeq>.json). - Automated Backup Cron:
server/index.tsautomatically runs daily state export tasks to back up contract storage. - Disaster Recovery Runbook: See
docs/disaster-recovery.mdfor state restoration procedures.
- Husky & lint-staged: Intercepts
git commitvia.husky/pre-committo automatically run linters and type-checkers on staged files. - Quality Verification:
npm run lint(eslint .) - Code style & quality checks.npm run typecheck(tsc --noEmit) - Strict TypeScript validation without building output.npm test- Vitest test suite execution.
- GitHub Actions CI:
.github/workflows/ci.ymlenforces quality, linting, type-checking, state export verification, crypto matrix tests, and the multi-resolution layout matrix on pull requests.
- Feature Flag Engine:
src/lib/featureFlags.tsevaluates feature flag toggles dynamically. - Remote Config: Fetches rulesets from
/config.jsonwithout requiring application rebuilds. - Percentage Hashing: Deterministically hashes user IDs / device IDs for 0-100% canary rollouts.
- React Hook Integration: Components use
useFeatureFlag('flag_name')for conditional rendering.
- Cryptographic Suite:
src/lib/crypto.tsprovides Ed25519 signature verification, WebAuthn P-256 (ECDSA SHA-256) parsing, and AES-256-GCM encryption/decryption. - Passkey Manager:
src/lib/passkey.tshandles browser WebAuthn credential registration and authentication. - Auth Middleware:
server/middleware/auth.tsenforces anti-replay timestamp freshness and cryptographic header verification. - Test Matrix:
test/crypto-verification.test.jscovers positive & negative boundary tests (tampered payload, invalid key, expired signature).
- HTTP Keep-Alive:
server/middleware/keepAlive.tsholds sockets open for 65 s (above the balancer's 60 s idle timeout) so sequential API and WebSocket traffic reuses one TCP connection. Seedocs/performance-optimization.md. - HTTP/2 Push / Preload Manifest:
server/middleware/http2Push.tsreads Vite'sdist/.vite/manifest.jsonat startup, walks the entry chunk graph and stampsLink: </assets/index-Abc123.js>; rel=preload; as=script; type=module; crossoriginon HTML responses (plus 103 Early Hints and, on HTTP/2,pushStream). The manifest is re-read when a release changes the asset hashes, so the header always matches what was deployed. Seedocs/performance-optimization.md. - Map Overlay Rendering:
src/lib/offscreenCanvas.ts+src/workers/canvas-worker.jsanimate map markers in a Web Worker via OffscreenCanvas, with a main-thread fallback and measured FPS. Seedocs/performance-optimization.md. - Client Storage Encryption:
src/lib/pbkdf2Key.ts+src/lib/secureStorage.tsderive an AES-256-GCM key via PBKDF2 (100k iterations, per-device salt in IndexedDB) to encrypt local data. Seedocs/security-architecture.md. - Network Resilience Testing:
tests/e2e/throttling.spec.tsemulates 2G, 3G, a 500 kbps cap, and offline via CDP, with a CI matrix leg per profile. Seedocs/network-resilience.md.
- Auditor:
scripts/audit-deps.jsauditspackage-lock.jsonandserver/package-lock.json(zero dependencies, offline) and fails CI on unauthorized copyleft licenses (GPL/AGPL/SSPL/EUPL/OSL/CPAL/RPL not inscripts/security/license_policy.jsEXCEPTIONS), unlisted or suspicious install scripts, and hijack indicators (untrusted registry host,http:///git sources, missing or non-sha512 integrity). - Report: a deterministic
licenses.json;npm run security:audit-depsregenerates it andnpm run security:audit-deps:check(CI) fails when it is stale. - Runbook: docs/security-runbook.md.
- Tests:
test/dep-audit.test.js.
- Monitor:
scripts/monitor-build-egress.shwraps a build command (npm run buildby default) with a packet capture (tcpdump, oriptablesLOG/REJECT when running as root) and classifies every observed destination — tcpdumpsrc > dstlines, iptablesDST=log lines, and DNS query names. - Unauthorized Connection Gate: loopback/RFC1918/CGNAT plus a curated registry allowlist (npm, GitHub, PyPI, crates.io, Node.js) are permitted; anything else — including cloud metadata endpoints (
169.254.169.254) — fails the build with exit code 1.--enforceadditionally REJECTs the connection through aniptablesOUTPUTchain while the build runs. - Egress Audit Logs:
egress-capture.log(raw packets),egress-audit.log(per-destination verdicts) andegress-summary.logare written toartifacts/build-egress/and uploaded as CI artifacts for security review. - CI Gate: the
build-egress-monitorjob in.github/workflows/ci.ymlruns installation and the production build inside the monitor in--strictmode (fails when capture is unavailable or unauthorized egress is seen). - Runbook: docs/security-runbook.md.
- Tests:
test/egress-detector.test.js.
- Analyzer:
scripts/detect-api-drift.jsextracts the exported type surface of every protected package — functions, interfaces, class members, call signatures andexport =modules — from its.d.tsentry point with the TypeScript Compiler API, then diffs the installed surface against the reviewed baseline committed inpackage.json→apiDrift.baseline. Signatures are normalized (whitespace,import("…")specifiers rewritten to theirnode_modules/form) so the same package produces byte-identical baselines on CI runners and developer machines. - Version Pinning Guard: dropped or re-typed signatures are breaking, new exports are additive. A breaking diff inside a semver-compatible (same/minor/patch) upgrade fails with exit 1 and names the version to pin; a breaking diff in a major upgrade is reported as a warning and needs a re-baseline. When a package does not bundle its own declarations the drift is classified with the
@types/<pkg>version, so an@typesminor bump that breaks call sites is caught too. - Exact Pin Opt-In:
npm run security:api-drift:pin(--require-exact-pin) additionally fails protected dependencies declared as^/~/>=instead of an exact1.2.3. - Rust half:
Cargo.toml→[workspace.metadata.api-drift](require-exact-pin,protected-crates) is validated against[workspace.dependencies],[dependencies]and[dev-dependencies], where only=1.2.3counts as pinned (a bare1.2.3means^1.2.3). - Baselines:
npm run security:api-drift:updatere-extracts and merges intopackage.json(root: cors, express, express-rate-limit, fuse.js, graphql, pg, react-dom;server/package.json: @stellar/stellar-sdk, @aztec/bb.js, @noir-lang/noir_js). Extraction options live intsconfig.json→apiDrift.compilerOptions, deliberately outsidecompilerOptionssotsc --noEmitignores them. - CI Gate: the
api-drift-guardjob in.github/workflows/ci.ymlinstalls withnpm ci --ignore-scripts, runsnpm run security:api-driftandsecurity:api-drift:server, and uploads the drift report when it fails. - Tests:
test/api-drift.test.js.
- Spec:
tests/e2e/layout.spec.tsreplays the same layout gates over/,/helpand/rankingon six device resolutions: iPhone SE (375×667), iPhone 14 (390×844), Pixel 7 (412×915), iPad (768×1024), Laptop (1366×768) and a 4K display (2560×1440). - Overflow Detection: each leg fails when
document.documentElement.scrollWidthexceedswindow.innerWidth— horizontal DOM scrolling on a phone cannot be panned back — and when a visible element is clipped by the right edge of the viewport (this is what catches a fixed header bar whose links run past 375 px). Landmark geometry (nav, primary heading) is additionally asserted to stay inside the viewport. - Visual Baselines: viewport screenshots live in
tests/e2e/layout.spec.ts-snapshots/with a 5 % pixel tolerance; non-replayable surfaces (Mapbox canvas, live RPC latency pill, video frames) are frozen or masked before capture so the shot records layout, not fresh data. Regenerate deliberately withnpm run test:layout:generate. - Resolution Projects: every device is its own Playwright project (
layout-iphone-se…layout-display-4k) declared inplaywright.config.js, so a failure names its resolution.npm run test:layoutruns the whole matrix;npx playwright test --project=layout-iphone-seruns one leg. - CI Matrix: the
e2e-layout-matrixjob in.github/workflows/ci.ymlfans out one leg per resolution on pull requests (fail-fast: false) and uploadstest-results/plus the baselines when a leg fails.
# Install dependencies
npm install
# Run local development server & indexer
npm run dev
# Run code quality & type checking
npm run lint
npm run typecheck
# Run complete Vitest test suite
npm test
# Run the multi-resolution Playwright layout matrix (6 device profiles)
npm run test:layout
# Export Soroban contract storage state manually
npm run export:stateConfigure .env:
VITE_MAPBOX_TOKEN=...
VITE_AEGIS_VAULT_ID=...
VITE_ZK_PROVER_URL=/zk
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
CONTRACT_ID=CC325F37QW7N2F5M3QGHL4A4O7J2K9L0M1N2O3P4Q5R6S7T8U9V0- Server Blueprint: Managed via
render.yamlwith web service and daily snapshot cron jobs. - CI/CD Pipeline: GitHub Actions workflow at
.github/workflows/ci.yml.
npm run security:lockfiles compares every npm SHA-512 integrity value and
Cargo SHA-256 checksum with the official npm and crates.io registries. CI runs
the check before installation and fails on divergence. Use
npm run security:lockfiles:offline to validate checksum shape without
network access; it is not a substitute for the CI registry check.
Normal npm installs have lifecycle scripts disabled by .npmrc. Run
npm run security:install for the standard install and scan. If a reviewed
native dependency genuinely requires a build script, pass its exact package
name to bash scripts/sandbox-install.sh <package>; the rebuild runs in a
rootless, capability-dropped container with no network, no host home/SSH mount,
a read-only container root, and only the repository mounted writable.
npm run security:ai-code parses JavaScript and TypeScript ASTs and fails on
hardcoded secrets, unsanitized request data at sensitive sinks, unsafe HTML,
dynamic code, swallowed errors, unauthenticated contract submissions, invalid
platform API signatures, and undeclared package imports. PRs containing
AI-generated logic must carry the ai-generated label; the CI
security-review environment then requires a human security reviewer.