Introduction
Getting started
The working manual for the White Tree Digital monorepo — how the marketing site is built, how its content is modelled in Sanity, and how it ships to the edge.
White Tree Digital is a one-person digital-marketing and web-dev studio; this repo is the lead-generating marketing site that fronts it. The codebase is a monorepo of two independent packages — an Astro front end (website/) and a Sanity Studio (studio/) — plus the runbooks that take it live. These docs are written for the people and agents who maintain it.
Project overview
What the project is, the two packages, and how schema and content flow between them.
Content & Sanity
The schema-vs-content mental model, the document types, and how content reaches the site.
Page builder
How every page is a sections[] array dispatched through one polymorphic renderer.
Design system
The dark forest-and-gold palette, the grid theme, typography, and the component library.
Website audit tool
The Free Website Audit lead magnet — server-side checks, a teaser, and a HubSpot lead.
Deployment & operations
Two Cloudflare Workers from one repo, the launch runbook, and the rollback paths.
How this site is organised
The sidebar groups the documentation the way the codebase is shaped. If you are new, read in roughly this order:
- Project overview and Monorepo architecture — the lay of the land: two packages, one content source, two builds.
- Development setup and Environment variables — clone, install, run both packages, and wire up the env contract.
- Content & Sanity — the content model, the Studio, and the GROQ queries the site reads.
- Page Builder — the heart of the site: composable section types and the checklist for adding one.
- Design System and Animation & Motion — how it looks and moves.
- Deployment & Operations — how it ships, and the launch runbook.
- Maintaining the docs — meta-docs for this site: adding pages, the Markdoc tags, and the branding.
The shape of the system
Astro renders the front end and reads everything from Sanity at build or request time; the site only ever reads the dataset — it never writes back. Editors compose pages in the Studio from a library of section types, and the front end dispatches those sections through a single renderer.
// A page is a sections[] array; one renderer dispatches on _type.
const data = await getPageBySlug('services')
<SectionRenderer
sections={data.page?.sections}
clients={data.clients}
testimonials={data.testimonials}
caseStudies={data.caseStudies}
/>
The same repo builds two ways: a static public site that is immune to a Sanity outage, and an SSR staging mirror that powers live visual editing. The two-build split explains how one BUILD_TARGET flag toggles between them.
Trust the code, not just the docs
These pages are written from the live source files. When a detail here disagrees with the code, the code wins — every page ends with a “Where this lives” pointer to the real files so you can confirm.
Conventions used here
- Footguns are called out. Watch for the warning callouts on the load-bearing traps — stega breaking string equality, never deleting a Sanity singleton, the dev-vs-build cache clobber, and
urlForthrowing on asset-less images. - Paths and commands are verbatim. File paths, npm scripts, env-var names, and schema field names match the repo exactly.
- No secrets. Environment variables are documented by name and purpose only — real keys and tokens live in gitignored files, never here.