Front-to-Back System Topology
Last verified from repository code on July 21, 2026. Use this page when Support needs to identify which system owns a symptom, which logs or tables to inspect first, and which client path is involved.The current target architecture makes Supabase the source of truth. The NestJS API still exists in the repository, but the latest migrations decommission legacy pull-sync jobs and route dashboard writes directly to Supabase.
Runtime Map
Component Responsibilities
Critical URLs and Identifiers
Source of Truth
Supabase Postgres is the primary data store for production flows. The migration20260612010000_dashboard_native.sql moved dashboard-owned data into Supabase by adding dashboard user fields, creating devotion_categories, creating the public devotions storage bucket, adding devotions.notifiedAt, and scheduling devotion-release-notify every 15 minutes.
The migration 20260615000000_decommission_legacy_api.sql unschedules legacy pull-sync jobs, including daily-devotions-sync, daily-devotions-sync-5am, daily-devotions-sync-730pm, daily-devotions-sync-morning, daily-devotions-sync-evening, and devotion-release-scheduler.
Primary Data Stores
Authentication Model
There are multiple auth surfaces in the repository. Support should verify the caller before assuming a token format.API Surface Inventory
End-to-End Flows
1. Dashboard Login and Publishing
Support checks:- Confirm the dashboard token belongs to a
usersrow withroleSYSTEM_ADMINorCONTENT_CREATOR. - Confirm the user
statusisACTIVE. - Confirm uploaded media exists under the public
devotionsstorage bucket. - For notification issues after publish, inspect
devotions.notifiedAt,device_tokens, Firebase secrets, anddashboardEdge Function logs.
2. Scheduled Devotion Release Notifications
Support checks:devotion-release-notifyonly acceptsAuthorization: Bearer <SUPABASE_SERVICE_ROLE_KEY>.- The cron job name is
devotion-release-notifyand should run every 15 minutes. - A devotion with
notifiedAtalready set will not send again. - FCM failures usually point to missing Firebase secrets, invalid device tokens, or no rows in
device_tokens.
3. Mobile Feed Loading
Support checks:- Standard users only see
status='PUBLISHED'devotions wherereleaseDateis null or in the past. - Content creators only see their own devotions in
devotions-paginated. - If a user still sees old content during an outage, the app may be showing Hive-cached devotions.
- Category filters are server-side for
devotions-paginated; a category table mismatch can make category names or filters look wrong.
4. Notes
Mobile notes usenotes-fetch, notes-save, and notes-delete.
Each function decodes the app token, extracts payload.id, and scopes database operations to notes.createdBy. Later migrations disabled notes RLS, so the function-level createdBy filter is the effective ownership control.
Support checks:
- Confirm the token decodes to the expected user id.
- Confirm the row exists in
noteswith matchingcreatedBy. - If only one note fails to delete or update, verify the
idand owner, not just the endpoint.
5. Password Reset
Support checks:- Email reset requires a matching
users.email, a row inemail_otps, and a workingRESEND_API_KEY. - SMS reset requires a matching
users.phoneNumberand Twilio secrets:TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN, andTWILIO_VERIFY_SERVICE_SID. - Passwords are stored as SHA-256 hashes in Supabase-native functions.
6. Profile Updates and Photos
Profile text updates use theuser function. Profile photo upload uses user-profile, uploads to Cloudinary, and writes the returned URL into users.profilePicture.
Support checks:
- Mobile sends
X-User-IDfor profile update/photo/delete flows. - Photo upload failures usually point to
CLOUDINARY_CLOUD_NAME,CLOUDINARY_API_KEY,CLOUDINARY_API_SECRET, multipart parsing, or a missingprofilePictureform field.
7. Public Website Deep Links
The website route/devotion/:devotionId currently does not query live Supabase data. DevotionRedirect.tsx uses a local mock object for known devotion details, then redirects to revelation14://devotion?id=:devotionId after a countdown.
If the app is installed, the Flutter route handler fetches devotions, finds the matching id, selects that devotion, and opens playback/detail context. If the app is not installed, the website offers app store fallbacks.
Support checks:
- A web deep link can display mock details even if Supabase content has changed.
- If the app opens but cannot find the devotion, confirm the devotion is returned by the mobile feed rules.
- If the browser stays on the website, confirm OS app-link/deep-link configuration and whether the app is installed.
8. Version Checking
The mobile splash screen callsPOST /version-check with current_version and platform.
The current function contains hard-coded version values. The Flutter app manifest is at 4.0.3+35, while the function currently reports 3.3.4 as latest and 3.3.0 as minimum. Treat version prompt issues as backend configuration/code issues first.
Symptom Triage Matrix
Operational Checks
Use these checks before escalating across teams.Devotions most relevant to feed and notification issues
User login and role checks
Notes owner check
Device token and notification checks
Scheduled release notification job
Edge Function smoke test