Files
perauset-e2e-mrfzot2p/docs/frontend-architecture.md
2026-07-11 08:34:30 +02:00

36 KiB

Perauset Frontend Architecture

Single Next.js application with Mantine v8, server-side rendering, and Pikku RPC for data fetching. Role-based UI adapts the experience from a focused guest view to a full operations dashboard for coordinators and admins.


Table of Contents

  1. Roles and Permissions Summary
  2. Navigation Structure
  3. Route Map
  4. Page Specifications
  5. Shared Components
  6. Data Fetching Strategy
  7. Mobile Considerations
  8. Authentication Flow

1. Roles and Permissions Summary

The backend defines 8 roles. The frontend groups them into three tiers for UI purposes:

Tier Roles What they see
Admin/Coordinator admin, coordinator Full operations dashboard: all domains, review queues, audit log, user management
Operational facilitator, boat_coordinator, kitchen_lead, staff Domain-specific management views plus personal tools. Each role sees expanded UI for their domain.
Community volunteer, community_member, guest Personal dashboard: own stay, own requests, claimable tasks, meal schedule, dietary profile

The frontend does NOT enforce permissions -- the backend does via tags. The frontend uses the session's roles array to determine which navigation items, pages, and action buttons to render. If a user lacks the permission for a page, the server call will fail with 403, and the UI shows a "not authorized" state.


2. Navigation Structure

Layout: Responsive AppShell

  • Desktop (>= 768px): Collapsible sidebar (240px open, 60px collapsed) + top bar with notifications and user menu
  • Mobile (< 768px): Bottom tab bar (5 primary items) + hamburger drawer for secondary navigation

Sidebar Sections (Desktop)

[Logo / App Name]

-- PERSONAL --
  Dashboard              (all authenticated users)
  My Stay                (all authenticated users)
  My Requests            (all authenticated users)
  Notifications          (all authenticated users)

-- OPERATIONS --          (staff+ roles only)
  Stays & Rooms          (stays.view_all OR rooms.view_all)
  Boat Schedule          (boats.view_all OR boats.manage)
  Task Board             (tasks.view_all)
  Retreats               (retreats.view OR retreats.manage)
  Kitchen                (kitchen.view OR kitchen.manage)
  Inventory              (inventory.manage OR inventory.request)

-- ADMIN --               (admin, coordinator only)
  Users                  (users.view)
  Audit Log              (audit_log.view)
  Settings               (admin only)

[User Avatar / Menu]
  Profile & Dietary
  Sign Out

Mobile Bottom Tab Bar

Tab Icon Route Visible to
Home house / All
Boats ship /boats All (request); operational roles see more
Tasks check-square /tasks All (claimable); staff+ see board
Meals utensils /kitchen All
More menu drawer All (opens sidebar content)

3. Route Map

All routes are under the Next.js App Router. Auth-gated routes use a middleware check; role-gated routes render a <RoleGate> wrapper that redirects or shows an empty state.

Public Routes

Route Purpose
/login Credentials login form (Auth.js)
/auth/error Auth error display

Authenticated Routes -- Personal

Route Page Title Min. Role API Calls
/ Dashboard any listStays(userId=me), listNotifications(limit=5), listTasks(status=open, limit=5), listBoatTrips(from=today, limit=3)
/stay My Stay any listStays(userId=me, status=checked_in), listStayRequests(userId=me)
/stay/request Request a Stay stays.request requestStay (mutation), listRetreats(status=published)
/requests My Requests any listStayRequests(userId=me), listBoatRequests(userId=me), listInventoryRequests(userId=me) (Note: some of these filters need to be added to the backend or the frontend filters client-side)
/notifications Notifications any listNotifications, markNotificationRead
/profile Profile & Dietary any getUser(userId=me), upsertDietaryProfile

Authenticated Routes -- Boats

Route Page Title Min. Permission API Calls
/boats Boat Schedule boats.request listBoatTrips(from=today)
/boats/trips/:tripId Trip Detail boats.request listBoatTrips, listBoatRequests(tripId)
/boats/trips/:tripId/request Request Seat boats.request requestBoatSeat (mutation)
/boats/manage Boat Management boats.manage listBoatTrips, listBoatRequests
/boats/manage/trips/new Create Trip boats.manage createBoatTrip (mutation)
/boats/manage/routes Route Management boats.manage createBoatRoute (mutation)
/boats/manage/fleet Fleet (Boats) boats.manage createBoat (mutation)

