This directory holds module guides aligned with folders under src/: purpose, responsibilities, patterns, routes, testing, and how to extend safely.
Operational setup—environment variables, Docker Compose, data volumes, deployment flags—is in the repository root README.md. Use that for day-one setup; use these docs for how code is structured and where to edit.
Here is where the pieces of project-showcase-backend live, and how they relate at a glance.
| Area | Typical paths | Role |
|---|---|---|
| Application | src/ |
Express API: feature folders, middleware, schemas, singleton clients |
| Data model & migrations | prisma/ (schema.prisma, migrations/, seed.ts) |
Database contracts and repeatable schema changes |
| Tests | test/, vitest.config.ts |
Vitest suites (structure mirrors src/ domains; shared setup.ts and helpers/) |
| Module docs | This folder (docs/) |
Markdown guides keyed to src/ domains |
| CI/CD | .github/workflows/ |
Build, test, and deploy pipelines |
| Container build | Dockerfile, legacy-docker-compose.yaml |
Backend image / legacy Compose reference |
| Examples for student projects | templates/ |
Sample Docker Compose / Dockerfiles referenced from ops docs |
Root config/tooling shared by scripts and editors includes package.json, tsconfig*.json, ESLint/Prettier, and package-lock.json.
See core.md for how server.ts, app.ts, and singleton files at the src/ root fit together.
Boxes are logical groupings—not every file name is listed. Feature names match folders under src/ and mirrored areas under test/.
flowchart TB
subgraph repoRoot [project-showcase-backend repo]
direction TB
subgraph toolingDelivery [Tooling CI and deployment artifacts]
direction TB
pkgScripts["package.json · package-lock · tsconfig *.json Vitest ESLint Prettier configs"]
ghaCi[".github/workflows ci.yml deploy-staging.yml deploy-production.yml"]
dockerArtifacts["Dockerfile · legacy-docker-compose.yaml"]
studentTemplates["templates example Docker Compose and Dockerfile SQL"]
end
subgraph srcTree [src application code]
direction TB
bootClients["Bootstrap and shared clients<br/>server.ts · app.ts · prisma.ts docker.ts firebase.ts git.ts"]
subgraph featureDirs [Feature modules routers controllers services schemas]
feAuth["auth · users"]
feCatalog["courses · semesters"]
feOffering["courseOfferings enrollment teams spark"]
feProjects["projects oldProjects"]
feAdmin["admin"]
end
subgraph infraDirs [Cross cutting inside src]
mw["middleware"]
guards["authorization"]
helpers["utils · schemas · types · constants · config"]
end
end
subgraph prismaTree [prisma]
direction LR
pSchema["schema.prisma"]
pMigrations["migrations"]
pSeed["seed.ts"]
end
subgraph testTree [test]
direction TB
twSetup["Vitest wiring setup.ts helpers"]
twSuites["Package dirs aligned with src e.g. admin auth authorization<br/>courseOfferings courses enrollment projects teams spark …<br/>plus top level app docker git integration tests"]
end
subgraph docTree [docs]
docsIndex["README.md developer index"]
docsPages["Markdown guides aligned with src modules"]
end
end
featureDirs -.-> prismaTree
feProjects -.-> bootClients
feOffering -.-> bootClients
feAuth -.-> bootClients
infraDirs -.->|"imported by"| featureDirs
twSuites -.->|"mirrors"| featureDirs
How to read the dashed arrows
-
Cross-cutting
src/layers → features —middleware,authorization, andutils/schemas/types/constants/configare imported by routers and controllers; most are not their own HTTP subtrees (/authis the notable public subtree fromauth). -
Feature modules →
prisma/— domain code persists via Prisma using models inschema.prisma. -
Feature modules → bootstrap clients (
prisma.ts,docker.ts,firebase.ts,git.ts) —authuses Firebase,projectsuses Docker plus Git clones, and most DB access goes throughprisma(seecorefor specifics). -
test/→ mirrorssrc/— atest/package directory usually exercises the matchingsrc/module (HTTP tests composecreateApp()fromapp.ts, notserver.ts).
When npm run dev / npm start runs server.ts, one Node process wires HTTP handling, cron-style background checks, and external integration clients like this:
flowchart TB
subgraph nodeProcess [Node process]
subgraph startup [Startup sequence]
SRV["server.ts"]
ENV["dotenv · loadEnv parsed env schema"]
FBINIT["Firebase Admin init skipped when NODE_ENV is test"]
SRV --> ENV
SRV --> FBINIT
end
subgraph httpStack [Express HTTP stack from createApp]
APPNODE["app.ts createApp"]
MID["middleware logger helmet JSON body cookies"]
HEALTH["GET /health Prisma raw query ping"]
PUB["public subtree /auth routes"]
PROTECT["requireAuth · userRateLimiter · mounted domain routers"]
ERR["globalErrorHandler"]
SRV --> APPNODE
APPNODE --> MID
MID --> HEALTH
MID --> PUB
MID --> PROTECT
APPNODE --> ERR
end
subgraph handlersLayer [Controllers and services behind routers]
CTRL["Feature controllers"]
SVCS["Prisma accesses dockerode simple-git Spark HTTPS etc."]
CTRL --> SVCS
end
subgraph externalProcesses [Depends on outside this repo]
DB_SIDE["Database at DATABASE_URL"]
DOCKER_SIDE["Docker daemon often socket mounted from host"]
end
subgraph backgroundCron [Cron started from server lifecycle]
CRONJOBS["containerMonitor and project pruning tasks"]
SRV --> CRONJOBS
end
PROTECT --> CTRL
SVCS --> DB_SIDE
SVCS --> DOCKER_SIDE
HEALTH --> DB_SIDE
CRONJOBS --> DB_SIDE
CRONJOBS --> DOCKER_SIDE
end
Background jobs: containerMonitor (and related pruner helpers in the same area) reconcile database Project state with live containers—see projects and core docs for shutdown behavior.
- Middleware (global):
requestLogger→ Helmet → JSON body (1mb) → cookie parser - Public routes:
GET /health,router.use('/auth', authRouter) - Authenticated stack:
requireAuth(Bearer JWT) →userRateLimiter - Domain routers:
/adminadditionally usesrequireAdminat mount time - Errors:
globalErrorHandler
| Topic | Doc | src/ path |
|---|---|---|
| App bootstrap, DB, Docker, Firebase, Git | core.md | app.ts, server.ts, prisma.ts, docker.ts, firebase.ts, git.ts |
| HTTP middleware stack | middleware.md | middleware/ |
| Env validation | config.md | config/ |
| Shared Zod route params | schemas.md | schemas/ |
| Roles and project statuses | constants.md | constants/ |
Express Request augmentation |
types.md | types/ |
| Errors + shared helpers | utils.md | utils/ |
| Offering / team guards | authorization.md | authorization/ |
| Firebase login → JWT | auth.md | auth/ |
| Current user profile | users.md | users/ |
| Catalog courses (admin CRUD) | courses.md | courses/ |
| Semesters | semesters.md | semesters/ |
| Course offerings (enrollment boundary) | courseOfferings.md | courseOfferings/ |
| Enrollments | enrollment.md | enrollment/ |
| Teams | teams.md | teams/ |
| Cornell Spark keys | spark.md | spark/ |
| Project deploy/containers | projects.md | projects/ |
| Legacy builders | oldProjects.md | oldProjects/ |
| Platform admin API | admin.md | admin/ |
| Command | Purpose |
|---|---|
npm run dev |
Watch mode: nodemon -x tsx src/server.ts |
npm run build |
tsc compile to dist/ |
npm start |
Production: node dist/server.js |
npm test |
Vitest (test/setup.ts loads env defaults) |
npm run lint |
ESLint on src/ and test/ |
npm run seed |
tsx prisma/seed.ts |
flowchart LR
schema["*.schema.ts + paramCoercions"] --> router["*Router + validateRequest"]
router --> controller["*Controller + auth asserts"]
controller --> service["*Service optional"]
service --> data["prisma / docker / external"]
- Extend or add Zod schema (often import
paramCoercionsfor ID params). - Register route on the Router with
validateRequest(schema). - Implement handler in Controller (
req.user,req.validated). - Enforce authorization with guards in
authorization/orauthorizationHelpers, orrequireAdmin. - Move non-trivial logic to Service modules.
- Add HTTP tests under
test/(seetest/helpers/signTestJwt.ts,test/helpers/prismaMock.ts).
For enrollment-scoped URLs, start with courseOfferings.md, enrollment.md, teams.md, and authorization.md.