Day 06 of 07
Build the results history and shareable grade links
Goal: Today you save every grade to Supabase, build a history page for users to revisit past results, and add a public share URL for each grade — the viral loop that brings new users to your product.
What to do
Create the grades table in Supabase
Add a database table to permanently store every grade result.
- In Supabase → Table Editor, click Create a new table.
- Name the table: grades
- Turn off "Enable Row Level Security" for now.
- Add these columns:
- — id: uuid, default gen_random_uuid(), primary key
- — user_id: text, NOT NULL
- — headline: text, NOT NULL
- — subheadline: text, NOT NULL
- — cta: text, NOT NULL
- — bullets: text, NOT NULL
- — result: text, NOT NULL (stores the full Claude response)
- — overall_score: int4, nullable (you will parse this from the result)
- — share_slug: text, nullable, UNIQUE constraint (check "Is Unique" checkbox)
- — created_at: timestamptz, default now(), NOT NULL
- Click Save.
- The share_slug column is how you will create a public URL for each grade — e.g. /grade/abc123.
- The UNIQUE constraint on share_slug prevents two grades from getting the same share URL.
Save each grade to the database
Update the API route to insert a new row into the grades table after every successful grade.
- Open Claude Code and paste: "Update the /api/grade route to: (1) After a successful Claude API response, extract the overall score by searching the result text for 'OVERALL SCORE: ' followed by a number — use: const scoreMatch = result.match(/OVERALL SCORE: (\d+)\/10/); const overallScore = scoreMatch ? parseInt(scoreMatch[1]) : null. (2) Generate a 6-character share slug: const shareSlug = Math.random().toString(36).substring(2, 8). (3) Insert a new row into the Supabase 'grades' table using the service_role client with: user_id (from the authenticated user), headline, subheadline, cta, bullets (all from the request body), result (the full Claude response text), overall_score, share_slug, created_at: new Date().toISOString(). (4) Return the existing grade result plus shareSlug in the response JSON: { result, gradesUsed, isPro, shareSlug }."
- After Claude Code updates the route, test a grade on localhost:3000.
- Go to Supabase → Table Editor → grades → Browse.
- You should see a new row with all the fields filled in.
- Check the share_slug column has a 6-character random string like "k4x8mq".
- Check overall_score has a number (or null if the regex did not match).
- If the row appears but overall_score is null, the regex is not matching. Paste an example result text into Claude Code and ask it to fix the regex.
Build the grade history page
Create a page where users can see all their past grades.
- Open Claude Code and paste: "Create a server component page at app/history/page.tsx that: (1) Gets the authenticated user using the Supabase server client. (2) If no user, redirects to /sign-in. (3) Queries the grades table for all rows where user_id = user.id, ordered by created_at descending. (4) Renders each grade as a card showing: the headline field (truncated to 60 characters with ... if longer), the overall_score as a coloured badge (green bg for 7+, amber bg for 5–6, red bg for below 5, grey if null), and the created_at date formatted as 'Jun 26, 2026'. (5) Each card is a link to /grade/[share_slug]. (6) If no grades yet, shows: 'No grades yet. Use the grader to see your history here.' with a link back to /. (7) Add a page title 'Your grade history' and a subtitle 'Every landing page you have graded.'"
- After Claude Code creates the page, add a link to it in your app.
- In page.tsx (the main grading page), add a "History" link in the top nav next to the Sign Out button.
- Test by visiting localhost:3000/history — you should see the grades you have already run.
- Click one of the grade cards — it should try to navigate to /grade/[share_slug] (which does not exist yet — you will build that next).
Build the public share page
Create a publicly accessible page that shows a grade result without requiring sign-in.
- Open Claude Code and paste: "Create a dynamic page at app/grade/[slug]/page.tsx that: (1) Gets the slug from params. (2) Queries the Supabase grades table using the anon key client (not service_role — this page is public) for a row where share_slug = slug. (3) If no row found, calls notFound(). (4) Displays the full result in the same five-card format as the main grader page. (5) At the top, shows a header: 'Grade result for:' followed by the headline in bold, and the overall_score badge. (6) At the bottom, shows a CTA box with: 'Grade your own landing page — free for your first 3 grades.' and a green button linking to /. (7) Exports generateMetadata that sets title to '[overall_score]/10 — Copy Grade for: [headline truncated]' and description to the Top priority fix from the result text. (8) This page must NOT require authentication."
- Test by copying a share_slug from your Supabase grades table and visiting: localhost:3000/grade/[that slug].
- Open the URL in a private browser window (not signed in) to confirm it works publicly.
- The CTA at the bottom is the most important part — every person who sees a shared grade and clicks through is a potential subscriber.
- The public share page is indexed by Google — good SEO content comes from your users sharing real grade results.
Add the share button to grade results
After every grade, show a share section with a copy link button and a pre-written tweet.
- Open Claude Code and paste: "After the grade result cards are displayed in page.tsx, add a share section with: (1) A subtitle 'Share your result' in small grey text. (2) A 'Copy link' button that copies https://[YOUR DOMAIN]/grade/[shareSlug] to the clipboard and shows 'Copied!' for 2 seconds. Use navigator.clipboard.writeText(url). (3) A 'Post on X' button that opens in a new tab: https://twitter.com/intent/tweet?text= followed by URL-encoded text: 'I graded my landing page with Copy Grader — scored [SCORE]/10. Top fix: [TOP PRIORITY FIX]. Try it free: [URL]'. Parse the top priority fix from the result text by finding 'Top priority fix:' and taking everything after it until the end of the line. (4) Style the share section with a light grey background, rounded corners, and a subtle border."
- Replace [YOUR DOMAIN] with your actual Vercel domain.
- Test the copy button — note that clipboard access requires HTTPS, so test on the live Vercel URL rather than localhost.
- Test the tweet button — it should open a Twitter compose window with the text pre-filled including the real score and real top fix.
- The pre-written tweet with a specific score and insight is far more shareable than a generic "check this out" message.
Deploy and test the full sharing flow
Get history and sharing live and verify the viral loop works end-to-end.
- Commit all changes: "Day 6: history and sharing complete". Push to GitHub.
- Wait for Vercel to deploy, then test the full sharing flow on your live URL:
- — Grade a page.
- — Click "Copy link" — paste in a new browser tab to confirm the URL works.
- — Open that URL in a private browser window (not signed in) — the result should be visible publicly.
- — Confirm the CTA at the bottom links to your home page.
- — Click "Post on X" — check the pre-filled tweet text includes the real score and insight.
- Visit /history — confirm past grades appear with score badges and dates.
- Share the updated product link with the same person from Day 2 and Day 3, or post a Day 6 update in your community.
Expected result
Every grade is saved. Users can browse their full grade history with coloured score badges. Each result has a public shareable URL. The Tweet button pre-fills with a real score and specific insight. You have a built-in growth loop.
Key takeaway
- Every shared grade is free advertising for your product. The CTA at the bottom of every share page converts viewers into users. The tweet with a specific score ("I scored 4/10 on my headline") is shareable because it is honest and specific — not just "check this tool out".