2026-04-06
PRs shipped
- #53 — PostHog analytics integration — merged (was open PR at end of April 5 session). Full event instrumentation on client and server, PostHog identity, Stripe data warehouse connected.
- #55 — Discord check-in notification with member context — when a member checks in, a Discord notification fires with name, tier, rank, and recent activity. Staff get context before the member reaches the counter.
- #56 — set join date to earliest Square purchase on backfill — backfill script now sets
joinedAtto the member’s oldest Square purchase rather than the script run date. Corrects historical join dates for existing members. - fix: correctly show last visit by excluding current check-in from query — last visit timestamp was showing the current check-in instead of the previous one. Fixed by excluding the in-progress check-in from the query.
Ideas & media review
Reviewed ideas.md and media.md against the vault. What’s captured and what isn’t:
Not yet in a plan doc
- Social photo sharing — “send a pic of you playing the RPG.” No doc yet. Social mechanic: members share in-character photos, tagged with guild. Possible Discord integration (post to channel when tagged).
- Pixel art shop / character avatars — “put our shop in the game world, pixel art of ourselves.” Not captured. Research-lab territory — a dungeon.club aesthetic layer where the store is rendered as a guild hall.
- Live inventory shelf — “click a shelf, see live inventory in real time.” Not captured. MeiliSearch + Medusa could power this; belongs in emporium or research-lab.
- Free tier store credit restriction — “you cannot convert store credit unless you pay.” Nuance missing from guild-onboarding-rethink: free members earn XP and can level up, but redeemable store credit (gold) requires a paid tier to unlock. Creates a clean upgrade incentive.
- Book club + purchase double XP — “buy the book and go to book club, double XP.” Not captured. Mechanic: purchase of a specific book + attendance at its book club event = XP multiplier. Party system + Hi.Events integration could power this.
- First quest: pick up your gear — “the first quest should be, come to the shop and pick up your gear.” Not captured as a formal onboarding quest. Ties into guild-achievements and guild-onboarding-flow — the intro quest that brings new members in physically.
- Tier change logging for backfill — “we can be smarter about backfill if we also record tier changes.” Insight: if we log tier change timestamps, we can retroactively attribute points at the correct multiplier when backfilling purchase history. Currently we can backfill purchases but not the multiplier that was active at the time.
- Party buffs vs guild-wide buffs — the distinction in ideas.md is more detailed than guild-potions.md. Party buffs (small group, stronger effect) vs guild-wide buffs (everyone, weaker, social flex). Stacking behavior. The “gift economy / buying a round” psychology. Should be added to guild-potions.md.
Captured (confirmed)
- Refer your friends → gold-for-xp.md (party recruit mechanic)
- Free tier signup → guild-onboarding-rethink.md
- Square auto-backfill on free signup → guild-onboarding-rethink.md
- JC business quest network → guild-quest-hub-network.md
- Buff purchase mechanic → guild-potions.md
- Character / Quests / Journal / Items / Guild nav → guild-portal-ui-mockups.md
- SCVNGR, Foursquare, Pokémon Go lessons → gamified-loyalty-prior-art.md
- BECMI gold-for-XP → gold-for-xp.md
- Goblin Slayer rank model → membership-program.md
- Media game references (FFXIV, WoW, HxH, etc.) → live in media.md as the reference doc; insights are scattered across plan docs
Guild issue triage
Reviewed all 19 open issues via GitHub MCP.
Resolved since this triage
#40 — extract escapeHtml— closed 2026-04-07#39 — webhook handlers return 200 on failure— fixed by #60 (2026-04-06)#16 — atomic increment for points/XP— fixed by #59 (2026-04-06)#24 — auth cookie dropped after billing portal— closed 2026-04-06#37 — setup scripts boot Payload against prod— fixed by #61 + #62 (2026-04-06)
Still open
- #6 — unit tests for square-customer.ts — small, pattern is established.
- #54, #46, #45 — level-up UX, Hall of Heroes, member profile
- #41 — integration tests for webhooks/checkout
- #36, #35 — multi-tenant scoping (not urgent until shop #2)
- #31 — XP transaction ledger (plan before building)
- #29, #28, #27, #19, #18 — kiosk features (post-MVP)
- #20 — dashboard e2e tests
Evening session — bug fixes and script refactoring
PRs shipped
- #58 — rename dashboard nav to Character, Activity, Quests, Rewards, Guild — aligns nav language with RPG theme.
- #59 — atomic increment for points and XP to prevent lost updates — replaced read-modify-write with SQL
UPDATE ... SET points = points + $1. Wrapped XP increment and level sync in a single DB transaction. Also fixed: member-not-found vs insufficient balance error distinction inredeemPoints, numeric coercion from Postgres, and ledger failure rollback. - #60 — return 500 on webhook processing failure to trigger retries — Square and Stripe webhook handlers were returning 200 even on processing errors, silently losing data. Now returns 500 so the provider retries.
- #61 — remove Payload bootstrap from setup scripts to prevent schema dev-push —
setup-square-discounts.tsnow uses direct Postgres viapg.Poolinstead ofgetPayload(). Prevents accidental migration push when run against productionDATABASE_URL. Copilot review feedback addressed: updated docstring, typedstore_discountasstring | numberfor pg numeric, addedupdated_at = now()to tier UPDATE, validatedDATABASE_URLbefore Pool creation, redacted credentials in error output. - #62 — make test scripts DB-free — all test scripts (
test-check-in,test-redemption,test-webhook,test-stripe-webhook,test-e2e-upgrade) now call HTTP APIs instead of importing Payload. Enabled API keys on Users collection. Scripts only need a running server + API key, no direct DB access. Also: reorganized.env.exampleby service, fixed trailing commas and docstring defaults from Copilot review.
Issues closed
- #37 — setup scripts must not boot Payload against prod DB — resolved by #61 and #62.
- #39 — webhook handlers return 200 on processing failure — resolved by #60.
- #16 — atomic increment for points/XP — resolved by #59.
Testing
- Ran
setup-square-discounts.tsagainst local and staging — confirmed no Payload boot, no migrations, group IDs written correctly. - Verified guard on
setup-square-attributes.ts— rejects non-localhostDATABASE_URLwith redacted credentials in error output.
Late session — Hi.Events API + Guild Hall
PRs opened
- #63 — Hi.Events API client library — authenticated client for Hi.Events cloud API with JWT login/refresh/cache. Fetches events, attendees, check-in stats.
server-onlyguard to prevent client bundle leaking credentials. Copilot review addressed: trailing slash normalization, partial pagination type, specific credential error messages. - #64 — Guild Hall community hub page (stacked on #63) — transforms the Guild Hall from a tier-only view into the community hub from the portal mockups. Upcoming events from Hi.Events, guild-wide activity feed (mock data for now), compact tier card, deferred section placeholders. Tier comparison relocated to
/dashboard/guild/tierssub-route.
Issues opened
- #65 — add
shopfield to Members collection + optionalguildNameon Shops — membership is shop-level, not org-level. Currently resolved throughmember.tier.shopas a workaround.
Key design decisions
- Membership is shop-level, not org-level. A bookstore in JC and one in Austin are different communities. Members join a shop. The org is invisible admin. Points/XP wallet could be org-wide (Book Off model) but community identity (guild hall, events, activity) is per-shop.
- Guild activity feed requires privacy controls. Stripped live purchases/visits/transactions — too personal to show guild-wide without consent. Replaced with mock data (1983 D&D cartoon characters). Real feed blocked until member privacy settings exist.
- Guild display name. Shops should have an optional
guildNamefield so “Dungeon Books” can show as “Dungeon Club” in the Guild Hall. Added to #65 scope. - Hi.Events event URLs require a slug. Bare
/event/{id}returns 404. Any slug works after the ID, but we use the realslugfield from the API response.
Docs added
docs/references/hi-events-api.md— API reference from actual sandbox responses: event object shape, endpoint inventory, embed widget, pagination, potential improvements.
PRs merged
PRs shipped (member-shop stack)
- #67 — add shop field to Members + guildName to Shops — nullable shop relationship on Members, optional guildName on Shops for custom guild branding, signup flow propagates shop from invite, Guild Hall reads member.shop directly. Migration adds nullable column; manual backfill required before tightening. Merged and deployed.
- #69 — make member shop field required (stacked on #67) — Payload-level required validation +
ALTER COLUMN SET NOT NULLmigration. Awaiting Copilot review; merge after prod backfill.
Issues opened
- #68 — support members belonging to multiple shops — future multi-location expansion. Single shop per member is correct for now.
Issues closed
- #65 — add shop field to Members — resolved by #67.
- #40 — extract escapeHtml — already resolved by #42 (Better Auth migration).
Additional design decisions
- Hi.Events embed widget — only shows ticket purchase flow, not useful for Guild Hall. Keep external links for now.
- Event descriptions — too long for cards (full event writeups with disclaimers). Title + date + register link is sufficient.
- Multi-shop membership — different beast from single shop field. Needs join collection or array relationship. Deferred to #68.
- Loyalty wallet scope — points/XP could be org-wide (Book Off model: earn anywhere, spend anywhere) while community identity stays shop-level. Separate decision from membership scoping.
- Button design hierarchy —
defaultfor primary CTAs,outlinefor per-item actions (register),ghostfor navigation/secondary links. - Use
gt submitfor PRs — notgh pr create. Bypassing Graphite causes stack tracking issues and branch cleanup problems after squash merges.
Staging tested
- Guild Hall shows “Dungeon Books Guild” after shop backfill
- Hi.Events upcoming events render with real slug URLs and event timezone
- Mock activity feed with D&D cartoon characters displays correctly
- Tier comparison sub-route at
/dashboard/guild/tiersworks - Migration ran cleanly on both local and staging
Action items
- Add party buff / guild-wide buff distinction to guild-potions.md
- Create plan stub for “first quest: pick up your gear” in guild-achievements.md or onboarding-flow
- Add free tier store credit restriction to guild-onboarding-rethink.md
- Add tier change logging to membership-platform.md backfill section
- Re-enable CI/CD (disabled for better-auth deploy)
- Discord OAuth — link from dashboard, not signup
- “Check your email” interstitial after signup
- Class unlock at Level 3 UI (full-screen overlay, screenshot moment)