Files
hackerspace.sh/content/docs/reference/classes-and-equipment.md
T
Moheeb Zara 16229ae523 feat(docs): add a Diátaxis documentation section to the public site
A new public /docs area covering the whole platform, organized by Diátaxis:
tutorials (learning), how-to guides (tasks), reference (facts), and explanation
(the why). 29 pages, each grounded in the actual routes, actions, schema, and
UI — verified against the code and corrected for accuracy (e.g. admin-only vs
admin+board gating, where the permissions matrix actually lives, how Stripe
reconciliation matches).

Implementation:
- lib/docs/nav.ts is the single source of truth (categories + pages), driving
  the sidebar, static params, and prev/next.
- Content authored as content/docs/<category>/<slug>.md, read at build time
  (the routes are statically generated), rendered by <DocsMarkdown> — reuses the
  existing react-markdown/GFM stack, no new dependencies.
- (docs) route group with its own theme (docs.css) matching the public site's
  dark / monospace / lime aesthetic; sidebar with active-state, breadcrumb,
  prev/next, and a Diátaxis home. Public — signed-in users can read it too.
- "Docs" link added to the landing nav.

typecheck 0 · lint 0 errors · build ok (all /docs pages prerendered)
2026-08-05 00:42:42 -07:00

107 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
The classes, certifications, and equipment modules share one spine: a certification type awarded by completing a class can gate who may reserve a piece of equipment. This page is the exhaustive reference for their data model, statuses, capacity rules, and the permissions that guard each action.
## Classes
A class is a per-space offering; a session is a scheduled occurrence; a signup is one member's place in a session. Members browse and sign up at [/classes](/classes); managers create classes and sessions at [/classes/manage](/classes/manage).
### Class fields
| Field | Notes |
| --- | --- |
| `title` | 1–200 chars, required |
| `description` | optional |
| `payment_link` | optional `http(s)` URL only; a manual link, no live payment integration |
| `capacity` | optional default per-session capacity; `> 0`; null = unlimited |
| `grants_certification_id` | optional; completing a session of this class can award this certification |
| `required_form_id` | optional; a published [form](/docs/how-to/build-a-form) that must be on file before signup |
| `is_active` | archive flag; inactive classes are hidden from members |
### Session fields
`class_sessions` carry `starts_at`, optional `ends_at` (must be `>= starts_at`), `location`, an optional `capacity` override, `notes`, and a status.
| Session status | Meaning |
| --- | --- |
| `scheduled` | open; the default |
| `cancelled` | closed to signups; signed-up members are emailed |
| `completed` | run and closed; set only via completion, which fires cert awards |
### Signup and waitlist rules
- **Effective capacity** = the session `capacity` if set, else the class `capacity`, else unlimited.
- A new signup is `registered` when the current registered count is below effective capacity, otherwise `waitlisted`.
- At most one non-cancelled signup per member per session; cancelling leaves the row as history and a re-signup is allowed.
- When a `registered` member cancels and a seat frees, the earliest-signed-up `waitlisted` member is promoted to `registered` and emailed.
- Signup and cancel run inside per-session transactional functions (`class_signup_tx` / `class_cancel_tx`) so concurrent signups cannot over-enroll and concurrent cancels cannot double-promote.
| Signup status | Set by |
| --- | --- |
| `registered` | signup below capacity, or waitlist promotion |
| `waitlisted` | signup at or above capacity |
| `cancelled` | member or manager cancel |
Signing up needs no permission, only space membership. If the class has a `required_form_id`, the member must have a completed submission on file first; a manager acting with override bypasses this and can sign another member up.
### Attendance and completion
Instructors mark `attended` per signup and complete a session. Completing sets the session to `completed`; if the class has `grants_certification_id`, the certification is awarded to every attended, non-cancelled member. That award goes through the normal certifications path, so it only succeeds if the acting instructor also holds `certifications.grant`; otherwise completion still succeeds and the response reports that certificates were not issued.
### Class permissions
| Permission | Grants |
| --- | --- |
| `classes.manage` | create/edit/archive classes; schedule/cancel/delete sessions |
| `classes.instruct` | view attendees, mark attendance, complete a session |
Both seed to the `board` role by default.
## Certifications
A certification is a per-space type (name unique case-insensitive, `description`, optional `validity_months`, `is_active`). A grant (`member_certifications`) awards one type to one member. Managed alongside members at [/certifications](/certifications) and [/members](/members).
- `expires_at` is computed and stored **at grant time** from the type's `validity_months` (null = never expires). Later edits to the type never change existing grants.
- At most one active (non-revoked) grant per member per type; revoked grants stay as history and a re-grant is allowed.
- Revoking is a soft revoke (`revoked_at`, `revoked_by`, `revoked_reason`); grants are never hard-deleted by clients.
- Renewing a non-revoked grant resets `granted_at` and recomputes expiry. A revoked grant is terminal — issue a fresh grant.
| Cert status | Rule |
| --- | --- |
| `active` | not revoked, not expired |
| `expiring_soon` | expires within 30 days |
| `expired` | past `expires_at` |
| `revoked` | `revoked_at` set (always wins) |
| Permission | Grants |
| --- | --- |
| `certifications.manage` | create/edit/archive certification types |
| `certifications.grant` | award/revoke/renew grants; this is the "instructor" capability |
## Equipment and reservations
Equipment is a per-space tool record; a reservation is one member's time window on one tool. Members browse and reserve at [/equipment](/equipment); managers maintain the registry at [/equipment/manage](/equipment/manage). See [Reserve equipment](/docs/how-to/equipment-reservations) for the task walkthrough.
Equipment fields: `name` (1–200), `description`, `location`, `asset_tag`, `is_active`, an optional `required_certification_id`, and an operational status.
| Equipment status | Reservable? |
| --- | --- |
| `available` | yes |
| `maintenance` | no |
| `retired` | no |
### Reservation rules
- Reservations use half-open `[starts_at, ends_at)` windows; `ends_at` must be after `starts_at` and cannot start in the past.
- Only `reserved` rows block; `cancelled` and `completed` never do. Two `reserved` windows on the same equipment may not overlap. Touching end-to-start does not overlap.
- No-overlap is enforced in the database by a GiST exclusion constraint, so concurrent requests cannot double-book.
- If the equipment has `required_certification_id`, the member must hold an active grant of it. A manager with `equipment.manage` override bypasses the cert gate and may book on another member's behalf, but override never bypasses an operational status block.
| Reservation status | Meaning |
| --- | --- |
| `reserved` | active; blocks overlaps |
| `cancelled` | released; member or manager |
| `completed` | past/closed |
Reserving needs only membership. `equipment.manage` covers registry CRUD, status changes, and adjusting or cancelling any reservation. Equipment that has reservations must be archived rather than deleted; likewise a class with sessions and a session with signups.
Cert-gating ties the modules together: grant a certification on class completion, require that certification to reserve a machine. Roles and the seeding of these permissions are covered in [Roles and permissions](/docs/reference/roles-and-permissions).