TECHNICAL HANDOFF

Developer Guide

Architecture, access control, deployment, data flows, and recovery notes for technically experienced maintainers of the Sunset Lake Ward website.

Architecture

FrontendStatic HTML, CSS, and browser JavaScript hosted by Netlify.
Production domainhttps://sunsetlakeward.com
Netlify fallbackhttps://sunsetlakeward.netlify.app
Database and authenticationSupabase project nftyhqoxdicwqddnowyv.
DNSCloudflare routes the apex and www domain to Netlify.
Identity providerGoogle OAuth through Supabase Auth, with email magic links retained as a fallback.

The browser uses only the Supabase publishable key. Authorization is enforced in PostgreSQL Row Level Security, not by hiding interface elements.

Deployed file map

FilePurpose
index.html, app.jsHomepage announcements, organizations, and compact event list.
calendar.html, calendar.jsMonth/list calendar, filters, details, and subscription links.
editor.html, editor.jsAuthentication and core events, announcements, reviews, and editor management.
editor-content.jsManaged pages, signup sheets, choices, and private roster tools.
signup-permissions.jsRoster Viewer and Signup Coordinator assignment and scoped interface behavior.
page.html, page.jsPublic managed-page rendering.
signup.html, signup.jsPublic signup rendering, submission, and cancellation.
embed.html, embed.jsEmbeddable events view for the stake website.
config.jsPublic Supabase URL, publishable key, and public endpoint configuration.
_headersNetlify security and frame-embedding headers.

Database model

TableResponsibility
auxiliariesOrganization directory and display order.
eventsWard, imported sheet, and Church-calendar events plus source metadata and editor overrides.
announcementsPublished and draft announcements.
site_pagesEditor-managed public resource pages.
signup_sheetsSignup settings, scheduling, privacy choices, and organizer-only notes.
signup_slotsTimes, items, volunteer positions, and capacity.
signup_entriesParticipant names, selections, private contact details, notes, and cancellation state.
signup_access_grantsPer-signup Roster Viewer and Signup Coordinator assignments.
site_membersActive editor identity and ward-wide or auxiliary role.
pending_site_membersEmail-based editor invitations awaiting or linked to an Auth user.

Every public-schema table uses RLS. Schema changes are recorded in Supabase migrations; do not make undocumented production-only changes.

Authentication and roles

Google redirects to Supabase, and Supabase redirects the authenticated browser back to the editor.

Google authorized redirect URI:
https://nftyhqoxdicwqddnowyv.supabase.co/auth/v1/callback

Application redirect URLs:
https://sunsetlakeward.com/editor.html
https://sunsetlakeward.netlify.app/editor.html

The Google OAuth Client ID and secret live in the Supabase Google provider configuration. The secret must never be placed in config.js, committed to a repository, included in a ZIP, or pasted into client-side code.

RoleServer-enforced scope
editorOne auxiliary; drafts and submissions, plus grants for that auxiliary’s signup sheets.
publisherAll organizations; review and publish authority.
adminAll content and editor administration.
signup_delegateOnly signup sheets listed in active signup_access_grants.

Security model

  • Use the publishable key in the browser; never expose a Supabase secret or service-role key.
  • RLS checks the authenticated user, active role, auxiliary, signup ID, and permission level.
  • Signup contact information, age information, notes, cancellation tokens, and organizer notes are not available through anonymous table reads.
  • The public signup Edge Function returns an explicit safe-field response rather than raw database rows.
  • Removing a signup grant deactivates signup-specific access when no active grants remain.
  • Interface visibility is convenience only; database policies remain the authority.
Before releasing a change: verify anonymous access, RLS behavior for every affected role, and that no secrets or private participant fields appear in browser responses.

Calendar data flow

  1. Organization calendar tabs are imported as canonical event rows. Combined Monthly and Weekly tabs are not imported as separate sources.
  2. The church-calendar Edge Function reads the connected Church iCalendar feed.
  3. Source identifiers and payloads support matching and duplicate handling.
  4. Editor overrides preserve locally improved details when an external source refreshes.
  5. The calendar page and combined ICS feed expose published public events for browser and calendar clients.

Edge Function church-calendar is intentionally public because calendar applications cannot attach a Supabase user session. Keep its output limited to published public event information.

Signup data flow

  1. An authorized editor creates a sheet and optional slots.
  2. The public page loads a sanitized response from the public-signups Edge Function.
  3. A participant submits through that function; capacity and validation are enforced server-side.
  4. The participant receives a private cancellation URL.
  5. Authorized editors or assigned signup delegates read the private roster through authenticated, RLS-protected requests.

The public-signups function does not require a user JWT because visitors must be able to volunteer. It must continue to perform its own validation and return only intentionally public fields.

Deployment runbook

  1. Make changes in the deployable dist/ directory or rebuild the source project when full source is available.
  2. Run JavaScript syntax checks and verify required HTML references.
  3. Test the homepage, calendar, editor login, role-restricted views, public signup, cancellation, and stake embed.
  4. Zip the dist directory so the archive contains dist/index.html and the other site files.
  5. Deploy the ZIP through Netlify and wait for the production deployment to complete.
  6. Open both the Netlify address and sunsetlakeward.com. Test in a private browser window and on a phone.

Database migrations and Edge Functions are deployed through Supabase, separately from the Netlify ZIP. Coordinate database-first changes so the existing frontend remains compatible during deployment.

Release checklist

  • Homepage loads announcements and only the compact initial event list.
  • Calendar month/list switching and organization filtering work.
  • Google, Outlook, Apple, and calendar-file subscription links open correctly.
  • Google OAuth returns to /editor.html on desktop and mobile.
  • Auxiliary Editors cannot edit another organization.
  • Roster Viewers cannot edit a signup or grant permissions.
  • Signup Coordinators see only assigned signup sheets.
  • Anonymous requests cannot read private signup columns.
  • Public signups enforce capacity and return a cancellation link.
  • The stake embed remains frameable while the editor remains protected from framing.

Troubleshooting and recovery

OAuth redirect mismatch

Confirm the error’s requested redirect URI exactly matches the Supabase callback registered on the same Google OAuth Client ID configured in Supabase. Confirm both custom-domain and Netlify editor URLs are in Supabase Auth redirect URLs.

Editor returns to sign-in

Confirm the Auth session is stored under sunset_lake_editor_session, the user has an active site_members record, and the browser is not using a stale embedded webview.

Content disappears

Check status, visibility, publish/expiration dates, organization filters, and RLS before changing data. External calendar refreshes should preserve editor overrides.

Bad deployment

Use Netlify’s prior deploy history to restore the previous frontend. Database rollback requires a deliberate reverse migration; do not delete tables or reset the project to repair a display problem.

Handoff

Transfer access to Netlify, Supabase, Cloudflare, and the Google Cloud OAuth project separately. Rotate secrets when maintainers change, but do not rotate the public publishable key unless necessary.

Participation, bulletin, and email additions

participate.html submits bulletin announcements, sacrament-meeting offers, ideas, ward-needs offers, and appointment requests through the constrained submit_ward_request database function. Direct public table access is denied. bulletin.html reads only published editions and items; planning and review editions remain authenticated.

Reviewer access uses get_ward_requests_for_editor, which masks anonymous submitters from Ward Publishers while preserving identity for Site Administrators. Site Administrators may block an abusive submitter through block_ward_submitter.

Resend is verified for sunsetlakeward.com with sending enabled and receiving disabled. Store the future Resend API key as a server-side Supabase secret; never place it in config.js or browser code.