Authenticated Routes -- Tasks

Route Page Title Min. Permission API Calls
/tasks Task Board tasks.claim listTasks
/tasks/:taskId Task Detail tasks.claim listTasks, claimTask, startTask, completeTask, markTaskBlocked
/tasks/manage Task Management tasks.manage listTasks, createTaskInstance, assignTask, updateTask
/tasks/manage/templates Task Templates tasks.manage createTaskTemplate

Authenticated Routes -- Retreats

Route Page Title Min. Permission API Calls
/retreats Retreats List retreats.view listRetreats
/retreats/:retreatId Retreat Detail retreats.view listRetreats(id), schedule items, persons
/retreats/manage Retreat Management retreats.manage listRetreats, createRetreat, updateRetreat
/retreats/manage/:retreatId Edit Retreat retreats.manage updateRetreat, addRetreatPerson, addRetreatScheduleItem, publishRetreat, cancelRetreat

Authenticated Routes -- Kitchen

Route Page Title Min. Permission API Calls
/kitchen Meal Schedule kitchen.view listMealServices(from=today)
/kitchen/dietary My Dietary Profile kitchen.update_dietary upsertDietaryProfile
/kitchen/manage Kitchen Board kitchen.manage listMealServices, createMealService

Authenticated Routes -- Stays & Rooms (Operational)

Route Page Title Min. Permission API Calls
/stays All Stays stays.view_all listStays, listStayRequests
/stays/requests Stay Request Queue stays.review listStayRequests(status=submitted), approveStayRequest, rejectStayRequest
/stays/:stayId Stay Detail stays.view_all listStays(stayId), checkInStay, checkOutStay, cancelStay
/rooms Room Overview rooms.view_all listRooms, listRoomAllocations
/rooms/manage Room Management rooms.manage createRoom, updateRoom, allocateRoom, releaseRoom

Authenticated Routes -- Inventory

Route Page Title Min. Permission API Calls
/inventory Inventory List inventory.manage listInventory
/inventory/request Request Supplies inventory.request requestInventory (mutation)
/inventory/requests Request Queue inventory.manage list requests, reviewInventoryRequest, fulfillInventoryRequest

Authenticated Routes -- Admin

Route Page Title Min. Permission API Calls
/admin/users User Directory users.view listUsers
/admin/users/:userId User Detail users.view getUser, updateUserProfile, setUserRoles
/admin/audit Audit Log audit_log.view listAuditLog

4. Page Specifications

4.1 Dashboard (/)

The dashboard is role-adaptive. Every user sees it, but the content blocks differ.

Layout: Single-column stack on mobile, 2-column grid on desktop.

Blocks (conditional on role):

Block Component Visible to Data
Welcome banner WelcomeBanner All Session user name, current date
Active stay card ActiveStayCard All listStays(userId=me, status=checked_in) -- shows room, dates, check-out date
Upcoming boats UpcomingBoatsList All listBoatTrips(from=today, limit=3) -- next departures
My tasks MyTasksList tasks.claim listTasks(assignedTo=me, status!=completed)
Claimable tasks ClaimableTasksList tasks.claim listTasks(status=open, limit=5)
Unread notifications NotificationPreview All listNotifications(limit=5, unreadOnly=true)
Stay requests pending PendingStayRequestsBadge stays.review listStayRequests(status=submitted) -- count
Boat requests pending PendingBoatRequestsBadge boats.manage listBoatRequests(status=submitted) -- count
Inventory requests pending PendingInventoryBadge inventory.manage count of submitted inventory requests
Today's meals TodayMealsSummary kitchen.view listMealServices(date=today)
Occupancy summary OccupancySummary rooms.view_all listStays(status=checked_in) count vs. listRooms total capacity
Retreat in progress ActiveRetreatCard retreats.view listRetreats(status=active)

Key interactions:

  • Each card links to its detail page
  • Notification items can be marked read inline
  • Pending-request badges are clickable shortcuts to the review queue

4.2 My Stay (/stay)

Purpose: Guest/community view of their current or upcoming stay.

Components:

Component Description
StayStatusTimeline Visual timeline: Requested > Approved > Checked In > Checked Out. Highlights current step.
StayDetailCard Dates, room allocation (if any), stay type, associated retreat
RequestStayButton Mantine Button linking to /stay/request. Shown when no active stay exists.
StayRequestList Table of the user's past and pending stay requests with status badges

