# Campus Catalog Backend ## Purpose This slice is the public, read-only surface for campus records: it returns the active campuses with their branding tokens so the frontend can render them without shipping campus rows as runtime constants. The database is the source of truth for campuses. Authenticated campus create/update/delete lives in a separate slice (see "campuses CRUD" below); this slice does not write. ## Slice Files (by layer) - Route: `src/routes/public_campuses.ts` (thin wiring; `GET /`). - Controller: `src/api/controllers/public_campuses.controller.ts` (custom — not the CRUD factory). - Service (BLL): `src/services/campus_catalog.ts`. - Repository (DAL): the catalog service queries `db.campuses.findAll` directly (it does not go through `src/db/api/campuses.ts`; that repository serves the authenticated campuses CRUD slice). - Model: `src/db/models/campuses.ts`. - Shared used: none beyond `db/models`. ## API The slice is mounted at `/api/public/campuses` in `src/index.ts`. Unlike the authenticated routes, this mount is registered before the `jwt` guard and has no authentication middleware — it is a public endpoint. - `GET /api/public/campuses` -> `200` `{ rows, count }`. No request parameters are read (the controller ignores the request). Each row is the campus catalog DTO below; rows are ordered by `name` ascending. `count` is `rows.length`. ## Access Rules Public. No JWT, no role check, no per-user gating. Only campuses with `active = true` are returned. ## Tenant Scope None. The query filters solely on `active = true` and is not scoped to any organization or campus — it returns active campuses across all organizations. ## Data Contract Campus catalog DTO (`toCampusCatalogDto`, also reflected in the service's selected `attributes`): `id`, `name`, `code`, `mascot`, `color`, `bgGradient`, `borderColor`, `textColor`, `bgLight`, `description`, `isOnline`. Other campus columns (address, phone, email, organizationId, audit fields) are intentionally not exposed by this endpoint. Relevant `campuses` model fields: `id` (UUID PK), `name` (TEXT, not null), `code` (TEXT, not null), `address` / `phone` / `email` (TEXT, nullable), `mascot`, `color`, `bgGradient`, `borderColor`, `textColor`, `bgLight`, `description` (all TEXT, nullable), `isOnline` (BOOLEAN, not null, default false), `active` (BOOLEAN, not null, default false), `importHash` (unique, nullable), `organizationId` (UUID, nullable), audit fields `createdById` / `updatedById`, and `createdAt` / `updatedAt` / `deletedAt`. The model is `paranoid` (soft delete) with `freezeTableName`. Associations include `belongsTo` organization, createdBy, updatedBy, and `hasMany` staff, classes, timetables, attendance_sessions, messages (all keyed on `campusId`). ## Behavior / Notes - The service selects only the catalog `attributes` so the SQL fetches just the columns the DTO needs. - Because the filter is `{ active: true }` with no tenant scope, inactive campuses are never returned and the result is not paginated. ## Tests None yet (no `campus_catalog` / `public_campuses` unit/e2e test in `src/`). ## Related - Frontend: `frontend/docs/campus-catalog.md`. - Related slices: campuses CRUD (authenticated `/api/campuses`, route `src/routes/campuses.ts`, repository `src/db/api/campuses.ts`) for create/update/delete of campus records.