71 lines
3.3 KiB
Markdown
71 lines
3.3 KiB
Markdown
# 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`
|
|
students, staff, classes, timetables, attendance_sessions, invoices, messages, documents (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.
|