Skip to content

Contributing

This page helps you build Goiabada from source, test a change and send it as a pull request.

Bug reports and pull requests are welcome. Code and contributions made with AI tools are welcome too, as long as they’re good quality: correct, tested and in keeping with the code around them, as any change must be. Not sure where to start? Pick something from the GitHub issues.

Everything you need, Go, the linters, the Tailwind CLI and the four databases, runs in a dev container, so the only things your machine needs are Docker, an editor that opens dev containers, such as VS Code with the Dev Containers extension, and sh, which Linux and macOS have. On Windows, clone the repository inside WSL and open it from there, or add Git for Windows’ usr\bin directory to the PATH: neither WSL nor Git for Windows’ default install puts sh on the Windows PATH.

  1. Clone the repository:

    Terminal window
    git clone https://github.com/leodip/goiabada.git
  2. Open the repository’s src folder in your editor, not the repository itself. The dev container is defined in src/.devcontainer, and an editor looks for it in the folder you open.

  3. Reopen the folder in the container. In VS Code, that’s Dev Containers: Reopen in Container from the command palette. The first build takes a few minutes. Before it, src/.devcontainer/generate-env.sh writes src/.devcontainer/.env, the stack’s data key and database passwords, drawn fresh for your checkout. It runs on your machine, which is why it needs sh.

Run the commands below inside the container, from the directory each names, except the npm commands, which run on your own machine.

  1. Start the auth server, from src/authserver:

    Terminal window
    make serve
  2. Start the admin console in a second terminal, from src/adminconsole:

    Terminal window
    make serve
  3. Open the admin console at http://localhost:19091 and sign in as the first administrator: email [email protected], password devcontainer-admin-password. The auth server is at http://localhost:19090.

Each rebuilds and restarts when you save a Go file or a template in its own module. A change under src/core isn’t watched: save a file in the server’s module, or run make serve again, to pick it up.

The test suite is one script, run-tests.sh. Run all of it, from src/authserver:

Terminal window
./run-tests.sh

That’s every tier below, the data and integration tiers on all four databases, so it takes a while. While you work, run the tier your change touches with --type:

Tier (--type) What it runs
internal The auth server’s unit tests
core The core module’s unit tests
adminconsole The admin console’s unit tests
setup The setup wizard’s tests
modules internal, core and adminconsole together
data The data layer against a real database
integration End-to-end tests against a running auth server, which the script builds, starts and stops
lint The linters, and the checks that generated files are committed
all Everything. The default

For example, the three unit tiers:

Terminal window
./run-tests.sh --type modules

Three more options narrow a run:

  • --db picks the database for data and integration: mysql, postgres, mssql, sqlite, or all, the default. SQLite is the quickest.
  • --run takes a go test -run pattern. A pattern that matches no test fails the run, so a typo doesn’t pass as green.
  • --race runs the unit tiers and the setup wizard’s tests under Go’s race detector.
Terminal window
./run-tests.sh --type integration --db sqlite --run 'TestToken_'

./run-tests.sh --help lists every option.

The Playwright suites in e2e/ run against the maintainer’s VPS and need SSH access, which external contributors don’t have. You’re welcome to write or improve these tests. Follow the e2e README, run npm ci and npm run typecheck from e2e/playwright on your machine, and say in your pull request that the browser suites need a maintainer to run them.

Some committed files are written by a tool. When your change touches what one is written from, run its command and commit what it changes:

When you change Run From
A database migration go run ./cmd/schemadump src/authserver
An exported symbol in a core package go run ./cmd/ownershipdump src/core
An interface a mock is generated for ./generate-mocks.sh src/authserver
A template’s CSS classes ./build.sh src/authserver or src/adminconsole, whichever owns the template
A tool version in versions.yaml ./version-manager.sh update src/authserver

schemadump regenerates the schema.golden file of all four databases, which the data tier compares against a freshly migrated database. The lint tier reruns the mocks, the ownership table and the CSS, and fails when any of them differs from what’s committed.

The docs site is in site/, and every page follows site/STYLE.md: the voice, the shape of a page and the words the glossary gives each concept.

The dev container has no npm, so build the site on your own machine, with the Node.js version site/Dockerfile builds it with, from site/:

Terminal window
npm ci
npm run dev

That serves a live preview at http://localhost:4321. Before you send a change, build the site and run its checks’ tests:

Terminal window
npm run build
npm test

The build fails on a broken link, including a link to the site from the Go code under src/, so move a page or rename a heading in the same change as every link to it.

Goiabada has four Go modules:

src/
├── authserver/ The auth server: OAuth2 and OpenID Connect, sign-in, the APIs
├── adminconsole/ The admin console, a client of the auth server
├── core/ What both servers share
├── cmd/goiabada-setup/ The setup wizard, a module of its own
└── build/ The release Dockerfiles and build scripts

ARCHITECTURE.md at the repository root says which module owns what, and the unit tiers hold the code to it. AGENTS.md gives AI coding assistants the commands and conventions for working here; CLAUDE.md is a checked copy. The guides in docs/development/ cover authentication, data access, application conventions, UI, tests, guards and package responsibilities. Read the guide for the part you’re changing.

Much of what a reviewer would otherwise check is a test that fails: the architecture rules, the logging convention, gofmt, the API error codes and audit events listed in the docs, and the docs pages that state a fact the code decides, this one included. When you change one of those facts, change the page in the same pull request.

The dev container runs MySQL, PostgreSQL and SQL Server beside it, and make serve uses SQL Server. The tests leave that database alone: each data and integration run starts from an empty database of its own. ./run-tests.sh does stop a running make serve, though: it frees ports 19090, 19091 and 19190 before the data and integration tiers and again when it exits, so start make serve again afterwards.

Mailpit runs beside them too. Under Email in the admin console’s settings, turn on Send email and set the host to mailpit, the port to 1025, the encryption to None, and Sender email to any address, such as [email protected]. Every mail Goiabada sends then lands in Mailpit, at http://localhost:8025.

CI runs the same tiers on every pull request, a job each, and builds the site. The data, integration and race jobs wait until the pull request is out of draft.