Skip to content

Latest commit

 

History

History
225 lines (179 loc) · 10.8 KB

File metadata and controls

225 lines (179 loc) · 10.8 KB

Developer documentation index

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.


Repository shape

Here is where the pieces of project-showcase-backend live, and how they relate at a glance.

What sits at the repo root (besides source)

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.

Directory map (what lives next to what)

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
Loading

How to read the dashed arrows

  • Cross-cutting src/ layers → featuresmiddleware, authorization, and utils / schemas / types / constants / config are imported by routers and controllers; most are not their own HTTP subtrees (/auth is the notable public subtree from auth).

  • Feature modules → prisma/ — domain code persists via Prisma using models in schema.prisma.

  • Feature modules → bootstrap clients (prisma.ts, docker.ts, firebase.ts, git.ts)auth uses Firebase, projects uses Docker plus Git clones, and most DB access goes through prisma (see core for specifics).

  • test/ → mirrors src/ — a test/ package directory usually exercises the matching src/ module (HTTP tests compose createApp() from app.ts, not server.ts).

Runtime layering (single process)

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
Loading

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.


Request lifecycle

  1. Middleware (global): requestLogger → Helmet → JSON body (1mb) → cookie parser
  2. Public routes: GET /health, router.use('/auth', authRouter)
  3. Authenticated stack: requireAuth (Bearer JWT) → userRateLimiter
  4. Domain routers: /admin additionally uses requireAdmin at mount time
  5. Errors: globalErrorHandler

Module documentation

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/

Common development commands

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

Adding an HTTP endpoint (typical pattern)

flowchart LR
  schema["*.schema.ts + paramCoercions"] --> router["*Router + validateRequest"]
  router --> controller["*Controller + auth asserts"]
  controller --> service["*Service optional"]
  service --> data["prisma / docker / external"]
Loading
  1. Extend or add Zod schema (often import paramCoercions for ID params).
  2. Register route on the Router with validateRequest(schema).
  3. Implement handler in Controller (req.user, req.validated).
  4. Enforce authorization with guards in authorization/ or authorizationHelpers, or requireAdmin.
  5. Move non-trivial logic to Service modules.
  6. Add HTTP tests under test/ (see test/helpers/signTestJwt.ts, test/helpers/prismaMock.ts).

For enrollment-scoped URLs, start with courseOfferings.md, enrollment.md, teams.md, and authorization.md.