Data flow:

  • SSR: listStays(userId=session.userId) + listStayRequests(userId=session.userId) (Note: backend may need a "my requests" variant or the frontend filters by userId client-side after fetching)

4.3 Request a Stay (/stay/request)

Purpose: Form to submit a stay request.

Components:

Component Description
StayRequestForm Mantine form: requestType (select), date range picker (requestedStartAt, requestedEndAt), optional retreat selector (populated from listRetreats(status=published)), notes textarea
RequestConfirmation Success state after submission showing request ID and "submitted" status

Data flow:

  • SSR: listRetreats(status=published) for the retreat dropdown
  • Client mutation: requestStay

4.4 Stay Request Queue (/stays/requests)

Purpose: Coordinators review incoming stay requests.

Components:

Component Description
StayRequestTable Mantine DataTable with columns: requester name, type, dates, retreat, status, submitted date. Filterable by status.
StayRequestReviewDrawer Slide-out drawer on row click. Shows full details, user profile link. Approve/Reject buttons with optional review notes.
StayRequestStatusFilter Segmented control: All / Submitted / Approved / Rejected

Data flow:

  • SSR: listStayRequests(status=submitted)
  • Client mutations: approveStayRequest, rejectStayRequest
  • After approval: prompt to createStayFromRequest

4.5 All Stays (/stays)

Purpose: Operational view of all active and historical stays.

Components:

Component Description
StayTable Paginated table: user, dates, type, status, room, check-in/out times
StayFilterBar Status filter (segmented), date range picker, user search
StayActions Per-row action menu: Check In, Check Out, Cancel, View Detail
StayDetailDrawer Drawer with full stay info + room allocation + linked request

Data flow:

  • SSR: listStays(limit=50), listRoomAllocations
  • Client mutations: checkInStay, checkOutStay, cancelStay

4.6 Room Overview (/rooms)

Purpose: Visual display of all rooms and their current allocation status.

Components:

Component Description
RoomGrid Card grid showing each room: name, code, type, capacity, current occupant(s). Color-coded by status (vacant=green, occupied=amber, blocked=red, maintenance=gray).
RoomAllocationTimeline Optional Gantt-style timeline view of room allocations over a date range. Uses Mantine Timeline or a custom canvas component.
RoomFilterBar Filter by type (dorm, private, shared, etc.), status
RoomDetailDrawer Drawer showing room details, allocation history, block history

Data flow:

  • SSR: listRooms, listRoomAllocations(from=today)

4.7 Room Management (/rooms/manage)

Purpose: Create rooms, allocate guests to rooms, manage blocks.

Components:

Component Description
CreateRoomForm Modal form: name, code, type, capacity, notes
EditRoomForm Same fields, pre-populated
AllocateRoomForm Modal: select room, select stay, date range, reason
ReleaseRoomButton Action on an active allocation
RoomBlockForm Create a room block (maintenance, admin hold, retreat reserved)

Data flow:

  • Client mutations: createRoom, updateRoom, allocateRoom, releaseRoom

4.8 Boat Schedule (/boats)

Purpose: View upcoming boat trips and request seats.

Components:

Component Description
BoatScheduleList Card list (mobile) or table (desktop) of upcoming trips. Each shows: route (origin > destination), departure time, boat name, available seats indicator, status badge.
TripCard Expanded view on click: full details + "Request Seat" button if status is open
BoatScheduleCalendar Optional calendar view for desktop showing trips by day
DateNavigator Day/week selector to browse the schedule

Data flow:

  • SSR: listBoatTrips(from=today, status=open)

4.9 Trip Detail (/boats/trips/:tripId)

Components:

Component Description
TripHeader Route, departure/arrival times, boat, status
ManifestList List of confirmed passengers (visible to boats.view_all)
RequestSeatButton Opens inline form or navigates to /boats/trips/:tripId/request
RequestsList (boats.manage) Table of all seat requests for this trip with confirm/decline actions

Data flow:

  • SSR: trip detail from listBoatTrips, listBoatRequests(tripId)
  • Client mutations: requestBoatSeat, confirmBoatRequest, declineBoatRequest

4.10 Boat Management (/boats/manage)

Purpose: Full boat operations for boat coordinators.

Components:

