Clickable prototype for Faith Layer Software · Yelevo LLC. DEMO · datos ficticios (fictional “Iglesia Esperanza” data).
Prototype:index.html — one self-contained file (inline CSS + JS, no build step, no dependencies except the Inter web font). Open it on a phone for the real mobile experience. On a desktop (≥ 1024px) the Leader role renders inside a phone frame with a side panel, while the Administración role renders as a full desktop dashboard (see “Desktop admin”). A “Vista móvil” button shows the phone version of the admin.
Language: Spanish is the default, English is a toggle on every screen (button in the demo bar). All strings are inline T('español','English') pairs — see the copy table.
Everything is fictional. Data lives in memory + localStorage (key faith-groups-proto-v1). No network calls, no real maps, no real people. A “DEMO · datos ficticios” bar is always visible; remove it for production.
Deep links for review:index.html#leader/report, #leader/review, #leader/success, #leader/home, #leader/group, #admin/overview, #admin/leaders, #admin/admins, #admin/map, #admin/notices, #admin/reports, #admin/print, #login.
Code layout: section comments in the CSS (tokens → base → screens/nav → components → screen-specific → animations → print) and in the JS (config/i18n → data → helpers → router → one block per screen → actions → boot). Every screen is registered as SCREENS['name'] = { tab, hash, render(), mount() }. Every interactive element declares data-act="…", handled in one ACTIONS map.
1. Design tokens
All tokens are CSS custom properties in the :root block of index.html. Use them by name; never hard-code values.
Brand colors
Same palette as the new faithgroups.app landing page. Navy = text/headers, teal = primary action and brand accent.
Token
Value
--navy
#05223a
--teal
#008d9b
--teal-d
#007883
--muted
#546675
--line
#e2e9ed
--bg
#fafcfd
--soft
#f0f6f8
--white
#fff
--teal-50
#e8f5f7
--teal-100
#cfe9ed
Semantic colors
ok = success/reported, warn = pending/attention (never alone: always paired with text or icon), danger = errors.
Token
Value
--ok
#1c8456
--ok-bg
#e6f5ed
--warn
#9a5b00
--warn-bg
#fff3de
--warn-line
#f1d29b
--danger
#b83227
--danger-bg
#fdecea
--blue
#2a6ab0
--overlay
rgba(5,34,58,.42)
--stage-bg
#e9f0f3
Typography
Inter 400/500/600/700/800. Body 15.5px/1.45, large titles 30px/800 with −0.025em tracking, display numbers 44px/800.
Minimum tap target 48px. Primary button 52px. Tab bar 64px + safe area.
Token
Value
--tap
48px
--btn-h
52px
--input-h
52px
--tabbar-h
64px
--demobar-h
38px
--statusbar-h
0px
Motion
Durations and easings used by every animation (see Animation specs).
Token
Value
--ease-ios
cubic-bezier(.32,.72,0,1)
--ease-out
cubic-bezier(.22,1,.36,1)
--ease-spring
cubic-bezier(.34,1.56,.64,1)
--dur-press
120ms
--dur-fast
180ms
--dur-base
280ms
--dur-screen
380ms
--dur-slow
560ms
--stagger
55ms
Desktop admin layout (>=1024px; --d-side-w and --d-pad grow at >=1280px)
Sidebar 232px (256px from 1280), top bar 64px, content padding 24px (32px from 1280) capped at 1320px, report drawer 480px, modal 540px. Colors, type, radii and shadows are the same tokens as mobile.
Pill button, 52px high (40px .btn-sm). Primary = teal with glow, secondary = white with border, dark = navy, WhatsApp = soft green (used only for share/remind actions).
State
Behavior
Default
Resting style per variant.
Hover (desktop)
Primary darkens to --teal-d.
Pressed
transform: scale(.965) in 120ms + 8ms haptic vibration where supported.
Focus-visible
3px teal outline, 2px offset.
Disabled
45% opacity, no pointer events, no shadow.
Loading
.is-loading: label hidden, 22px spinner; used by Save report and Send notice (800ms / 650ms simulated).
Card
.card .card--hero .card--alert .card.tap .metric
White surface, 1px --line, radius 20px, --shadow-md. Hero = navy gradient for the weekly status. Alert = amber surface for “groups without a report”. .tap cards are fully clickable.
State
Behavior
Default
Pressed (.tap)
scale(.985)
Alert
Amber background + border; always has an icon + text.
52px high fields, 14px radius, label above (13.5px/600). Numeric fields use inputmode; dates/times use native pickers.
State
Behavior
Default
1.5px --line border.
Focus
Teal border + 4px teal halo (14% alpha).
Read-only
Soft grey background (group name in step 1).
Error
.field.has-error: red border/halo and .err text under the field; field shakes via haptic 20ms.
Chip
.chip (.is-on, .dashed)
42px pill. Used for quick-adding attendees, assigning helpers, group filters and recipient selection. Toggle chips use aria-pressed.
State
Behavior
Off
White, 1.5px border.
On
Teal-50 background, teal border/text, check icon slides in (width 0→16px) and chip pops (280ms spring).
Dashed
Action chip “Otra persona” (opens Add person sheet).
Segmented control
.seg (--n, --i) / .seg.sm
Sliding white thumb driven by CSS variables --n (segments) and --i (active index). Used for login method, Leaders/Administrators, and attendee category.
State
Behavior
Active
Navy label, white thumb.
Transition
Thumb translates 280ms --ease-ios.
Counter stepper
.counter
Large − / + buttons (48px) around a 24px value. Used for kids, Sunday attendance and fasting count.
State
Behavior
Default
Pressed
Button scales .88 and tints teal-100.
At minimum
− button disabled (35% opacity).
Value change
Value ‘bumps’ (scale 1→1.28→1, 280ms spring).
Switch row
.switch-row[role=switch][aria-checked]
iOS-style 52×32 switch with label and optional hint. Whole row is the tap target.
State
Behavior
Off
Grey track.
On
Teal track, knob slides 20px with spring easing.
Wizard progress
.progress > i (.done, .now)
Five segments (6px tall) above the step title; role=progressbar. Review step shows all five complete.
State
Behavior
Pending
Grey.
Current
Half-filled, gentle pulse.
Done
Fills left→right in 560ms.
Person card
.person
One attendee: initial avatar, name, remove (✕, not for the leader), category segmented control (Discípulo / Visita / Visita nueva) and a ‘Lección’ pill to mark who taught (single selection).
State
Behavior
New
Fades up on insert.
Teacher on
Navy pill, aria-pressed=true.
Bottom sheet
#sheet-root .sheet
Modal sheet with drag handle, title, close button. One open at a time; content can be swapped in place (Add leader → Invitation → WhatsApp preview). Max height 88%.
State
Behavior
Opening
Backdrop fades in 280ms; sheet slides up 380ms --ease-ios.
Dismiss
Tap backdrop, ✕, Esc, or drag the handle down > 110px.
Let leaders and administrators sign in on their phone and save the app to the home screen.
Contents
Brand, church name, three methods in a segmented control: Código (access code field with show/hide), PIN (6-dot keypad), Face ID (scan animation). “Guardar en mi teléfono” opens iPhone/Android install steps. Demo bar lets reviewers pick which role they enter as.
Interactions
Valid code (111115 Elena, 000000 admin, others in the demo) → signs in as that user. PIN 123456 → signs in as the selected demo role. Face ID → scans then signs in.
States
Error: wrong code → red field + “Código de acceso inválido.” + shake; wrong PIN → dots turn red, shake, toast “PIN incorrecto o bloqueado…”. Loading/success: Face ID scan → green check → home. Empty: n/a.
Leader · Inicio #leader/home
Purpose
At a glance: has my group reported this week, and a one-tap way to start the report.
Contents
Greeting (“Hola, Elena”), hero status card for the current week, optional new-notice banner, two metrics (last meeting, 4-week average), meeting place card with mini map, last 3 reports.
Interactions
“Nuevo reporte” → wizard. Hero becomes “¡Reporte enviado!” with total and “Ver reporte” once submitted. Banner → Avisos. “Editar” → Mi grupo. Report row → detail.
States
Pending (CTA with pulse ring) / Sent (total + view). Empty reports: “Todavía no hay reportes guardados.” Already reported: tapping Reporte shows info toast “Ya se envió un reporte de tu célula para esta fecha.”
File the weekly meeting report in about two minutes, one focused step per screen.
Contents
1 Reunión: group (read-only), date, start/end, lesson, offering. 2 Asistencia: roster chips to tap who attended, “Otra persona” sheet, per-person category (Discípulo/Visita/Visita nueva) and Lección toggle, kids stepper, live total (also in the Next button). 3 Cierre de la reunión: vision / mission / announcements switches + notes. 4 Planeación de la próxima reunión: welcome & prayer, worship, closing, childcare, refreshments — type or tap a name. 5 Motivación y crecimiento: absent chips, who calls them, Sunday count, who can bring a guest, people to invite, prayer, fasting count + names. Revisar y guardar: summary by section with Edit links.
Interactions
Next/Previous slide steps; step 1 validates date. ✕ with unsaved changes opens “¿Salir sin guardar?” sheet. “Llenar ejemplo” (demo helper only) fills a realistic report (total 14 for Amistad → week total 69). Save → success screen.
States
Validation errors: missing date; no attendees and no kids → toast “Agrega al menos una persona o un niño.” and jumps to step 2; duplicate week → toast “Ya se envió un reporte de tu célula…”. Loading: Save button spinner 800ms. Success: see next screen. Empty roster: “Todos asistieron” in absent list.
Leader · Reporte enviado #leader/success
Purpose
Reward and confirm the submission.
Contents
Animated checkmark, light confetti, “¡Reporte enviado!”, summary (attendees, new guests, children counting up), Volver al inicio / Ver reporte.
Interactions
Home returns to Inicio with the sent state; Ver reporte opens the detail.
States
Success only. Offline/failed-send handling is not prototyped (see Open questions).
Leader · Mi grupo #leader/group
Purpose
Let the leader keep the meeting place current and review their own history.
Contents
Group header, meeting address field, mini map (tap to move the pin), coordinates, “Usar mi ubicación”, “Guardar lugar”, privacy note, list of the leader’s reports, Cerrar sesión.
Interactions
Tap map → pin drops there. Save validates the address.
States
Error: empty address → “Escribe la dirección de reunión.” Success: toast “Lugar de reunión guardado.”
Avisos (leader and admin) #leader/notices · #admin/notices
Purpose
Admin sends messages to all active leaders or a selection; leaders read them.
Contents
Admin: composer (asunto, mensaje, “Todos los líderes activos” switch or recipient chips), Enviar aviso, Compartir por WhatsApp (preview sheet), sent list with recipient count. Leader: received list; unread dot on tab.
Interactions
Send validates and shows spinner → toast “Aviso enviado a N líder(es).” WhatsApp opens a preview bubble sheet (simulated).
States
Empty: “Todavía no hay avisos.” Errors: empty subject/message, no recipients (“Selecciona destinatarios.”). Success: toast + list updates.
Admin · Resumen #admin/overview
Purpose
See how the week is going and who still needs a nudge.
Contents
Week selector (◀ ▶, last 6 weeks), four metrics (Grupos que reportaron, Grupos sin reporte, Asistencia total, Visitas nuevas), amber alert card listing groups without a report with “Recordar por WhatsApp”, attendance trend chart (labeled Datos ficticios), group list with progress meters and status badges, Agregar líder.
Interactions
Changing week re-animates counters, chart and list. Pending group row or alert button opens the reminder sheet (WhatsApp preview, simulated). Reported row opens the report.
States
All reported: green “¡Todos los grupos reportaron!” and the chart footnote is hidden. Partial: amber alert, chart bar flagged , and the footnote “ Semana incompleta: faltan grupos por reportar.” is shown (only when a group is missing). Reset “Practicar desde cero”: all five groups pending.
Admin · Líderes #admin/leaders
Purpose
Find leaders, invite new ones privately, manage access; manage administrators.
Contents
Segmented Líderes / Administradores. Search by name or group (accent-insensitive). Rows open a manage sheet: Editar nombre, Restablecer código, Desactivar, Archivar (with confirmations). “+” opens Agregar líder → creates access code → Invitación privada (code, message) → Compartir por WhatsApp (preview) / Copiar mensaje. Administrators tab invites a new admin the same way.
Interactions
Reset code shows the new invitation. Deactivate keeps reports. Archive hides the leader.
States
Errors: empty name/group, “Esta célula ya tiene un líder activo.” Empty: “Todavía no hay líderes guardados.” / “No se encontraron líderes.” Inactive rows are dimmed with a badge.
Admin · Mapa de células #admin/map
Purpose
See where groups meet (privately) and how far each is from the church.
Contents
Labeled ‘Ubicaciones privadas’ and ‘Ubicaciones ficticias · Phoenix’. Stylized illustration (not real tiles), church pin + numbered group pins, zoom +/−, “Ver iglesia”, selected-pin card with address and distance, “Medir desde” chips (church or any group) and a distance list sorted ascending in miles (“en línea recta”).
Interactions
Tap a pin or row to select (pin enlarges, card updates); zoom centers on the selection.
States
Pins drop in on entry. For production use real tiles and real coordinates (see Notes).
Admin · Reportes #admin/reports
Purpose
Review submitted reports and print or save them as PDF.
Contents
Filtros sheet (desde, hasta, grupo), group filter chips, Imprimir / PDF sheet (Resumen de asistencia, Totales por Grupo de Amistad, Imprimir selección, Imprimir todos), list with group, date, leader and attendance.
Interactions
Row → report detail (all five sections + attendance by name). Print options → print preview → browser print dialog (window.print()), where PDF can be saved.
States
Loading: skeleton rows ~520ms. Empty: “No hay reportes para esta selección.” Error: from > to → “La fecha inicial debe ser anterior o igual a la final.”
Report detail & Print preview #admin/print
Purpose
Read one report fully, or preview a printable sheet.
Print copies the sheet into #print-sheet; @media print hides the app and prints only that sheet.
States
Error: “No se pudo cargar el reporte.” if the id is missing.
Demo bar, role sheet, account sheet (always visible)
Purpose
Prototype-only tools so reviewers can explore every role and language. Remove in production (account sheet content such as Cerrar sesión stays).
Contents
Demo bar: ‘DEMO · datos ficticios’, role button (Administración or a leader), ES/EN toggle. Role sheet lists the six demo roles with their report status. Account sheet: restore sample data, practice from scratch, sign out.
Interactions
Switching role signs in without a code. ES/EN re-renders every open screen and sheet in place.
States
—
5. Desktop admin (≥ 1024px)
At ≥ 1024px the Administración role renders as a desktop dashboard instead of the phone frame. Leader role and any width below 1024px keep the phone experience. A “Vista móvil” button (top bar) shows the phone version of the admin; “Vista de escritorio” (side panel) returns. “Cambiar vista” opens the role switcher; picking a leader switches to the phone UI. Everything stays labeled DEMO · datos ficticios.
Layout, regions and measurements
Region
Size / structure
Behavior
Shell #desk
Fixed, full viewport. CSS grid var(--d-side-w) minmax(0,1fr); fades in (280ms).
.desk / body.is-desk hides .stage (phone frame + side panel).
Sidebar .d-side
232px (256px ≥ 1280). Logo 32px · church card (“Iglesia Esperanza / Grupos de Amistad”) · nav · demo note · account button.
Nav = 6 items (Resumen, Líderes, Mapa, Avisos, Reportes, Administradores), 46px high, 4px gap. A teal-50 highlight slides between items (translateY(var(--i)*50px), 560ms --ease-ios). Active item: teal text + aria-current=page.
Top bar .d-top
64px, translucent white, bottom border.
Breadcrumb “Iglesia Esperanza › {screen}” · week selector (Resumen only: ◀ label ▶, 44px, label cross-fades) · DEMO pill · ES/EN toggle · “Cambiar vista” · “Vista móvil” · admin avatar (opens Account sheet). Below 1180px the buttons become icon-only, the breadcrumb shows only the screen name.
Page header = title 30px/800 + one-line subtitle + actions on the right.
Cards / tables
Card = white, 1px --line, radius 20px, --shadow-md. Tables live in .d-table-wrap (horizontal scroll inside the card only).
Header row 11px/700 uppercase on --soft; body rows ≥ 58px, hover --soft; numeric columns right-aligned with tabular figures; totals row on Reportes; pending row tinted amber; inactive rows 60% opacity.
Report drawer .d-drawer
Right slide-over, 480px (max 94vw), 560ms --ease-ios; backdrop fades.
Opens from any report row/card. Hero total (counter) + all report sections + “Imprimir o guardar PDF”. Esc / backdrop / ✕ close; focus returns to the row.
S.mobileView = true → dashboard hides, phone frame + side panel return on the matching phone tab (Administradores → Líderes ▸ Administradores). The side panel shows “Vista de escritorio” to go back.
“Cambiar vista” → a leader
Role switches; leader UI is always the phone frame (also on desktop).
Window resized below 1024px / back above
Dashboard ↔ phone UI, same screen kept. Open modal/drawer is closed.
Language toggle
ES/EN repaints sidebar, top bar, content, drawer and any open modal without losing scroll or state.
Deep links
#admin/overview, #admin/leaders, #admin/admins, #admin/map, #admin/notices, #admin/reports, #admin/print open the dashboard at ≥ 1024px and the phone UI below.
Desktop screens
Desktop · Resumen #admin/overview
Purpose
See the week at a glance and nudge groups that have not reported.
Contents
Amber banner (“N grupo(s) sin reporte” + “Recordar por WhatsApp”) or green “¡Todos los grupos reportaron!”; four KPI cards (Grupos que reportaron x/N with progress meter, Grupos sin reporte, Asistencia total, Visitas nuevas; deltas vs previous week only for complete weeks); large attendance trend chart (bars + line + gridlines + tooltips, last 6 weeks, Datos ficticios, legend, footnote only when a week is incomplete); “Reportes recientes” list; groups table (Grupo, Líder, Estado Reportado/Pendiente, Asistentes with meter, Visitas nuevas, Niños, Fecha, action).
Interactions
Week selector in the top bar re-animates counters/chart/table. “Imprimir resumen” opens the print preview. Table “Ver reporte” / recent item opens the drawer; “Recordar” opens the WhatsApp reminder modal.
States
All reported / Partial / Past week supported. Counters animate; reduced motion shows final values.
Desktop · Líderes #admin/leaders
Purpose
Find, invite and manage leaders.
Contents
Search field with live count; table (Líder + group, Grupo, Acceso Activo/Inactivo, Esta semana Reportado/Pendiente, Promedio · últimas 4, actions “Invitación” and “Gestionar”); “Agregar líder” button.
Interactions
Search filters as you type (accent-insensitive). “Agregar líder” → modal (validation: name, group, duplicate group) → private invitation modal → “Compartir por WhatsApp” (chat preview) / “Copiar mensaje”. “Invitación” re-opens the invitation for an existing code. “Gestionar” → rename / reset code / deactivate / archive modals.
States
Empty / no results illustrations; inactive rows dimmed; new leader appears with 0 average.
Desktop · Mapa #admin/map
Purpose
See where groups meet and how far they are from the church or each other.
Contents
Large illustrated map with dropping pins (church = navy cross, groups = numbered teal), zoom +/−, “Ver iglesia”, “Ilustración ficticia” tag; side panel with selected-place card, “Medir desde” select and the distance list (mi, en línea recta).
Interactions
Click a pin or a list row to select (pin scales, card updates, map zooms toward it when zoomed in); the select re-sorts the list from the chosen origin.
States
Pins fall in staggered (reduced motion: no fall). Locations are private to administration (badge).
Desktop · Avisos #admin/notices
Purpose
Write a notice and see exactly how leaders will receive it.
Contents
Composer (Asunto, Mensaje, “Todos los líderes activos” switch or recipient chips, “Enviar aviso”, “Compartir por WhatsApp”); live preview card (as the leader sees it) and WhatsApp bubble preview; “Avisos enviados” grid.
Interactions
Preview updates on every keystroke and recipient change. Send validates subject, message and recipients, shows a loading state, toasts and clears the form. WhatsApp opens the simulated share modal.
States
Field errors; loading button; empty sent list illustration.
Desktop · Reportes #admin/reports
Purpose
Filter, review and print or save attendance reports.
Contents
Filter bar (Desde, Hasta, Grupo de Amistad, Limpiar, live “N reporte(s) · Promedio por reunión”); data table (Fecha, Grupo, Líder, Disc., Visitas, Nuevas, Niños, Total, Ofrenda) with a totals row; “Imprimir / PDF” button.
Mobile 390×844 captured from the automated walkthrough. Desktop admin captures are in section 5 (screenshots/dd-*.png); screenshots/d-*.png show the phone frame on desktop. Report-flow video (mp4).
Login · código / PIN / Face IDLeader · InicioReport · Paso 1 ReuniónReport · Paso 2 AsistenciaReport · Paso 3 CierreReport · Paso 4 PlaneaciónReport · Paso 5 Motivación y crecimientoReport · Revisar y guardarReporte enviadoLeader · Mi grupoAdmin · ResumenAdmin · Grupos y tendenciaAdmin · LíderesInvitación privada (EN)Admin · Mapa de célulasAdmin · AvisosAdmin · ReportesVista previa de impresiónDetalle del reporteAdmin · Resumen (English)
7. ES / EN copy (key strings)
Español (default)
English
Where
Grupos de Amistad
Friendship Groups
App title / login
Acceso de líderes y administradores
Leader and administrator access
Login subtitle
Código de acceso
Access code
Login
Entrar con código
Sign in with code
Login button
Entrar con Face ID
Sign in with Face ID
Login
Guardar en mi teléfono
Add to my phone
Install guide
Código de acceso inválido.
Invalid access code.
Error
PIN incorrecto o bloqueado. Usa Face ID o tu código de recuperación.
Incorrect or locked PIN. Use Face ID or your recovery code.
La fecha inicial debe ser anterior o igual a la final.
The start date must be on or before the end date.
Error
Ya se envió un reporte de tu célula para esta fecha.
A report was already submitted for your group on this date.
Error
Cerrar sesión
Sign out
Account
DEMO · datos ficticios
DEMO · fictional data
Demo bar
All copy lives inline as T('español','English'). Dates: fmtDate / weekLabel.
8. Accessibility notes
Touch targets: every control is ≥ 42px; primary controls, tabs, steppers and keypad keys are 48–64px.
Contrast: navy #05223a on #fafcfd ≈ 15:1; teal #008d9b is used for large/bold text and fills with white text (≈ 4:1 — keep ≥ 15.5px/600 on teal fills); muted #546675 on white ≈ 6:1. Verify final brand colors with your tool before release.
State is never color-only: report status uses text + icon badges (Reportó / Pendiente); errors have text under the field; chips show a check icon when on.
Semantics: chips use aria-pressed; switches use role=switch + aria-checked; wizard progress is role=progressbar with aria-valuenow; sheets are role=dialog aria-modal; toasts are a role=status live region; tab bar buttons set aria-current=page; icon-only buttons have aria-label.
Keyboard: all controls are native buttons/inputs; map pins are focusable and respond to Enter/Space; Esc closes sheets; visible 3px teal focus ring.
Desktop admin: landmarks are aside (nav with aria-label and aria-current=page), header (top bar) and main; tables use th scope=col and a visually hidden “Acciones/Actions” header; clickable report rows are focusable (role=button, Enter/Space opens the drawer); the drawer and the modal are role=dialog aria-modal, move focus in on open, trap Tab, close with Esc and return focus to the trigger; search/filter results announce counts via aria-live; the week selector is a labeled group with disabled ends.
Reduced motion:prefers-reduced-motion: reduce removes transitions/animations (CSS) and JS transitions/counters jump to their end state; the app stays fully usable.
Language:<html lang> follows the toggle (es/en); inputs use inputmode (numeric PIN/code, decimal offering).
Safe areas:env(safe-area-inset-*) is applied to the demo bar, tab bar and footers for notched phones. Use viewport-fit=cover.
To do in production: trap focus inside sheets and return focus to the trigger on close; move focus to the screen heading after each route change and announce it; add screen-reader text for the chart (table alternative); add real error-recovery/offline states.
#login section in index.html: #access-form (access code + show/hide), #device-pin-login (personal PIN), #unlock-device (Face ID), .install-guide (“Guardar en mi teléfono”)
Three methods become one segmented screen; PIN becomes a keypad; Face ID gets a scan animation.
Leader · Inicio
New. Replaces landing on the report form: show('new') + #quick-new “Nuevo reporte” and the account banner
Adds weekly status, last reports, notice banner and meeting place card.
Leader · Reporte (5 pasos)
#report form in pilot.js: five <details> sections 1 Reunión · 2 Asistencia · 3 Cierre de la reunión · 4 Planeación de la próxima reunión · 5 Motivación y crecimiento; person() rows; children field; #total + #breakdown
Accordion → one step per screen. Líder/Asistente rows with Dom./Lunes checkboxes → roster chips + category segmented control; “Lección por” radio → Lección toggle. Same fields and the same total formula (disciples + guests + new + children).
Reporte enviado
toast('Reporte enviado. Un administrador puede consultarlo.')
Filters → sheet + chips; four print actions → one sheet; list cards → rows + detail screen; print preview added.
Desktop admin · all screens
Same sources as the matching admin screens above (#overview, #leader-form + #leader-directory + #admin-management, #groups-map-panel, #notice-panel, #reports) — the demo is a single-column responsive page
Left sidebar + top bar replace the stacked <details> panels; tables replace list cards; report detail opens in a drawer; same copy, rules and actions.
Demo bar / role switcher
.demo-banner: #demo-role select, “Abrir vista”, “Practicar desde cero”, “Ver cinco reportes”, “Llenar reporte de ejemplo”
Role select → role sheet; reset buttons → account sheet; “Llenar ejemplo” in the wizard header.
Desktop admin is a second layout, not a second app: it reads the same data, helpers, i18n and sheet definitions as the phone UI. In production use one responsive admin app (CSS grid breakpoint at 1024px) and keep the phone UI for leaders. Desktop DOM ids are prefixed d- only because the prototype keeps the hidden phone DOM alive.
Prototype-only (do not ship): DEMO bar and role sheet, fixed date (2026-11-10, week 9–15 nov), seeded data, “Llenar ejemplo”, stylized map, simulated WhatsApp/clipboard/PIN (123456)/Face ID, attendance chart data, localStorage persistence.
Map: the existing app uses OpenStreetMap tiles. Keep a real map in production (MapLibre/Leaflet/OSM) with these pins, zoom controls and the distance list; the illustration only shows the layout and animation. Keep locations private to administrators.
Week definition: weeks run Monday–Sunday; weekId is the Monday. Attendance total counts disciples + guests + new guests + children (same as the current app).
WhatsApp: real sharing should use the Web Share API / https://wa.me/?text= with the same invitation/reminder text; the prototype only previews the message.
Open questions for the product owner: offline/queued report submission; whether leaders can edit a submitted report; whether reminders should be automatic; push notifications for new notices.
Brand: logo/mark and colors come from the new faithgroups.app landing page; the church (tenant) name is fictional here — in production it should come from tenant settings.
12. Weekly-report form editor (admin)
Where: desktop #admin/form (sidebar → Formulario del reporte, three panes: palette · canvas · properties/preview/versions). Phone: Administración → Formulario del reporte (#admin/form at <1024px): list with ↑/↓ buttons, bottom-sheet editor, Vista previa tab, sticky Guardar borrador / Publicar.
WPAC source (honest note). The two Drive docs (1eKSdLeJ7aC7r6NZml9T_IR7PoA42MbDVCiO4hufzNiU, 1UWtL8XjAs4kGG4Y6CqksTgyXSivU2M_sp4SPASIpCjs) list only the sections of the WPAC report (lugar de reunión; datos de la reunión incl. asistencia, visitas, niños y ofrenda; cierre; planeación; motivación y crecimiento; visión y misión). Individual WPAC questions were not found in those docs. The editor therefore shows the sections from WPAC's docs and the questions from the prototype's 5-step wizard, labeled as the prototype base form — not as WPAC's own wording.
Concept
Shape
Notes
form_version
{ id, n, fields[], published_at, applies_from_week, status: draft|published }
Publishing creates n+1; it applies from the next week (weekStart + 7d). Banner: “Versión 3 — se aplica desde la semana del 16–22 nov 2026”.
Types: short text, long text, number, yes/no, single choice, multi choice, date, time, attendee list, group person, photo. Hidden fields stay in the form but are not shown to leaders.
report.form_version_id
FK to the version the report was submitted with
Past reports keep their original questions and show “Formulario v2”. Render-time fallback: reports without the id resolve to the version in force that week (no DB migration in the prototype).
Drag & drop: HTML5 DnD (palette → canvas, row → row) with FLIP animation; keyboard/phone: ↑/↓ buttons (fe-up, fe-down). Both write the same fields[] order.
Autosave: the draft autosaves (debounced) with the cloud pill (Guardando… / Borrador guardado en la nube / Sin conexión · Pendiente de sincronizar). Publicar is a separate, explicit action with a confirmation dialog.
Storage in the prototype:localStorage['fg-proto-forms-v1'] (RFORM). The leader's real 5-step wizard is still hard-coded; the published form drives the preview only (see caveats). Production: the wizard must render from form_version.fields.
Desktop · editor with the WPAC base formDesktop · drag a field inDesktop · bilingual edit, savedDesktop · publish dialogDesktop · published v3Desktop · version historyMobile · list with ↑/↓Mobile · bottom-sheet editorMobile · live preview tab
13. Church identity (logo, accent color, contrast)
Where: desktop #admin/identity (sidebar → Identidad de la iglesia); phone Administración → Identidad; also an optional step in onboarding (Omitir por ahora).
Field
Type
Meaning
church.logo_url
string (https URL or data URL in the prototype)
Uploaded logo. Production: store in object storage, re-encode PNG/WebP, max 2 MB, serve via CDN.
church.accent_hex
#RRGGBB
Accent used for buttons, progress bars, links. Everything else stays Faith Groups navy/teal.
church.uses_default_theme
bool
true → official Faith Groups navy #05223a / teal #008d9b (“Faith Groups (predeterminado)”).
Color extraction (client-side): the logo is drawn to a 96-px canvas; transparent/near-white pixels are dropped; k-means (k=4, 8 iterations, deterministic seeding) returns 4–6 swatches (dominant colors + tonal variants) plus the default swatch.
Contrast rule: the accent must reach 4.5:1 against white (WCAG AA for text). Below that, the UI shows the exact ratio and Ajustar automáticamente (darkens in small steps until ≥ 4.5:1). The official default teal measures 3.97:1 and is exempt (shown as meeting the 3:1 UI-component threshold) — flagged for Victor to decide whether to darken it for text.
Logo placements: login screen, app header (leader/admin), desktop sidebar, onboarding preview, printed/PDF reports (header), invitation screens, giving QR screen.
WPAC demo: WPAC uses the default colors plus the WPAC logo. Logo source: Google Drive file Logo Clear.png (id 1c9fZ318GqPQKB6Ft6PAmkfG0koM42O-d), downloaded and visually verified (navy “WP” + orange “AC” wordmark on a transparent background). The church switcher toggles Iglesia Esperanza (fictional, untouched) ↔ WPAC.
Default themeLogo uploaded, colors extractedContrast warning + live previewAuto-adjustedLogo on a printed reportMobileLogin with church logo
Feature bullets under each plan are illustrative placeholders for Victor to confirm. No payment is taken and there are no card fields. Every plan lists: Copias de seguridad automáticas y cifradas (automatic, encrypted backups included).
Flow: registration form → verify e-mail (demo code button) → plan → offerings (optional) → identity (optional, Omitir por ahora) → preview → Entrar a mi panel; stepper on every step.
Setup checklist: (1) review the form → opens the editor, (2) create first group, (3) invite first leader (share menu). Invitation list shows Vence en 46 h / Aceptada / Venció with Renovar.
Join my church: admin shares a link (WhatsApp or SMS) or a 6-char code; leader sees church name + logo + assigned group before Aceptar invitación; the code is single-use. Expired: screen Esta invitación venció → Solicitar nueva invitación → request lands in the admin's Primeros pasos with Enviar nueva invitación.
Tests: python3 _tests/onboard.py (plans, no card fields, stepper, identity, Path A, Path B, expired, request).
15. Cloud save states, offline queue and idempotent submit
State
ES
EN
When
saving
Guardando…
Saving…
debounced autosave in flight
saved
Borrador guardado en la nube
Draft saved to the cloud
server ack of draft.save
offline
Sin conexión · Pendiente de sincronizar
Offline · Pending sync
navigator.onLine === false or request failed; data kept locally
sending
Enviando…
Submitting…
submit in flight
sent
Reporte enviado
Report submitted
only after the server acknowledges the submit (celebration plays here and nowhere else)
retry
Reintentar
Retry
manual retry; also automatic on online
Autosave: every keystroke writes a local copy (fg-proto-local-v1); a debounced (900 ms) draft.save goes to the server. A lost connection never loses typed data.
Submit:POST /reports with header Idempotency-Key: idem-<leader>-<week>-<random>. The key is generated once per submission series and reused on every retry; the server stores key → report and returns the stored receipt (duplicate: true) on repeats → exactly one report.
Offline at submit: state offline, banner + Reintentar, no celebration, report is not in the admin list. On online the app retries automatically with the same key.
Mock server (prototype):NET.call(type, payload) with 350–900 ms latency, navigator.onLine + a demo toggle (En línea / Sin conexión button), fg-proto-server-v1 as the “server database”.
Backups: automatic, encrypted, included in every plan (stated on the plans page, settings and checklist). Real implementation = managed DB with PITR + encryption at rest; not simulated beyond copy.
Admin form editor shows the same pill (saving/saved/offline); Publicar is separate.
Mobile · Guardando…Mobile · Borrador guardado en la nubeMobile · offline at submitMobile · ReintentarMobile · reconnectingMobile · Reporte enviadoDesktop · editor savingDesktop · saved, Publicar separate
Test: python3 _tests/cloud.py [--shots] — WPAC leader Daniel Torres; context.set_offline(True) exactly at Submit → offline/pending with data preserved → set_offline(False) → submit → Reporte enviado; asserts exactly one report and a deduplicated second report.submit with the same key.
16. Native iPhone app + web panel (Path A / Path B)
Web panel: select a group → Compartir invitación / Share invitation → Copiar enlace, Copiar código, Correo, Mensaje de texto, WhatsApp (one option), Más apps (Web Share API when available). iPhone app (iOS-native look, Inter, navy/teal, iOS status bar): showcase at #ios/<scene> (full-bleed 390×844; framed on desktop) and the synced journey at #journey (web panel left, iPhone right, 17 steps; autoplay).
Path
Steps
A · universal link
Admin → Mensaje de texto → SMS bubble with https://<domain>/join/<CODE> → app installed → opens straight on the invitation (church, logo, group) → Aceptar
B · no app
Link opens a web fallback page → text button Descargar en App Store (no Apple badge art) → App Store listing (mockup, labeled) → open app → welcome → Unirme con un código / Join with a code → 6-char segmented code → confirm church/logo/group → Aceptar
Expired
Esta invitación venció → Solicitar nueva invitación → admin notice
Report
5-step report with cloud states; offline at submit → draft kept → reconnect → exactly one report → Reporte enviado + celebration only on server confirmation; admin shows 1 report received
Universal links / associated domains: host https://<app-domain>/.well-known/apple-app-site-association (no redirect, application/json): {"applinks":{"details":[{"appIDs":["<TEAMID>.com.faithlayer.faithgroups"],"components":[{"/":"/join/"},{"/":"/give/","exclude":true}]}]}}. Add the entitlement com.apple.developer.associated-domains = applinks:<app-domain>. Handle in application(_:continue:) / SwiftUI .onOpenURL → route /join/<CODE>.
Deferred deep link: iOS cannot hand the link through an App Store install. Do not rely on the clipboard or fingerprinting; the web fallback shows the 6-char code and the app asks for it on first launch (Unirme con un código). A first-party deferred-link service (Branch/AppsFlyer) is optional later.
Invitation API:POST /churches/:id/invitations {group_id, leader_name, channel} → {code, link, expires_at}; GET /invitations/:code (public: church name, logo, group, status — no personal data); POST /invitations/:code/accept {name, device_id} (single use, 410 when expired, 409 when used); POST /invitations/:code/request-new {name, contact} → notifies admins.
Push (later): APNs for aviso and reporte pendiente reminders; token registered on accept.
Prototype caveat: the iPhone scenes are web-rendered; the App Store page is a labeled mockup; the SMS/e-mail/WhatsApp buttons show a simulated preview (nothing is sent).
Path A · SMSPath A · app opens on invitationPath B · web fallbackPath B · App Store (mockup)Path B · welcomePath B · codePath B · confirmExpiredReport · savingReport · offline at submitReport · submitted
Tests: onboard.py covers Path A/B/expired in the real UI; cloud.py covers the offline report; the #ios and #journey scenes are exercised by shots_ext.py (no console errors).
17. Ofrendas y diezmos / Offerings & tithes (optional)
Where: onboarding step Ofrendas y diezmos (optional) and later Configuración → Ofrendas y diezmos (#admin/giving; phone: Administración → Ofrendas y diezmos). Leader: Mi grupo → Compartir ofrendas y diezmos. Visitor pages: #give/<church>/<group> (Stripe-style, TEST MODE) and #give-ext/<church>/<group> (example external provider).
Mode
What it does
Conectar Stripe
States: not connected → connecting → verification pending → Habilitada para recibir pagos. Only when enabled does Faith Groups generate a link + QR per célula. Confirmed payments show in the weekly report as Efectivo vs En línea (Stripe) and in the admin week summary.
Usar mi enlace de donaciones
Paste an https:// link → Probar enlace (format validation, simulated reachability, opens a new tab) → save. General or per-célula link. If the provider has categories the person picks Ofrenda or Diezmo there. With an external link, payments are checked in the church’s own system; reflecting them automatically in Faith Groups would require an integration with that provider. The weekly report keeps cash entry only.
Configurar más adelante
Continue onboarding; enable anytime; cash keeps being recorded.
Simulation boundaries: no real Stripe keys, no real charges. Everything Stripe-related is a clearly-labeled simulated TEST MODE (banner MODO DE PRUEBA / TEST MODE, test-card hint 4242 4242 4242 4242). QR codes are real and scannable (generated client-side with the inline MIT library qrcode-generator 2.0.4; no CDN) and are verified by decoding in the tests. Stripe demo URL: https://faithgroups-app-prototype.vercel.app/#give/wpac/<celula>.
Onboarding: Stripe Connect Standard (church owns the Stripe account; fewer compliance duties for us) or Express. POST /v1/accounts → POST /v1/account_links {type: account_onboarding} → redirect → return URL. Store stripe_account_id on the church.
Enabled state: webhook account.updated → when charges_enabled && details_submitted set giving.stripe = enabled (pending until then).
Per-group link: create a Payment Link or a Checkout Session (mode=payment, payment_intent_data.on_behalf_of/direct charge with Stripe-Account header) per group with metadata: { church_id, group_id, category }; the visitor chooses Ofrenda/Diezmo (two prices or a custom amount + category metadata). QR encodes the Faith Groups short URL /give/<church>/<group> that creates the Session on demand.
Recording payments: webhooks checkout.session.completed and payment_intent.succeeded (verify signature; handle retries) → insert payment keyed by checkout_session.id/payment_intent.id (unique index = idempotency) → add to the group's weekly report for the week of created. Refunds (charge.refunded) subtract.
Reporting: weekly report shows Efectivo (manual entry) and En línea (Stripe) (sum of succeeded payments for that group + week) separately, plus the total; the admin summary adds both.
External link mode: only store the URL and optional per-group overrides; no webhooks. An integration (e.g., the provider's API/webhook) would be needed to reflect gifts automatically.
Registration step · 3 optionsStripe · connectingStripe · pendingStripe · enabledExternal link testedSettings · links + QRWeek summaryWeekly report · Efectivo vs En línea (Stripe)Leader · share buttonFull-screen QR · Stripe testFull-screen QR · external linkShare sheetVisitor · checkout (TEST MODE)Visitor · external provider pageVisitor · success
Test: python3 _tests/give.py (Stripe states, TEST MODE banner, payments recorded once, cash vs online report rows, external validation/test/save, QR decoded with OpenCV for one WPAC célula in both modes, leader share sheet).
cloud states + offline at submit (context.set_offline)
_tests/give.py
offerings & tithes, QR decode
_tests/shots_ext.py
all fe-/ci-/ob-/pl-/cs-/ios-/jr-/og- screenshots
Plan feature lists are placeholders for Victor to confirm; prices are $39 / $99 / quote as requested.
The WPAC individual questions were not found in the Drive docs; the question set is the prototype's wizard, labeled as such.
The leader's 5-step wizard remains hard-coded; the published form drives the preview only (production wizard must render from form_version.fields).
Stripe, the App Store page, SMS/e-mail/WhatsApp sending, e-mail verification and the server are all simulated; the QR codes, the color extraction, contrast math, offline queue and idempotency logic are real code.
The Faith Groups default teal (#008d9b) is 3.97:1 on white: fine for large text and UI components, below 4.5:1 for small text — decide whether to darken the default.
19. Legal: Terms of Use, Privacy Policy and acceptance record (draft)
Status: drafts pending legal review, version 2026-11-11-draft1. Pages: privacidad.html and terminos.html (bilingual ES/EN, English default, ?lang=es|en, toggle remembered in localStorage key fg-lang), served next to the app and on the landing preview. noindex while in draft.
Where
What
Registration (#onboarding)
Required checkbox Acepto los Términos de uso y he leído la Política de privacidad / I accept the Terms of Use and have read the Privacy Policy, with links (new tab) and the version. Continue is blocked without it (inline error, focus moves to the checkbox). The sample-data button never ticks it.
Configuración → Legal y privacidad (#admin/legal)
Desktop sidebar item and phone account sheet row. Shows links, versions, and Términos aceptados: versión X el <fecha> with who accepted. If LEGAL.terms changes, it asks the administrator to accept the new version (history is kept in ORG.consentLog).
Other links
Login, plans page, leader Mi grupo, leader account sheet, desktop sidebar footer, landing footer and waitlist note.
Production requirement. Store acceptances server-side in an append-only table terms_acceptance { id, church_id, admin_user_id, terms_version, privacy_version, accepted_at (server time, UTC), source, ip?, user_agent? } (IP and user agent are optional, decision pending). Never trust the client timestamp. On sign-in, compare the latest accepted versions with the current ones and block the admin dashboard with an Accept new version screen until accepted. Keep every version's text (immutable, addressable by version id) so an acceptance can be reproduced. Leaders do not accept; the church does through its administrator.
Permissions the policy describes (verify on the server):
Data
Leader
Other leaders
Admins
Visitors
Weekly reports (with attendee names)
own group only
no
all groups
no
Group address + map point
own group (can edit)
no
all (private map)
no
Map tab
none
none
yes
no
Leader list and access codes
no
no
yes (owner manages admins)
no
Giving page #give/…
shares own group link
no
configures
church name/logo/group name only
In the prototype these limits live in the UI over localStorage data; a leader could read other data from the browser. The API must enforce them per request (list = admin all, leader own; meeting_location writes by leader limited to own group; list_meeting_locations admin only).
All admins see everything (no per-admin scopes); Permisos por iglesia for the network plan is future.
Report free-text fields (notes, prayer, fasting names, absent names) can hold sensitive data; children are captured as a count only.
Fonts are loaded from Google Fonts on the landing and the app (visitor IP goes to Google): self-host Inter before launch if the policy should say no third-party requests. A production map (OpenStreetMap tiles) also discloses the viewer's IP.
Faith Layer Software · Yelevo LLC · Prototype and handoff generated from the same source as index.html. Source repo path: /workspace/faithgroups-app-prototype.