1 Architecture and API
Nico edited this page 2026-05-26 00:31:28 -07:00

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_admin role.
  • 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.