Component Description
TripManagementTable All trips (not just open). Status filter. Actions: open, update, cancel, complete.
CreateTripForm Modal: select route, select boat, departure datetime, arrival datetime, notes
RequestReviewPanel Pending seat requests across all trips. Bulk confirm/decline.
RouteManagementTab CRUD for boat routes
FleetManagementTab CRUD for boats (name, capacity, cargo capacity)

Tabs within page: Trips | Requests | Routes | Fleet

Data flow:

  • SSR: listBoatTrips, listBoatRequests
  • Client mutations: createBoatTrip, openBoatTrip, updateBoatTrip, cancelBoatTrip, completeBoatTrip, confirmBoatRequest, declineBoatRequest, createBoatRoute, createBoat

4.11 Task Board (/tasks)

Purpose: Kanban-style board of tasks. Community users see claimable tasks. Staff+ sees all tasks.

Components:

Component Description
TaskKanban Columns: Open, Assigned, In Progress, Blocked, Completed. Each card shows title, category badge, location, scheduled time. Drag-and-drop on desktop (optional).
TaskListView Alternative list view (default on mobile). Sortable by category, status, date.
TaskCard Title, category pill, time, location. Click opens detail drawer.
TaskDetailDrawer Full task info. Actions based on status: Claim (if open), Start (if assigned to me), Complete, Mark Blocked.
TaskCategoryFilter Filter chips: housekeeping, kitchen, maintenance, operations, retreat, transport
ViewToggle Board view / List view toggle

Data flow:

  • SSR: listTasks
  • Client mutations: claimTask, startTask, completeTask, markTaskBlocked

4.12 Task Management (/tasks/manage)

Purpose: Coordinators create tasks, assign to people, manage templates.

Components:

Component Description
CreateTaskForm Modal: title, description, category, location, scheduled start/end, optional template, linked retreat/stay
AssignTaskDrawer Select a user, add notes. Triggers assignTask.
TaskTemplateTable List of templates with title, category, recurrence, claimable flag. Create/edit actions.
CreateTemplateForm Modal: title, description, category, estimated minutes, default location, recurrence cron, isClaimable toggle

Data flow:

  • Client mutations: createTaskInstance, assignTask, updateTask, createTaskTemplate

4.13 Retreats List (/retreats)

Purpose: Browse retreats. Community users see published/active retreats. Facilitators+ see all statuses.

Components:

Component Description
RetreatCardGrid Card per retreat: name, dates, status badge, capacity indicator, description excerpt
RetreatStatusFilter Tabs or segmented: All / Published / Active / Completed / Draft (draft only for retreats.manage)

Data flow:

  • SSR: listRetreats

4.14 Retreat Detail (/retreats/:retreatId)

Components:

Component Description
RetreatHeader Name, dates, status, capacity bar
RetreatSchedule Timeline/agenda view of schedule items (title, time, location, lead person)
RetreatParticipantList Table of persons: name, role (organizer/facilitator/participant), attendance status
RetreatDescription Full description text

Data flow:

  • SSR: retreat detail, schedule items, persons (these may need dedicated list endpoints or be embedded in a "get retreat" response -- if not available, consider adding getRetreat endpoint)

4.15 Retreat Management (/retreats/manage/:retreatId)

Purpose: Full CRUD for a retreat.

Components:

Component Description
RetreatForm Edit name, description, dates, capacity, check-in/out defaults
ScheduleEditor Add/edit/remove schedule items. Each item: title, start, end, location, lead person
PersonManager Add persons (by user search or email/name for external). Set role type. Track attendance status.
RetreatActions Publish, Cancel buttons with confirmation modals

Data flow:

  • Client mutations: updateRetreat, addRetreatPerson, addRetreatScheduleItem, publishRetreat, cancelRetreat

4.16 Meal Schedule (/kitchen)

Purpose: View upcoming meals for all community members.

Components:

Component Description
MealDayView Grouped by day, showing breakfast/lunch/dinner/snack cards. Each card: meal type icon, time, headcount, menu notes, status badge.
MealDatePicker Navigate between days
DietaryProfileLink Banner linking to /kitchen/dietary if profile is incomplete

Data flow:

  • SSR: listMealServices(date=today)

4.17 Kitchen Board (/kitchen/manage)

Purpose: Kitchen lead manages meal services.

Components:

