Build log — STATUS
The running session log: everything shipped, newest first.
ACTS — build status / resume doc
Last updated 2026-08-17, pre-Steve-call (Bryan's NIGHT LIST of 9 — all shipped). Read this first to resume.
2026-08-17 — demo data + refresh lever + visit door
- /refresh — one URL purges every cached page site-wide (revalidatePath from the root layout). Hit it after any data change.
- Steve-demo data curated: 14 nonsense missions purged (jb;hbhjb etc., children first: proofs/comments/story cards); 10 HEARTFELT requests seeded (Rosa's surgery · Danny 28 days sober · Sister Agnes at St. Mary's · Grace's biopsy · the Alvarez family · Elena & Tom · Marcus 17 · Grandpa Joe at St. Columba · Nurse Kemi · the valley floods) with live praying counts (9–63) + a word of encouragement each. 31 missions total, all real.
- "Acts at a place" on the hamburger → /visit door (redirects to the freshest place-anchored request's location loop).
2026-08-17 — STEVE'S LANGUAGE RULE: you ask for an ACT
- Steve (reviewing, liked it): "Ask for an ACT — correct; ask for a prayer — incorrect." Swept en masse across every version: feed door ("Do you need an act?"), menu, cards view, /get, /p ("Someone asked for an act"), AMEN ask, MARKET door ("Ask for an act — a prayer, a candle, a visit"), Ask wizard title + posted screen ("Your ask is posted."), roles, site meta description. OFFER side (Bryan's follow-up): decision points say "Offer an Act" (feed card CTA, /m CTA, immersive rail, pray-flow entry "You are offering an Act"); once prayer IS the chosen act it says prayer ("Amen — Offer this Prayer", the /p one-tap, "Say the prayer here"). Zero residual "ask for prayer" matches; production build verified locally.
2026-08-17 — EXPERIENCE MODES (pre-meeting): you stay where you entered
- Bryan on phone: entered HYBRID, a click later he was in the classic-brown triptych. Fix: acts_mode cookie (ModeMarker set by MarketHome/AmenShell: hybrid · market · amen) — ① shared flow pages adopt the matching skin (hybrid/market → modern, amen → acts) via the skin store; ② "/app" bounces back to the experience's OWN home (meta-refresh redirect; ?skin= links escape + reset to classic); ③ the market stalls (/market/ask · offer · you) wear .hybrid-scope when the mode is hybrid. Landing embed pinned to /app?skin=acts so the hub phone never gets hijacked by the cookie.
- AskWizard's "Connect to your parish and earn a saint card" is now a LINK to /start/parish (Bryan).
2026-08-17 — THE NIGHT LIST (9 items for the Steve call, all live)
- /design opens with VERSION CARDS — 5 across: icon tile · name · 4 color swatches · identifying phrase · the metaphor at the foot (7 versions).
- $PRAY — THE MEME COIN OF MERCY, /app/coin (Bryan: a blockchain meme coin): gold coin + ticker + $PRAY/USD price (▲% since genesis), up-only sparkline, your bag / holders / market cap, tokenomics ("every act is a block", "no rug possible — the ledger is mercy"), testnet contract mock 0xPRAY…mercy. Price is deterministic from world acts; 100 pts mint 1 $PRAY. The real chain arrives with the wrapper. Linked from ladder + menu.
- CLIENT MODE — /c/steve IS the hub, filtered (v2 after Bryan: "same as my page, just fewer tabs"): the link sets an acts_client cookie and opens the real hub — identical pages, but the TabBar shows ONLY the tabs checked in Admin ("Steve's page" section, plain-form Save → activity_event latest-wins). Admin/Users/Paths etc. hidden for him (Admin is never even offerable). Header reads "Prepared for Steve" + exit; /c/exit leaves the mode. In client mode HOME leads the nav, before the Versions group. Verified in-browser both ways. New clients = new URL, zero code.
- CARDS ARE EARNED AT PLACES: completeAtPlace grants the place's saint (deterministic per mission) and the done screen reveals it ("This place gave you the {name} card →"). Widget milestone → Carlo; parish → Joseph.
- INSTALL THE APP → THE JESUS CARD: new "jesus" card leads SAINT_DECK; get_app claim grants it; MilestoneCta reveals "The Jesus Christ card is yours — pray to it →". Art: public/saints/jesus.jpg when dropped.
- CELEBRATION v3 — JESUS RECEIVING LIGHT: the award celebration is now an image of Jesus gaining light in waves until totally lit (~3.6s, halo bloom, then fades). Same Confetti contract → all award surfaces upgraded at once. NOTE: uses the shrine stand-in photo until public/saints/jesus.jpg exists (one drop fixes the celebration AND the card).
- ARTIST EDITIONS: 8 top cards carry artist credits (fictional ateliers — swap for real commissions) — ✦ chips on the deck, credit line on /card.
- THE EARN LADDER opens /app/you: pray +10 · app +50 · widget +50 · account +100 · share +100 · post a request +25 (NEW — createMission now pays ASK_POINTS) · do an act +25–250; done-states struck through.
- THE WORLD — /app/world + hub tab + menu: world events as shared intentions (world audience layer), one tap to pray with the world, and the add-a-world-event form (+25, lands in every feed). Form click-path could not be browser-tested (the preview pane's renderer died — code path is the same createMission used everywhere); SSR + feed rendering verified.
- QA: all new + core routes 200 (/c/newclient falls back to defaults); typecheck clean throughout; each item its own commit.
2026-08-16 — demo-day batch (Bryan shows Steve tomorrow)
- Confetti v2 = a centered EXPLOSION, longer (Bryan): pieces detonate from mid-screen on their own angle, arc out, then gravity + fade, ~3–4s (was top-rain ~2s).
confetti-boomkeyframes with per-piece --tx/--ty/--fall; two-phase easing (blast → gravity). - Confetti now fires on EVERY points-gaining activity. Newly wired: PrayButton (+10 tap) · StrippedPray (/p and /free one-tap) · CompleteProof · MilestoneCta claims · VisitFlow CHECK-IN (celebrate-per-step state so mere navigation never replays) · PrayFlow invite milestone (+100 on share) · helper-offer joins (new JoinOfferButton client component replaces the server
<form action>in OfferCard + MarketHome — "Sent ✓" + burst). Funnel steps that navigate away on award (signup/parish/location) don't burst — nothing to see mid-redirect; their next page shows the ledger. - FREE PRAY — the app-free social page + hub tab (first in Versions): /free is the evergreen link (redirects to the freshest open request's /p one-tap page — no install, no login, works in in-app browsers). Tab explains the funnel + live embed + share row.
- Map strip pills fixed for embeds (Bryan's screenshot): chips were mid-wrapping ("1,101⏎praying"). Now whitespace-nowrap + tighter metrics + "6 at places" copy — whole pills only, never broken text.
- QA sweep for demo day: all 46 static routes + /p /m /pray /visit /card/[slug] with live ids → 200; bad ids → 404; typecheck + console clean; /free tap-to-pray verified end-to-end with the new explosion.
2026-08-15 — donate prompt made prominent
- DonateLink (bottom of /m request pages) upgraded from the quiet gray strip to a tinted brand-bordered card: filled heart badge · "Give to keep Acts free" bold + "every gift keeps prayers free for everyone" · "Give →". Still quieter than the pray/app CTAs; recolors per skin. Verified on /m (TikTok skin, mobile).
2026-08-15 — "Get link" share row under every hub screen
- components/ShareVersion.tsx sits under EVERY phone embed (baked into PhoneEmbed): Get link (clipboard + execCommand fallback) · Text (sms:) · Email (mailto:) · native Share… where supported. The body reads "Try this — {version name}: {url}" — Steve sends it, the recipient opens it on their phone and it just works (guest-first web app).
- Gotchas fixed while building: navigator/window checks in render caused an SSR 500 + hydration mismatch → origin + canShare resolve in useEffect (SSR falls back to the prod origin for the link bodies). New
mailicon in the set (the typed /design meanings record caught it).
2026-08-15 — hub embeds fixed: one PhoneEmbed, true-width viewport
- Bryan: "versions all have scaling issues with buttons and what not." Root cause: the 375px-wide iframes lose ~15px to the desktop scrollbar gutter INSIDE the frame, so the app laid out at ~360px — chips wrapped ("1,100 praying", "the vigil"), the map info strip collided, buttons crowded.
- components/PhoneEmbed.tsx is now THE phone frame (411×852 inner viewport = iPhone width + gutter slack, scaled 0.73 to the 300px card): replaced the five drifting copies (landing, triptych, amen, market, hybrid reviews). Verified: chips single-line, map strip fits, all three Triptych panels clean.
2026-08-15 — TRIPTYCH tab + Expo named in next steps
- /triptych-review — "Triptych" leads the Versions nav group: the MAIN app's three skins side by side like altarpiece panels (Classic · Apple · TikTok), each a live phone embed of /app?skin=… with a one-line character note. The name = the clever word for "one scene, three panels".
- Landing next-steps step ① now names Expo as the wrapper; step ② Astro clarified as the builder the original prototype was made in.
2026-08-15 — hub: Steve's landing page + the Design system page
- "/" is now WHERE STEVE LANDS (Users moved to /users): left column = the product in the simplest terms (Ask/Act/See it/Keep going); right column = the latest build LIVE in a phone frame (iframe of /app) with "Open the latest build →" + the share URL under it. Below: Latest build (renders STATUS.md's newest section via lib/md.ts + "Full build log →"), Tech specs (stack, data, hosting, skins, guests-first, what's mocked), and Next steps (① add the native wrapper ② get into Astro ③ TestFlight).
- /design — the Design system page, first section ICONS: all 37 glyphs from components/Icon.tsx, each on its own card (SVG · name · intended meaning), wrapping rows; MEANING is a typed Record<IconName,string> so a new icon without a meaning fails the build. TabBar: + Home, Users → /users, + Design system.
2026-08-15 — hub cleanup: Versions group + the Docs reader
- TabBar regrouped (Bryan): "Versions" section (Amen · Market · Hybrid · Widgets) FIRST, a pipe divider, then Users/Paths/Lists/Images/Saints/ Gamification/Docs/Admin.
- /docs — one readable content model for every document: left rail groups "Bryan's docs" (Phase 1.2 lists · prototype estimate · audit framework) and "the build's docs" (STATUS · DESIGN · SCHEMA · IMAGE-GUIDE);
?doc=keypicks, whitelisted server-side. Markdown renders vialib/md.ts— a tiny renderer (headings/lists/bold/italics/code/links/blockquote/hr; buffers wrapped bullets so bold spanning lines still formats;.doc-prosestyles in globals). All 7 docs verified rendering with zero raw markdown leaking.
2026-08-15 — ICON design pass (Bryan: same type of icons, clear to all ages)
components/Icon.tsxis THE icon system: ~35 hand-tuned stroke glyphs (24px grid, stroke 2, round caps,currentColor→ recolors per skin). Platform emoji are GONE from UI chrome — every button, nav, chip, tile and menu row draws from this one set. Add icons there, never inline.pray= Bryan's praying hands (the Noun Project logo mark, hands only, filled) — after the stroke attempt "did not read as hands". Used everywhere: Offer Prayer CTAs, praying counts, navs, map markers.- Data now carries icon names, not emoji: OFFER_ACTS/PLACE_ACTS/MILESTONES (scoring), MOMENTS, PRAYER_MODES/ROSARY_MYSTERIES (prayers), BADGE_ART, ACT_IMAGES, SKIN_VOCAB.rankIcon.
BigCta icon="candle"resolves names (falls back to raw text). Leaflet markers = inline SVG strings (MARK_SVGin ActsMap; sized via.acts-map-emoji svgin globals). - Swept: feed (cards/header/map/menu/home-nav), Ask wizard, pray flow + act hub, candle/rosary/visit loops, moments, donate, parish, you/map/cards pages, AMEN (nav/rail/vigil/ask), MARKET (doors/feed/nav/stalls), badges (medal seal + editor). Kept: content emoji (iOS mock home screen), trailing ✨ in reward copy.
- MARKET wording: "market/marketplace" was the CONCEPT name, not app copy (Bryan; he likes "Home") — tagline now "give help · receive help", nav tab "Home", "Post my offer", "Back home", "How it works". Routes + Steve tab keep the name. Hamburger added to the market chrome (MarketHome header + MarketTopBar → MenuSheet with an
inkprop for non-feed scopes); HYBRID inherits it. - Verified in-browser (mobile, all three skins + amen + market + hybrid): feed, menu sheet, prayer choice, act hub, check-in loop. Console clean.
2026-08-14 — confetti when you win points
components/Confetti.tsx— zero-dep CSS confetti burst (32 pieces, token colors so it recolors per skin — violet on TikTok, gold/vermillion on Acts). Mounting it = the trigger; it rains once (~1.3–2.2s per piece) and fades. Keyframes +prefers-reduced-motion(hidden) live in globals.css (.confetti-piece,confetti-fall).- Fires on every points win: PrayFlow act hub (prayer offered) + Offering sent · VisitFlow act logged + COMPLETE at place · MomentJoin joined · AmenVigil joined · AmenApp card Amen. Verified in-browser on /moment/evening (mobile, TikTok skin) — burst plays over the joined screen, console clean.
2026-08-13 — the ACT LOOPS session (Bryan's spec, all verified in-browser)
- PRAY flow rebuilt as a loop (
components/PrayFlow.tsx): offer → encouragement → choose your prayer (💗 Heartfelt · ✝️ Lord's Prayer · 🕊️ Saint's Prayer —lib/prayers.ts) → full-screen prayer mode per choice → ACT HUB: add candle/rosary/fasting/novena, each pays viaaddDevotionAct(repeatable, running total, ✓ done-states) → Complete → share screen; first share claims the new invite milestone (+100) (MILESTONES.invite). - Process flows:
CandleFlow.tsx(prepare → tap-to-light CSS candle.candle-*in globals.css, flicker + glow keyframes, optional dedication → comment) ·RosaryFlow.tsx(mystery set by weekday fromlib/prayers.ts→ 5 decade screens w/.beadprogress). Both reused inside the location loop. - LOCATION LOOP (
components/VisitFlow.tsxrebuilt): plan screen ("You've chosen an act at {place}" + 🔔 mock arrival reminder;?here=1skips) → map + "Arrived at {place}" strip → Check in (+25,checkInAtPlace) → Actions at {place} (PLACE_ACTSin scoring.ts: candle 50 · prayer 25 · rosary 150 · Mass 200 · adoration 250 · tend 100) — each act has its OWN screen (candle/rosary = full flows; pray/Mass/adoration/tend = per-act guidance) → "Make it real" log (photo = 2× base + 1,000,logPlaceAct) → share moment → next action loop → COMPLETE at {place} (completeAtPlace+20 + story card). /m entry: "I'm here" (→?here=1) + "Going later? reminder" link. - Gathering wall on /m (Bryan: each request is where acts+comments group up): "N acts completed • M comments" strip + all proof photos/notes + comments in chrono order (
getMissionWallin lib/data.ts;Comments composeOnlykeeps the input, wall shows the list). - Saint-card SHOP
/app/deck: "You have N cards", buy any card with 500 pts or $0.99 (mock) —buySaintCard(points path checks + deducts viaawardPointsnegative; owned =card:<slug>counters; cash = mock, no charge). Entry: /card/[slug] "You have N — get another →" + /app/you deck link.BuyCardButtons.tsx(two-tap confirm on $0.99). - Scoring canon doc →
docs/PHASE-1.2-LISTS.md(Bryan's full Phase 1.2 lists paste) + memoryscoring-canon.md.lib/recognition.tsgained genericawardPoints(actor, pts, counters)(badges included; offer acts now use it). - Feed nav tightened: filter row = All/Parish/World/Live short labels, justify-between, snug
.feed-scope .feed-filter— fits 375px, no side-scroll. - CITY_COORDS + pilgrimage cities (Vatican City, Lourdes, Fátima, Mexico City, Knock, Assisi) so seeded place missions map correctly.
- Verified end-to-end on the dev server (mobile 375px + desktop): pray loop paid +210 (10+50+150) + 100 invite; location loop +170 (25+125+20); card bought with points deducted 500. ShareRow extracted (
components/ShareRow.tsx). - Menu everywhere: MenuSheet added to /app/you · parish · deck · donate · role doors (active states; menu "Saint cards" now → /app/deck).
- /saints curation at review size: each card renders LARGE (aspect 3/4, 3-up grid) with name overlay; the image itself is the upload target ("↑ Click to upload correct art") + remove-upload; Bryan/Steve drop the real card art there (or
public/saints/<slug>.jpgstill wins by convention). - Feed + visit restructure (Bryan's batch): ① visit actions list shows 3 + "See all N acts" → bottom-sheet MODAL (requests stay in view); requested cards now PROMINENT (.card, serif name, ⛪ parish tag, 🙏 praying count + "asks: {act}", gradient "Serve them →"), ordered place → parish → most popular. ② Feed: "Do you need a prayer?" small box at top → seeker; parish connect = prominent CARD below the map (connected: name + Edit + "Open your parish room" BigCta; else "Connect with your local congregation" + Find-your-parish BigCta); "Going on a pilgrimage?" card → offer wizard. FeedHeader's old parish line removed. ③ AskWizard: "Where should it happen? 🌍 Anywhere / 📍 At a location" chooser (place field only when at-location; anywhere clears place_label).
- Location loop = a true multi-person session: the header (📍 place + accumulated points chip) is STICKY over the scrolling acts; selecting from the "Requested while you're here" feed no longer navigates — it switches the ACTIVE person in place (scrolls up under the pinned location, actions title reads "Serving {who}", per-person act done-keys, log targets their mission). One check-in, many people served, one COMPLETE.
- Medals in ALL versions + requested-acts feed at locations: the devotional medal set now renders on /amen/you (Honors, 3-up) and /market/you (Honors, both-sides page) with real earned state + uploaded-art overrides — every app version shares one badge system. The location loop's actions screen now carries "Requested while you're here 📥": up to 6 asked acts (person · asked act · text · +25 chip) so a helper picks up new needs without leaving the church; taps jump into that person's loop at the place.
- Badges v2 — the SAINTS aesthetic (Bryan: v1 read as 90s clipart): medals are now devotional photographs in double GOLD bezels on parchment (
--holy-gold/--holy-parchment), sepia + candlelight vignette, glyph seal at the foot, display-italic serif names, ✦ gold captions — the holy-card language worn as a medal. Default photo per badge fromphotoCategoryin lib/badges.ts; the medal itself is the click-to-upload target on /gamification (hover "↑ upload art", reset to default). - Badge art is UPLOADABLE: each medal on /gamification has "↑ art" (upload →
uploadImage→saveBadgeArt; latest-winsbadge_artrows in the activity log — the saint-card pattern) + "reset" back to the glyph. Uploaded art renders clipped inside the medal disc (rosette frame stays, so the set keeps reading as a family); /app/you honors overrides viagetBadgeArtOverrides. Verified upload→render→reset live. - Badge MEDALLIONS (
components/BadgeMedal.tsx+lib/badges.ts+--medal-*palette): the 11 badges are now a cohesive SVG medallion set — scalloped rosette seal, jewel tone + glyph each, metal ring, glass shine, ribbon tails; earned = color, locked = ghosted 🔒. Front and center at the TOP of /gamification ("The badge set") and on /app/you (3-up medal grid, real earned state). Old text-row badge lists removed. - Logo trial:
PrayerMark(Bryan's praying-hands SVG, Noun Project — license before production) swapped into the Wordmark lockup, currentColor + breathing glow; one-line revert to FlameMark. - 2026-08-14 sweep: ① Feed polish — FeedCard = ONE card (who + intention + CTA inside; feed-list hairlines → space-y-5 wherever FeedCard renders), crosshair locate icon (not a paper airplane),
.btn-bigrefined (centered icon+text group, layered shadows + inset highlight, tighter metrics so "Offer Prayer" never wraps beside the 💬 tile). ② HYBRID (/hybrid+ hub tab): THE MARKET's exact components re-skinned modern via.hybrid-scope(--mkt-* remap: cool paper, blue need / green help, sans voice) — proof the concept re-skins without a rewrite. ③ Art direction panels on Amen/Market/Hybrid review tabs: upload per category (hands/candle/church/shrine/pilgrimage/portrait) →app_image; uploaded pools OVERRIDE stock Unsplash on concept surfaces viagetPhotoPools+pickFromPool(verified end-to-end: uploaded church art appeared on /hybrid need cards; hide = setImageHidden). Saints tab already had its own upload; /images = the general gallery. - THE MARKET is a WHOLE app:
/market(sticky collapsing doors, one zipped need/offer feed, four-stall nav Market·Ask·Offer·You) ·/market/ask(seeker stall → real createMission → share) ·/market/offer(the signature stall: place pills from the formal catalog + act chips compose the sentence "I'm headed to [PLACE] — who wants [ACT]?" → real createOffer; verified live end-to-end) ·/market/you(both sides of you: given=green Grace/level/cards, asked=vermillion your needs gathering, via getMyAsks). Shell =components/MarketShell.tsx. Hub tab embeds all four live. - THE MARKET — the two-sided 30–45 concept (
/market+ hub tab "Market"); replaced DAYLIGHT same-day (Bryan: "I hate it… angry fruit salad… missing the 2-sided marketplace"). Discipline: paper + ink + photography + exactly TWO colors (needs = deep vermillion--mkt-need, helpers = deep green--mkt-help). Front page IS the market: "I need help / I can help" doors, pulse chips, Helpers on the road (real helper_offer rows, one-tapjoinOfferActionjoin — verified count 1→2) above Open needs (photo cards → pray/visit loops), how-the-market-works both sides. Directions now: Classic · AMEN (young/vigil) · THE MARKET (30–45/two-sided). - AMEN is now a WHOLE app + hub tab "Amen" (
/amen-review, live iframe embeds):/amenstack ·/amen/ask(one-screen ask → real createMission → "watch the Amens gather" + share) ·/amen/vigil(moments in the dialect, real joinMoment) ·/amen/you(flame/Grace/level/card shelf, real data). Shared chromecomponents/AmenShell.tsx(AmenHeader vigil bar + AmenNav three verbs). Everything hits the real backend. - AMEN — the next-gen concept (
/amen, linked from /paths): Bryan's "coolest new designer" brief — younger grammar + parent-proof reverence, instantly legible to every Christian. Full-bleed vertical prayer stack, ONE word as the CTA (Amen = the universal liturgical act, +10 via the real prayForMission), side rail 🕯️📿⤴ into the real act hub/invite, vigil bar (live praying count + moment chip), three-verb nav (Pray·Ask·You), candlelit--amen-*tokens (never pure black), design-notes screen at the stack's end (brand: keep lowercase acts + "say amen."; rename candidate if ever wanted: EMBER). A new face on the same body — all real data/actions. - LIVE MOMENTS — the synchronous act (Bryan: group live events, full in all feeds + a join path):
lib/moments.ts= code-defined daily world moments (Morning Offering 8:00 · Noon Prayer 12:00 · Evening Peace 20:00, 20-min live windows, never empty).joinMomentaction = tap points ×streak; joins are activity_event "moment_join" rows, count-per-day = the live counter (getMomentJoinCount).MomentCard(ticking countdown → LIVE pulse) pinned on /app, /app/cards, /app/parish;/moment/[key]= the gathering screen (countdown/LIVE, avatar stack, join +10, "you prayed together" + share). Pastor-created + parish-scoped moments and push reminders = next phase; the widget's top ladder rung now has something true to show. - Hub "Widgets" tab (
/widgets): 9 iOS home-widget INCENTIVE mockups for Steve — streak flame · pray-at-noon · Today in the Church (the daily feast/season content lives HERE now, not the feed) · Grace & level · next saint card · needs near you · novena companion · answer-one-ask · invite. WidgetKit sizes (158² / 338×158), candlelit via.feed-scopetokens; each with "what it pays / when it fires" notes. Real widget = native Swift later./widgets/add= the iOS add-a-widget PROCESS in 5 phone-frame steps (touch & hold → + → gallery → Add Widget → on the home screen) + the metaphor note: widget = vigil candle, the +50 retention moment. - /app/donate rebuilt in the feed dialect (
components/DonateFlow.tsx): serif hero, amount pills → Give BigCta, sponsor-a-pilgrim pledge cards (10¢/act · $1/pilgrimage-day), thank-you state. Still a mockup — no charge.
2026-08-12 sweep — old screens → new design (DONE)
- Ask wizard rebuilt (
components/AskWizard.tsx, feed-scoped at/app/seeker): big Prayer intention card + Candle/Church/Cross/Rosary grid (Cross/Rosary map to acts over theprayerimage — DB enum unchanged), NAME field w/ floating label (.field-floatin globals.css; resting label plays the placeholder), relationship pills, progress bar, BigCta nav, PrayFlow-style celebration. - /m/[missionId] = the feed card opened: avatar-ring who-row, serif intention card,
OfferPrayerCta(new client comp — BigCta →/pray/[id]with skin vocab) + BigCta "Get the app". One-tap PrayButton replaced by the PRAY flow. - /app/you + /app/parish + /manage feed-scoped; parish lists now render
FeedCard(not MissionCard); saint-card gold hex →var(--color-brand). - /paths: feed hero + Cards/Immersive as 2-up thumbs. Demo content:
scripts/seed-demo-missions.mjs(idempotent; Sarah's Mother 24🙏 · parish storm candle 12 · world peace 57). capture-previews.py sets acts_city/acts_parish cookies → captures aren't zero-state. All 9 re-captured. - View toggle cleanup:
/app/cardsfeed-scoped (FeedCard + missionCopy, underlined sort tabs, parish chip from cookie); ImmersivePanel now uses OfferPrayerCta into the PRAY flow + t-hero (killed atext-[2rem]).lib/mission-copy.ts= display copy for every feed-card surface; zero counts read "Be the first to offer this ✨"..feed-list= hairline between feed items (feed/cards/parish). Social share row (Messages/WhatsApp/FB/X/Copy) on the PRAY "sent" screen. - Hamburger menu (
components/MenuSheet.tsx): the Figma ≡ on feed/cards/map/immersive; right-side sheet with all destinations; HomeViewSwitch deleted. Overlay zIndex 1200 (beats Leaflet panes). - Flame logo everywhere: LogoMark → FlameMark (currentColor); ⚠️
app/icon.svgSHADOWSpublic/icon.svgat /icon.svg (Next metadata convention) — both now carry the flame-on-brown app icon. - /paths funnel strip: "The path in — tap any step" — 6 numbered, clickable step thumbs per skin (capture-previews.py shoots them; mission id resolved from the live feed).
- ⚠️ Vercel gotchas: root tsconfig must exclude
native/(react-native types absent on Vercel → 3 failed builds); when a push doesn't trigger a deploy,npx vercel --prod --forcefrom repo root. - TestFlight Option A wrapper BUILT (
native/): Expo SDK 57 WebView shell around the live app — native share bridge, external-link handoff, flame icon + candlelit splash (scripts/gen-assets.py), lib/theme.ts token source, com.actsventures.acts, eas.json. expo-doctor 20/20. 🔴 NEXT: Bryan runsnative/RUNBOOK-testflight.md(Apple Developer enroll → eas login → build → submit → add Steve as internal tester). Web deploys need NO new build; Option B native screens replace the shell in the same TestFlight app later. - The loop closes both ways (gap sweep 1-4): ① Asker loop — /app/you "Your asks" (getMyAsks: counts + words back) + markAnswered action → status=completed + story card. ② Novena in OFFER_ACTS (+100, ACT-NVN ×9 → Novena Companion) + "Pray at noon" join-at-time card in parish room. ③ scripts/seed-local-parishes.mjs — 4 parishes + 5 local place rows, missions back-linked by label. ④ ~~ChurchDayCard/liturgical~~ REMOVED 2026-08-13 (Bryan: not asked for, didn't land) — restore from git if a feast-day surface ever comes back.
- Ask = the Figma design (acts playground → "Prayer Request Designs" frames, node 18:1280 + Make v64): header w/ brand mark + ACTS·SEEKER + progress dots, left serif title, glowing PRAYER card ("Select an intention to ask for"), 2×2 devotion grid (emoji-beside-label), ✍️ inline-icon name field, short pills (Mom/Dad/BFF/Community), ⛪ parish toggle (sets audience_layer=parish; Self-only → me), sticky Next → bar.
- Photo avatars:
components/Avatar.tsx+portraitcategory in lib/photos.ts — every profile circle (feed header, feed cards, /m, parish stacks) is a deterministic portrait photo in the ring color; same seed (name) → same face everywhere. - Place-based act path:
/visit/[missionId](components/VisitFlow.tsx) — "We see you're at {place} — check off the visit?" → add photo (+1,000) + word back → completeMission scores it + story card. Entry: "📍 I'm here" on /m's Where card + /app/map rows. GPS itself is native-app phase; web starts the flow from the place's screens. - Final port: OfferWizard rebuilt like AskWizard (feed-scope, progress bar, BigCta, serif celebration; WizardShell now unused);
/app/map, supporter + advocate doors feed-scoped (advocate cards use missionCopy; StoryCard FB hex → btn-pray). The whole/app/*surface is now the new design — no Phase-1 screens left.
2026-08-12 late session — design system · PRAY flow · real map
- Design system LOCKED:
scripts/guard.mjsprecommit ratchet (no NEWtext-[Npx],tracking-[…], raw hex;--audit= 107 hex baseline to burn down; escape:git commit --no-verify). Contract merged intoCLAUDE.md. ONE button system:.btn48pt /.btn-big72pt (title+reward subline) /.btn-icon48×48, icons 22–24px, pills 44pt. Feed geometry now matches the Figma guides (points t-title, map 220pt, 40pt item gaps, Classic = underlined text tabs via.feed-filter). - REAL MAP:
components/ActsMap.tsx— Leaflet + free CARTO tiles, NO token ($0; swap TILE_URL + token for Mapbox later). Themed per skin (Classic = dark_all + sepiaacts-map-candlelit, Apple = light_all, Night = dark_all). Emoji divIcon markers;CITY_COORDSfor the 4 location-step cities;fadeAnimation: falseREQUIRED (tiles stall at opacity 0 under React double-mount). Feed card 220pt static;/app/mapinteractive 420pt. - PRAY flow (Bryan's Figma guides): FeedCard CTA →
/pray/[id]→components/PrayFlow.tsxstate machine: offer summary + add an act (candle +50 / fasting +100 / rosary +150,OFFER_ACTS→ badge counters viaawardOfferAct) → encouragement note (suggestion pills → comment row) → choose saint (deck cards,lib/saint.tsnow hasprayertext) → prayer mode (full-screen saint card) →completeOfferaction (tap points + act bonus + comment + saint in activity log) → offering sent → share → return to feed./p/[id]invite landing stays one-tap (funnel top). BigCta= THE button (cf1f497): LARGE icon left, two stacked rows right (title / reward), 64pt. Never hand-roll a big CTA — use the component.
🔴 NEXT SESSION — new-design sweep (Bryan: "all the Ask etc screens are old")
New design (feed-scope + BigCta) covers ONLY: /app feed · /pray/[id] · /p/[id] · /start/* · /get. Everything else is still the old Phase-1 look. Sweep order:
- Ask wizard (/app/seeker) → Bryan's Apple guide: big intention card (Prayer primary) + Candle/Church/Cross/Rosary grid, NAME field w/ floating label, relationship pills, progress bar. Feed-scope it.
- Act detail /m/[id] → feed-card look + BigCta.
- /app/you + parish room/manage → feed-scope + BigCta.
- /paths thumbnails (Bryan asked, unfinished): seed 2-3 rich demo missions ("Sarah's Mother — healing…", parish storms candle) via service-role script, set acts_city/acts_parish cookies in scripts/capture-previews.py so captures aren't zero-state, layout = feed hero + cards/immersive as 2-up thumbs, then re-capture.
Where it lives
- Live: https://acts-ten.vercel.app · Deploy =
git push origin main(Vercel auto-deploys ~1–2 min). - Repo: github.com/AutoMaticDelight/acts · Supabase project in
.env.local(gitignored; also set in Vercel). - Local dev:
npm run dev(or preview serveracts-devon port 3200). Never needs Docker. - Verify a deploy: poll a route/marker, e.g.
curl -s -o /dev/null -w "%{http_code}" https://acts-ten.vercel.app/<route>.
Stack
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 · Supabase (Postgres + Storage + RLS).
The product path (Bryan's framing — important)
Web prototype = top of funnel: a shared web link opens on the phone, you pray in one tap, *then* it invites you to download the native app (built separately) and add the widget. The native app is its own phase (Expo / React Native + EAS → TestFlight → App Store). The web work is the design + backend spec the native build reuses. See Expo notes in chat / plan below.
The path (2026-08-12) — every step gamified
Invite → member funnel, in order (Bryan's spec, matched to the Figma feed): share link → /p/[id] stripped one-tap pray → /get?flow=1 app (+50) → widget (+50) → /start/signup (+100) → /start/parish (+150) → /start/location (+50) → /app feed.
- Milestones:
lib/scoring.ts MILESTONES+awardMilestone(idempotent — claimed state =recognition_score.category_counts["milestone:<key>"], no schema change). Actions:claimMilestone/setLocation/connectParish(city/parish = cookiesacts_city/acts_parish). Profile/app/youshows the Journey ledger + parish card. /app= the Figma feed (view one): header (avatar · points · rank chip · parish teaser · ✨Ask) + dotted map card (city chip, locate →/start/location) + filter pills (All/My Parish/World Events/Live) + FeedCards with one bigbtn-big btn-prayCTA showing the reward on its face. Older views kept:/app/cards(grid) +/app/immersive; switcher = feed/cards/immersive (map absorbed into feed)..feed-scope(globals.css) remaps tokens per skin like.admin-scope: acts=Classic candlelit gold · modern=Apple light blue · night=TikTok black/violet. Per-skin vocabSKIN_VOCAB(Grace/Devout 🕊️ · pts/MVP 🏆 · XP/Warrior 🛡️) viauseSkinVocab()from SkinScope context. Figma source: "acts playground" file.- Invites now share
/p/[id](ShareInvite on/m);/m"Keep it with you" →/get?flow=1. - Hub
/paths— the three design systems side by side, all three views as large images (real captures inpublic/previews/, re-capture withpython3 scripts/capture-previews.pyagainst the dev server;?shot=1hides the skin switcher) + a Send-link per path (opens the funnel in that skin). - Parish manager
/app/parish/manage— pastor side of the parish room: live stats, broadcast composer (postBroadcast→ broadcast table, need pills not dropdowns), QR + Send-link parishioner invite. Linked from/app/parish("Manage").
Built & live (routes)
- App (skinnable,
/app/*):/appHome (Cards) ·/app/immersive(18–25 full-screen) ·/app/map(stub+list) ·/app/[role](seeker=AskWizard, doer feed, supporter=story cards, advocate=QR broadcast) ·/app/offer(OfferWizard → significant places) ·/app/parish(room + Join) ·/app/donate(mockup) ·/app/you(guest→member ladder). - Shared:
/m/[id]Act Detail (photo, geographic+Directions, Share/Invite, completion loop trust-led, comments, subtle donate, ✦ prayer-card link) ·/s/[slug]Story Card ·/card/[id]Saint card ·/getApp Store listing mockup + widget mockup. - Control room (
/): Users · Lists · Images (gathering guide) · Saints (approve/edit/upload) · Admin (moderation).
Gamification (2026-08-11)
- Engine:
lib/scoring.ts(bonuses, levels, badge rules, SAINT_CARD_EVERY=5) +lib/recognition.ts(service-role recorder: streaks, counters, auto-badges, 10-min anti-farm). Every pray/join/complete/photo-upload is scored viarecordAct. - Saint cards = the REWARD, not per-prayer artifacts. A collectible deck (
lib/saint.tsSAINT_DECK), next card earned every 5 completions, collection on/app/you, card page/card/[slug]. Steve curates the deck on/saints. - Control room
/gamification: levels, streaks/bonuses, saint-card rule + deck, badges, editable per-item points list (updatesact.default_pointslive), top helpers. - Admin = Apple style (
.admin-scopein globals.css): SF system font, #f5f5f7, white cards, Apple blue/green/red. The app keeps the Acts brand. - LogoMark (
components/LogoMark.tsx) renders/public/icon.svg— swap that one file to change the logo everywhere. Feed is THE center — keep Home chrome slim.
Key decisions (don't relitigate)
- Ask = ONE act (OR selector); actors add any. The seeker's chosen act is a featured suggestion, not a constraint — the PRAY act hub highlights it ("what {who} asked for ✨", sorts first via
offerActForActCode) and any helper can stack any devotion. At a location the loop is open too: any act at the place, then the person-loop — "while you're at {place}" offers other people to serve from the same spot (same place → same city → any, each with the +25 check-in chip), on the logged and complete screens. - Brand: Cormorant Garamond (italic for feeling) + Instrument Sans + #ec612b vermillion. Logo = vermillion candle disc (
app/icon.svg, favicon/PWA). Ring colors: me/vermillion · another/terracotta · parish/green · world/blue. - 8pt grid + named type scale (
.t-hero/title/headline/body/sub/caption). Pills, not dropdowns (PillSelect/.pill). - Completion: ~~four candidates side-by-side on /m~~ RETIRED 2026-08-13 — the act loops (pray hub · location loop) ARE completion now; trust stays the philosophy (no tracking), CompletionMethods component kept but unmounted.
- Photography:
lib/photos.ts= curated Unsplash interim (License-free, no key), deterministic per item. Swap for owned photos later; shot list indocs/IMAGE-GUIDE.md. - Saint cards: patron saint matched to the intention (
lib/saint.ts); Steve curates on/saints; curation persists in the activity_event log (no schema change) — public/card/[id]renders curated data. - Guest→member: prototype only — a name, no credentials (never collect passwords / create real accounts).
- Design contract:
DESIGN.md(rules + full screen spec). Never regress to the generic AI look.
Data
19 tables, all seeded. Seed utilities (run cd ~/acts && node --env-file=.env.local scripts/<x>.mjs): seed-all.mjs (audit + backfill all tables) · seed-offers.mjs · seed-place-needs.mjs. Migrations in supabase/. Note: proof counting is paginated past the 1000-row cap (lib/data.ts proofCounts).
Next / not done
- Wire the
/get"download the app" invites into the "Keep it with you" sections (Act Detail,/m, wizard posted states). - Advocate broadcast wizard (pick a need → QR + link).
- Expo native app — scaffold
create-expo-app+ Expo Router + NativeWind + supabase-js; port screens reusing the Supabase backend + taxonomy + tokens. Widget = native Swift/WidgetKit (sized L). EAS build/submit needs Bryan's Apple Developer account (his step; I supply theeascommands). - Out of scope (mockups): real payments, real SMS, real widget install, real App Store submission.