Skip to content

Commit f865f2d

Browse files
committed
feat: add blog-ready sandbox workflow
1 parent 1f26254 commit f865f2d

32 files changed

Lines changed: 2260 additions & 970 deletions

.devcontainer/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Contributor Devcontainer
2+
3+
This devcontainer is for people working on `git-cms` itself.
4+
5+
It intentionally supports the existing contributor workflow:
6+
7+
- `npm run dev`
8+
- `npm test`
9+
- `npm run test:e2e`
10+
- `npm run playground`
11+
12+
Why it exists:
13+
14+
- gives contributors a reproducible Node 22 + Git environment
15+
- includes native build tooling
16+
- installs Playwright browsers in post-create
17+
- includes Docker-in-Docker so the existing Compose-based scripts still work inside the container
18+
19+
It is **not** the main reader quickstart. Blog readers should start with:
20+
21+
- `npm run demo`
22+
- `npm run playground`
23+
24+
Those paths are documented in [README.md](../README.md) and [docs/GETTING_STARTED.md](../docs/GETTING_STARTED.md).

.devcontainer/devcontainer.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "git-cms contributor",
3+
"build": {
4+
"context": "..",
5+
"dockerfile": "../Dockerfile",
6+
"target": "dev"
7+
},
8+
"workspaceFolder": "/app",
9+
"workspaceMount": "source=${localWorkspaceFolder},target=/app,type=bind,consistency=cached",
10+
"mounts": [
11+
"source=git-cms-devcontainer-node_modules,target=/app/node_modules,type=volume"
12+
],
13+
"features": {
14+
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
15+
},
16+
"forwardPorts": [4638],
17+
"postCreateCommand": "npm ci && npx playwright install --with-deps chromium",
18+
"customizations": {
19+
"vscode": {
20+
"extensions": [
21+
"ms-playwright.playwright",
22+
"dbaeumer.vscode-eslint",
23+
"esbenp.prettier-vscode"
24+
]
25+
}
26+
}
27+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ cms-chunks-*/
77
cms-upload-*/
88
git-cms-test-*/
99
.obsidian/
10+
STUNT-BLOG.md
1011