Component Description
MealServiceTable Table with date, type, headcount, status, actions. Filterable by date range and meal type.
CreateMealServiceForm Modal: date, type (breakfast/lunch/dinner/snack), planned headcount, menu notes, optional linked retreat
MealStatusUpdater Quick status transitions: planned > ready > served > completed
DietarySummary Aggregated dietary needs for a given date (count of vegetarian, vegan, gluten-free, etc. across expected attendees)

Data flow:

  • SSR: listMealServices
  • Client mutations: createMealService

4.18 Dietary Profile (/kitchen/dietary or /profile)

Components:

Component Description
DietaryProfileForm Toggle switches: isVegetarian, isVegan, isGlutenFree, isDairyFree, hasNutAllergy. Text fields: allergyNotes, dislikes, otherRequirements.

Data flow:

  • Client mutation: upsertDietaryProfile

4.19 Inventory (/inventory)

Components:

Component Description
InventoryTable Table: name, unit, current qty, minimum qty, status indicator (low stock = qty < minimum). Sortable.
LowStockAlert Banner at top if any items are below minimum
RequestSuppliesButton Links to /inventory/request

Data flow:

  • SSR: listInventory

4.20 Inventory Request (/inventory/request)

Components:

Component Description
InventoryRequestForm Item selector (from inventory list or free-text name), quantity, unit, purpose

Data flow:

  • SSR: listInventory (for item selector)
  • Client mutation: requestInventory

4.21 Inventory Request Queue (/inventory/requests)

Components:

Component Description
InventoryRequestTable Table: item name, qty, requester, status, date. Actions: review (approve/reject), fulfill.
ReviewDrawer Review notes, approve or reject
FulfillButton Marks a request as fulfilled

Data flow:

  • Client mutations: reviewInventoryRequest, fulfillInventoryRequest

4.22 User Directory (/admin/users)

Components:

Component Description
UserTable Paginated table: name, email, roles (pills), status, joined date
UserSearchBar Search by name or email
UserStatusFilter Active / Inactive / Archived

Data flow:

  • SSR: listUsers

4.23 User Detail (/admin/users/:userId)

Components:

Component Description
UserProfileCard Name, email, phone, status, date of birth, nationality, emergency contact
RoleManager Multi-select of roles with save button. Uses setUserRoles.
UserProfileEditForm Edit profile fields. Uses updateUserProfile.
UserActivityTimeline Recent stays, tasks, requests (read-only, assembled from multiple API calls)

Data flow:

  • SSR: getUser(userId)
  • Client mutations: setUserRoles, updateUserProfile

4.24 Audit Log (/admin/audit)

Components:

Component Description
AuditLogTable Paginated table: timestamp, user, action, table, record ID, changed fields (JSON expandable)
AuditLogFilters Filter by table name, user, action, date range

Data flow:

  • SSR: listAuditLog

4.25 Notifications (/notifications)

Components:

Component Description
NotificationList Grouped by date. Each item: icon by type, title, body preview, timestamp, read/unread indicator. Click marks as read and navigates to linked entity.
MarkAllReadButton Bulk action (may need backend endpoint or iterative calls)
NotificationBell In top bar, shows unread count badge. Dropdown with last 5 notifications.

Data flow:

  • SSR: listNotifications
  • Client mutation: markNotificationRead

5. Shared Components

Layout Components

Component Description
AppShell Mantine AppShell with sidebar, header, main content area. Responsive breakpoints.
RoleGate Wrapper that checks session.roles against required permissions. Renders children or a "not authorized" message.
SidebarNav Role-filtered navigation links. Active state via usePathname().
MobileTabBar Fixed bottom bar for mobile. 5 tabs with icons and labels.
PageHeader Title, breadcrumbs, optional action buttons (top-right).
NotificationBell Header icon with unread count, dropdown preview.

Data Display Components

Component Description
StatusBadge Mantine Badge with color mapped to status string. Reused across stays, boats, tasks, retreats, inventory.
DateRangeDisplay Formatted date range (e.g., "Mar 15 - Mar 22, 2026")
UserAvatar Avatar with name tooltip. Links to user detail for admin roles.
PaginatedTable Wrapper around Mantine Table with limit/offset pagination controls.
EmptyState Illustration + message + optional CTA button for empty lists.
LoadingState Skeleton loaders matching the expected content shape.
ConfirmModal Reusable confirmation dialog for destructive actions (cancel stay, reject request, etc.)

Form Components

