# SRS Specification Deviations — NFR1 & NFR5

**Date:** 2026-07-28
**Status:** Draft — pending client sign-off
**Owner:** Lesticom Development Team (fchin — review/merge owner)
**Affects:** NFR1 (Scalability), NFR5 (Deployability)
**Source:** `Next Gen Learning SRS.pdf` §3.2 + `Next Gen Learning SRS and strategic summary.pdf` §4.2, §4.1

---

## 1. NFR1 — Scalability (Kubernetes, 100→2,000+ schools)

### What the SRS said

> NFR1 (Scalability): The cloud architecture must dynamically scale using Kubernetes to support from 100 to over 2,000+ schools seamlessly, accommodating national rollout spikes.

The summary doc (§4.1) elaborated on this: declarative partitioning by `tenant_id`, horizontal sharding at the 50,000-student / 500 GB threshold, Supabase RLS at the kernel level, an API gateway that routes by `school UUID`, and stateless microservices.

### What we shipped

- **Single-container Docker** (`Dockerfile` + `docker-compose.yml`) — Express API + Vite-built React client + SQLite in one image. Local deploy story only.
- **No Kubernetes manifests** — no `k8s/`, `helm/`, `argocd/`, or `deployment.yaml` files in the repo.
- **No sharding logic** — single SQLite file (`server/data/school.db`) with WAL mode. Works for one school; not designed for thousands.
- **Multi-tenant table is present but inert** — the `licenses` table + `licenses_middleware.js` exists, and the RLS migration (`2026072200000000_multitenant_licensing_rls.js`) ships, but the runtime deployment has not been tested with multiple tenants concurrently.
- **Supabase target is configured** but `SUPABASE_KEY` is unset in dev, so the sync engine no-ops (per the SRS's offline-first design).

### Why we deviated

The MVP scope was an 8-week delivery targeting a single pilot school. Building K8s manifests, a sharding gateway, and a multi-tenant production deployment was out of scope for the MVP and a follow-on Phase 2/3 item. The SRS explicitly placed K8s/scaling in §4.2 as the "scale-up phase" beyond the MVP, with Kubernetes described in the implementation roadmap (Gantt chart) as W9-10 work.

We kept the **schema-level hooks** in place (RLS migration, `licenses` table, `tenant_id` columns on key tables) so the Phase 2/3 build is a deployment change, not a schema migration.

### What we ask the client to accept

Either:

(a) **Formally accept the deviation** — the MVP is single-school; K8s + sharding is a Phase 2 deliverable. Lock the W9-10 Gantt slot and refresh the SRS milestone dates accordingly.

(b) **Move K8s into MVP** — increase MVP scope and timeline. We can scope the work (estimate: 3 dev-weeks for K8s + HPA + sharding gateway + multi-tenant smoke test).

### Risk if (a) is accepted and we ship before Phase 2

- Production deployment requires a Phase 2 K8s build before the 2,000-school scale.
- Local pilot (single school) is fully functional on the single-container Docker.
- The SRS Gantt chart places K8s at W9-10, which is after the MVP launch milestone.

---

## 2. NFR5 — Deployability (GitLab + ArgoCD GitOps)

### What the SRS said

> NFR5 (Deployability): All cloud updates must be deployed using a GitOps pipeline (GitLab + ArgoCD) ensuring zero-downtime continuous delivery.

The summary doc (§4.1) elaborated: GitLab as the central repo + CI, ArgoCD for CD, Kubernetes for orchestration.

### What we shipped

- **Gitea-hosted repo** (not GitLab). The team's actual remote is `https://git.techarvest.co.zw/fchinembiri/next-gen.git`.
- **Gitea Actions workflows** (`.gitea/workflows/ci.yml` + `build-push.yaml`) handle container build + push.
- **No ArgoCD** — no `argocd/`, no ArgoCD app definitions, no GitOps sync loops.
- **Deployment is manual** — `docker-compose up --build` for a single host. No zero-downtime rolling deploys.

### Why we deviated

The hosting reality on the ground is a Gitea instance, not a GitLab SaaS subscription. The Gitea Actions CI is the closest functional equivalent to GitLab CI for a single-org project. The ArgoCD layer was not built because there is no K8s cluster to deploy into (see NFR1 deviation above) — ArgoCD is a deployment orchestrator and we don't have a deployment target for it.

### What we ask the client to accept

Either:

(a) **Formally accept the deviation** — treat Gitea + single-container Docker as the deploy story for MVP. Document the Gitea Actions pipeline as the CI. Move ArgoCD into Phase 2 alongside the K8s work (NFR1).

(b) **Add GitLab mirror + ArgoCD** — we set up a GitLab mirror of the Gitea repo, run GitLab CI for tests, and have ArgoCD deploy to a test K8s cluster. Estimate: 1 dev-week for the pipeline plumbing + 1 dev-week for the K8s cluster bootstrap (depends on NFR1).

### Risk if (a) is accepted

- No zero-downtime deploys until K8s is in place. Acceptable for an 8-week MVP pilot.
- The CI surface (`.gitea/workflows/ci.yml`) already builds + pushes a container image, so the swap to GitLab CI later is config-only.
- The SRS implementation roadmap (Gantt chart) places GitOps at W9-10, which is after the MVP launch.

---

## 3. What the client should do

Please confirm one of the two options above for each NFR (a or b). Lesticom will then either:

- Update the SRS Addendum with the accepted deviations and the new Phase 2/3 milestone dates, OR
- Submit a Change Request (per SRS §9.1) to expand the MVP scope to include NFR1 + NFR5 fully.

Either way, the deviation is **documented and traceable**, not silently dropped.

---

## 4. Reference

- **Audit report:** `evidence/audit-2026-07-28.md` §3.3 P2-6
- **NFR1 in SRS:** `Next Gen Learning SRS.pdf` §3.2
- **NFR5 in SRS:** `Next Gen Learning SRS.pdf` §3.2
- **NFR1/NFR5 in summary doc:** `Next Gen Learning SRS and strategic summary.pdf` §4.1, §4.2
- **Gantt chart placement:** `Next Gen Learning SRS and strategic summary.pdf` §8 (K8s + GitOps at W9-10, after MVP launch)

---

*Drafted 2026-07-28 by fchin (Lesticom). Review required by Next Gen delivery lead before sign-off.*
