Cadence Lab is an Astro 7 website with TinaCMS-backed content editing, Astro Content Collections, Tailwind CSS, local web fonts, and statically generated routes.
The project supports:
- Markdown-based blog posts and page content
- Local TinaCMS visual editing
- TinaCloud integration
- Date-based blog URLs
- Local Graphik and Tiempos web fonts
- TypeScript validation
- Static Astro builds with the Node adapter
- Astro
- TypeScript
- TinaCMS
- Tailwind CSS
- Astro Content Collections
- Node.js adapter
- npm
- Node.js 22.12 or newer
- npm
Check the installed versions:
node --version
npm --versionUse the version defined by .nvmrc when that file is present:
nvm useClone the repository and enter the project directory:
git clone https://github.com/matt-rabah/cadencelab-astro7.git
cd cadencelab-astro7Install dependencies:
npm installCreate a local environment file:
cp .env.example .envAdd the required TinaCMS values to .env:
NEXT_PUBLIC_TINA_CLIENT_ID=
TINA_READ_ONLY_TOKEN=
TINA_SEARCH_TOKEN=
PUBLIC_TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=Do not commit .env or expose Tina tokens publicly.
Start TinaCMS and Astro together:
npm run devThe local site is available at:
http://localhost:4321
The TinaCMS admin is available at:
http://localhost:4321/admin/index.html
The local Tina GraphQL API is available at:
http://localhost:4001/graphql
When Tina displays local mode, content changes are written directly to the Markdown files in the local repository.
/
├── .vscode/ # VS Code workspace settings
│
├── public/
│ ├── admin/ # Generated TinaCMS admin application
│ ├── fonts/ # Local Graphik and Tiempos web fonts
│ ├── uploads/ # Tina-managed media
│ └── favicon.svg
│
├── src/
│ ├── assets/ # Assets imported by Astro components
│ │
│ ├── components/ # Reusable Astro components
│ │ ├── NavHeader.astro
│ │ ├── Footer.astro
│ │ └── ...
│ │
│ ├── content/
│ │ ├── blog/ # Blog post Markdown files
│ │ └── pages/ # Tina-managed page Markdown files
│ │
│ ├── layouts/
│ │ └── Layout.astro # Shared site layout
│ │
│ ├── lib/
│ │ └── tina/
│ │ ├── data.ts # Tina data helpers
│ │ └── islands.ts # Tina island registration
│ │
│ ├── pages/
│ │ ├── blog/
│ │ │ ├── index.astro
│ │ │ └── [year]/
│ │ │ └── [month]/
│ │ │ └── [slug].astro
│ │ │
│ │ ├── tina-island/
│ │ │ └── [name].ts
│ │ │
│ │ ├── [...slug].astro
│ │ ├── fit-check.astro
│ │ ├── index.astro
│ │ └── thanks.astro
│ │
│ ├── styles/ # Global and feature-level CSS
│ │
│ └── content.config.ts # Astro content collection schemas
│
├── tina/
│ ├── __generated__/ # Generated Tina client and TypeScript types
│ ├── config.ts # TinaCMS collections and configuration
│ └── tina-lock.json
│
├── .env.example # Environment variable template
├── .gitignore
├── AGENTS.md # Repository instructions for coding agents
├── astro.config.mjs # Astro integrations and build configuration
├── CLAUDE.md # Claude project instructions
├── package-lock.json
├── package.json
├── README.md
├── tailwind.config.js
└── tsconfig.json
The project must have only one application root. There should not be another complete cadencelab-astro7/ project directory nested inside this repository.
The following directories are generated locally and are not maintained as source code:
.astro/
dist/
node_modules/
tina/__generated__/.cache/
Their purposes are:
| Directory | Purpose |
|---|---|
.astro/ |
Astro-generated metadata and types |
dist/ |
Production build output |
node_modules/ |
Installed npm packages |
tina/__generated__/ |
Tina GraphQL client and TypeScript types |
tina/__generated__/.cache/ |
Temporary Tina build cache |
public/admin/ |
Generated TinaCMS admin application |
Do not manually edit generated cache files.
Blog posts are stored in:
src/content/blog/
Each Markdown filename becomes the URL slug.
For example:
src/content/blog/adoption-fatigue.md
may generate:
/blog/2026/06/adoption-fatigue/
Blog URLs use this pattern:
/blog/YYYY/MM/slug/
The year and month are derived from the post’s date field.
A typical blog post contains frontmatter similar to:
---
title: The Hidden Operational Cost of User Adoption Fatigue
subtitle: An investigation into workflow friction and enterprise adoption.
date: 2026-06-23
readTime: 9 min read
category: Advisory
---The shared article route is:
src/pages/blog/[year]/[month]/[slug].astro
That file controls the layout, typography, metadata, and Markdown rendering for individual posts.
The blog index is:
src/pages/blog/index.astro
Tina-managed page content is stored in:
src/content/pages/
The catch-all page route is:
src/pages/[...slug].astro
The TinaCMS configuration is defined in:
tina/config.ts
It defines:
- Content collections
- Editable fields
- Blog routing
- Page routing
- Media configuration
- TinaCloud connection settings
- Optional search configuration
The generated Tina client and types are stored in:
tina/__generated__/
To regenerate Tina files during development, restart the development server:
npm run devTo regenerate them during a production build:
npm run buildOpen:
http://localhost:4321/admin/index.html
In local mode, Tina edits files directly in:
src/content/
After saving an edit, verify the change with:
git status
git diffFor TinaCloud editing, the deployed site must have the required environment variables configured.
The deployed admin route is:
https://your-domain.example/admin/index.html
Cloud-connected saves can create commits in the linked GitHub repository.
The project uses these environment variables:
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_TINA_CLIENT_ID |
Connects the Tina admin to the TinaCloud project |
TINA_READ_ONLY_TOKEN |
Provides read-only TinaCloud access during server-side builds |
TINA_SEARCH_TOKEN |
Provides Tina search indexing access |
PUBLIC_TURNSTILE_SITE_KEY |
Renders the public Turnstile widget on the Fit Check form |
TURNSTILE_SECRET_KEY |
Verifies Fit Check Turnstile tokens in the Pages Function |
Example:
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id
TINA_READ_ONLY_TOKEN=your_read_only_token
TINA_SEARCH_TOKEN=your_search_token
PUBLIC_TURNSTILE_SITE_KEY=your_site_key
TURNSTILE_SECRET_KEY=your_secret_keyNever commit real token values.
The project may temporarily support an older TINA_CLIENT_ID variable for compatibility, but NEXT_PUBLIC_TINA_CLIENT_ID is the preferred name for the browser-based Tina admin.
Local web fonts are stored under:
public/fonts/
The project uses Graphik and Tiempos font files configured through Astro.
Font registration and paths are managed in:
astro.config.mjs
Global font variables and typography rules are managed under:
src/styles/
Use the existing font variables in components instead of hardcoding font-family names repeatedly.
Astro routes are defined by files in:
src/pages/
Key routes include:
| Source file | URL |
|---|---|
src/pages/index.astro |
/ |
src/pages/blog/index.astro |
/blog/ |
src/pages/blog/[year]/[month]/[slug].astro |
/blog/YYYY/MM/slug/ |
src/pages/fit-check.astro |
/fit-check/ |
src/pages/thanks.astro |
/thanks/ |
src/pages/[...slug].astro |
Dynamic page routes |
src/pages/tina-island/[name].ts |
Tina island endpoint |
Global and reusable styles are stored in:
src/styles/
Page-specific styles may also exist inside Astro components.
For reusable blog typography and layout, prefer a dedicated stylesheet such as:
src/styles/article.css
Reusable article components should be placed under:
src/components/blog/
Potential article components include:
ArticleHeader.astro
ArticleSidebar.astro
ArticleToc.astro
ArticleTags.astro
AuthorBio.astro
RelatedPosts.astro
Run the TypeScript compiler without emitting files:
npx tsc --noEmitThis command should complete without errors before changes are committed.
Build TinaCMS and Astro:
npm run buildThe production build is written to:
dist/
A successful build should:
- Generate the Tina admin
- Generate Tina GraphQL types and client files
- Sync Astro content collections
- Build server entrypoints
- Prerender static routes
- Finish without TypeScript or routing errors
All commands are run from the project root.
| Command | Action |
|---|---|
npm install |
Install dependencies |
npm run dev |
Start TinaCMS and Astro locally |
npm run build |
Build TinaCMS and the Astro site |
npm run preview |
Preview the production build locally |
npx tsc --noEmit |
Run TypeScript validation |
npm run format -- <path> |
Format an explicit file or directory with Prettier |
npm run format:check -- <path> |
Check an explicit file or directory without changing it |
npm run astro -- --help |
Display Astro CLI help |
git status |
Show repository changes |
git diff |
Review unstaged changes |
git diff --cached |
Review staged changes |
Do not make feature work directly on main.
Update the local main branch:
git switch main
git pull origin mainCreate a feature branch:
git switch -c feature/branch-nameExamples:
git switch -c feature/blog-layout
git switch -c fix/tina-routing
git switch -c cleanup/project-structureValidate changes before committing:
npx tsc --noEmit
npm run buildReview the changes:
git status
git diffStage and commit:
git add -A
git commit -m "Describe the change"Push the branch:
git push -u origin feature/branch-nameOpen a pull request into main.
For branches whose history has intentionally been rewritten, use:
git push --force-with-lease origin branch-nameDo not use a plain --force push.
Before merging a pull request:
- Confirm the changed files match the intended scope
- Confirm no nested duplicate project was introduced
- Confirm no environment tokens were committed
- Run
npx tsc --noEmit - Run
npm run build - Review the Files changed tab
- Resolve all conflicts
- Prefer Squash and merge for cleanup branches with multiple intermediate commits
Do not commit:
.env- Tina tokens
- API keys
- private credentials
- generated secrets
- private font license files
- temporary exports or backups
If a token is exposed in a screenshot, commit, chat, or public repository, rotate it.
This is expected when running:
npm run devLocal mode edits Markdown files directly.
Confirm that the date in the Markdown frontmatter matches the generated route.
For example:
date: 2026-06-26should generate:
/blog/2026/06/slug/
Restart the development server after changing Tina routing configuration.
The preview page may be rendering without contextual editing metadata.
Check:
src/lib/tina/data.ts
src/lib/tina/islands.ts
src/pages/tina-island/[name].ts
Also confirm that the page uses the Tina-aware data and island workflow.
Remove generated Tina cache files:
rm -rf tina/__generated__/.cacheThen reload VS Code.
Confirm that only the root TypeScript configuration exists:
find . -name tsconfig.json \
-not -path "./node_modules/*" \
-not -path "./.git/*"Expected result:
./tsconfig.json
React Router warnings displayed inside the Tina admin are emitted by TinaCMS dependencies.
They are informational unless Tina navigation or routing stops working.
A warning similar to this may appear when Tina launches Astro:
[DEP0190] DeprecationWarning
It does not normally prevent the development server or build from running.
FitCheck submissions are reviewed manually. Use the FitCheck Decision Brief method and reply template to deliver the free email brief. The optional automated answer receipt is separate from the assessment.