Adapted from the repo's README.md — Part of Internals: the platform's design set, published as content on the platform it describes.
A file-based blog: articles are Markdown files on disk — no admin panel — indexed and served on schedule by a read-only Laravel API and rendered by a Next.js reader front-end. Built contract-first by a Claude Code agent team: one repository, strict tier ownership, and a versioned machine-checkable contract as the only surface the tiers share.
Status: delivery roadmap complete (Phases 0–4, docs/master-blueprint.md §11).
Contract v0.8.1 (OpenAPI 3.1 + AsyncAPI 3.1, contract/CHANGELOG.md); ADRs
0001–0017 Accepted.
Stack: DDEV · PHP 8.5 · Laravel 13.x · PostgreSQL 16 · Redis · Next.js 16 (Node 22)
Run it
ddev start
- Reader app: https://publishing-platform.ddev.site
- API (base path
/v1): https://api.publishing-platform.ddev.site/v1
First-time setup, publishing articles, verify commands, troubleshooting:
docs/runbook.md.
How it works
The filesystem is the CMS (ADR-0005): content lives under
backend/storage/app/content/ — each directory a section, each *.md file an article,
path = URL. A scheduler reindexes every minute and honours each file's publication
schedule; publishing is save the file — a relay → signed webhook → revalidateTag
loop (ADR-0016) makes it live in well under 90 seconds, no restarts. The public API is
read-only and unauthenticated (ADR-0006). Full technical walkthrough with diagrams:
docs/how-it-works.md.
Layout
| Path | Purpose |
|---|---|
CLAUDE.md |
The operating constitution every Claude Code session loads: stack, roster, rules, verify commands |
contract/ |
OpenAPI 3.1 + AsyncAPI 3.1 + Spectral ruleset + changelog — the team-to-team boundary |
backend/ |
Laravel API tier (Http → Domain → Data); its README.md is the tier's design doc |
frontend/ |
Next.js reader tier; consumes the API only through the contract |
infra/ |
DDEV topology source of truth; generates .ddev/ |
docs/ |
Canonical design set — architecture, product blueprint, team, orchestration, rules, working agreement, UI/UX, runbook, ADRs (reading order: docs/README.md) |
.claude/agents/ |
The member roster: contract-owner, backend-api, domain-engineer, data-engineer, frontend-engineer, platform-engineer |
Requirements
The host is deliberately kept agnostic — everything runs inside DDEV. The only host requirements are:
- DDEV ≥ 1.23.5 and a Docker provider.
- Claude Code with Agent Teams enabled (preconfigured in
.claude/settings.json).
No host Node.js or PHP is required or assumed. If a tool isn't reachable through
ddev, that's a gap to close in infra/, not a missing host dependency.
Template heritage
This repository was spun from a reusable contract-first project template; the tier
model, stack baseline (ADR-0003/0004), roster, and rules of engagement come from it
unchanged. To spin a new project from the same scaffold (referenced by
docs/runbook.md § First-time setup B):
# 1. Copy the template and make it yours
cp -r <this-template> my-project && cd my-project && git init
grep -rl '<PROJECT_NAME>' . --exclude-dir=.git | xargs sed -i 's/<PROJECT_NAME>/my-project/g'
# 2. Bootstrap the runtime (DDEV + PostgreSQL 16 + Redis + frontend service + lint cmd).
# The host needs only Docker + DDEV — no Node.js or PHP.
infra/ddev/bootstrap.sh my-project
# 3. Install the framework skeletons (Laravel into backend/, Next.js into frontend/)
# following the runbook in infra/README.md
# 4. Lint the contracts (Spectral runs inside the DDEV web container)
ddev contract-lint
Then open Claude Code in the repo root: CLAUDE.md is the operating constitution, and
the roster in .claude/agents/ is ready to be spawned as an agent team.