Document 01 of 14 · SPEC.md
One line: A studio of well-designed PDF templates you customize in the browser, then buy and download. Each template is composed by hand, prints true on a home printer, and is made yours in about a minute.
Tagline (recommended): Well-made PDF templates, made yours.
This document is the source of truth. It becomes the seed for CLAUDE.md when the repo is bootstrapped. Every decision below is made unless it is listed in section 11. Companion documents: ARCHITECTURE.md (how a PDF gets made, paid for and delivered), DESIGN.md (identity and the customizer), CATALOG.md (the roster), SETUP.md (what the owner creates before session one).
This is a consolidation of every earlier PDF farm attempt into one relaunch: one name, one repo, one database, one standard. Checked 2026-09-16 from the repo, the Lovable workspace, the Supabase org and DNS; the Lovable workspace and GitHub were also searched for farm, template, printable, document, certificate, invoice and studio, and nothing beyond the rows below turned up. Nothing below holds a customer, an order, a subscriber or a design worth carrying, so the replacement is a clean one.
| Piece | Today | What happens |
|---|---|---|
The repo, brentspore/artisan-pdf-studio |
A Lovable export: Vite, React, Tailwind, shadcn, PDFs rendered in the browser by react-pdf. Eight template components (two invoices, two certificates, two résumés, an award, a contract), accounts, an admin page, premium templates at $2. The memory scaffold was added in May 2026 and never filled. Last design change 2026-01-31; Lovable last touched it 2026-07-10. | Kept as the repo, replaced as the code. Done 2026-09-16: Lovable's GitHub connection was severed first, then the rebuild (the plan, the filled memory scaffold, none of the app) was merged to main as a fast-forward. The old app is in history before 4ef8d36. |
The Lovable project (91289ef8…) |
Was published and hosting the custom domain: artisanpdfstudio.com and www both resolved to Lovable's 185.158.133.1. |
Deleted by the owner on 2026-09-16, after DNS moved to Vercel and www was verified there (the domain moved at separation rather than at the end of Phase 1; DECISIONS.md). Nothing was attached to PDF Farm. |
Its database, Supabase wonwshiaormnewhwtwwn |
Managed by Lovable and not visible from the Synergy Supabase org. Tables: profiles, templates, template_purchases, user_roles. Edge functions for Stripe checkout, a subscription check and the customer portal. | Gone with the Lovable project (2026-09-16). Nothing in it was needed. |
"PDF Farm", Supabase ahjsvadwxacschqgdahj in the Synergy org |
An earlier attempt from August 2025. Eight tables, every one empty; one auth user (the owner); two public buckets holding one file; twelve edge functions including Google Docs export and logo generation; a trigger on auth.users, seven helper functions and one enum. Already paid for at $10 a month on the Pro org. |
Kept, and becomes the new site's database. Reset in place in Phase 0: the first migration in supabase/migrations/ drops every old object, the second creates the orders schema; the twelve edge functions are deleted in the dashboard; the project is renamed "Artisan PDF Studio"; a new secret API key replaces the legacy keys that earlier attempts may still hold. Nothing new is spent. |
| Stripe | An account, with whatever $2 products the old functions created. | Kept. Archive the old products; the new site creates prices inline, so nothing depends on them. |
| Domain and DNS | The Cloudflare zone. | Kept, and on Vercel since 2026-09-16: @, www and plan are CNAMEs to Vercel's project target, DNS only; www is primary and the apex 308s to it. www shows a holding page until Phase 0 replaces it. |
| The eight designs and four preview JPEGs | react-pdf components and raster previews. | Not carried over. They are the wrong kind of file for the new pipeline (the HTML template is the file), the contract falls under the no-legal-documents rule in section 5, the résumé is wave 2, and none has been printed on paper. Every subject among them is in the catalog. |
Why one database rather than a new one: PDF Farm is already in the Synergy org, already paid for, in the same region Vercel deploys to, and empty. Resetting it is two migrations and a dashboard visit, and it leaves the org with one PDF project instead of two.
Why replace rather than extend: the old build renders PDFs on the client with react-pdf, so the preview and the file were two different pieces of code and could disagree; an account stood between a visitor and a $2 file; the look was default shadcn; and the two databases between them hold zero rows of anything. Starting clean costs nothing and keeps nothing that would have needed defending later.
api/ folder (checkout, webhook, render, order lookup, draft assist, subscribe). Vercel's "Other" preset serves api/*.js beside static files with no build. That is the one place code runs on a server, and it is the only place secrets live.ARCHITECTURE.md section 4 carries the fallback (Chromium inside the Vercel function) if this ever needs replacing.claude-opus-5 by default) powers "Write it for me" on long-text fields and the hand-run copy drafting script. It is never in the checkout or render path. See ARCHITECTURE.md section 7.main. No CI build. A GitHub Action may run hand-written checks (link sweep, render smoke test) but nothing runs at deploy time. Same reading of "no build step" as measureandbuy's generators decision: hand-run design tools whose output is committed static files.human-voice lint before shipping. Template descriptions, FAQs, pin text, and every email.artisanpdfstudio/
index.html # homepage: working mini-customizer + roster
templates/
planners/index.html # category page (generated)
planners/weekly-planner/
index.html # template page, indexable (generated)
customize/index.html # the customizer, noindex (generated)
free/weekly-planner-letter.pdf # the plain version, pre-rendered, static
...
studio/ # TEMPLATE SOURCES, the actual design work
weekly-planner/
template.html # the sheet(s): plain HTML with data-bind hooks
template.css # print-first CSS, @page size, .sheet dimensions
fields.json # what the customizer exposes, with limits + defaults
meta.json # title, category, price, sizes, themes, SEO phrase
shots/ # preview.png, og.png, pin.png (generated)
assets/
css/site.css # shell only: header, footer, grids, prose, sheet frame
css/studio.css # the customizer UI
js/site.js # footer, GA4 guard, related grid (CATALOG constant)
js/studio.js # THE RUNTIME: apply(values) -> DOM; shared by preview and render
fonts/ # self-hosted, OFL only; one file per face actually used
api/
checkout.js # POST: validate values, create order, open Stripe session
stripe-webhook.js # POST: verify signature, mark paid, kick render, email
render.js # internal: template + values -> PDF -> Storage
order.js # GET: status + signed URLs for success page / email link
draft.js # POST: Claude writes a field's text (Turnstile + limits)
subscribe.js # POST: add to the Resend audience (Turnstile)
data/
catalog.json # generated index of every template (one list, many consumers)
fonts.md # append-only: face, license, source URL, date, where used
studio-src/ # hand-run generators and checks, NOT a build step
build.mjs # studio/* -> templates/* pages + catalog.json + sitemap
shots.mjs # preview / OG / pin images from the real template
free.mjs # pre-render the plain PDFs
copy.mjs # Claude drafts description/FAQ/pin text to review
sweep.cjs # drive every page at 1440 and 390, assert, fail loudly
serve.py # no-store local server (copied from measureandbuy)
supabase/migrations/ # SQL, applied by hand with the CLI or MCP
og/, pins/ # generated share images
help/ # six evergreen print-help pages (the link magnets)
license/, terms/, privacy/, refunds/ # the legal four, plain HTML
SPEC.md, DESIGN_SYSTEM.md, CLAUDE.md, .ai/memory/
Rules:
studio/<slug>/ plus assets/js/studio.js and the fonts it names is everything needed to preview and render it. Nothing about a template lives in the database. The database holds orders, not designs.template.html is the one source of the design. The customizer preview, the free PDF, the paid PDF, the preview image, the OG card and the pin are all rendered from that file. There is no second copy that can drift.studio.js sets text, swaps theme variables, toggles sections and fills repeated rows from values. A template may declare a small compute hook in fields.json (invoice totals) and that hook is the only arithmetic. Same rule as measureandbuy's diagram layer, for the same reason.data/fonts.md is append-only. Every face that ships is logged with its license and where it came from. A face that cannot be traced to an OFL or equivalent commercial-use license does not ship. This is the audit trail that makes "artisan" defensible.studio.css./templates/<category>/<slug>/, the page that ranks)copy.mjs and then rewritten by a person. Human-voice lint before commit./help/ page.catalog.json.Schema on this page: Product with an Offer (price, currency, availability, URL) and image, BreadcrumbList, FAQPage. Never an AggregateRating we did not earn. og:type is product with product:price:amount so Pinterest reads it as a Rich Pin. Every page has an OG card (1200 by 630) and a pin image (1000 by 1500), both rendered from the template itself.
/templates/<category>/<slug>/customize/, noindex)Desktop: a 380px form column on the left, the sheet on the right, scaled to fit, with a "PROOF" pattern over it. Fields are grouped (Text, Dates, Colors, Options, Logo, Paper size). A sticky top bar carries the template name, the price and the one button: "Download your PDF, $7". Mobile: the sheet on top at about 40% of the screen height (tap to expand), the form under it, a fixed bottom bar with price and button, shown until the real button scrolls into view (the measureandbuy answer-bar pattern).
Rules that make it trustworthy:
fields.json, and the runtime measures overflow inside fixed boxes. Overflow shows a plain warning on the field and disables the buy button until it fits. No vendor does this; every one of them lets you buy a certificate whose name runs off the ribbon.localStorage keyed by slug, so a phone interruption does not lose the work.fields.json marks assist: true (certificate wording, invitation lines, an "about" paragraph). It drafts into the field; it does not send anything anywhere else./order/?id=…&t=…)Polls /api/order until the PDF is ready, then shows two download buttons (Letter, A4), the order number, "sent to your email", and "Make another" links back to the category. A failed render shows a real message with the order number and the support address, never a spinner forever.
/templates/<category>/)Short intro (100 to 200 words, written for the reader, not the crawler), then the templates as sheets in a grid, newest first, with price and "free version" marked. Category pages are the internal-linking spine.
The hero is a working mini-customizer: a certificate (or the current featured template) with two fields, name and title. Type and the sheet sets your name in the display face. Same runtime, same template. Under it: "New this month" as a row of sheets, then the categories as a labeled drawer list, then the Studio Standard as six short promises the visitor can check, then the email signup, then the footer. Same principle as measureandbuy's homepage calculator: demonstrate the product instead of describing it.
@page rules and a .sheet sized in inches or millimetres. Every template ships a light-ink theme because home printers are paid for by the cartridge. What the customizer shows is rendered by the same file that makes the PDF; there is no "final may differ".data/fonts.md, self-hosted as static instances, embedded in the PDF (the file check proves it on every template). No stock photography, no clip art we cannot source. Decoration is drawn in CSS or SVG we made.Two exclusions, on the same reasoning as measureandbuy's no-electrical rule: no legal documents (leases, contracts, wills, bills of sale, NDAs) and no medical or financial forms that carry regulatory weight. A pretty lease is legal advice in a PDF and we are not lawyers. Invoices, receipts and quotes are fine; they are stationery.
| Plain version, free | Made yours, paid | |
|---|---|---|
| The design, one theme, Letter | yes | yes |
| Your text, names, dates, logo | no | yes |
| All color themes, including light-ink | no | yes |
| Letter and A4 | Letter only | both |
| Credit line at the foot | small, one line | none |
| Re-download link, one year | no | yes |
| License | personal | personal + small-business |
Why a free version at all: the search intent behind "printable weekly planner" is overwhelmingly free-seeking, and Pinterest traffic bounces off a paywall it cannot see through. The free PDF is what earns links, saves and repeat visits, and the credit line on every one of them is the cheapest advertising we will ever buy. The paid product is not the design, it is the design with the visitor on it, in both sizes, in their colors. Templates whose whole point is personalization (invoice, certificate, invitation, letterhead) lose nothing to the free version, because a plain sample with someone else's company name is useless to a business.
No email gate on the free download in v1. The signup offer appears once the download has started. Gating can be added later behind one flag once there is traffic to measure it on.
Prices (recommended, section 11 lists them as an owner decision): three tiers, $4 for paper and simple trackers, $7 for planners, certificates and cards, $12 for business stationery and event-suite pieces. Whole families sell as bundles at about two and a half singles (Planner set $19, Business set $29, Wedding suite $29, Certificate set $15, Classroom set $15). The research in CATALOG.md section 4 is what moved these up from a first draft of $3 / $5 / $8: Etsy's going rates are $12 to $40 for business templates and $15 to $50 for wedding suites with browser editing included, and a site that sells the plain version for free is not competing on price with them anyway. An all-access pass is Phase 3 and needs accounts first.
The list is a channel, not a nicety. Email drives about 42% of sales on Gumroad against 23% from social. So the free download is not gated, but the moment it starts the page offers one thing: "Get the paper set free and one new template a month," which puts the subscriber on the Resend list in exchange for a real bundle, not a promise. The monthly broadcast is the cheapest repeat traffic the site will have.
Thirty templates across seven categories, in CATALOG.md, in build order. The first three are the ones that set the pattern, and the fourth is the one that scales:
| # | Template | Why first |
|---|---|---|
| 1 | Invoice | The reference implementation. Exercises every field type the runtime needs: text, logo, repeating line items with computed totals, currency, a show/hide notes section, paper size. Strong paid intent. |
| 2 | Weekly Planner | The volume play. Themes, start-day option, dated and undated variants, the free version that will carry most of the early traffic. |
| 3 | Certificate of Completion | The customization play and the first "Write it for me" field. Names in a display face, the overflow guard earning its keep. |
| 4 | Monthly Calendar 2027 | The volume play that the research found: month-by-month calendar phrases carry the largest search volume in the whole category (hundreds of thousands a month for a single month name). One template source emits twelve indexable month pages a year, each showing that month's real sheet, plus the twelve-page set. That is "PDF farm" done honestly: every generated page shows a genuinely different, genuinely useful sheet. |
Judge nothing until all thirty are live and the sitemap has sat in Search Console for eight weeks, the same rule measureandbuy runs on.
new-template skill (sibling of new-tool)Written after the invoice proves the pattern. It carries:
template.html hooks, template.css rules for print, fields.json schema with limits, meta.json, themesshots.mjs for preview, OG and pin; free.mjs for the plain PDFcatalog.json via build.mjs, category page, sitemap, related grids, homepage "new this month"pdffonts showing every face embeddedTarget: one template = one design session + one build prompt.
SETUP.md (about an hour): disconnects Lovable from the repo and from PDF Farm, merges the rebuild branch to main, creates the Vercel project, deletes PDF Farm's old edge functions and renames it, puts Stripe in test mode, verifies the Resend domain, sets the env vars. One session: the two migrations applied to PDF Farm (reset, then the orders schema), site shell, design system, homepage with the hero wired to a placeholder template, the four legal pages, /help/ with two articles. Live at www as soon as it is pushed, since main is the production branch and the domain is already on Vercel (amended 2026-09-16: the owner moved the domain at separation and accepted a holding page until Phase 0; DECISIONS.md).SETUP.md section 7: the Stripe webhook, the legacy keys, the old products, Search Console (the domain move and the Lovable deletion happened at separation, 2026-09-16). Then extract the new-template skill.A template marketplace has the scale. A single-product SaaS has the editor. Neither has all of these at once, and each is cheap for us because of how the site is built:
@page makes it free for us and every marketplace sells them as two listings./help/): how to print at actual size, what paper to use, double-siding a planner. These are the pages that earn links from people who never buy anything, and that is fine.DESIGN.md section 1.CATALOG.md section 4.