590 lines
38 KiB
Markdown
590 lines
38 KiB
Markdown
# AGENTS.md — Africa Alert PWA
|
|
|
|
> **Audience.** This file is the single source of truth for any AI coding agent (or human contributor) working in this repository. Read it end-to-end before making changes.
|
|
>
|
|
> **Status.** Living document. Update it in the same PR that changes the architecture, the coding standards, or the team-agent roster.
|
|
|
|
---
|
|
|
|
## 1. Project Overview
|
|
|
|
### 1.1 Purpose
|
|
|
|
**Africa Alert** is a Progressive Web App (PWA) school-management system for African schools. It unifies the four stakeholders of a school — **administrators, teachers, students, and parents** — into one role-aware interface, and ships with offline support so it works in low-connectivity environments (the primary deployment context is Zimbabwe, based on the Paynow payment-gateway integration at `https://www.paynow.co.zw`).
|
|
|
|
### 1.2 Key Business Goals
|
|
|
|
| Goal | What it means in code |
|
|
|---|---|
|
|
| **Unified school operations** | One app for student records, classes, attendance, fees, messaging, calendar, exams, payroll, inventory, hostel, transport, and front-office. |
|
|
| **Offline-first PWA** | The React client must install and run without a network. A local SQLite mirror keeps working data available offline; a sync engine reconciles to Supabase when online. |
|
|
| **Role-based experience** | Four user roles (admin / teacher / student / parent) with distinct dashboards, navigation, and permissions. |
|
|
| **Cashless fee collection** | Integration with **Paynow Zimbabwe** (Ecocash, Visa, etc.) so parents can pay fees online. |
|
|
| **Easy deployment** | One-command `docker-compose up` for non-technical school operators. |
|
|
|
|
### 1.3 High-Level Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Africa Alert System │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
Browser / Mobile PWA
|
|
┌──────────────────────────────────────────┐
|
|
│ React 18 + Vite + TypeScript │
|
|
│ - React Router 6 (role-gated routes) │
|
|
│ - Zustand stores (auth, api, exams, …) │
|
|
│ - Axios HTTP client │
|
|
│ - vite-plugin-pwa (service worker) │
|
|
│ - Recharts, Lucide icons │
|
|
└──────────────┬───────────────────────────┘
|
|
│ /api/* (Vite dev proxy :3001)
|
|
▼
|
|
┌──────────────────────────────────────────┐ ┌─────────────────────┐
|
|
│ Node.js 20 + Express API (port 3001) │ sync │ Supabase (Postgres)│
|
|
│ - JWT auth (jsonwebtoken) │ ◀────▶ │ api.next_gen. │
|
|
│ - bcrypt password hashing │ 30 s │ techarvest.co.zw │
|
|
│ - 12 controllers (one per module) │ └─────────────────────┘
|
|
│ - SQLite (better-sqlite3) local mirror │ ▲
|
|
│ - SyncEngine (push/pull, server-wins) │ ───────────────┘
|
|
│ - Paynow integration
|
|
│ - Multer file uploads
|
|
└──────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
./data/school.db (SQLite, persistent volume in Docker)
|
|
|
|
All in one container via multi-stage Dockerfile + docker-compose.
|
|
```
|
|
|
|
**Architectural style.** A classic **three-tier monolith** (React SPA → Express REST → SQLite) with a **bidirectional sync adapter** to a managed Postgres (Supabase) for backup and cross-device replication. There is no microservice decomposition; modules are Express `Router()` instances mounted under `/api/<module>`.
|
|
|
|
---
|
|
|
|
## 2. Technology Stack
|
|
|
|
### 2.1 Frontend (`client/`)
|
|
- **Language:** TypeScript 5.3+
|
|
- **Framework:** React 18.2 (function components + hooks)
|
|
- **Build tool:** Vite 5 (`vite.config.ts`)
|
|
- **Routing:** react-router-dom 6
|
|
- **State management:** Zustand 4 (with `persist` middleware for auth)
|
|
- **HTTP client:** Axios 1
|
|
- **Charts:** Recharts 2
|
|
- **Icons:** lucide-react
|
|
- **PWA:** vite-plugin-pwa (Workbox runtime caching, autoUpdate)
|
|
|
|
### 2.2 Backend (`server/`)
|
|
- **Runtime:** Node.js 20 (Alpine in Docker)
|
|
- **Framework:** Express 4
|
|
- **Storage:** SQLite via `better-sqlite3` 12 (WAL mode, `foreign_keys = ON`)
|
|
- **Auth:** `jsonwebtoken` 9 (HS256, 7-day expiry) + `bcryptjs` 2
|
|
- **CORS:** `cors` 2 (currently wide-open; see §6 Security)
|
|
- **Uploads:** `multer` 1.4
|
|
- **Cloud sync:** `@supabase/supabase-js` 2
|
|
- **IDs:** `uuid` 9 (for sync `uid` columns)
|
|
- **Dev loop:** `nodemon` 3
|
|
|
|
### 2.3 Database
|
|
- **Primary (local):** SQLite (single file at `server/data/school.db`, mode WAL).
|
|
- **Replica (cloud):** Supabase Postgres. Push/pull through the Supabase REST API.
|
|
- **Schema source of truth:** `server/src/database/init.js` (CREATE TABLE IF NOT EXISTS — see §10 for migration plan).
|
|
- **Soft-delete + sync metadata on every table:**
|
|
```sql
|
|
last_synced_at DATETIME,
|
|
sync_status TEXT DEFAULT 'pending' CHECK(sync_status IN ('synced','pending','conflict')),
|
|
is_deleted INTEGER DEFAULT 0
|
|
```
|
|
|
|
### 2.4 Infrastructure
|
|
- **Containerization:** Docker (multi-stage `Dockerfile` — `client-build` → `server-build` → `production`) + Docker Compose v3.8.
|
|
- **Base image:** `node:20-alpine`.
|
|
- **Persistent volumes:** `./data` (SQLite) and `./uploads` (file uploads).
|
|
- **Ports:** 3000 (static client via `npx serve`), 3001 (API).
|
|
- **Entrypoint:** `docker-entrypoint.sh` — runs DB init on first boot, then launches API + static server.
|
|
|
|
### 2.5 DevOps
|
|
- **CI/CD:** *None configured.* Recommended: GitHub Actions — see §13.
|
|
- **Backups:** Manual `cp -r data data-backup-…` (documented in `DOCKER_README.md`). No automation.
|
|
- **Monitoring / health check:** *Not implemented.* Recommended: `/api/health` endpoint, see §13.
|
|
- **Secrets management:** Currently via `docker-compose.yml` env block (with a **hardcoded fallback secret** — see §6). Recommended: Docker secrets or a `.env` file with `dotenv` (NOT committed).
|
|
|
|
### 2.6 AI/ML Components
|
|
- *None.* No ML models, embeddings, or AI services are integrated. The system is purely transactional. If you add AI features (e.g. attendance anomaly detection, grade prediction), add a new sub-section here.
|
|
|
|
---
|
|
|
|
## 3. Team AI Agents
|
|
|
|
These are the persistent agent roles this repo expects AI agents to assume. Each role is scoped so two agents can work in parallel without stepping on each other.
|
|
|
|
### 3.1 Architect Agent
|
|
|
|
**Owns:** `client/src/App.tsx`, `client/vite.config.ts`, `server/src/index.js`, `docker-compose.yml`, `Dockerfile`, `docker-entrypoint.sh`, `AGENTS.md`.
|
|
|
|
**Responsibilities:**
|
|
- System architecture and module boundaries.
|
|
- Scalability (SQLite → Postgres migration, sync sharding, multi-tenant tenancy).
|
|
- Security review (authn, authz, secrets, CORS, rate limiting, payload validation).
|
|
- Design decisions and ADRs (architecture-decision records — see §11).
|
|
- Cross-cutting concerns: error handling, logging, observability.
|
|
|
|
**Out of scope:** Implementing feature CRUD — that's the Backend / Frontend agents.
|
|
|
|
### 3.2 Backend Agent
|
|
|
|
**Owns:** `server/src/**` (controllers, services, middleware, db), `server/package.json`.
|
|
|
|
**Responsibilities:**
|
|
- Express API development.
|
|
- Business logic, validation, transactions.
|
|
- Database schema and migrations (when extracted from `init.js`).
|
|
- Sync engine correctness (push/pull ordering, conflict resolution).
|
|
- Backend testing (Jest / Vitest + supertest, once set up — see §13).
|
|
- Paynow integration and webhook security.
|
|
|
|
**Out of scope:** React UI, deployment infrastructure.
|
|
|
|
### 3.3 Frontend Agent
|
|
|
|
**Owns:** `client/src/**` (components, pages, stores, hooks), `client/package.json`, `client/vite.config.ts`, PWA manifest, service-worker config.
|
|
|
|
**Responsibilities:**
|
|
- UI / UX implementation.
|
|
- Accessibility (WCAG 2.1 AA — semantic HTML, focus management, ARIA only when needed).
|
|
- State management (Zustand stores) and API caching.
|
|
- Offline / service-worker behavior (Workbox strategies, runtime caching).
|
|
- Frontend testing (Vitest + React Testing Library, once set up — see §13).
|
|
- Form validation and user-facing error handling.
|
|
|
|
**Out of scope:** Server endpoints, DB schema.
|
|
|
|
### 3.4 DevOps Agent
|
|
|
|
**Owns:** `Dockerfile`, `docker-compose.yml`, `docker-entrypoint.sh`, `.github/` or `.gitlab/` (when created), CI/CD pipelines, backup scripts, deployment docs.
|
|
|
|
**Responsibilities:**
|
|
- CI/CD pipelines (lint → typecheck → test → build → deploy).
|
|
- Container hardening (non-root user, healthcheck, multi-stage size optimization).
|
|
- Infrastructure-as-code (when promoted beyond Docker Compose).
|
|
- Monitoring / observability (logs, metrics, traces).
|
|
- Backups (automated SQLite snapshots + restore drills).
|
|
- Secrets management (`.env`, Docker secrets, vault).
|
|
|
|
**Out of scope:** Application logic.
|
|
|
|
### 3.5 QA Agent
|
|
|
|
**Owns:** `tests/` (once created), test plans, regression suites, performance baselines.
|
|
|
|
**Responsibilities:**
|
|
- Test plans for each user role (admin / teacher / student / parent).
|
|
- Automated test suite (unit + integration + e2e — Playwright recommended for e2e).
|
|
- Regression testing on every PR.
|
|
- Performance testing (especially the exam timer and bulk attendance endpoints).
|
|
- Accessibility audits (axe-core, manual screen-reader checks).
|
|
|
|
**Out of scope:** Writing new feature code; QA flags defects, the owning agent fixes them.
|
|
|
|
### 3.6 Documentation Agent
|
|
|
|
**Owns:** `README.md`, `DOCKER_README.md`, `IMPLEMENTATION_SUMMARY.md`, `SCREENS.md`, this file, OpenAPI/Swagger specs (when added), ADRs in `docs/adr/`.
|
|
|
|
**Responsibilities:**
|
|
- Keep `README.md` in sync with the running app.
|
|
- Maintain `SCREENS.md` as the canonical UI map (it currently lists screens and the permissions matrix — keep that current as features land).
|
|
- Generate / curate API documentation (OpenAPI from route comments or a `swagger-jsdoc` setup).
|
|
- Architecture diagrams (use Mermaid in `.md` files — they render in GitHub / GitLab).
|
|
- Runbooks for common operations (DB reset, sync repair, backup restore).
|
|
|
|
**Out of scope:** Writing the code that the docs describe; that is owned by the implementing agent.
|
|
|
|
---
|
|
|
|
## 4. Coding Standards
|
|
|
|
### 4.1 Naming Conventions
|
|
| Layer | Convention | Example |
|
|
|---|---|---|
|
|
| React components | PascalCase, file matches export | `AdminDashboard.tsx` exports `AdminDashboard` |
|
|
| Hooks | `useX` camelCase | `useAuthStore` |
|
|
| Zustand stores | camelCase, `use` prefix | `useExamsStore` |
|
|
| TypeScript types / interfaces | PascalCase | `interface User { … }` |
|
|
| Express controllers | camelCase + `.controller.js` | `exams.controller.js` |
|
|
| Express services | camelCase + `.service.js` | `syncEngine.js` (existing convention) — keep aligned |
|
|
| Database columns | snake_case | `first_name`, `sync_status` |
|
|
| Environment variables | SCREAMING_SNAKE_CASE | `JWT_SECRET`, `SUPABASE_URL` |
|
|
| Branches | `feature/<kebab>` or `fix/<kebab>` | `feature/online-exams`, `fix/login-redirect` |
|
|
|
|
### 4.2 Folder Organization
|
|
- All **backend** code under `server/src/`. Subfolders: `controllers/`, `services/`, `database/`, `middleware/`, `routes/` (when split out).
|
|
- All **frontend** code under `client/src/`. Subfolders: `components/`, `pages/`, `store/`, `hooks/`, `utils/`, `services/`.
|
|
- **Role-specific** pages live under `client/src/pages/<role>/` (admin / teacher / student / parent). Cross-role pages stay at `client/src/pages/`.
|
|
- **Shared modules** (e.g. an `Avatar` used by every role) go in `client/src/components/`, never in a role subfolder.
|
|
- **Database artifacts** (`init.js`, future migrations) live in `server/src/database/`. Do not scatter SQL across controllers.
|
|
|
|
### 4.3 Commit Message Format
|
|
Use **Conventional Commits**:
|
|
```
|
|
<type>(<scope>): <short imperative summary>
|
|
|
|
<body — explain WHY, not what>
|
|
|
|
<footer — breaking changes, issue refs>
|
|
```
|
|
- Types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `ci`, `perf`, `build`.
|
|
- Scope examples: `client`, `server`, `db`, `docker`, `auth`, `exams`, `paynow`, `sync`.
|
|
- Example: `feat(exams): auto-grade multiple-choice on submit`.
|
|
|
|
### 4.4 Documentation Requirements
|
|
- Every **public module** (controller, store, hook, component used across roles) gets a JSDoc / TSDoc header explaining its purpose and one example.
|
|
- Every **non-trivial function** gets a short JSDoc with `@param` / `@returns` for edge cases.
|
|
- Every **API route** is documented in `docs/API.md` (or via generated OpenAPI — see §13).
|
|
- Every **architectural decision** gets an ADR in `docs/adr/NNNN-title.md` (use `docs/adr/0001-record-architecture-decisions.md` as the template).
|
|
|
|
### 4.5 Testing Requirements
|
|
- **Every new controller** has at least one integration test (supertest) covering the happy path and one error case.
|
|
- **Every new store** has a unit test for each action.
|
|
- **Every new page** has a smoke test (renders without crashing) and an interaction test for the primary user flow.
|
|
- **Bug fixes** add a regression test that fails before the fix and passes after.
|
|
- Coverage gate: target **≥ 70 %** lines on the backend, **≥ 60 %** on the frontend (raise over time — see §13).
|
|
|
|
---
|
|
|
|
## 5. Pull Request Rules
|
|
|
|
A PR is mergeable **only** when **all** of the following are true. The Author is responsible for self-checking; the Reviewer verifies.
|
|
|
|
### 5.1 Review Requirements
|
|
- **Minimum 1 reviewer** for changes under 200 lines, **2 reviewers** for ≥ 200 lines or any change touching `server/src/index.js`, `client/src/App.tsx`, `Dockerfile`, `docker-compose.yml`, or `server/src/database/init.js`.
|
|
- The owning agent (per §3) must approve changes in their owned area.
|
|
- The **Architect agent** must approve any change that crosses module boundaries or modifies the auth / sync layer.
|
|
|
|
### 5.2 Testing Requirements
|
|
- All **new and modified** code paths are covered by tests (see §4.5).
|
|
- The full test suite passes locally AND in CI.
|
|
- No tests are skipped or `.only` left in.
|
|
|
|
### 5.3 Security Checks
|
|
- No secrets in code or committed `.env` files. Verify with `git diff --staged` before pushing.
|
|
- Any new dependency has been audited (`npm audit --omit=dev` clean; criticals = 0).
|
|
- Any new endpoint goes through `auth` and (where applicable) role-check middleware.
|
|
- User-supplied input is validated; raw SQL is parameterized (it already is in this repo — keep that standard).
|
|
- Webhook handlers (Paynow, future Supabase webhooks) verify signatures.
|
|
|
|
### 5.4 Documentation Checks
|
|
- `README.md` and `SCREENS.md` updated if the user-visible behaviour changes.
|
|
- This `AGENTS.md` updated if the architecture, standards, or agent roster changes.
|
|
- New API endpoints documented in `docs/API.md` (or OpenAPI).
|
|
- ADRs added for any non-obvious decision.
|
|
|
|
### 5.5 Lint / Typecheck / Build
|
|
- `npm run lint` (or the configured linter) — 0 errors.
|
|
- `npm run typecheck` (frontend) — 0 errors.
|
|
- `npm run build` — succeeds.
|
|
|
|
---
|
|
|
|
## 6. Definition of Done
|
|
|
|
A user story is **Done** when **all** of the following hold:
|
|
|
|
1. **Code builds successfully** — `docker-compose build` (or `npm run build` in each subproject) succeeds.
|
|
2. **Tests pass** — full test suite green, coverage meets the gate in §4.5.
|
|
3. **Documentation updated** — README, SCREENS, and AGENTS touched where applicable.
|
|
4. **Security checks completed** — secrets scan clean, deps audited, auth in place, input validated.
|
|
5. **Linting passes** — 0 lint errors, 0 type errors.
|
|
6. **Demo verified** — the change has been exercised end-to-end against a running dev environment.
|
|
7. **PR merged** — at least one approval, CI green, branch deleted.
|
|
|
|
---
|
|
|
|
## 7. Development Workflow
|
|
|
|
### 7.1 Branch Strategy
|
|
This repo follows a strict two-branch model — **Git Flow style, with `main` as production**.
|
|
|
|
| Branch | Purpose | Pushable from | Invariant |
|
|
|---|---|---|---|
|
|
| `dev` | **Work and test.** All day-to-day work, new features, refactors, and bug fixes land here. The integration branch for in-progress code. | Any local commit / merge | May be broken. May have unreleased features. |
|
|
| `main` | **Production.** Only receives code that has been **tested on `dev`**. Every commit on `main` MUST be deployable. | A green test run against `dev`, followed by a deliberate merge | **Must always be deployable.** No broken builds, no half-finished features, no WIP commits. |
|
|
| `feature/<kebab>` | A new feature. | — | Branched from `dev`. Merged back into `dev` (PR). |
|
|
| `fix/<kebab>` | A bug fix. | — | Branched from `dev`. Merged back into `dev` (PR). |
|
|
| `hotfix/<kebab>` | An emergency fix that must reach production **without** going through the full `dev` test cycle. | — | Branched from `main`. Merged into **both** `main` and `dev` so `dev` doesn't drift. Used sparingly. |
|
|
|
|
**Promotion path: `dev` → `main`.** Promote only after:
|
|
1. All required tests pass on `dev` (whatever the team has agreed — currently there are no automated tests, so this is at minimum: manual smoke + a green `docker-compose up`). The audit recommends a real test suite — see §13.4.
|
|
2. The `dev` tip is reviewed and accepted.
|
|
3. A human (the maintainer) merges `dev` into `main` with a deliberate commit (no fast-forward). Tag the resulting `main` tip as a release (see §7.3).
|
|
|
|
**Why this matters.** If you commit straight to `main`, or merge an untested feature into `main`, you break the "always deployable" invariant. Subsequent deployments will ship broken code. **Treat any direct commit to `main` as a release-blocker.**
|
|
|
|
**Branch names:** kebab-case, ≤ 50 chars, no prefixes like `my/`. Use the `worktree-management` skill — every code change goes in `.worktrees/feature-<name>/` (or `fix-<name>`, `hotfix-<name>`).
|
|
|
|
### 7.2 PR Workflow
|
|
1. Pick or open an issue describing the change.
|
|
2. **Branch from `dev`** (not `main`) unless this is a hotfix (§7.1).
|
|
3. Implement + test locally.
|
|
4. Run the Definition of Done checklist (§6).
|
|
5. Open a PR targeting **`dev`**. Title in Conventional Commits format. Description links the issue and lists the user-visible behaviour change.
|
|
6. Address review feedback.
|
|
7. Merge via **squash** (or whatever the team agrees on). Delete the source branch.
|
|
8. **Promote to `main` separately**, after a green test run on `dev` (§7.1).
|
|
|
|
### 7.3 Release Workflow
|
|
- `main` is the source of release tags. When you promote `dev` → `main` and that merge is a release candidate:
|
|
- Tag the new `main` tip as `vMAJOR.MINOR.PATCH` (semver).
|
|
- Maintain a `CHANGELOG.md` per release (group: Added / Changed / Fixed / Removed).
|
|
- Backwards-incompatible changes bump MAJOR and write an ADR + migration guide.
|
|
|
|
### 7.4 Deployment Workflow
|
|
- **Container image** is the unit of deployment. `Dockerfile` produces one image that runs both API and static client.
|
|
- `docker-compose up -d` on the target host. Persistent volumes: `data/`, `uploads/`.
|
|
- Pre-deploy checklist:
|
|
- [ ] DB backup taken (`cp -r data data-backup-$(date +%F)`).
|
|
- [ ] `.env` file present and validated (no missing required vars).
|
|
- [ ] Image tag matches the release tag.
|
|
- Post-deploy: run smoke tests, verify `/api/health` (once added), check sync status (`GET /api/sync/status`).
|
|
|
|
---
|
|
|
|
## 8. Security Guidelines
|
|
|
|
### 8.1 Secret Management
|
|
- **Never** commit secrets. The current repo already has a hardcoded JWT secret in `docker-compose.yml` (`africa-alert-production-secret-2024`) **and** in `server/src/index.js` (`africa-alert-secret-key-2024`). **Action required** — see §13.3.
|
|
- Use environment variables. Provide an `.env.example` (NOT `.env`) that lists every required var.
|
|
- Production secrets live in a secret manager (Docker secrets, HashiCorp Vault, cloud KMS). Rotate JWT secrets at least quarterly.
|
|
- The `Supabase service key` and `Paynow integration key` are particularly sensitive — never log them, never return them to the client.
|
|
|
|
### 8.2 Dependency Scanning
|
|
- `npm audit --omit=dev` on every PR. **Block** on any `high` or `critical` CVE.
|
|
- Dependabot / Renovate configured to open weekly PRs.
|
|
- Pin major versions in `package.json`; let `package-lock.json` pin exact.
|
|
|
|
### 8.3 Authentication Standards
|
|
- All `/api/*` routes (except `/api/auth/login` and `/api/auth/register`) require a valid JWT in the `Authorization: Bearer <token>` header.
|
|
- Passwords stored with **bcrypt** (cost factor ≥ 10). Never store plaintext.
|
|
- Tokens expire in **7 days** (current setting). Add refresh-token flow for longer sessions.
|
|
- Rate-limit `/api/auth/login` (e.g. `express-rate-limit`, 5 attempts per 15 min per IP) to slow credential stuffing.
|
|
- Invalidate tokens on logout (blocklist or short-lived access tokens + refresh tokens).
|
|
|
|
### 8.4 Authorization Standards
|
|
- Every endpoint must check **both** authentication (`auth` middleware) **and** role where applicable.
|
|
- Use a role-based check helper: `requireRole('admin', 'teacher')` — do not sprinkle `if (req.user.role !== 'admin')` across controllers (the codebase already has this duplication — see §13.2).
|
|
- Never trust client-supplied user IDs. Always read `req.user.id` for the "current user".
|
|
- Resource-level access (a student reading their own grade) must be enforced in the controller, not only in the UI.
|
|
|
|
---
|
|
|
|
## 9. AI Collaboration Rules
|
|
|
|
These rules apply to every AI agent (Mavis rein, GitHub Copilot, or any other tool) working in this repo. They are non-negotiable.
|
|
|
|
1. **Do not modify unrelated files.** Stay inside the area you own (§3). Cross-cutting changes require an Architect-agent review.
|
|
2. **Explain major architectural changes** in an ADR before writing code. Surface the trade-offs in the PR description.
|
|
3. **Create tests for every new feature** in the same change. No untested code lands on `dev`.
|
|
4. **Update documentation when changing functionality.** README, SCREENS, AGENTS, and the API doc all reflect what the code actually does.
|
|
5. **Prefer maintainability over cleverness.** A 50-line explicit controller beats a 10-line abstract one that nobody can debug at 2am.
|
|
6. **Ask before destructive changes.** Deleting files, force-pushing, dropping tables, hard-resetting the DB — always confirm with the user first.
|
|
7. **Read this file end-to-end before your first change** in the repo. If anything is unclear or out of date, flag it in the PR.
|
|
8. **Use the worktree workflow.** All code changes go in `.worktrees/feature-<name>/` — never in the main checkout. See `worktree-management` skill.
|
|
9. **Reference code with `path:line`** when discussing it in chat or PRs — never paste a wall of context.
|
|
10. **Be conservative with new dependencies.** Each new `package.json` entry increases the supply-chain surface. Justify it.
|
|
|
|
---
|
|
|
|
## 10. Repository Knowledge Base
|
|
|
|
> A condensed map of the codebase. New agents: read this section first.
|
|
|
|
### 10.1 Important Modules
|
|
|
|
| Module | Frontend | Backend Controller | Notes |
|
|
|---|---|---|---|
|
|
| Auth | `client/src/store/auth.ts` | `POST /api/auth/login`, `/register` in `server/src/index.js` | JWT + bcrypt; 7-day expiry |
|
|
| Users | `client/src/pages/Students.tsx`, `Teachers.tsx`, `admin/Users.tsx` | `controllers/users.controller.js` | Roles: admin / teacher / student / parent (+ accountant / librarian / nurse in schema) |
|
|
| Classes & Subjects | `client/src/pages/Classes.tsx` | inline in `server/src/index.js` (classes + subjects) | |
|
|
| Enrollments | — | inline in `server/src/index.js` | |
|
|
| Attendance | `client/src/pages/Attendance.tsx` | inline + `controllers/attendance.controller.js` | Supports bulk upsert |
|
|
| Fees | `client/src/pages/Fees.tsx` | inline + `controllers/paynow.controller.js` | Paynow integration for online payment |
|
|
| Messages | `client/src/pages/Messages.tsx` | `controllers/messages.controller.js` | |
|
|
| Calendar / Events | `client/src/pages/Events.tsx` | `controllers/calendar.controller.js` | |
|
|
| Exams | `client/src/pages/exams/ExamViews.tsx` + `client/src/store/exams.ts` | `controllers/exams.controller.js` | Full exam lifecycle: groups → questions → schedules → attempts → grading |
|
|
| Assignments | `client/src/store/assignments.ts` | `controllers/assignments.controller.js` | |
|
|
| Grades | `client/src/pages/student/Grades.tsx` | `controllers/grades.controller.js` | |
|
|
| Reports | `client/src/pages/admin/Reports.tsx` | `controllers/reports.controller.js` | |
|
|
| Settings | `client/src/pages/admin/Settings.tsx` | `controllers/settings.controller.js` | |
|
|
| Departments | `client/src/pages/admin/Departments.tsx` | `controllers/departments.controller.js` | |
|
|
| Payroll & HR | (frontend TBD) | DB only (`init.js`) | 8 tables: staff_roles, salary_grades, staff_records, leave_types, leave_requests, staff_attendance, payroll_runs, payslips |
|
|
| Inventory | (frontend TBD) | DB only | 7 tables: item_categories, suppliers, store_locations, items, item_stock, stock_transactions, item_issues |
|
|
| Hostel | (frontend TBD) | DB only | 6 tables |
|
|
| Transport | (frontend TBD) | DB only | 5 tables |
|
|
| Front Office | (frontend TBD) | DB only | 5 tables |
|
|
| Sync | — | `services/SyncEngine.js` | Bidirectional, server-wins conflict policy, 30 s interval |
|
|
|
|
### 10.2 Key Services
|
|
- **SyncEngine** (`server/src/services/SyncEngine.js`) — singleton (`getSyncEngine()`). Runs every `SYNC_INTERVAL` ms (default 30000). Pushes local `sync_status = 'pending'` rows to Supabase REST, pulls remote `updated_at >= lastSync` rows back. Logs errors to `sync_logs`. Exposes `/api/sync/status` and `/api/sync/force`.
|
|
- **Paynow client** (`server/src/controllers/paynow.controller.js`) — integrates with `https://www.paynow.co.zw/interface/initiatetransaction`. Endpoints: `POST /initiate`, `GET /status/:id`, `POST /webhook`, `GET /student/:id`, `DELETE /:id`.
|
|
- **Auth** — JWT signed with `JWT_SECRET` (env), 7-day expiry. Role embedded in payload.
|
|
|
|
### 10.3 Database Schema (39+ tables)
|
|
Full schema lives in `server/src/database/init.js` (1675 lines). All tables share the sync columns: `uid`, `last_synced_at`, `sync_status`, `is_deleted`. Core groups:
|
|
- **Core (11):** users, classes, subjects, enrollments, attendance, fee_groups, student_fees, payments, messages, events, expenses, grades, sync_logs, sync_config, system_settings.
|
|
- **Payroll & HR (8):** staff_roles, salary_grades, staff_records, leave_types, leave_requests, staff_attendance, payroll_runs, payslips.
|
|
- **Inventory (7):** item_categories, suppliers, store_locations, items, item_stock, stock_transactions, item_issues.
|
|
- **Exams (5):** exam_groups, question_banks, exam_schedules, exam_attempts, exam_answers.
|
|
- **Hostel (6):** hostels, room_types, rooms, room_assignments, hostel_fees.
|
|
- **Transport (5):** vehicles, routes, pickup_points, vehicle_routes, transport_allocations.
|
|
- **Front Office (5):** admission_enquiries, visitor_logs, phone_call_logs, postal_dispatch, complaints.
|
|
|
|
User roles supported by the schema `CHECK` constraint: `admin`, `teacher`, `student`, `parent`, `accountant`, `librarian`, `nurse`. The frontend currently only authenticates the first four.
|
|
|
|
### 10.4 API Structure
|
|
- All routes mounted under `/api/<module>` in `server/src/index.js`.
|
|
- 12 controller routers + 2 inline route blocks (auth, dashboard stats) + 2 inline CRUD blocks (classes, subjects, enrollments, attendance, fees, messages, events, expenses).
|
|
- Response shape: JSON. Errors are `{ "error": "<message>" }` (no error code, no stack trace in production — see §13.4).
|
|
- All authenticated routes set `req.user = { id, email, role }` from the JWT.
|
|
|
|
### 10.5 Infrastructure Components
|
|
- **Dockerfile** — multi-stage: `client-build` (Vite build) → `server-build` (npm ci) → `production` (Alpine runtime, copies built artefacts, runs `docker-entrypoint.sh`).
|
|
- **docker-compose.yml** — single `app` service. Mounts `./data` and `./uploads` as volumes. Exposes 3000 (client) and 3001 (API). **Currently hardcodes `JWT_SECRET`** — see §13.3.
|
|
- **docker-entrypoint.sh** — initializes DB on first run, starts API in background, then `npx serve` for the static client.
|
|
|
|
### 10.6 Environment Variables
|
|
|
|
| Name | Default | Required | Purpose |
|
|
|---|---|---|---|
|
|
| `PORT` | `3001` | no | API port |
|
|
| `JWT_SECRET` | ⚠️ hardcoded fallback | **yes (prod)** | Signs JWTs. **MUST** be set in production. |
|
|
| `DB_PATH` | `./data/school.db` | no | SQLite path |
|
|
| `SUPABASE_URL` | `https://api.next_gen.techarvest.co.zw` | no | Cloud sync target |
|
|
| `SUPABASE_KEY` | empty | no (offline mode if missing) | Cloud sync auth |
|
|
| `SYNC_INTERVAL` | `30000` | no | Sync period in ms |
|
|
| `PAYNOW_INTEGRATION_ID` | empty | **yes (prod)** | Paynow merchant id |
|
|
| `PAYNOW_INTEGRATION_KEY` | empty | **yes (prod)** | Paynow signing key |
|
|
| `PAYNOW_RETURN_URL` | `http://localhost:3000/fees` | no | Post-payment redirect |
|
|
| `PAYNOW_BLOCKING_URL` | `http://localhost:3000/api/payments/webhook` | no | Webhook target |
|
|
| `NODE_ENV` | `production` (in Docker) | no | Standard Node env |
|
|
|
|
---
|
|
|
|
## 11. Architecture Decision Records (ADRs)
|
|
|
|
Place new ADRs in `docs/adr/NNNN-<title>.md`. Use [MADR](https://adr.github.io/madr/) or a simplified template:
|
|
|
|
```markdown
|
|
# NNNN. <Title>
|
|
|
|
- **Status:** Proposed | Accepted | Superseded by NNNN
|
|
- **Date:** YYYY-MM-DD
|
|
- **Deciders:** <agents / humans>
|
|
|
|
## Context
|
|
<what's the situation>
|
|
|
|
## Decision
|
|
<what we chose>
|
|
|
|
## Consequences
|
|
<what becomes easier, what becomes harder>
|
|
```
|
|
|
|
Suggested first ADRs to write:
|
|
1. **0001** — Use SQLite as the local mirror + Supabase as cloud (current model).
|
|
2. **0002** — Server-wins conflict resolution in sync.
|
|
3. **0003** — JWT-only auth (no session cookies).
|
|
4. **0004** — Single-container deployment.
|
|
5. **0005** — Role-based access (admin / teacher / student / parent).
|
|
|
|
---
|
|
|
|
## 12. Onboarding Checklist (for any new agent)
|
|
|
|
Use this when picking up the repo fresh:
|
|
|
|
- [ ] Read this `AGENTS.md` end-to-end.
|
|
- [ ] Skim `README.md`, `SCREENS.md`, `IMPLEMENTATION_SUMMARY.md`, `DOCKER_README.md`.
|
|
- [ ] Run `docker-compose up -d` and log in as `admin@school.com / admin123`.
|
|
- [ ] Click through every dashboard and module once.
|
|
- [ ] Read `server/src/index.js` and `server/src/services/SyncEngine.js`.
|
|
- [ ] Read `client/src/App.tsx` and `client/src/store/auth.ts`.
|
|
- [ ] Read `server/src/database/init.js` (it's long — focus on the `CHECK` constraints and the sync columns).
|
|
- [ ] Skim one controller per module (e.g. `exams.controller.js`, `paynow.controller.js`).
|
|
- [ ] Run the dev servers in worktrees per the `worktree-management` skill.
|
|
- [ ] Pick a small, scoped issue from the backlog and follow the PR workflow in §7.
|
|
|
|
---
|
|
|
|
## 13. Recommendations (action items for the human maintainer)
|
|
|
|
The audit identified the following. Treat them as a prioritised backlog — not a demand. Every recommendation has a one-line rationale.
|
|
|
|
### 13.1 Architecture Improvements (priority: medium → high)
|
|
- **M1 — Move schema out of `init.js` into versioned migrations** (use `node-pg-migrate` style or `knex`). `init.js` is 1675 lines and grows linearly with every new module. *Why:* current `CREATE TABLE IF NOT EXISTS` pattern cannot represent ALTER statements, so any schema change is a full DB rebuild.
|
|
- **M2 — Extract a shared `auth` middleware module.** Each controller currently re-declares its own `auth` (e.g. `exams.controller.js:17`, `paynow.controller.js:18`, `index.js:55`). *Why:* drift risk — a security fix to one will be missed in the others.
|
|
- **M3 — Introduce a service layer between controllers and the DB.** Right now controllers inline SQL strings. Extract `users.service.js`, `exams.service.js`, etc. *Why:* testability (mock the service, not the DB) and reuse (the sync engine will share services).
|
|
- **M4 — Add request validation.** Use `zod` or `joi` schemas at the route boundary. *Why:* the current code trusts `req.body` to have the right shape; a malformed payload currently throws inside better-sqlite3.
|
|
- **M5 — Make the sync engine resilient to a missing/disrupted Supabase.** It already no-ops on missing key; harden the timeout, retry, and circuit-breaker paths. *Why:* when sync is down, the API must not slow down.
|
|
- **M6 — Multi-tenant design (if applicable).** If multiple schools will use one deployment, add a `school_id` to every table and a tenant-scoping middleware. *Why:* retrofitting tenant IDs is a painful migration.
|
|
|
|
### 13.2 Missing Documentation (priority: medium)
|
|
- **D1 — `docs/API.md` (or `docs/openapi.yaml`).** No central API reference. Generate from JSDoc with `swagger-jsdoc` + `swagger-ui-express`.
|
|
- **D2 — `docs/adr/` with the suggested ADRs from §11.**
|
|
- **D3 — `.env.example` at repo root** listing every variable from §10.6.
|
|
- **D4 — Operations runbook** (`docs/runbook.md`): how to reset the DB, repair a broken sync, restore from backup, rotate secrets.
|
|
- **D5 — Document the schema** in `docs/schema.md` (Mermaid ER diagram is fine).
|
|
- **D6 — Document the `scopes` / permissions** in a code-readable form (a JSON `permissions.json` that the server can import), so frontend and backend share one source of truth. Currently the matrix lives only in `SCREENS.md` and is duplicated in `App.tsx` and `Nav.tsx`.
|
|
|
|
### 13.3 Security Improvements (priority: HIGH)
|
|
- **S1 — Remove the hardcoded JWT secret fallbacks.** `server/src/index.js:25` and every controller that does `process.env.JWT_SECRET || 'africa-alert-secret-key-2024'`. Refuse to start without `JWT_SECRET` in production. *Why:* anyone reading the public repo can mint admin JWTs.
|
|
- **S2 — Remove the hardcoded `JWT_SECRET` from `docker-compose.yml`** (line 18). It is currently `africa-alert-production-secret-2024` — a **production-named** secret committed to git. *Why:* it is now public knowledge. Rotate immediately in any environment that ever used this value.
|
|
- **S3 — Add `express-rate-limit` to `/api/auth/login` and `/api/auth/register`.** No throttling today.
|
|
- **S4 — Tighten CORS.** `app.use(cors())` is wide-open (`server/src/index.js:36`). Restrict to known origins.
|
|
- **S5 — Add a request-size limit** (`express.json({ limit: '1mb' })`). Default is 100kb, but be explicit.
|
|
- **S6 — Verify Paynow webhook signatures.** Currently the webhook handler accepts any payload; the hash check appears in `generateHash` but is it verified on inbound? Audit `paynow.controller.js` end-to-end.
|
|
- **S7 — Add `helmet`** for sensible HTTP security headers.
|
|
- **S8 — Scan dependencies in CI** (`npm audit` + a Dependabot config).
|
|
|
|
### 13.4 Testing Improvements (priority: medium → high)
|
|
- **T1 — Add a test runner to both packages.** No tests exist today. Backend: **Jest** + **supertest**. Frontend: **Vitest** + **React Testing Library** + **@testing-library/jest-dom**. E2E: **Playwright**.
|
|
- **T2 — Write integration tests for the auth flow** first (login, bad password, expired token, role denial).
|
|
- **T3 — Write integration tests for the exam timer + auto-submit** (race-condition-prone).
|
|
- **T4 — Write a regression test for the sync engine's conflict resolution** (server-wins).
|
|
- **T5 — Add a coverage gate** in CI (see §4.5).
|
|
- **T6 — Add a smoke test for the Docker image** — start the container, hit `/api/health` (once added), assert 200.
|
|
|
|
### 13.5 DevOps Improvements (priority: medium)
|
|
- **O1 — Add `/api/health` and `/api/ready` endpoints.** Liveness vs readiness (the latter should return 503 until the DB is initialized).
|
|
- **O2 — Add CI** (GitHub Actions recommended): install → lint → typecheck → test → build → docker build.
|
|
- **O3 — Pin Node version in `.nvmrc` and in `Dockerfile` (`FROM node:20.x-alpine`).** Pinning to `node:20-alpine` is OK but explicit `20.x.y` is safer.
|
|
- **O4 — Add a non-root `USER` in the production Dockerfile stage.** Containers currently run as root.
|
|
- **O5 — Add a `HEALTHCHECK` instruction** to the Dockerfile.
|
|
- **O6 — Automate SQLite backups** (cron sidecar or a simple `node-cron` task in the API). Ship a documented `restore.sh`.
|
|
- **O7 — Add log aggregation.** Today logs go to stdout only. Pipe to a log shipper (Loki, CloudWatch, etc.) in production.
|
|
- **O8 — Add `.dockerignore`** to keep `node_modules`, `data/`, `dist/`, `uploads/`, `.git/`, `.harness/` out of the build context.
|
|
- **O9 — Split the Docker image** into `client` (Nginx serving `dist/`) + `api` for cleaner scaling. Optional — current single-image design is simpler to operate.
|
|
|
|
### 13.6 Documentation-as-Product (priority: low → medium)
|
|
- **P1 — Promote `SCREENS.md` to a generated artefact.** It is already excellent; consider a small script that builds it from the route table.
|
|
- **P2 — Add a `CONTRIBUTING.md`** linking to this file and the worktree workflow.
|
|
- **P3 — Add a `SECURITY.md`** with a disclosure address (e.g. `security@…`).
|
|
|
|
---
|
|
|
|
## 14. Open Questions for the Maintainer
|
|
|
|
These are decisions the audit surfaced that only you can answer. Each is one PR away from being resolved.
|
|
|
|
1. ~~Which branch is the integration target — `dev` or `main`?~~ **Resolved 2026-06-03** — `dev` is for work + test, `main` is for deployable code only. Documented in §7.1.
|
|
2. Do you plan to scale beyond a single SQLite file? If so, when — that determines whether to invest in the migration to Postgres now or in 6 months.
|
|
3. Are `accountant`, `librarian`, `nurse` (defined in the schema) planned roles? They have no UI today.
|
|
4. Will the same deployment serve multiple schools, or one-school-per-install?
|
|
5. Who hosts the Supabase project, and who rotates the service key?
|
|
6. Is there a separate staging environment, or does `docker-compose up` on a developer laptop serve as staging?
|
|
7. What is the on-call story for a school that loses connectivity during exam day?
|
|
8. Are there any school-data privacy requirements I should encode into the architecture (e.g. POPIA, GDPR, local equivalents)?
|
|
|
|
---
|
|
|
|
*Document version: 1.0 — written 2026-06-03 by an initial repository audit. Update in the same PR as any change to the architecture, the standards, or the agent roster.*
|