Skip to content

Project structure

Markdown

The tree is what git tracks in the starter today, with src/, src/pages/ and .github/ opened one level. The table under it is the map from AGENTS.md, the file an agent reads first, so the two never disagree. Files with .free. in the name are the free edition’s versions of their neighbours; the release tooling swaps them in.

zerodirs/
├── .agents/
├── .github/
│ ├── docs/
│ ├── release/
│ └── workflows/
├── docs/
├── drizzle/
├── integrations/
├── public/
├── scripts/
├── seed/
├── src/
│ ├── actions/
│ ├── assets/
│ ├── components/
│ ├── config/
│ ├── content/
│ ├── db/
│ ├── features/
│ ├── icons/
│ ├── islands/
│ ├── layouts/
│ ├── lib/
│ ├── loaders/
│ ├── pages/
│ │ ├── account/
│ │ ├── admin/
│ │ ├── api/
│ │ ├── auth/
│ │ ├── blog/
│ │ ├── login/
│ │ ├── og/
│ │ ├── out/
│ │ ├── submit/
│ │ ├── 404.astro
│ │ ├── [...path].astro
│ │ ├── [advertise].astro
│ │ ├── about.astro
│ │ ├── index.astro
│ │ ├── privacy.astro
│ │ ├── robots.txt.ts
│ │ ├── rss.xml.ts
│ │ ├── search.astro
│ │ └── terms.astro
│ ├── server/
│ ├── styles/
│ ├── templates/
│ ├── content.config.ts
│ ├── env.d.ts
│ ├── env.free.d.ts
│ ├── middleware.ts
│ └── worker.ts
├── tests/
├── .dev.vars.example
├── .editorconfig
├── .env.example
├── .gitignore
├── .nvmrc
├── AGENTS.free.md
├── AGENTS.md
├── astro.config.ts
├── CHANGELOG.md
├── CLAUDE.md
├── drizzle.config.ts
├── LICENSE
├── LICENSE.free
├── lighthouserc.cjs
├── lighthouserc.mobile.cjs
├── package.json
├── playwright.config.ts
├── pnpm-lock.yaml
├── README.free.md
├── README.md
├── site.config.ts
├── tsconfig.json
├── vitest.config.ts
├── vitest.workers.config.ts
├── worker-configuration.d.ts
├── wrangler.free.jsonc
└── wrangler.jsonc

Nothing under node_modules/, dist/, .astro/ or .wrangler/ is tracked: install, build, astro check and the dev server create those.

The free edition column says what the release tooling does with the path: deleted means the free edition does not have it; replaced means it has a smaller version of it.

Path What Free edition
site.config.ts The one file a buyer edits: brand, routes, categories, tags, tiers, SEO, pSEO, theme, feature flags yes
astro.config.ts Derived from site.config.ts; adapter, fonts, integrations, env.schema yes
src/config/schema.ts The zod schema and the ten cross-field rules behind pnpm check:config yes
src/config/defaults.ts Every default the schema fills in yes
src/config/presets.ts Theme preset registry (default, warm, mono) plus each preset’s OG hex colours yes
src/config/types.ts The public SiteConfig type yes
src/content/listings/ One Markdown file per listing; the file name is the slug yes
src/content/blog/ Blog posts yes
src/content/pseo/ Optional per-slug intro/title overrides for generated pSEO pages yes
src/content/schema.ts Collection schemas: listingSchema, blogSchema, pseoCopySchema yes
src/content.config.ts Collection definitions (which loader feeds which schema) yes
src/loaders/files.ts The Markdown listings loader yes
src/loaders/normalize.ts Source → Listing: category check, tag filter, date coercion, isFeatured yes
src/pages/[...path].astro The only dynamic route; getStaticPaths builds every directory page yes
src/pages/ Fixed pages: home, search, about, terms, privacy, 404, blog, /rss.xml, /robots.txt, OG endpoint yes
src/lib/routes.ts The pure route table (buildRoutes, matchers, reserved segments) yes
src/lib/paths.ts The only URL constructor in the project yes
src/lib/seo.ts Titles, descriptions, canonicals, noindex, sitemap chunks yes
src/templates/ One template per page kind; the catch-all dispatches to these yes
src/components/listing/Detail.astro The listing detail body — the file to edit for “change the detail page” yes
src/components/ Everything else presentational (listing/, category/, blog/, pseo/, seo/, site/, ui/, and ads/ — the four placements site.config.ts ads switches on) yes
src/features/index.ts Facade for the paid-only features; templates import from here, never from paid/ replaced
src/features/paid/pseo/patterns.ts The pSEO template registry — a new template’s candidate logic goes here; src/features/paid/pseo/generate.ts handles minItems, collisions, maxPages, siblings and copy deleted
src/features/paid/og/ Build-time OG image rendering (satori + resvg) deleted
src/styles/global.css Tailwind v4 entry: @source allow-list, dark variant, preset imports, @theme inline yes
src/styles/presets/ One CSS file per theme preset yes
src/islands/SearchPanel.tsx The only hydrated component in the whole site yes
src/db/schema.ts The D1 schema. Migrations in drizzle/ are generated from it deleted
src/loaders/d1.ts Build-time D1 REST loader (LISTINGS_SOURCE=d1) deleted
src/middleware.ts Guards /admin/** and /_actions/; lazy-imports the DB so prerender stays clean deleted
src/actions/ The two Action namespaces: submit (public) and admin deleted
src/server/ Everything that runs per request: db, env (the only reader of the astro env module), token, admin-auth, submit, queries, meta-fetcher, media, jobs, queue, email/, rebuild/, auth/ deleted
src/pages/submit/ The public two-step form and the token-addressed status page deleted
src/pages/account/ Submitter accounts (features.accounts): /account/ lists a signed-in submitter’s submissions; src/pages/login/ is the sign-in page and src/pages/auth/ the emailed-link and Google callbacks. src/server/auth/ holds sessions, links and the Google exchange deleted
src/pages/admin/ Login, queue, listing detail, featured, stats deleted
src/worker.ts The Worker entry (main): the adapter’s fetch, plus scheduled running the four hourly jobs deleted
integrations/sitemap.ts Chunked sitemap yes
integrations/pagefind.ts Search index, written at astro:build:done yes
integrations/budget.ts Static-file count against the Cloudflare plan limit yes
integrations/seo-report.ts Inbound-link / orphan / sitemap audit; can fail the build deleted
scripts/ The CLI scripts behind the pnpm commands below yes
tests/unit/ Vitest node tests (vitest.config.ts) yes
seed/datasets/ai-tools/ The demo dataset pnpm content:use restores yes
public/ Copied verbatim into the build: public/favicon.svg, public/og-default.png, public/logos/, public/_headers yes
.agents/skills/ Task recipes; pnpm skills:sync copies them to .claude/skills/ deleted
wrangler.jsonc Worker name, main, compatibility date, the DB / MEDIA / EMAIL bindings replaced
.env.example Build-time variables yes
.dev.vars.example Runtime secrets deleted
  • Commands: every pnpm script, and which file it runs.
  • Configuration: the one file in the tree a buyer edits first.
  • Free vs Pro: the line the last column draws, in prose.