Architecture and API
This page summarizes the current app architecture and active API shape.
High-Level Flow
React/Vite SPA
-> frontend/src/api shared Axios client
-> Express route
-> controller
-> middleware/services/models
-> external Postgres
The active grocery flow is:
User -> Household -> Store Location -> Zones -> List Items / Available Items
Frontend
Routes:
| Route | Page |
|---|---|
/login |
Login |
/register |
Register |
/invite/:token |
Invite link summary and acceptance |
/ |
Grocery list |
/manage |
Household and store management |
/settings |
User settings |
/admin |
System admin panel |
Core providers:
AuthProvider: login state.HouseholdProvider: user households and active household.StoreProvider: household stores, active store/location, and zones.UploadQueueProvider: queued image uploads and retry/discard behavior.ActionToastProvider: user-visible action outcomes.SettingsProvider: per-user local settings.
Backend
Route families:
| Prefix | Purpose |
|---|---|
/auth |
Register, login, logout. |
/users |
Current user profile, password change, username availability. |
/admin |
System admin user operations. |
/config |
Public frontend config such as image limits. |
/households |
Households, members, stores, locations, zones, lists, and available items. |
/stores |
Global store records and legacy household store helpers. |
/api/groups |
Invite links, join requests, and join policy. |
/api/invite-links |
Public invite link summary and authenticated acceptance. |
/list |
Legacy/global list routes; prefer scoped household/location routes for new work. |
Active Scoped Endpoints
Households:
GET /households
POST /households
GET /households/:householdId
PATCH /households/:householdId
DELETE /households/:householdId
GET /households/:householdId/members
PATCH /households/:householdId/members/:userId/role
DELETE /households/:householdId/members/:userId
Stores, locations, and zones:
GET /households/:householdId/stores
POST /households/:householdId/stores
PATCH /households/:householdId/stores/:householdStoreId
DELETE /households/:householdId/stores/:householdStoreId
POST /households/:householdId/stores/:householdStoreId/locations
PATCH /households/:householdId/locations/:locationId
DELETE /households/:householdId/locations/:locationId
PATCH /households/:householdId/locations/:locationId/default
GET /households/:householdId/locations/:locationId/zones
POST /households/:householdId/locations/:locationId/zones
PATCH /households/:householdId/locations/:locationId/zones/:zoneId
DELETE /households/:householdId/locations/:locationId/zones/:zoneId
Location-scoped list:
GET /households/:householdId/locations/:locationId/list
GET /households/:householdId/locations/:locationId/list/item
POST /households/:householdId/locations/:locationId/list/add
PUT /households/:householdId/locations/:locationId/list/item
PATCH /households/:householdId/locations/:locationId/list/item
DELETE /households/:householdId/locations/:locationId/list/item
GET /households/:householdId/locations/:locationId/list/suggestions
GET /households/:householdId/locations/:locationId/list/recent
GET /households/:householdId/locations/:locationId/list/classification
POST /households/:householdId/locations/:locationId/list/classification
POST /households/:householdId/locations/:locationId/list/update-image
Available items:
GET /households/:householdId/locations/:locationId/available-items
POST /households/:householdId/locations/:locationId/available-items
PATCH /households/:householdId/locations/:locationId/available-items/:itemId
DELETE /households/:householdId/locations/:locationId/available-items/:itemId
POST /households/:householdId/locations/:locationId/available-items/import-current
Invite links:
GET /api/groups/invites
POST /api/groups/invites
GET /api/groups/join-requests
POST /api/groups/join-requests/decision
POST /api/groups/invites/revoke
POST /api/groups/invites/revive
POST /api/groups/invites/delete
GET /api/groups/join-policy
POST /api/groups/join-policy
GET /api/invite-links/:token
POST /api/invite-links/:token
Group invite management uses a X-Group-Id header from the frontend wrapper when the user manages multiple groups.
Auth And Authorization
Authentication:
- Login validates a lowercase username and password.
- Login creates a DB session and sets an HttpOnly cookie.
- Login also returns a JWT-compatible token used by existing client code.
- Protected routes accept valid session or token credentials.
Authorization:
- System admin routes require the
system_adminrole. - Household routes require membership in the target household.
- Household admin routes require owner/admin membership.
- Location/list routes also verify access to the selected store location.
Request IDs And Errors
Every API response includes a request ID and sends it as the X-Request-Id response header.
Error responses are normalized to:
{
"error": {
"code": "bad_request",
"message": "Readable message"
},
"request_id": "generated-request-id"
}
Frontend API wrappers unwrap { data, request_id } success payloads when needed.
Image Handling
Image uploads use Multer and Sharp.
Configuration is exposed by /config and includes:
- Maximum image file size.
- Maximum image dimension.
- Image quality.
Frontend uploads use UploadQueueContext, which persists queued jobs and lets users retry failed uploads.