Skip to content

Development

This page is generated from CONTRIBUTING.md in the Stackyard repository, so it matches the source. Links in it resolve to files on GitHub.

Contributions are welcome within the constraints that keep Stackyard small and auditable. A change that breaks one of these will not be merged:

  • One container: Nginx and the Node API run together under supervisord. No extra services, no database.
  • No runtime dependencies: the API ships zero npm runtime packages; the frontend is vanilla HTML/CSS/JS with no framework and no build step.
  • Server-side is CommonJS, the frontend is ES modules.

If a feature seems to need a dependency or a build step, open an issue first.

Development

The frontend is static; edit files under ui/ and reload. Unit tests use Node's built-in runner and need nothing installed; coverage and the browser tests use the dev tooling in the root package.json.

An export whose name starts with _ exists for the tests and is not part of what the module offers: _internals for functions reached directly, _reset* for the hooks that clear state between tests. Anything else exported is API, and is exported under the name it is defined with.

Before opening a PR

These are the checks CI runs, in the order it runs them. They are defined once, in .github/actions/checks/action.yml, so the list here is the whole of it:

npm ci
node scripts/changelog-check.js
node scripts/bump-cache-busting.js --check
npm run paths:check
cd api && npm test
cd api && npx c8 check-coverage --lines 92
cd ui/test && node --test
npm run lint
npm run format:check
npm run typecheck
npm run typecheck:ui
docker build -t stackyard:ci .

CodeQL also runs on every pull request. A finding it reports has to be resolved before merge.

  • changelog-check.js verifies the structure of CHANGELOG.md: the Keep a Changelog header, the six section names, a real date on every released version, descending versions, and a compare link per version. Structure fails the check. Style problems in [Unreleased], such as a rationale clause or a three-sentence entry, print as warnings on the pull request and do not fail it. Releasing is documented in docs/releasing.md.

  • bump-cache-busting.js --check verifies that every /css/ and /js/ reference carries a ?v= stamp. The release build recomputes the hashes, so write ?v=1 and never edit a stamp by hand.

  • npm run typecheck:ui typechecks every module under ui/js from its JSDoc, with no build step and nothing emitted. It has to stay clean. A new module needs two entries in tsconfig.frontend.json, the plain path and the ?v=* form, because TypeScript allows one wildcard per pattern.

  • Test code is linted and formatted along with everything else, with a few rules relaxed for api/test, api/test-support and ui/test in biome.json: a stub whose signature has to match a real one keeps its unused parameter, a scanner keeps while ((m = re.exec(s))), and 'use strict' stays where a test depends on strict-mode semantics.

    They are not typechecked. checkJs over api/test reports 131 errors, almost all narrowing around Node's server.address() in test harnesses. Changing that is its own piece of work, not a side effect of something else.

  • npm run lint is Biome, from node_modules. Run it through npm: a bare npx biome resolves to an unrelated package that exits 0 without checking anything.

More

Reference

Deeper notes in the repository, beyond the ones linked above.

DocumentCovers
ArchitectureHow a request is served, and where config lives.
Design systemColour, type, geometry and motion.
API errorsThe error shape the API returns, and what each code means.
ReleasingHow a version is cut and published.