Contributing to kafkito¶
Thanks for considering a contribution!
DCO¶
Every commit must include a Signed-off-by: trailer certifying the
Developer Certificate of Origin.
Add it automatically with git commit -s. The DCO check is enforced by
GitHub Actions.
Workflow¶
- Fork, branch, code.
make check— runs Go tests, golangci-lint, the OpenAPI lint and generated-types drift check (make api-check) and all frontend checks. Requires Go, Bun and curl on your PATH.make lintdownloads the pinned golangci-lint release (GOLANGCI_LINT_VERSIONin theMakefile, the same version CI uses) into./binon first use and lints both the default and thebtpbuild. To bump it, change the Makefile variable and thegolangci-lint-actionversion in.github/workflows/ci.ymltogether (make lint-version-checkenforces this). CI runs the same Makefile targets (make test,make api-check,make frontend-check); only golangci-lint runs via its GitHub Action, pinned to the same version.make actionlintlints the GitHub workflows.
make frontend-check runs Biome (lint and format, including the
accessibility rules and the file-naming convention), TypeScript, knip
(unused files, exports and dependencies), the production build and Vitest.
The Vitest run includes the repo-wide checks in frontend/src/__checks__/
(design tokens, contrast, query keys, route orphans, date formatting).
make e2e is opt-in: it starts Kafka and the Schema Registry via Compose
and a devauth build of kafkito, then runs the Playwright walks in
frontend/e2e/ (including axe accessibility scans). Besides Docker, Bun
and Go it needs curl and jq on your PATH (the fixture seeding talks to
the Schema Registry REST API). After a failed run,
stop the binary and the Schema Registry with make e2e-down. See
frontend/e2e/README.md.
CI jobs: go, frontend, api-breaking (oasdiff against the base
branch, PRs only), docker-build, actionlint and dco in ci.yml;
playwright in e2e.yml; the secret scans in secret-scan.yml.
3. Changing the HTTP API? Edit api/openapi.yaml (the contract, see ADR-0005)
and run make api-generate to refresh the generated server interface and
frontend types. A new endpoint then needs its strict handler method, its
mount in internal/server/api_routes.go and an apiOps test entry; the
steps are in
ADR-0005, "Adding an endpoint".
4. Open a PR with a clear description and a Test plan.
5. Sign off your commits (-s).
Pure formatting commits are listed in .git-blame-ignore-revs. GitHub skips
them in blame views; locally run
git config blame.ignoreRevsFile .git-blame-ignore-revs once per clone.
Local development¶
Requires Go 1.26+, Bun 1.4+, and Docker.
make worktree-init # writes .env.dev with a free port pair
make dev # Compose + backend (air) + frontend (Vite), one command
Open the Vite URL printed in the [frontend] stream
(default http://localhost:37422). Backend changes under cmd/,
internal/, or api/ rebuild automatically; frontend changes hot-reload
through Vite. Press Ctrl-C in the make dev terminal to stop both
processes (the Compose stack stays up — tear it down with make dev-down).
The backend listens on 127.0.0.1 only, because auth mode off requires a
loopback address; Vite proxies /api to it.
Multiple git worktrees can run make dev in parallel; each calls
make worktree-init once to claim a free port pair, and they share the
same Compose-backed Kafka and Schema Registry.
From an IDE, running air directly works too — .air.toml loads
.env.dev itself, as long as you've run make worktree-init once.
Pre-commit hooks¶
Optional. .pre-commit-config.yaml defines lean hooks that only look at
staged files:
gitleaks— blocks credentials (see Secret scanning).golangci-lint-fmt— gofmt/goimports via the pinned golangci-lint in./bin(installed on first use, likemake lint).biome-check— Biome lint and format check for the frontend sources (frontend/src,frontend/e2e, config files); needsmake frontend-install.
Enable them once per clone:
The formatter hook rewrites files in place and fails the commit; review and
stage the changes, then commit again. make check and CI remain the gate.
Style¶
- Backend: idiomatic Go 1.26, golangci-lint clean.
- Frontend: Tailwind tokens from
@theme; the default palette is disabled there. Seedocs/DESIGN_GUIDELINES.md. - Frontend layout: primitives in
frontend/src/components/ui/, domain components infrontend/src/features/<domain>/, PascalCase component files (enforced by Biome). Seedocs/DESIGN_GUIDELINES.md§ 10. - UI strings and code comments are English only. No emojis in UI chrome, logs, or commit messages.
AI coding agents¶
AGENTS.md and frontend/AGENTS.md are the instructions for coding agents
(Claude Code, Codex, Cursor, Copilot); CLAUDE.md and frontend/CLAUDE.md
import them and add what is specific to Claude Code. The shared Claude Code
configuration is committed: .claude/settings.json (permissions and hooks),
.claude/hooks/, .claude/skills/, .claude/agents/ and .mcp.json.
Personal settings belong in .claude/settings.local.json and
CLAUDE.local.md, which are gitignored. Agents follow the rules above (DCO
sign-off, make check, no edits to generated files) and open pull requests
as drafts, because .github/workflows/auto-merge-from-owner.yml enables
auto-merge for every non-draft PR by the owner. When you change a command, a
path or a convention these files mention, update them in the same PR.
Releasing¶
Releases are cut manually by pushing a signed v* tag; everything else is
automated by .github/workflows/release.yml and .goreleaser.yaml.
- In the release-prep commit, add an entry for the new version (without the
leading
v) and today's date (YYYY-MM-DD) tofrontend/src/content/changelog.ts. This is the curated, user-facing "What's new" shown in the app. Check it withmake release-check VERSION=vX.Y.Z. - Tag and push:
git tag -s vX.Y.Z -m vX.Y.Z && git push origin vX.Y.Z. - The
release-gatejob fails the release before anything is built if step 1 is missing. Then goreleaser builds the binaries and archives (withSHA256SUMSand SBOMs), pushes theghcr.io/finkeflo/kafkitoimages (vX.Y.Z,latest, and the-btp/-localvariants) and publishes the GitHub release. Tags with a pre-release suffix (e.g.v1.2.0-rc.1) are marked as pre-releases.
The GitHub release notes are generated from the Conventional Commit subjects
since the previous tag (grouped into Features, Bug Fixes, Security, Others and
Dependencies; chore, ci, test, style and docs(changelog) are left
out), so write commit subjects for humans.
make release-snapshot runs the whole pipeline locally without publishing
(requires goreleaser v2, Docker with buildx and syft); output goes to ./dist.
Secret scanning¶
Secrets must never enter the repo. Three layers protect against accidents:
- Local pre-commit hook (Gitleaks). Enable the
pre-commit hooks once after cloning;
git committhen aborts when Gitleaks finds a credential in the staged diff. - CI scan (TruffleHog).
.github/workflows/secret-scan.ymlscans every push tomainand every PR. Verified findings fail the job. - GitHub Push Protection. Enabled in repo settings; blocks pushes containing recognised provider tokens server-side.
If a secret leaks despite this, rotate the credential at the provider first, then clean the history (git filter-repo).
License¶
By submitting a contribution, you agree that your work is licensed under the Apache-2.0 License (this project's outbound license), as certified by the DCO sign-off.