1112
# LaTeX artifacts
1213
docs/adr-tex-2/*.aux

.vscode/tasks.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "git-cms: dev",
6+
"type": "shell",
7+
"command": "npm run dev",
8+
"problemMatcher": []
9+
},
10+
{
11+
"label": "git-cms: test",
12+
"type": "shell",
13+
"command": "npm test",
14+
"problemMatcher": []
15+
},
16+
{
17+
"label": "git-cms: test:e2e",
18+
"type": "shell",
19+
"command": "npm run test:e2e",
20+
"problemMatcher": []
21+
},
22+
{
23+
"label": "git-cms: playground",
24+
"type": "shell",
25+
"command": "npm run playground",
26+
"problemMatcher": []
27+
}
28+
]
29+
}

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ RUN npm ci --include=dev
1515
# Development stage
1616
FROM base AS dev
1717
ENV NODE_ENV=development
18+
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
1819
COPY --from=deps /app/node_modules ./node_modules
1920
COPY . .
2021
RUN git config --global user.email "dev@git-cms.local" \

QUICK_REFERENCE.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Git CMS Quick Reference
22

3-
> Validated against v1.1.5 on 2026-02-14.
3+
> Validated against v1.1.5 on 2026-03-15.
44
55
One-page cheat sheet for Git CMS commands, API endpoints, and concepts.
66

@@ -13,6 +13,7 @@ git clone https://github.com/flyingrobots/git-cms.git
1313
cd git-cms
1414
npm run setup # Validate Docker prerequisites
1515
npm run demo # Watch a guided walkthrough
16+
npm run sandbox
1617
```
1718

1819
---
@@ -22,15 +23,29 @@ npm run demo # Watch a guided walkthrough
2223
| Command | Purpose |
2324
|---------|---------|
2425
| `npm run setup` | One-time environment validation |
25-
| `npm run demo` | Guided CLI + Git walkthrough |
26+
| `npm run demo` | Guided CLI + Git walkthrough in a disposable isolated repo |
27+
| `npm run sandbox` | Start the seeded long-lived sandbox server on port 4638 |
28+
| `npm run sandbox:shell` | Open a shell in the running sandbox container |
29+
| `npm run sandbox:logs` | Tail sandbox logs |
30+
| `npm run playground` | Compatibility alias for `npm run sandbox` |
31+
| `npm run playground:shell` | Compatibility alias for `npm run sandbox:shell` |
32+
| `npm run playground:logs` | Compatibility alias for `npm run sandbox:logs` |
2633
| `npm run quickstart` | Interactive Docker menu |
27-
| `npm run dev` | Start HTTP server ([http://localhost:4638](http://localhost:4638)) |
34+
| `npm run dev` | Contributor server ([http://localhost:4638](http://localhost:4638)); uses the checkout as the repo |
2835
| `npm run serve` | Start server directly with Node |
2936
| `npm test` | Run integration tests in Docker |
3037
| `npm run test:setup` | Run setup-script tests (BATS) |
38+
| `npm run test:sandbox` | Smoke-test the seeded reader sandbox on the host |
39+
| `npm run test:playground` | Compatibility alias for `npm run test:sandbox` |
3140
| `npm run test:local` | Run Vitest directly on host (advanced) |
3241
| `npm run check:docs` | Check documentation drift against source code |
3342

43+
Mode summary:
44+
45+
- `demo` = reader-safe, guided, ephemeral
46+
- `sandbox` = reader-safe, long-lived, seeded, inspectable
47+
- `dev` = contributor workflow, uses `/app` as the runtime repo
48+
3449
---
3550

3651
## CLI Commands
@@ -40,7 +55,7 @@ All 9 commands available via `node bin/git-cms.js <command>` or `git cms <comman
4055
| Command | Usage | Description |
4156
|---------|-------|-------------|
4257
| `draft` | `echo "body" \| git cms draft <slug> "Title"` | Create or update a draft (reads body from stdin) |
43-
| `publish` | `git cms publish <slug>` | Fast-forward published ref to match draft |
58+
| `publish` | `git cms publish <slug>` | Move published ref to the current draft tip |
4459
| `unpublish` | `git cms unpublish <slug>` | Remove from published, keep as unpublished draft |
4560
| `revert` | `git cms revert <slug>` | Move article to 'reverted' state (creates new draft commit with `Status: reverted` trailer) |
4661
| `list` | `git cms list` | List all draft articles |
@@ -50,8 +65,8 @@ All 9 commands available via `node bin/git-cms.js <command>` or `git cms <comman
5065
| `layout-version` | `git cms layout-version` | Print repo and codebase layout versions |
5166

5267
```bash
53-
# Enter container
54-
docker compose run --rm app sh
68+
# Enter the live sandbox container
69+
npm run sandbox:shell
5570

5671
# Draft an article (reads body from stdin)
5772
echo "# My Post" | node bin/git-cms.js draft my-slug "My Title"
@@ -79,9 +94,6 @@ node bin/git-cms.js layout-version
7994

8095
# Run pending migrations
8196
node bin/git-cms.js migrate
82-
83-
# Exit container
84-
exit
8597
```
8698

8799
`node bin/git-cms.js list` does not support `--kind`. Kind filtering is available in the HTTP API (`GET /api/cms/list?kind=published`).
@@ -97,13 +109,15 @@ All endpoints are served by `git cms serve` (default port 4638). Slugs are NFKC-
97109
| `GET` | `/api/cms/list` | `?kind=articles\|published` | List articles by kind |
98110
| `GET` | `/api/cms/show` | `?slug=xxx&kind=articles` | Read article content |
99111
| `POST` | `/api/cms/snapshot` | `{ slug, title, body, trailers (optional) }` | Create or update a draft |
100-
| `POST` | `/api/cms/publish` | `{ slug, sha (optional) }` | Publish a draft (omitting `sha` uses optimistic concurrency) |
112+
| `POST` | `/api/cms/publish` | `{ slug, sha (optional) }` | Publish current draft tip (`sha` acts as optimistic-concurrency token if supplied) |
101113
| `POST` | `/api/cms/unpublish` | `{ slug }` | Unpublish an article |
102114
| `POST` | `/api/cms/revert` | `{ slug }` | Revert to draft state |
103115
| `GET` | `/api/cms/history` | `?slug=xxx&limit=50` | List version history (max 200) |
104116
| `GET` | `/api/cms/show-version` | `?slug=xxx&sha=<oid>` | Read a specific historical version |
105117
| `POST` | `/api/cms/restore` | `{ slug, sha }` | Restore a historical version as new draft |
106-
| `POST` | `/api/cms/upload` | `{ slug, filename, data }` | Upload base64-encoded asset (encrypted) |
118+
| `POST` | `/api/cms/upload` | `{ slug, filename, data }` | Upload base64-encoded asset (optionally encrypted server-side) |
119+
120+
Historical version endpoints currently assume Git's default SHA-1 object format and therefore validate 40-character hexadecimal commit IDs.
107121

108122
---
109123

@@ -170,7 +184,7 @@ The trick: content lives in commit messages while commits point at the repo's em
170184
| Ref Pattern | Purpose |
171185
|-------------|---------|
172186
| `{refPrefix}/articles/{slug}` | Draft pointer (moves on every save) |
173-
| `{refPrefix}/published/{slug}` | Published pointer (fast-forward only) |
187+
| `{refPrefix}/published/{slug}` | Published pointer to the current draft tip |
174188
| `{refPrefix}/chunks/{slug}@current` | Current asset-manifest pointer |
175189

176190
---
@@ -235,7 +249,9 @@ Trailers are parsed by `@git-stunts/trailer-codec`.
235249
| `test/chunks.test.js` | Asset encryption and chunking |
236250
| `test/server.test.js` | HTTP API endpoints, validation, error responses |
237251
| `test/git-e2e.test.js` | Real-git smoke tests (subprocess forks) |
252+
| `test/playground-bootstrap.test.js` | Seed/bootstrap behavior and `GIT_CMS_REPO` CLI routing |
238253
| `test/setup.bats` | Setup script tests (BATS) |
254+
| `test/playground-smoke.sh` | Host-side container smoke test for the seeded sandbox |
239255
| `test/run-docker.sh` | Docker test harness |
240256

241257
---
@@ -252,11 +268,10 @@ npm ci
252268

253269
### Port 4638 already in use
254270

255-
Edit `docker-compose.yml`:
271+
Override the published port when starting the sandbox:
256272

257-
```yaml
258-
ports:
259-
- "5000:4638"
273+
```bash
274+
PLAYGROUND_PORT=5000 npm run sandbox
260275
```
261276

262277
### Docker daemon not running

0 commit comments

Comments
 (0)