Contributing
How to add a parser, run tests, submit a pull request, and what code style is expected.
Setup
bash
git clone https://github.com/annavetech/annave-pdf-engine-golang
cd annave-pdf-engine-golang
# Build
go build ./cmd/server
# Run tests
go test ./...
# Run the server locally (no auth)
go run cmd/server/main.goGo 1.23 or later is required.
Running tests
bash
# All tests
go test ./...
# Single package with verbose output
go test -v ./internal/engine/...
# Single test function
go test -v -run TestPipeline_Run_Markdown ./internal/engine/...
# Fuzz the Markdown parser for 30 seconds
go test -fuzz=FuzzMdParser -fuzztime=30s ./internal/parser/...
# Race detector
go test -race ./...Code style
SPDX header on every .go file:
go
// Copyright 2026 Anna Veretennykova
//
// SPDX-License-Identifier: Apache-2.0- Comments only when the reason is non-obvious — not what the code does, but why it does it that way.
- No
_test.gofile uses mocks for the database, filesystem, or HTTP. The pipeline tests callPipeline.Rundirectly. The HTTP tests usehttptest.NewRecorder. No fakes for the PDF renderer — tests assert on the error return, not the PDF content. gofmtis the formatter. No additional linters are required, butgo vet ./...must pass.- Error codes must be added to
config/messages.yamlbefore they are used in Go code. Do not hardcode message strings in.gofiles.
How to add an input format
See docs/ARCHITECTURE.md for the full walkthrough. Short version:
- Create
internal/parser/yourformat.gowith a struct implementingDocumentParser(two methods:CanParse,Parse). - Add the format constant and extension mappings to
internal/parser/registry.go. - Register the parser in
NewRegistry()— binary parsers (magic-byte checks) before text parsers in theorderedslice. - Write a test in
internal/parser/yourformat_test.go. The test fixture should be a real document from the ANNÁVE PDF Engine documentation — not lorem ipsum. This doubles as self-documenting content that people will not delete. - Update the
ENGINE_ERR_UNSUPPORTED_FORMATmessage inconfig/messages.yamlto include the new format name.
The HTTP handler, pipeline, and renderer require no changes.
How to add a pipeline stage
The six stages are fixed at the architectural level. Adding a seventh stage requires:
- Write the stage function in
internal/engine/. - Add a new
EngineStageconstant ininternal/engine/errors.goand add it to thestageenum inschema/error.v1.schema.json. - Call it in
Pipeline.Runininternal/engine/pipeline.goat the correct position. - Write tests in
internal/engine/that exercise the new stage in isolation and as part of the full pipeline.
Submitting a pull request
- Fork and create a branch from
main. - Make your changes.
go build ./...andgo test ./...must pass. - Add a test for any new behaviour. For parsers, use a real fixture from the engine documentation.
- Open a PR against
main. Describe what the change does and why, not just what files changed. - Do not bump the version in
internal/engine/config.go— that is done at release time.
Versioning
The engine follows Semantic Versioning. The version is set in internal/engine/config.go:
go
const EngineVersion = "1.0.0"- Patch (1.0.x): bug fixes, no API or config key changes
- Minor (1.x.0): new parsers, new config keys (all backward compatible)
- Major (x.0.0): breaking changes to the HTTP API, error code scheme, or AST structure
Reporting bugs
Open an issue at the project repository. Include:
- The input format
- A minimal reproduction (smallest input that triggers the bug)
- The
X-Request-Idheader from the failing response - The full JSON error body