This file provides guidance to AI agents when working with code in this repository.
This is a pnpm monorepo for Code for Africa's civic tech applications. It contains multiple Next.js apps and shared packages, orchestrated by Turbo. Apps are deployed as Docker containers to Dokku.
pnpm install # Install all dependencies
pnpm dev # Run all apps in parallel with hot reload
pnpm dev --filter=<app> # Run a single app (e.g., --filter=techlabblog)pnpm build # Build all apps and packages (respects dependency order)
pnpm build --filter=<app> # Build a single app
pnpm build:next # Build only Next.js apps
pnpm build-payload # Build Payload CMSBefore first run, install Playwright browsers:
npx playwright installpnpm test # Run Jest + Playwright in parallel (requires build first)
pnpm jest # Unit tests only
pnpm jest --filter=<app> # Unit tests for a single app
pnpm playwright # E2E tests only (requires build)pnpm lint:check # Check linting without fixing
pnpm lint # Lint and auto-fix
pnpm format:check # Check Oxfmt formatting
pnpm format # Format supported source and config files with Oxfmtmake <app> # Build image and run via docker compose (e.g., make techlabblog)
make down # Stop all containers
docker buildx bake --file docker-bake.hcl <app> # Build image manually
docker compose up <app> # Run locally after bakeapps/— Independent Next.js applications, each with its ownpackage.json, Next.js config, and environment filespackages/— Shared libraries published to npm or consumed via workspace references
| App | Description |
|---|---|
charterafrica |
Digital database for communities |
civicsignalblog |
CivicSignal research blog |
climatemappedafrica |
Climate data platform |
codeforafrica |
Main CFA website |
pesayetu |
Government accountability data |
roboshield |
Bot protection service |
techlabblog |
TechLab engineering blog |
trustlab |
CSO/CBO digital threats platform |
twoopstracker |
Social media analysis |
vpnmanager |
VPN management |
| Package | Purpose |
|---|---|
commons-ui-core |
Base React components |
commons-ui-next |
Next.js-specific helpers |
commons-ui-payload |
Payload CMS integration helpers |
commons-ui-testing-library |
Shared test utilities |
eslint-config-commons-ui |
Shared ESLint flat config |
jest-config-commons-ui |
Shared Jest config |
playwright-config-commons-ui |
Shared Playwright config |
hurumap-core / hurumap-next |
Hurumap data visualization library |
- UI stack:
- Current: MUI v6 + Emotion for most apps and shared UI packages.
- Legacy:
- MUI v5 +
@mui/stylesvia themui-stylescatalog forpesayetuandtwoopstracker.
- MUI v5 +
- CMS stack:
- Current:
- Payload CMS v3.x (
catalog:payload-v3) forroboshield,trustlab,commons-ui-payload. - MDX with remark/rehype pipeline for
techlabblog.
- Payload CMS v3.x (
- Legacy:
- Payload CMS v2.x (
catalog:) forcharterafrica,civicsignalblog,climatemappedafrica,codeforafrica. - WordPress via WPGraphQL for
pesayetu. - Netlify CMS markdown content for
twoopstracker.
- Payload CMS v2.x (
- Current:
- Testing:
- Jest v30 shared through
jest-config-commons-ui. - Playwright shared through
playwright-config-commons-ui.
- Jest v30 shared through
All package versions are pinned in pnpm-workspace.yaml using catalogs:
catalog:— default catalog for most packagesmui-styles:— MUI v5 for legacy appspayload-v3:— Payload CMS 3.xreact-19:— React 19 (opt-in)
Reference catalog versions in package.json as "some-pkg": "catalog:" or "some-pkg": "catalog:payload-v3".
Docker is for deployment image validation only — use pnpm dev for development.
docker/base.Dockerfile— shared Node 24 Alpine base images (ui-builder-base,ui-runner-base) with independentBASE_TAGversioningdocker/apps/<app>/Dockerfile— per-app multi-stage builds (pruned → deps → builder → runner)docker-bake.hcl— orchestrates all build targets; app targets inherit from_app-runnerdocker-compose.yml— local dev services; for migrated apps usesimage:(notbuild:)
Migration status is tracked in docker/README.md; keep that checklist as the single source of truth when migrating additional apps.
GitHub Actions workflows in .github/workflows/:
ci.yml— lint, test, build on every push/PRbuild-base-images.yml— triggered manually when base Docker tooling changesbake-and-push.yml— builds and pushes app images- Per-app deploy workflows (e.g.,
techlabblog.yml) deploy to Dokku
NEXT_PUBLIC_*— client-side env vars (baked at build time)MONGO_URL/MONGODB_URL— database connection (required for Payload CMS apps)PAYLOAD_SECRET/PAYLOAD_SECRET_KEY— CMS authenticationSENTRY_AUTH_TOKEN,SENTRY_ORG,SENTRY_PROJECT— error tracking- Build-time args must be exported in shell for local Docker builds; runtime vars are loaded from
apps/<app>/.envandapps/<app>/.env.localbydocker compose