Component Description
DateRangePicker Mantine DatePickerInput configured for range selection
UserSelect Async searchable select that queries listUsers
RoomSelect Select populated from listRooms
RetreatSelect Select populated from listRetreats
StatusFilter Segmented control or select for status enum values

6. Data Fetching Strategy

Server-Side (SSR)

Next.js App Router server components call Pikku RPC functions directly (or via a server-side HTTP client to localhost:6002/api/...). This provides:

  • Fast initial page loads
  • SEO for any public pages (currently none, but future-proofed)
  • Session cookie forwarded from the incoming request
// Example: app/stays/page.tsx (server component)
async function StaysPage() {
  const stays = await pikkuClient.listStays({ limit: 50 })
  return <StayTable data={stays} />
}

Client-Side (Mutations + Polling)

  • All write operations (create, approve, reject, claim, etc.) are client-side via Pikku RPC
  • After mutation success: invalidate relevant server data using router.refresh() or React Query / SWR cache invalidation
  • Polling: notifications badge polls every 60 seconds via listNotifications(limit=1, unreadOnly=true) to update the count
  • Optimistic updates for instant feedback on claim/complete task actions

Use @tanstack/react-query for client-side cache management:

  • Query keys follow the pattern: ['domain', 'action', params] (e.g., ['stays', 'list', { status: 'checked_in' }])
  • Mutations invalidate related query keys on success
  • Server components pass initial data as props; client components hydrate from those props

7. Mobile Considerations

The island context means many users will be on phones, often with intermittent connectivity.

Design Principles

  1. Touch-first: All interactive targets minimum 44x44px. Use Mantine's size="lg" for buttons and inputs on mobile.
  2. Single-column layouts: All pages stack to single column below 768px. No horizontal scrolling.
  3. Bottom-anchored actions: Primary actions (Request Seat, Claim Task, Check In) use sticky bottom action bars on mobile, not top-right buttons.
  4. Offline tolerance: Show last-fetched data with a "stale data" indicator when offline. Queue mutations and retry when connectivity returns (stretch goal -- implement in v2).
  5. Minimal data transfer: Use pagination aggressively. Default limit=20 on mobile (vs. 50 on desktop). Avoid loading images where text suffices.

Mobile-Specific Components

Component Description
BottomActionBar Sticky bottom bar with primary action button(s). Replaces top-right action buttons on mobile.
SwipeableCard Swipe-right to claim a task, swipe-left to dismiss. Provides fast interaction on task board.
PullToRefresh Pull-down gesture triggers router.refresh() on list pages.
CompactTable Table that collapses to a card-list layout on mobile, showing only key fields with expandable detail.

8. Authentication Flow

