-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
sarmakska edited this page Jun 1, 2026
·
3 revisions
How StaffPortal is wired together. This reflects the current code: a single Next.js 16 App Router application on React 19, backed by Supabase, with no separate backend service.
graph TD
Browser[Browser / Mobile web] -->|HTTPS| Vercel[Vercel]
Browser -->|public kiosk| Kiosk[/kiosk, PIN based, no login/]
Vercel --> NextApp[Next.js 16 App Router, React 19]
NextApp -->|server actions| Supabase[(Supabase Postgres + Auth + RLS)]
NextApp -->|OAuth / SAML| IdP[Identity provider]
NextApp -->|email send| Resend[Resend API]
NextApp -->|optional AI| Groq[Groq llama-3.3-70b]
CronJobs[Vercel Cron / GitHub Actions] -->|Bearer CRON_SECRET| NextApp
-
app/App Router routes-
app/(app)/authenticated routes (attendance, leave, timesheets, expenses, calendar, directory, wellness, IT, and more) -
app/(app)/admin/admin and accounts routes (users, leave allowances, leave accruals, single sign-on, audit log, analytics, notifications, system status) -
app/(auth)/login, signup, password reset, email verification -
app/kiosk/public kiosk (no login, per-user PIN) -
app/api/chat/the assistant AI assistant (Groq, OpenAI-compatible) -
app/api/cron/scheduled tasks (reminders, cleanups, leave accrual, year-end rollover) -
app/api/gdpr/export/GDPR data portability endpoint -
app/auth/callback/OAuth, SAML, and email-link callback handler
-
-
lib/shared logic-
lib/supabase/server, browser, and admin (service-role) clients -
lib/actions/server actions, the only place that mutates the database -
lib/audit.tsimmutable audit-log writer -
lib/sso.tsSSO provider-resolution helpers (pure, unit tested) -
lib/leave-accrual.tsaccrual calculation (pure, unit tested) -
lib/gdpr.tsexport bundle assembly (pure, unit tested) -
lib/email.tsResend templates and PDF generators (PDFKit)
-
-
components/UI primitives and shadcn/ui customisations -
supabase/migrations/schema as code (ordered SQL files, currently through025) -
types/database.tsgenerated and hand-extended database types -
tests/Node test-runner suites with fixtures
- Supabase Auth with email and password plus single sign-on
- Server-side session via
@supabase/ssrcookies, refreshed inmiddleware.ts - Five roles (
employee,reception,director,accounts,admin) enforced by Postgres Row Level Security on every table - SSO is layered on Supabase Auth: OAuth providers use
signInWithOAuth, SAML 2.0 usessignInWithSSO, and both return through/auth/callback
graph LR
User[User] --> Login[Login screen]
Login -->|domain has SSO| IdP[Identity provider]
Login -->|no SSO| Password[Email + password]
IdP --> Callback[/auth/callback/]
Password --> Auth[Supabase Auth]
Callback --> Auth
Auth -->|JWT in cookie| Middleware[Next middleware]
Middleware -->|gates routes| Pages[/(app), /admin, /kiosk/]
Pages -->|server action| RLS[(Postgres + RLS)]
- An employee uploads a receipt photo on the expenses page.
- A server action stores the image in Supabase Storage and inserts an
expensesrow. - Optional vision OCR extracts merchant, total, and line items into structured columns.
- Resend emails the approver.
- The approver approves or rejects in the admin UI.
- A PDF claim form is generated on demand by PDFKit and served by a route handler.
- The claim appears in the accounts export for bank-statement reconciliation.
- On the first of each month the scheduler calls
/api/cron/leave-accrualwith theCRON_SECRETbearer token. - The route reads every balance with a positive
accrual_ratefor the current year. -
computeAccrualinlib/leave-accrual.tsworks out the days to grant from the months elapsed sincelast_accrued_on, capped at the entitlement. - The balance total,
accrued_to_date, andlast_accrued_onare updated, and the grant is written to the audit log. Re-running the same day grants nothing.
| Cron | Frequency | Purpose |
|---|---|---|
| birthday-reminder | daily 08:00 UTC | Notify the team of upcoming birthdays |
| absent-reminder | daily 10:00 UTC | Remind staff who have not clocked in |
| missing-attendance | daily 18:00 UTC | Flag missing attendance |
| forgotten-clockout | daily 20:00 UTC | Detect staff who forgot to clock out |
| stretch-reminder | weekdays 14:00 UTC | Wellness stretch nudge |
| diary-reminders | daily | Date-based diary note reminders |
| it-ticket-cleanup | weekly | Archive resolved IT tickets |
| leave-accrual | monthly, 1st 00:10 UTC | Top up accruing leave balances |
| year-end-rollover | yearly, 1 Jan 00:05 UTC | Carry forward annual leave |
Vercel Cron entries live in vercel.json; the bundled GitHub Actions workflows in .github/workflows/ call the same endpoints with the bearer token.
- Quick-Start: install
- Single-Sign-On: SSO setup
- Leave-Accruals: accrual mechanics
- Roadmap: what is next