local development¶
everything runs on one machine: no cluster and no github app.
hack/build-editor.sh # first run pulls upstream and installs deps: slow
cp .env.example .env
podman compose up # or docker compose
- editor: http://localhost:3000 (anonymous editing is on)
- board: http://localhost:8080
both talk to the compose postgres. state lives in named volumes, so
podman compose down keeps your notes and podman compose down -v throws them
away.
what the first build does¶
hack/build-editor.sh builds two images:
specdoc-editor-src:<tag>: upstream hedgedoc cloned at the tag ineditor/UPSTREAM, with the fork's commits fetched fromeditor/critic.bundleon top, plusyarn install. a full clone and a full dependency install, cached as its own image: it only needs rebuilding whenUPSTREAMorcritic.bundlechanges. delete the image to force it.specdoc-editor:<tag>: the rebrand overlay and the webpack build on top. this is what rebuilds while you work, in minutes rather than tens of minutes.
BUILDER=buildah hack/build-editor.sh if rootless podman fails to mount an
overlay over the build context.
working on the editor¶
the fork's source is not in this repo: it lives on the critic branch inside
editor/critic.bundle. to get a working tree:
reuse an existing editor/.work checkout when present. use node 20 and the
checked-in yarn release to install and verify it:
cd editor/.work
corepack yarn install --immutable
corepack yarn exec mocha test/critic-markup.js test/critic-contexts.js test/critic-footnotes.js test/critic-review-ui.js test/critic-margin.js test/critic-suggestion.js test/frontmatter-repair.js
corepack yarn eslint
corepack yarn mocha-suite
corepack yarn build
commit the tested source changes on critic, then from this repository:
hack/sync-critic.sh editor/.work
git -C editor/.work bundle create ../critic.bundle "$(cat editor/UPSTREAM)..critic"
git -C editor/.work bundle verify ../critic.bundle
commit the bundle and synchronized board parser files together. editor/.work
is gitignored; the bundle carries its commits. editor/rebase.sh is for
upstream upgrades, and can reset unfinished work.
for browser checks, test wide view (at least 993 pixels), split mode and a narrow viewport. enter multiline comments, follow line links, move the editor caret between commented lines, and grow/shrink replies in crowded margins. check expanded groups and a remote re-render while a reply has a selection in the middle. accept/reject inline-code suggestions, undo them, and verify locked/read-only notes, stale previews and published output.
working on the board¶
spec-board/ is a plain node service, so the fast loop is outside compose:
cd spec-board && npm ci
PGHOST=localhost PGUSER=specdoc PGPASSWORD=specdoc PGDATABASE=specdoc \
HEDGEDOC_BASE_URL=http://localhost:3000 node server.js
node spec-board/test.js covers the pure logic and needs no database.
the feedback suites also use provider and model fixtures:
node spec-board/feedback-github-test.js
node spec-board/feedback-test.js
node spec-board/feedback-service-test.js
the persistence suite needs a separate postgres database. it creates a random schema inside that database and drops only its own schema after the test:
podman run --rm -d --name specdoc-feedback-test \
-e POSTGRES_PASSWORD=feedback-test -e POSTGRES_DB=feedback_test \
-p 127.0.0.1:55432:5432 docker.io/library/postgres:16-alpine
podman exec specdoc-feedback-test pg_isready -U postgres
FEEDBACK_TEST_DATABASE_URL=postgresql://postgres:feedback-test@127.0.0.1:55432/feedback_test \
node spec-board/feedback-db-test.js
podman stop specdoc-feedback-test
wait for pg_isready to report that connections are accepted before running
the suite. it checks replay, concurrent decisions, migration reruns, settings
changes during analysis and decision retention.
working on the mcp server¶
mcp/ needs a git checkout to index and a board to read, nothing else.
against the compose stack:
cd mcp && npm ci && node test.js
cd /some/rust/checkout && SPECDOC_URL=http://localhost:8080 node /path/to/specdoc/mcp/server.js brief
npx @modelcontextprotocol/inspector node /path/to/specdoc/mcp/server.js
opens a browser ui to call the tools by hand. the test builds its own
throwaway repo and fake board, so it runs anywhere.
what does not work locally¶
- github login (the editor falls back to anonymous editing)
- opening spec PRs, unless you put a token in
.envand name a repo you can write to inNAMESPACES - email digests and review bots, unless you point them at real endpoints