Complex Areas
A short, honest list of areas where the code is genuinely complex and worth reading carefully before changing. Not a list of bugs or warnings — these are load-bearing, well-functioning systems whose shape matters.
PayrollContext.tsx
File: ../../src/routes/PayrollNew/PayrollContext.tsx (3,037 lines)
The aggregator for the PayrollNew feature. Subscribes to multiple RTDB
trees, exposes hours / tips / cuts calculations, and feeds the eight
export-format generators in
../../src/routes/PayrollNew/export-formats/.
It is heavily memoized (~37 useMemo/useCallback sites), so the
risk isn't render perf — the risk is just size. A lot of consumers
depend on the values it exposes, so changes ripple. When extending,
prefer adding a focused hook in
../../src/routes/PayrollNew/ and
plugging it into the context, rather than growing the context body.
requests module — multi-type state machine
Folder: ../../functions/modules/requests/
Handles several request types (availability changes, time-off, shift swaps, exchange offers, emergency coverage) on a shared state machine. Transitions are interlinked — for example, an exchange offer creates an inverse request on the counterparty; expirations cascade.
Before changing transitions or permission checks on one request type,
read the state-transition logic under
../../functions/modules/requests/logic/
and check the other types don't depend on the path you're modifying.
integration-engine/ provider abstraction
Folder: ../../functions/integration-engine/ (100+ files)
The standard way to add a POS or reservation provider. Deep
inheritance: BaseProvider → domain (sales, reservation) →
concrete provider (opentable, lightspeed, …). A sync-job planner
orchestrates pipeline runs; an observability layer reports health and
writes state to Firestore (see
decisions.md → data-stores).
Plan a few hours to read core/, domains/<your-domain>/, and one
existing provider end-to-end before adding a new one. The older
per-provider folders under
../../functions/integrations/ are
legacy and predate this engine — new providers go through the engine.
Schedule → Postgres replication is asynchronous
Listener: ../../functions/db/pg-sync/on-schedule-write.listener.ts
(and siblings for company / employee / user / schedule-settings)
A schedule edit is committed to RTDB first (the source of truth that web + mobile observe). A separate RTDB → Postgres listener then mirrors that change into Cloud SQL for analytics/reporting use.
If the Postgres write fails, the two stores can diverge silently —
reports run against Postgres lag or contradict the live UI. When
investigating "the dashboard doesn't match what I see in the app,"
check Rollbar for pg-sync errors. Keep the dataflow one-way: don't
add ad-hoc Postgres writes outside of pg-sync.