Login (/login)

  • Credentials form (email + password) using Auth.js
  • On success: redirect to / (dashboard)
  • Session stored as HTTP-only cookie
  • Auth.js endpoints at /auth/* (handled by auth.wiring.ts)

Session Management

  • Middleware (middleware.ts in Next.js root) checks for valid session on all routes except /login and /auth/*
  • Session object shape: { userId: string, roles: string[] }
  • Roles array used by RoleGate and sidebar filtering
  • Session refresh handled automatically by Auth.js JWT rotation

Logout

  • POST to /auth/signout (Auth.js endpoint)
  • Clear local state and redirect to /login

Appendix: Complete API Endpoint Reference

For reference, here is every backend endpoint grouped by domain, with its HTTP method, route, and required permission tag.

System

Method Route Permission Function
GET /health-check none (public) healthCheck

Users

Method Route Permission Function
GET /users users.view listUsers
GET /users/:userId users.view getUser
PUT /users/:userId/profile users.manage updateUserProfile
GET /roles authenticated listRoles
PUT /users/:userId/roles roles.assign setUserRoles

Stays

Method Route Permission Function
POST /stays/requests stays.request requestStay
POST /stays/requests/:requestId/approve stays.review approveStayRequest
POST /stays/requests/:requestId/reject stays.review rejectStayRequest
GET /stays/requests stays.view_all listStayRequests
POST /stays stays.manage createStayFromRequest
POST /stays/:stayId/check-in stays.manage checkInStay
POST /stays/:stayId/check-out stays.manage checkOutStay
POST /stays/:stayId/cancel stays.manage cancelStay
GET /stays stays.view_all listStays

Rooms

Method Route Permission Function
POST /rooms rooms.manage createRoom
PUT /rooms/:roomId rooms.manage updateRoom
POST /rooms/allocations rooms.manage allocateRoom
POST /rooms/allocations/:allocationId/release rooms.manage releaseRoom
GET /rooms rooms.view_all listRooms
GET /rooms/allocations rooms.view_all listRoomAllocations

Boats

Method Route Permission Function
POST /boats/routes boats.manage createBoatRoute
POST /boats boats.manage createBoat
POST /boats/trips boats.manage createBoatTrip
POST /boats/trips/:tripId/open boats.manage openBoatTrip
POST /boats/trips/:tripId/request-seat boats.request requestBoatSeat
POST /boats/requests/:requestId/confirm boats.manage confirmBoatRequest
POST /boats/requests/:requestId/decline boats.manage declineBoatRequest
PUT /boats/trips/:tripId boats.manage updateBoatTrip
POST /boats/trips/:tripId/cancel boats.manage cancelBoatTrip
POST /boats/trips/:tripId/complete boats.manage completeBoatTrip
GET /boats/trips boats.view_all listBoatTrips
GET /boats/requests boats.view_all listBoatRequests

Tasks

Method Route Permission Function
POST /tasks/templates tasks.manage createTaskTemplate
POST /tasks tasks.manage createTaskInstance
POST /tasks/:taskId/assign tasks.assign assignTask
POST /tasks/:taskId/claim tasks.claim claimTask
POST /tasks/:taskId/start tasks.manage startTask
PUT /tasks/:taskId tasks.manage updateTask
POST /tasks/:taskId/complete tasks.manage completeTask
POST /tasks/:taskId/block tasks.manage markTaskBlocked
GET /tasks tasks.view_all listTasks

Retreats

Method Route Permission Function
POST /retreats retreats.manage createRetreat
PUT /retreats/:retreatId retreats.manage updateRetreat
POST /retreats/:retreatId/persons retreats.manage addRetreatPerson
POST /retreats/:retreatId/publish retreats.manage publishRetreat
POST /retreats/:retreatId/cancel retreats.manage cancelRetreat
POST /retreats/:retreatId/schedule retreats.manage addRetreatScheduleItem
GET /retreats retreats.view listRetreats

Kitchen

Method Route Permission Function
PUT /kitchen/dietary-profile kitchen.update_dietary upsertDietaryProfile
POST /kitchen/meal-services kitchen.manage createMealService
GET /kitchen/meal-services kitchen.view listMealServices

Inventory

Method Route Permission Function
POST /inventory/requests inventory.request requestInventory
POST /inventory/requests/:requestId/review inventory.manage reviewInventoryRequest
POST /inventory/requests/:requestId/fulfill inventory.manage fulfillInventoryRequest
GET /inventory inventory.manage listInventory

Notifications

Method Route Permission Function
GET /notifications authenticated listNotifications
POST /notifications/:notificationId/read authenticated markNotificationRead

Audit

Method Route Permission Function
GET /audit-log audit_log.view listAuditLog

Appendix: Backend Gaps Identified

During architecture design, several backend additions would improve the frontend experience. These are not blockers for v1 but should be prioritized for the first iteration.

Gap Impact Suggested Endpoint
No "get single entity" endpoints for stay, retreat, trip, task Detail pages must filter list endpoints or add dedicated getStay, getRetreat, getBoatTrip, getTask GET /stays/:stayId, GET /retreats/:retreatId, GET /boats/trips/:tripId, GET /tasks/:taskId
No "my requests" filter on stay requests Guest cannot efficiently see only their own requests Add userId filter param to listStayRequests
No "my boat requests" filter Guest cannot see their own boat reservation requests Add userId filter param to listBoatRequests
No "my inventory requests" view Users who requested supplies can't track them Add listInventoryRequests with userId filter
No "get retreat" with schedule + persons Retreat detail page needs 3 separate calls or a compound endpoint GET /retreats/:retreatId returning nested schedule + persons
No list endpoints for boat routes or boats (fleet) Boat management UI needs to populate dropdowns GET /boats/routes, GET /boats
No "mark all notifications read" Common UX pattern, currently requires N calls POST /notifications/mark-all-read
No unread notification count Notification bell badge requires fetching full list GET /notifications/unread-count
listStayRequests filtered to own user for non-admin Guests with stays.request but not stays.view_all need to see their own requests Either a separate GET /stays/my-requests or backend auto-filters by session userId when stays.view_all is absent