Open Source Languages โ Software Development Blueprint
A complete development guide from kickoff to deployment Team size: 6 ยท Timeline: 6 weeks ยท Course: COMS3011A
Table of Contentsโ
- Project Architecture
- Software Development Lifecycle
- Development Workflow
- Database-First Approach
- Backend Development Pipeline
- API Design
- Frontend Development Pipeline
- Full Request Lifecycle
- Authentication Flow
- Testing Strategy
- Git Workflow
- CI/CD Pipeline
- Project Folder Structure
- Coding Standards
- Team Workflow
- Security Considerations
- Performance Optimization
- Deployment
- Maintenance
- Project Timeline
1. Project Architectureโ
Purposeโ
Establish, before anyone writes a feature, exactly which process talks to which โ so six people can build in parallel without stepping on each other.
The shape of the systemโ
This project is a microservices-oriented backend behind a hand-written API, plus a fully separate frontend and a static docs site โ not one monolithic app doing everything. That split isn't a style choice; it's a project requirement (non-monolithic frontend/backend, hand-written API), and the microservices split within the backend is what lets multiple people own distinct domains (content, moderation, assessments, conversation-spaces) without one giant Express app becoming a bottleneck.
Why this split mattersโ
- The frontend never talks to the database directly. It only ever calls the Express API.
- The backend never renders HTML. It only ever returns JSON.
- Within the backend, each domain (content, moderation, assessments, conversation-spaces) is built as its own service module with a clear boundary โ this is the microservices principle applied at whatever granularity a 6-week project can realistically support. Modules can be split into fully separate deployables later without a rewrite, because they don't share internal state.
- This means the frontend, backend gateway, and each service module can be developed and tested independently โ which is exactly what lets 6 people work in parallel without a merge-conflict nightmare in one file tree.
Component interaction diagramโ
Exit criteria before moving to Phase 2โ
- Everyone agrees the frontend, backend gateway, and each service module are independent units
- Everyone can name which module they own
- The diagrams above are understood by the whole team, not just the lead
2. Software Development Lifecycleโ
Given a 6-week timeline, phases overlap rather than running strictly sequentially โ but each phase has a clear owner and a clear exit gate.
| Phase | Purpose | Primary owner(s) | Depends on | Exit checklist |
|---|---|---|---|---|
| Requirement analysis | Turn the brief into a feature list | Whole team | โ | Feature list agreed, tiers (Basic/Intermediate/Advanced) mapped to weeks |
| Planning | Assign ownership, set conventions | Lead | Requirements | Ownership table filled, API convention doc written |
| System design | Architecture + module boundaries | Lead | Planning | Diagrams in Section 1 approved |
| Database design | Schema, ERD, migrations | Lead + backend team | System design | Schema merged, migrations run cleanly |
| API design | Endpoint contracts | Backend team | Database design | Endpoint list with request/response shapes documented |
| Backend development | Implement service modules | Backend team (3) | API design | All Basic-tier endpoints pass integration tests |
| Frontend development | Implement UI against real API | Frontend team (2-3) | Backend endpoints exist (even stubbed) | All Basic-tier screens functional |
| Testing | Unit/integration/E2E coverage | Whole team | Features exist | CI green on main |
| Deployment | Ship to Cloudflare Pages + Render | Lead + CI owner | Testing | App reachable at public URL |
| Monitoring | Confirm it stays up | CI owner | Deployment | Health check + basic logging in place |
| Maintenance | Bug fixes, small iteration | Whole team | Deployment | Ongoing until submission |
Treating "requirement analysis" and "planning" as a full week of meetings. Timebox this to 2-3 days โ the brief is already detailed; the job is translating it into your ownership table and schema, not re-deriving it from scratch.
3. Development Workflowโ
Every developer, on every task, follows the same loop:
Best practicesโ
- No one pushes directly to
developormainโ everything goes through a PR, even for a one-line fix. - A PR that touches
schema.prismagets reviewed by the lead specifically, not just any teammate (see Section 11). - Keep PRs small โ one feature or one bug, not a week of accumulated work. Small PRs get reviewed faster and break less.
- Husky runs ESLint + Prettier on every commit locally, so style and obvious lint issues never even reach a PR.
- Merging your own PR without review "because it's just a small fix" โ this is how silent breakage creeps into
develop. - Writing tests after the PR is already up, as an afterthought to satisfy CI โ write them alongside the feature so they actually catch bugs.
4. Database-First Approachโ
From requirements to entitiesโ
Read the brief's feature list and pull out every noun that persists: course, lesson, user, suggestion, flag, moderator action, assessment, result, fork, conversation space, session. Each becomes a table. Verbs between them (authors, forks, targets, resolves) become foreign keys or join tables.
Entity Relationship Diagramโ
Normalization notesโ
flags.target_idis polymorphic (a flag can point at a course, a lesson, or a conversation space) โ pair it withtarget_typerather than a strict FK, and enforce validity in application code, not the DB constraint.courses.forked_from_idself-referencescoursesโ this single column is the entire fork mechanism. Lineage tracing (Advanced tier) means walking this chain recursively.
Migration strategyโ
- Database is hosted on Supabase (managed PostgreSQL); the app only ever reaches it through Prisma, never through Supabase's auto-generated data API.
- One migration per schema change, committed alongside the code that needs it โ never hand-edit the database directly, even in development.
- The lead is the only person who merges changes to the shared schema file; everyone else proposes additions via PR (see Section 11).
- Seed a small fixture dataset (a handful of users, courses, lessons) so every developer has consistent local data to test against.
- ERD reviewed and agreed by the whole team
- Migrations run cleanly from empty on every teammate's machine
- Seed script produces usable local test data
5. Backend Development Pipelineโ
Build bottom-up โ nothing above a layer should exist before the layer below it is real. Each service module (content, moderation, assessments, conversation-spaces) follows this same pipeline independently.
Why this orderโ
- Repositories before services: a service that queries the DB directly is untestable without a real database. A repository layer lets you mock data access in service tests.
- Services before controllers: business logic (e.g. "can this user accept this suggestion") should not live inside a controller โ controllers only translate HTTP in and out.
- Validation and auth as middleware, not inline checks: keeps every route consistent and means you write the check once, not per-endpoint. Validation is handled by Zod schemas shared across a module; auth is verified once via Supabase Auth's JWT.
Example folder structure (backend)โ
backend/
src/
config/ # env loading, constants
db/ # Prisma client, migrations
models/ # Prisma schema
services/ # domain service modules (content, moderation, assessments, convo)
content/
repositories/
services/
controllers/
routes/
moderation/
...
middleware/ # auth (Supabase), Zod validation, error handling
utils/
tests/
unit/
integration/
Dockerfile
- Putting SQL/Prisma calls directly in controllers "to save time" โ this is exactly what makes fork-merge and moderation logic (the two hardest features) unmanageable once they grow.
- Skipping the repository layer for "simple" entities and then needing it later once a feature turns out non-trivial (forking always turns out non-trivial).
- Letting service modules reach into each other's repositories directly instead of going through the gateway โ this quietly turns the microservices split back into a monolith.
6. API Designโ
Principlesโ
- REST, resource-oriented:
/courses,/courses/:id/lessons,/courses/:id/suggestions - Standard HTTP verbs: GET (read), POST (create), PATCH (partial update), DELETE (remove)
- Consistent status codes: 200/201 success, 400 validation error, 401 unauthenticated, 403 unauthorized, 404 not found, 409 conflict, 500 server error
- Every request body validated with Zod before it reaches a controller; a failed validation returns a consistent error shape
- Consistent error shape across every endpoint:
{ "error": { "code": "VALIDATION_ERROR", "message": "title is required", "fields": ["title"] } }
- Pagination via
?page=1&limit=20, filtering via query params (?language=xhosa&level=beginner), sorting via?sort=-created_at - Versioning: prefix routes with
/api/v1from day one โ free to add now, painful to retrofit - Rate limiting: apply per-user limits scaled by reputation (ties into the trust engine from the moderation design)
Request flowโ
- Every Basic-tier endpoint documented (method, path, request body, response shape, error cases) before implementation starts
- Error shape and status-code conventions agreed by the whole team
7. Frontend Development Pipelineโ
Build in this order โ each step needs the one before it to make sense:
- Initialize React + Vite + TypeScript โ scaffolding first
- Configure project โ env vars, API base URL, ESLint/Prettier, Husky hooks
- Folder structure โ routes, components, hooks (see Section 13)
- Layout โ shared shell (nav, footer) before any page content
- Routing โ page structure mapped to features (reader, workspace, mod queue), via a client-side router
- Authentication โ Supabase Auth session state available globally before building anything gated
- API layer โ a thin typed client wrapping
fetchto the Express API, used by every page โ never callfetchad hoc in components - Reusable components โ buttons, form fields, cards, each with its own CSS Module โ before building pages that need them repeatedly
- State management โ React Context or a light library (e.g. Zustand) for auth/session state; server data via React Query/SWR rather than manual
useEffectfetching - Pages โ build screen by screen, against the real backend
- Forms + validation โ reuse the same Zod schemas as the backend where practical
- Loading and error states โ every data-fetching screen needs both, not just the happy path
- Caching โ via React Query's built-in cache, invalidated on mutation
- Optimization โ code splitting, image optimization, only once functionality is stable
- Testing โ Vitest + React Testing Library component tests as you go, E2E once flows are stable
Why this order mattersโ
Building pages before you have a real API client means you either mock everything (and rebuild it all when the mock diverges from reality) or hardcode fetch calls per component (impossible to maintain auth/error handling consistently). The API layer is infrastructure, not a feature โ build it once, early.
Data flow diagramโ
8. Full Request Lifecycleโ
Example: a learner submits a correction to a lesson.
9. Authentication Flowโ
Per the requirements: you use an established auth library โ Supabase Auth โ you do not write your own password hashing, token issuance, or session logic.
- Sign up
- Sign in
- Password reset
- Account deletion
Account deletion is the one teams forget โ build and test it in Week 1 alongside the others, not at the end.
Authorization on top of authenticationโ
Authentication answers "who is this." Authorization (can this user moderate, can this user edit this course) is your own logic, sitting in the service layer, driven by reputation_score and ownership checks โ this part you do write yourselves, and it's a core project feature, not boilerplate.
10. Testing Strategyโ
| Test type | What it covers | Tooling | Written by | When |
|---|---|---|---|---|
| Unit | Individual functions (services, utils) | Vitest | Feature owner | Alongside the code |
| Integration | API endpoint behavior against a real test DB | Vitest + Supertest | Feature owner | Once endpoint works |
| Component | Individual React components in isolation | Vitest + React Testing Library | Frontend owner | Alongside the component |
| End-to-end | Full user flows (sign up โ create course โ suggest edit) | Vitest (or Playwright) | Whole team, rotating | Once a full flow exists |
| Regression | Re-run of the above on every PR | CI (GitHub Actions) | Automatically | Every push |
Why Vitest + Supertestโ
Both frontend and backend share Vitest as the single test runner โ one config style, one set of commands, one thing for new contributors to learn. Supertest layers on top for the backend specifically, letting integration tests hit real Express routes in-process without booting an actual server per test, which keeps the suite fast enough to run on every commit via Husky and every PR via CI.
Coverage expectationsโ
Aim for meaningful coverage on services and controllers (the logic that can actually break), not 100% coverage on trivial getters. A moderation-decision function with no tests is a bigger risk than an untested formatDate helper.
CI integrationโ
Every PR runs lint โ unit โ integration tests automatically (see Section 12). A PR cannot merge if any of these fail.
11. Git Workflowโ
Branch namingโ
feature/short-descriptionโ new functionalitybugfix/short-descriptionโ non-urgent fixhotfix/short-descriptionโ urgent fix tomain
Commit conventionsโ
Use Conventional Commits: feat:, fix:, test:, docs:, chore: โ e.g. feat: add suggestion review endpoint. This makes the history readable, lets you generate a changelog for free, and maps cleanly onto Semantic Versioning (a feat: implies a MINOR bump, a fix: implies a PATCH, a breaking change implies MAJOR).
Versioning: SemVerโ
Tags follow MAJOR.MINOR.PATCH:
- MAJOR โ breaking API changes (rare during the project, reserved for real contract breaks)
- MINOR โ new backwards-compatible features (e.g. a new endpoint or tier of functionality)
- PATCH โ bug fixes, no behavior change to the contract
Tag milestones as they're reached, e.g. v0.1.0 at end of Basic tier, v0.2.0 at end of Intermediate tier โ this gives an honest, inspectable history of what worked at each stage.
Merge strategyโ
- Feature branches merge into
developvia PR, squash-merged to keep history clean developmerges intomainat each milestone (end of Basic tier, end of Intermediate tier, final submission), tagged with the corresponding SemVer version- The lead is the required reviewer on any PR touching
schema.prismaor shared middleware/config
- Tests written and passing (Vitest / Supertest)
- Husky pre-commit hooks passed (lint + format)
- No direct pushes to
developormain - Description explains what changed and why
12. CI/CD Pipelineโ
Example GitHub Actions workflow (backend)โ
name: backend-ci
on:
pull_request:
paths: ["backend/**"]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports: ["5432:5432"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
working-directory: backend
- run: npm run lint
working-directory: backend
- run: npm run test
working-directory: backend
- name: Build Docker image
run: docker build -t backend:ci ./backend
Notesโ
- Run frontend and backend CI as separate jobs, triggered only by changes in their respective folders โ keeps CI fast and relevant.
- Backend CI builds the Docker image as part of the pipeline, so a broken image is caught before it reaches Render.
- Deployment triggers only on merge to
main, never on every PR push. - Cloudflare Pages gives free preview deployments per PR out of the box for the frontend โ no extra CI config needed for that part.
- Add a rollback step (redeploy the previous successful build) so a bad deploy doesn't take the app down for the rest of the team during a demo prep week.
13. Project Folder Structureโ
open-source-languages/
frontend/
src/
routes/ # page-level components
components/
hooks/
lib/ # API client, utils
styles/ # global CSS + shared CSS Modules
tests/
vite.config.ts
vitest.config.ts
backend/
src/
config/
db/ # Prisma client, migrations
models/ # Prisma schema
services/ # microservice modules (content, moderation, assessments, convo)
middleware/ # Supabase Auth, Zod validation, error handling
utils/
tests/
Dockerfile
docs/ # Docusaurus site source
.github/
workflows/ # CI/CD definitions
scripts/ # one-off dev/seed scripts
.husky/ # git hooks
Each folder maps to a section of this document โ if you're unsure where a file goes, it should mirror the layer it belongs to in Section 5 or 7.
14. Coding Standardsโ
| Area | Convention |
|---|---|
| Files | kebab-case.ts, React components PascalCase.tsx, CSS Modules ComponentName.module.css |
| Variables/functions | camelCase |
| Types/interfaces | PascalCase, prefer type for unions, interface for object shapes |
| Database tables/columns | snake_case, plural table names (courses, mod_actions) |
| API routes | plural nouns, lowercase, hyphenated, versioned (/api/v1/courses/:id/suggestions) |
| React components | one component per file, named exports preferred, styled via its own CSS Module |
| Validation | Zod schemas colocated with the module they validate, shared between frontend and backend where practical |
| TypeScript | strict: true in tsconfig.json from day one โ retrofitting strict mode later is far more painful |
| Formatting | Enforced automatically by Prettier + ESLint, checked by Husky on commit and CI on push |
| Documentation | every service function gets a one-line JSDoc comment explaining intent, not restating the code |
15. Team Workflowโ
- Sprint length: weekly, aligned to the tier boundaries in Section 20
- Daily: a 10-minute async standup (Slack/Discord message: yesterday, today, blockers) โ six people, six weeks, don't spend real meeting time on this
- Feature ownership: one primary owner per service module (Section 1's ownership table), but anyone can review any PR
- Definition of Done: code merged to
develop, tests passing in CI, Husky hooks clean, docs updated if the change affects setup or API contracts - Conflict resolution: schema and shared-config conflicts go to the lead; feature-level disagreements get a 15-minute sync call rather than a long thread
16. Security Considerationsโ
- Authentication: delegated entirely to Supabase Auth (Section 9) โ never store or hash passwords yourselves
- Authorization: enforced server-side in the service layer on every mutating endpoint, never trusted from the frontend
- Input validation: every request body validated via Zod before it reaches a controller
- SQL injection: mitigated by using Prisma's parameterized queries exclusively โ never string-concatenate raw SQL
- XSS: sanitize any user-generated content rendered as HTML (course/lesson content); React escapes by default, but be careful with any
dangerouslySetInnerHTML - CSRF: use
SameSitecookies or bearer tokens rather than cookie-based sessions without CSRF tokens - Secrets management: all keys/secrets in environment variables, never committed โ use
.env.examplewith placeholder values in the repo, and configure real values in Render's/Cloudflare's secret manager - Rate limiting: apply at the API gateway layer, scaled by user reputation, to blunt abuse (ties into the trust-engine design)
- Container hygiene: keep the backend's Docker base image minimal and patched, since it's what actually runs in production on Render
- HTTPS: enforced by Cloudflare Pages and Render by default โ confirm it, don't assume it
17. Performance Optimizationโ
| Layer | Techniques |
|---|---|
| Database | Indexes on foreign keys and frequently filtered columns (courses.language, courses.status) |
| Backend | Pagination on all list endpoints, avoid N+1 queries (use Prisma's include deliberately) |
| Frontend | Vite's automatic code splitting per route, optimized image assets |
| Caching | React Query cache on the frontend; Cloudflare's edge cache for static assets; consider a Redis cache only if a specific endpoint proves slow โ don't add it speculatively |
| Real-time | Limit conversation-space payload size, throttle presence updates rather than broadcasting on every keystroke |
Optimize once something is measurably slow โ don't spend Week 2 hours on caching a feature that doesn't exist yet.
18. Deploymentโ
- Frontend (Cloudflare Pages)
- Backend (Render)
- Database (Supabase)
Connect the GitHub repo, deploy the Vite build output on merge to main, and get automatic preview deployments on every PR for free. Set the API base URL as an environment variable so staging and production point at different backends.
Connect the repo, deploy the Docker image, and set environment variables (DB connection string, Supabase keys, external API keys) in Render's secret manager โ never in code. Expose the /health endpoint so Render can monitor it.
Use Supabase's managed Postgres instance, accessed only via Prisma. Confirm automatic backups are enabled โ don't assume they are by default.
- Health checks: a
/healthendpoint returning 200 + basic status, checked by Render and by CI post-deploy - Logging: structured logs (e.g. via
pino) shipped to Render's log viewer โ sufficient for a project this size, no need for a dedicated logging service - Rollback: redeploy the last known-good build via Render's or Cloudflare's dashboard if a deploy breaks something close to a demo
19. Maintenanceโ
- Bug fixes: triaged the same way user-submitted flags are โ a lightweight issue board, not a formal process
- Dependency updates: run
npm auditweekly, update non-breaking patches as you go rather than in one risky batch at the end - Database migrations: every schema change ships with a migration file, tested against the seed dataset before merging
- Versioning: tag releases at each milestone using SemVer (
v0.1.0โ Basic tier,v0.2.0โ Intermediate tier) so you can always point to "what worked" if a later change breaks something - Future enhancements: keep a running "Advanced tier โ deferred" list (fork conflict resolution depth, real sockpuppet detection, elected moderators) so your final documentation can honestly state what's implemented vs. designed-only
20. Project Timelineโ
| Week | Focus | Key deliverables |
|---|---|---|
| 1 | Foundation | Frontend and backend wired together over HTTP, auth (signup/signin/reset/delete) working end-to-end via Supabase Auth, CI running lint+test, Docusaurus site live (even empty), schema + migrations merged, API convention doc agreed, Dockerfile building cleanly |
| 2 | Basic tier (backend) | Course CRUD, lessons, suggestions, flags endpoints across their service modules; conversation-space WebSocket spike started |
| 3 | Basic tier (frontend) + integration | Reader, workspace, profile UI against real backend; checkpoint: Basic tier demoable end-to-end, tagged v0.1.0 |
| 4 | Intermediate tier, part 1 | Assessments, forking, moderation workflow (queue, multi-mod decisions, appeals) |
| 5 | Intermediate tier, part 2 + Advanced tier selection | Reputation scoring, feeds/notifications, turn-managed conversation rooms; pick 2-3 Advanced features to actually build, document the rest; tag v0.2.0 |
| 6 | Advanced tier + hardening | Chosen Advanced features complete; accessibility/responsiveness pass; docs site finished (architecture, setup, API reference); integration freeze in final 3-4 days; demo script rehearsed; final tag v1.0.0 |
Milestonesโ
- End of Week 1: foundation live, nothing user-facing yet, but every piece of infrastructure is real
- End of Week 3: Basic tier fully working, deployed, demoable (
v0.1.0) - End of Week 5: Intermediate tier fully working (
v0.2.0) - End of Week 6: submission โ Advanced tier partially implemented and honestly documented, full test suite green in CI, docs site complete (
v1.0.0)
This document is a living guide โ update it as decisions change, rather than letting the team's actual practice drift away from what's written here.