Walkies is a security-first community and structured-walk platform for dog owners and organisers in Australia and New Zealand.
- Canonical, versioned temperament contracts
- Deterministic and explainable compatibility evaluator
- Supabase/PostGIS core schema with append-only profile and audit records
- Transactional outbox contract for AWS SQS workers
- NestJS BFF shell with security headers, request IDs, strict CORS, and OpenAPI
- Owner-scoped dog creation and listing with canonical identity fields
- Append-only, versioned temperament profiles with transactional audit and outbox events
- Expo mobile email authentication with encrypted session persistence and owner onboarding
- Mobile dog identity, temperament, multi-dog household, and profile-summary workflows
- Optional private owner portraits and ordered five-photo dog galleries with native editing
- Database-backed idempotency for dog and temperament submissions
- Pack discovery, creation, joining questions, organiser rosters, decisions, and expiring invitations
- Hashed invitation bearer tokens, Pack organiser integrity, and self-archiving E2E fixtures
- GitHub Actions quality, migration-from-zero, and secret-scanning gates
- Architecture decision and Release 1 threat model
This repository pins pnpm 10.13.1. On environments without Corepack, invoke that version through npx for installation.
npx --yes pnpm@10.13.1 install
./node_modules/.bin/tsc -p packages/contracts/tsconfig.json --noEmit
./node_modules/.bin/tsc -p packages/matching/tsconfig.json --noEmit
./node_modules/.bin/vitest run packages/matching/src/index.test.tsNo Supabase or AWS credentials are required for the current unit-tested foundation.
The API requires a PostgreSQL connection URL and an explicit trusted CA bundle. Keep both the
database password and CA runtime mount outside Git; local Supabase link artifacts under
supabase/.temp are ignored automatically.
The API has a provider-neutral, multi-stage production image. It runs as a non-root user, exposes
port 3000 by default, and reports container health through GET /v1/health.
Build it from the repository root:
pnpm container:apiSupply secrets through the deployment platform at runtime, never as image build arguments. The
database CA must be mounted into the container and DATABASE_CA_CERT_PATH must reference that
container path. For example, to run the image locally with the existing ignored .env file:
docker run --rm --name walkies-api \
--env-file .env \
--env NODE_ENV=production \
--env DATABASE_CA_CERT_PATH=/run/secrets/database-ca.crt \
--mount type=bind,src="$PWD/supabase/.temp/pgdelta/pgdelta-target-ca.crt",dst=/run/secrets/database-ca.crt,readonly \
--publish 3000:3000 \
walkies-api:localAny container platform can deploy the resulting image if it supports runtime environment
variables, a read-only secret file mount, and HTTP traffic to PORT. Configure its health check
as /v1/health. Set CORS_ORIGINS to the exact browser origins used by web clients; native Expo
requests do not depend on browser CORS enforcement.
- Expo and Next.js use the Supabase publishable key for sign-in and session refresh.
- The NestJS BFF verifies access tokens against Supabase JWKS.
- The BFF and workers connect through the Supabase pooler as
walkies_apifor transactional domain writes. - The BFF alone receives
SUPABASE_SECRET_KEYso it can create short-lived signed upload and read URLs for the privateSUPABASE_MEDIA_BUCKET. Keep this key in the deployment secret store and never expose it through anEXPO_PUBLIC_variable. - Mobile uploads use one-time signed upload tokens. Photo reads use five-minute signed URLs issued only after the BFF checks owner or Pack-context access. The bucket is not public and clients cannot enumerate application media metadata.
Owner, media, audit, and outbox metadata remain behind the BFF. The broad Storage credential is isolated to a small transport service; subject ownership, manifest versions, and Pack visibility are still enforced by application queries before any signed capability is issued.
The mobile application is under apps/mobile and targets Expo SDK 54. Copy its .env.example to
.env.local, then set only these public values:
EXPO_PUBLIC_SUPABASE_URL
EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY
EXPO_PUBLIC_API_URL
EXPO_PUBLIC_INVITE_URL
EXPO_PUBLIC_INVITE_URL is the HTTPS origin that serves Pack invitation links, such as
https://join.walkies.example. Invitation bearer tokens are placed in the URL fragment so they
are not sent in HTTP requests or access logs.
Never place the Supabase secret key or DATABASE_URL in an EXPO_PUBLIC_ variable. For an iOS
Simulator on the same Mac, the API URL can be http://127.0.0.1:3000. A physical device needs an
HTTPS development endpoint or a reachable LAN endpoint; do not use production credentials over an
unencrypted LAN endpoint.
Run the BFF and Metro in separate terminals:
node --env-file=.env services/api/dist/main.js
cd apps/mobile && ./node_modules/.bin/expo startHosted smoke tests use the ignored TEST_USER_EMAIL and TEST_USER_PASSWORD values and retain
immutable audit history while archiving generated dog and Pack fixtures:
cd services/api && node --env-file=../../.env test/hosted-e2e.mjsThe two-user Pack authorization matrix additionally requires confirmed TEST_USER_2_EMAIL and
TEST_USER_2_PASSWORD credentials. It verifies cross-owner denial, open/request/hidden Pack
behavior, applicant answers, co-organiser removal and privilege reset, invitation use limits, and
hidden-Pack privacy. Generated fixtures are archived before a successful run is reported:
cd services/api && node --env-file=../../.env test/two-user-packs-e2e.mjsThese hosted suites must run only against a dedicated non-production project. Never expose their credentials to pull-request workflows or store them in tracked environment files.