Session 11: Beta Feedback Fixes
Date: 2026-03-02 Focus: Sheri's beta testing feedback — 8 bugs + 2 discussion items + one-pager
Context
Sheri conducted beta testing and sent feedback with 8 issues and 2 discussion items. The core problem was architectural: the submission model stored one database row per prompt answer (not per contributor), causing tribute counts, PDF layout, and preview to all treat each individual answer as a separate "tribute."
Beta Feedback Traceability Matrix
| # | Type | Sheri's Feedback | Root Cause | Fix Applied | Files Changed | Deploy Dep. | Status |
|---|---|---|---|---|---|---|---|
| 1 | Bug | Anyone logged in can see all books (titles visible including test books) | RLS policy "Public can view books by share code" uses USING(true), returns all rows to any authenticated user |
Added .eq('owner_id', session.user.id) filter to dashboard query; kept broad RLS for anonymous contributor form access (defense-in-depth) |
dashboard/index.astro |
None | Done |
| 2 | Bug | Prompts aren't included — e.g., "one word to describe" just shows the word without context | Submission data pipeline didn't fetch or pass promptText to PDF or preview |
Added promptText to submission data; PDF shows italic prompt label above each answer; preview does the same with [Name] replacement |
TributeBookPDF.tsx, preview/[code].astro |
None | Done |
| 3 | Bug | Lets you upload 5 photos but only one shows in preview/PDF | Photos attached only to first submission per contributor (i === 0 logic); each prompt answer was a separate submission |
After grouping by contributor, all photo_urls consolidated into one array per contributor; preview shows full gallery |
TributeBookPDF.tsx, preview/[code].astro |
None | Done |
| 4 | Bug | Photos aren't oriented correctly | @react-pdf/renderer doesn't apply EXIF rotation from raw JPEG bytes; phone photos often have EXIF orientation metadata |
Always re-encode through HTML canvas before upload; modern browsers auto-apply EXIF on canvas draw, baking correct orientation into output pixels | b/[code].astro |
None | Done |
| 5 | Bug | Each question is a separate page instead of compiled per contributor | One DB row per prompt answer; PDF and preview treated each row as a separate "tribute" with its own page/card | New ContributorGroup interface; groupSubmissions() utility groups by name+relationship key; one PDF section per contributor with all responses + photos |
TributeBookPDF.tsx, PDFDownloadButton.tsx, PDFGenerator.tsx, preview/[code].astro |
None | Done |
| 6 | Bug | Each question counted as individual tribute vs. everything from a contributor | Dashboard counted submissions.length (rows) not unique people |
Changed to new Set(submissions.map(s => name+email)).size; PDFGenerator shows contributor count |
dashboard/[bookId].astro, PDFGenerator.tsx |
None | Done |
| 7 | Bug | Invitation link can be used more than once by same person (duplicate tributes) | No check for existing submissions; every visit created new rows | checkExistingSubmissions() for signed-in users; pre-populates form; submit updates existing rows instead of inserting; new RLS policies for UPDATE + SELECT |
b/[code].astro, migration SQL |
RLS migration | Done (needs migration) |
| 8 | Bug | PDF says "sayitnow.com" (wrong domain) | Hardcoded old domain in PDF back cover and preview | Changed to sayitnowbook.com in both locations |
TributeBookPDF.tsx, preview/[code].astro |
None | Done |
| 9 | Discussion | Need to finalize book and send to print | No "complete" workflow; book stayed in active status forever |
"Finalize Book" button sets status to published; green banner + prominent PDF download; "Reopen for Contributions" to revert; confirmation dialog |
dashboard/[bookId].astro |
None | Done |
| 10 | Discussion | Pricing shows "/book" — confusing re: physical books | Price displays said $29/book implying physical book included |
Removed /book suffix; added subtitle clarifying digital-only with separate print option; updated feature lists in both stripe config and pricing page |
pricing.astro, stripe.ts |
None | Done |
| 11 | Extra | One-pager for Sheri to share with potential customers | N/A — new deliverable | Standalone print-ready HTML following notes.ath.how pattern; system fonts, @page print styles; sections: hero, how it works, stats, occasions, pricing, CTA |
landing-site/one-pager.html |
None | Done |
Detailed Fix Notes
Bug #1: Dashboard showing all books
- Added
.eq('owner_id', session.user.id)filter to dashboard query - Root cause: RLS policy
"Public can view books by share code"withUSING(true)was overly permissive - Defense-in-depth: query filter + RLS (RLS kept for contributor form anonymous access)
Bug #2: Prompts not included in PDF/preview
- Added
promptTextfield to submission data pipeline - PDF now shows each prompt question as an italic label above the answer
- Preview page also shows prompt text with
[Name]→ honoree name replacement
Bug #3: Only one photo showing
- Photos were only attached to first submission per contributor (
i === 0logic) - After grouping by contributor, all photos consolidated into one array
- Preview shows full photo gallery per contributor
Bug #4: Photo orientation wrong
- Root cause:
@react-pdf/rendererdoesn't apply EXIF rotation from raw image bytes - Fix: Always re-encode images through HTML canvas before upload (modern browsers auto-apply EXIF rotation on canvas draw)
- Changed from conditional compression (>8MB only) to always-process
Bug #5: Each question = separate page
- Major PDF rewrite: new
ContributorGroupinterface groups all responses per person - Each contributor gets one page section with header, all responses, and all photos
- Table of Contents lists unique contributors
groupSubmissions()utility function for data transformation
Bug #6: Wrong tribute count
- Dashboard now counts
new Set(submissions.map(s => name+email))for unique contributors - PDFGenerator shows contributor count, not submission count
Bug #7: Link reusable by same person
- Added
checkExistingSubmissions()for signed-in users - Pre-populates form with previous responses
- Submit in edit mode updates existing rows instead of inserting
- New RLS policies:
"Contributors can update own submissions"and"Contributors can view own submissions" - Requires migration:
20260302000001_fix_books_rls_and_contributor_updates.sql
Bug #8: PDF says sayitnow.com
- Fixed to
sayitnowbook.comin TributeBookPDF.tsx - Also fixed
sayitnow.ioin preview back cover
Discussion #1: Finalize workflow
- Added "Finalize Book" button → sets status to
published - Finalized books show green banner + "Download PDF" prominently
- "Reopen for Contributions" button to revert
- Confirmation dialog before finalizing
Discussion #2: Pricing wording
- Removed
/booksuffix from all price displays - Added subtitle: "All plans include a digital book with downloadable PDF. Physical printing available separately through our print partner."
- Updated feature lists in stripe.ts and pricing.astro
- Premium tier: consolidated "High-resolution PDF" + "Print-ready format" into one line
One-Pager (extra)
- Created
landing-site/one-pager.html— standalone print-ready HTML - Follows notes.ath.how pattern: self-contained, system fonts,
@pageprint styles - Sections: hero, how it works, stats, for creators/contributors, occasions, pricing, CTA
- Sheri can print to PDF or share the URL
Decisions Made
| Decision | Context |
|---|---|
| Group by contributor in PDF | One section per person, not per question answer |
| Canvas re-encode all images | Bakes in EXIF orientation for PDF compatibility |
| Edit mode for signed-in only | Anonymous contributors can't reliably be identified for updates |
Finalize = published status |
Existing status values already include published |
| Keep broad books RLS policy | Needed for anonymous contributor form access; dashboard query filtered instead |
| Physical book pricing deferred | Sheri considering options; text changes done now, pricing structure later |
Files Modified
| File | Changes |
|---|---|
src/components/TributeBookPDF.tsx |
Major rewrite: ContributorGroup interface, prompt labels, grouped layout, fixed URL |
src/components/PDFDownloadButton.tsx |
Updated to ContributorGroup interface |
src/components/PDFGenerator.tsx |
Updated interface, counts contributors not submissions |
src/pages/preview/[code].astro |
Contributor grouping, prompt text display, all photos, fixed URL |
src/pages/dashboard/index.astro |
Added owner_id filter |
src/pages/dashboard/[bookId].astro |
Unique contributor count, finalize/reopen workflow |
src/pages/b/[code].astro |
EXIF orientation fix, edit mode for returning contributors |
src/pages/pricing.astro |
Removed /book, added digital clarification, updated features |
src/lib/stripe.ts |
Updated feature list wording |
supabase/migrations/20260302000001_*.sql |
RLS policies for contributor updates |
landing-site/one-pager.html |
New: shareable one-pager for Sheri |
Verification Summary
| Test | Result |
|---|---|
npm run build |
Pass — clean build |
| All pages return HTTP 200 | Pass — dashboard, preview, pricing, contribute form, one-pager |
| Pricing text updated | Pass — no "/book" suffix, digital clarification present |
| Contributor grouping code | Pass — groupByContributor() in preview, groupSubmissions() in PDF |
| Finalize UI elements | Pass — finalize/reopen buttons present in dashboard |
| Edit mode code | Pass — checkExistingSubmissions() present in contribute form |
| Branding URLs | Pass — sayitnowbook.com in PDF and preview |
Next Steps
- Apply RLS migration via Supabase SQL Editor
- Deploy to production (push to master)
- Sheri to test finalize workflow and PDF download
- Discuss physical book pricing for premium tier (Sheri considering)
- Review one-pager with Sheri