Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,18 @@ in VSCode. A pre-commit hook formats and lints staged files automatically.

## Scripts

| Command | Does |
| ---------------------- | ------------------------------------------- |
| `npm run dev` | Start the dev server |
| `npm run build` | Production build |
| `npm run lint` | ESLint |
| `npm run typecheck` | `tsc --noEmit` |
| `npm run format` | Prettier write |
| `npm run format:check` | Prettier check (runs in CI) |
| `npm run seed` | Create settings and the first admin account |
| `npm run seed:staging` | Seed the staging database with demo data |
| `npm run jobs` | Run the scheduled jobs against a dev server |
| Command | Does |
| ------------------------- | ------------------------------------------- |
| `npm run dev` | Start the dev server |
| `npm run build` | Production build |
| `npm run lint` | ESLint |
| `npm run typecheck` | `tsc --noEmit` |
| `npm run format` | Prettier write |
| `npm run format:check` | Prettier check (runs in CI) |
| `npm run seed` | Create settings and the first admin account |
| `npm run seed:staging` | Seed the staging database with demo data |
| `npm run jobs` | Run the scheduled jobs against a dev server |
| `npm run screening:check` | Offline checks for the registry pre-check |

## API

Expand All @@ -108,7 +109,7 @@ authorization is enforced server-side on every request by `withAuth`.
| Sign-ups | `signups`, `signups/:id/{cancel,absence,approve,promote,attendance,calendar}` |
| Messaging | `threads`, `threads/:id`, `threads/:id/messages`, `threads/:id/report`, `threads/:id/review` |
| Certificates | `certificates/:id/pdf`, `certificates/:id/revoke` |
| Admin | `admin/{approvals,people,people/:id,people/:id/clearance,people/:id/signout,invitations,organizers,events,hours,audit,reports/:kind,settings}` |
| Admin | `admin/{approvals,people,people/:id,people/:id/{clearance,screening,signout},invitations,organizers,events,hours,audit,reports/:kind,settings}` |
| Jobs | `jobs/run` (bearer `CRON_SECRET`) |

## Structure
Expand Down
6 changes: 4 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ src/app/**/page.tsx UI. No fetch calls, no business rules.
| `src/db/actions/` | DAO classes with static methods |
| `src/db/models/` | Mongoose schemas; the interfaces they implement live in `types` |
| `src/http/` | Typed frontend API clients |
| `src/lib/` | Session signing, dates, tokens, email templates, PDF, CSV, ICS |
| `src/lib/` | Session, dates, tokens, emails, PDF, CSV, ICS, registry lookups |
| `src/middleware/` | Response header helpers |
| `src/services/` | Business logic classes with static methods |
| `src/styles/` | Global CSS and font configuration |
Expand Down Expand Up @@ -77,6 +77,7 @@ through a hook in `src/components/hooks/`, so no screen fetches from
| ------------------ | ------------------------------------------------------------------------------- |
| `users` | Accounts, profile, waiver acceptance, notification preferences, session version |
| `clearances` | Screening outcome per user; admins only. Organizers receive a derived boolean |
| `screeningchecks` | Latest registry pre-check per volunteer and any queued rerun; admins only |
| `events` | Organizer-owned events: draft → published → completed, cancelled from any state |
| `shifts` | The unit volunteers sign up for; `filledCount` is maintained atomically |
| `signups` | One per volunteer per shift, ever; pending reasons; embedded attendance/absence |
Expand Down Expand Up @@ -104,7 +105,8 @@ Two decisions carry most of the weight:

`JobService.runAll` (`POST /api/v1/jobs/run`, through `runExclusive`) sends shift reminders, low-fill
alerts, unapproved-roster nudges, clearance expiry warnings, note and message
digests, and the organizer digest, and closes stale threads. Every send is
digests, and the organizer digest, closes stale threads, and runs the registry
pre-check for volunteers waiting on clearance. Every send is
keyed in `notificationlogs`, so the runner is safe to fire hourly and a late
or repeated run is harmless. `JobService.runExclusive` holds an expiring lock
in the same collection, so a manual run never overlaps the scheduled one.
Expand Down
3 changes: 2 additions & 1 deletion netlify/functions/scheduled-jobs.mts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { Config } from "@netlify/functions";

/**
* Hourly trigger for reminders, digests, clearance expiry, and roster nudges.
* Hourly trigger for reminders, digests, clearance expiry, roster nudges, and
* the registry pre-check.
* The work itself lives in the app (POST /api/v1/jobs/run) so it shares the
* services and the database connection; this function only rings the bell.
*/
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"prepare": "husky",
"seed": "tsx --env-file=.env.local scripts/seed.ts",
"seed:staging": "tsx --env-file=.env.staging.local scripts/seed.ts demo",
"jobs": "tsx --env-file=.env.local scripts/jobs.ts"
"jobs": "tsx --env-file=.env.local scripts/jobs.ts",
"screening:check": "tsx scripts/screening-check.ts"
},
"dependencies": {
"@tanstack/react-query": "^5.102.2",
Expand Down
Loading
Loading