mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-07-02 00:17:40 +08:00
docs(markdown): human-centric instead of agents first [skip ci]
This commit is contained in:
@@ -59,7 +59,7 @@ headers {
|
|||||||
## Checklist When Adding/Updating a Route
|
## Checklist When Adding/Updating a Route
|
||||||
|
|
||||||
1. Create or update the `.bru` file in the matching folder under `.bruno/`.
|
1. Create or update the `.bru` file in the matching folder under `.bruno/`.
|
||||||
2. Include all form fields from the route handler — check `FormData*` calls in the route function.
|
2. Include all form fields from the route handler. Check `FormData*` calls in the route function.
|
||||||
3. For file upload fields (`files`, `watermark`, `stamp`, `embeds`), use `@file(...)` with a suitable test file.
|
3. For file upload fields (`files`, `watermark`, `stamp`, `embeds`), use `@file(...)` with a suitable test file.
|
||||||
4. Verify the URL path matches the route's `Path` field exactly.
|
4. Verify the URL path matches the route's `Path` field exactly.
|
||||||
5. If you add a new module folder, keep the naming consistent (e.g., `PDF Engines/Rotate/`).
|
5. If you add a new module folder, keep the naming consistent (e.g., `PDF Engines/Rotate/`).
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
# Operational Guidelines for Gotenberg
|
|
||||||
|
|
||||||
You are working on **Gotenberg**, a Docker-based API for converting documents to PDF. It is a widely used production dependency. Stability and backward compatibility are paramount. When in doubt about whether a change is breaking, flag it rather than assuming it's safe.
|
|
||||||
|
|
||||||
## Mandatory Workflow
|
|
||||||
|
|
||||||
Every task MUST follow these five steps in order. Do not skip any step.
|
|
||||||
|
|
||||||
### Step 1 — Plan
|
|
||||||
|
|
||||||
Before writing any code, produce a plan that covers:
|
|
||||||
|
|
||||||
- **Problem statement**: What needs to change and why.
|
|
||||||
- **Proposed solution**: The recommended approach with enough detail to implement (files to modify, interface changes, pipeline positioning, form fields, etc.).
|
|
||||||
- **Alternatives considered**: At least one alternative approach when pertinent, with a brief explanation of why the proposed solution is preferred.
|
|
||||||
- **Scope**: List every file that will be created or modified.
|
|
||||||
- **Testing strategy**: Which integration test tags will be affected, what new scenarios are needed, and whether unit tests are required.
|
|
||||||
|
|
||||||
Present the plan to the user and wait for approval before proceeding to Step 2. If the user provides a plan, validate it against the codebase and flag any issues before implementing.
|
|
||||||
|
|
||||||
### Step 2 — Implement
|
|
||||||
|
|
||||||
Implement the approved plan following the coding standards and patterns described in this document. After implementation, verify the build compiles (`go build ./...`).
|
|
||||||
|
|
||||||
### Step 3 — Test
|
|
||||||
|
|
||||||
Write or update tests based on the plan's testing strategy:
|
|
||||||
|
|
||||||
- **Integration tests** (primary): Gherkin scenarios in `test/integration/features/`. See [`test/integration/AGENTS.md`](test/integration/AGENTS.md) for the full reference.
|
|
||||||
- **Unit tests** (when applicable): Table-driven tests in `*_test.go` files using mocks from `pkg/gotenberg/mocks.go`.
|
|
||||||
|
|
||||||
### Step 4 — Review
|
|
||||||
|
|
||||||
Self-review the implementation against the [Review Checklist](#review-checklist). Fix any issues found before presenting the result to the user.
|
|
||||||
|
|
||||||
### Step 5 — Commit
|
|
||||||
|
|
||||||
Present the review to the user and **wait for explicit approval**. Do NOT commit until the user confirms. Once approved, create a commit following the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
||||||
|
|
||||||
```
|
|
||||||
<type>(<scope>): <description>
|
|
||||||
```
|
|
||||||
|
|
||||||
Common types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `ci`, `build`. The scope should match the module or area of the change (e.g., `chromium`, `pdfengines`, `api`).
|
|
||||||
|
|
||||||
Stage only the files related to the change. Do not use `git add -A` or `git add .`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Core Principles
|
|
||||||
|
|
||||||
- **Backward compatibility is law.** Never modify existing CLI flags, environment variables, or API form fields unless explicitly instructed to perform a breaking change. Flag any breaking change immediately.
|
|
||||||
- **Defensive programming.** Assume input is malformed. Handle errors explicitly. Never panic.
|
|
||||||
- **Atomic commits.** One feature or fix per PR. Isolate refactoring from feature work.
|
|
||||||
- **Idiomatic Go.** Follow "Effective Go" principles. All exported symbols must have GoDoc comments starting with their name.
|
|
||||||
|
|
||||||
## Project Layout
|
|
||||||
|
|
||||||
```
|
|
||||||
cmd/gotenberg/ → Entry point only (wiring/startup). No business logic.
|
|
||||||
pkg/gotenberg/ → Core module system, interfaces, utilities, mocks.
|
|
||||||
pkg/modules/ → Feature modules (api, chromium, libreoffice, pdfengines, etc.).
|
|
||||||
pkg/standard/ → Wires all standard modules together via imports.
|
|
||||||
test/integration/ → Gherkin feature files + Go test infrastructure.
|
|
||||||
build/ → Dockerfile, fonts, Chromium config.
|
|
||||||
.bruno/ → Bruno API collection (mirrors every route).
|
|
||||||
```
|
|
||||||
|
|
||||||
Key interfaces live in `pkg/gotenberg/` — `Module`, `Provisioner`, `Validator`, `Debuggable`. Every module implements `Descriptor()` and self-registers. When adding features, determine if they belong in an existing module or require a new one.
|
|
||||||
|
|
||||||
## Codebase Navigation
|
|
||||||
|
|
||||||
- Start with `pkg/gotenberg/` for core interfaces and `pkg/modules/` for feature implementations.
|
|
||||||
- The integration test infrastructure in `test/integration/scenario/` is well-structured — read `scenario.go` and `containers.go` to understand the Gherkin step definitions before writing new tests.
|
|
||||||
- Mocks for all major interfaces are in `pkg/gotenberg/mocks.go` — use them for unit tests rather than creating new ones.
|
|
||||||
- Import ordering is enforced: standard library, third-party, then `github.com/gotenberg/gotenberg/v8` — separated by blank lines.
|
|
||||||
- When making changes, run only the relevant integration test tag rather than the full suite (40min timeout).
|
|
||||||
- Telemetry infrastructure lives in `pkg/gotenberg/telemetry.go` (global Logger, Tracer, Meter) and `pkg/gotenberg/internal/` (log handlers, OTEL SDK init). HTTP semantic conventions are in `pkg/gotenberg/semconv/`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Makefile — the Only Build Interface
|
|
||||||
|
|
||||||
All build and verification tasks go through the Makefile. Do not run `go` commands directly unless debugging a specific package.
|
|
||||||
|
|
||||||
| Command | Purpose | When to use |
|
|
||||||
| ----------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
||||||
| `make build` | Build the Docker image | Before integration tests, or to verify compilation |
|
|
||||||
| `make run` | Run Gotenberg container via `docker compose` | Manual testing. Flags are configured via Makefile variables and compose.yaml |
|
|
||||||
| `make telemetry` | Start OpenTelemetry collector and OpenObserve | When testing telemetry locally |
|
|
||||||
| `make down` | Stop all compose containers | After manual testing |
|
|
||||||
| `make fmt` | Format Go code (`go fix`, `golangci-lint fmt`, `go mod tidy`) | Before every commit |
|
|
||||||
| `make lint` | Lint Go code (strict `.golangci.yml` config) | Before every commit. Zero errors permitted |
|
|
||||||
| `make lint-prettier` | Lint non-Go files (Markdown, YAML, etc.) with Prettier | Before every commit |
|
|
||||||
| `make prettify` | Format non-Go files (Markdown, YAML, etc.) with Prettier | Before every commit |
|
|
||||||
| `make test-unit` | Run unit tests (`go test -race ./...`) | After code changes to `pkg/` |
|
|
||||||
| `make test-integration` | Run integration tests (Gherkin/Godog, 40min timeout) | After any feature or route change |
|
|
||||||
| `make godoc` | Serve GoDoc at `localhost:6060` | To verify documentation |
|
|
||||||
|
|
||||||
## Module System
|
|
||||||
|
|
||||||
Gotenberg uses a self-registering module architecture inspired by CaddyServer. Each module:
|
|
||||||
|
|
||||||
- Lives in `pkg/modules/<name>/`
|
|
||||||
- Implements the `gotenberg.Module` interface (at minimum `Descriptor()`)
|
|
||||||
- May also implement `gotenberg.Provisioner`, `gotenberg.Validator`, or `gotenberg.Debuggable`
|
|
||||||
- Self-registers via `init()` and is wired through `pkg/standard/`
|
|
||||||
|
|
||||||
When adding a feature, first determine if it belongs in an existing module. Only create a new module if the feature represents a genuinely separate concern.
|
|
||||||
|
|
||||||
## Coding Patterns
|
|
||||||
|
|
||||||
- **Error handling:** Always wrap errors with context using `fmt.Errorf("description: %w", err)`. Never swallow errors silently.
|
|
||||||
- **Import ordering:** Enforced by `gci` — standard library, then third-party, then `github.com/gotenberg/gotenberg/v8`. Three groups separated by blank lines.
|
|
||||||
- **Mocks:** Comprehensive mock implementations for all major interfaces live in `pkg/gotenberg/mocks.go`. Use these for unit tests.
|
|
||||||
- **Logging:** Use `gotenberg.Logger(mod)` to get the module's slog logger during `Provision()`. All log calls must be context-aware: `logger.DebugContext(ctx, msg)`, `logger.InfoContext(ctx, msg)`, `logger.ErrorContext(ctx, msg)`. This propagates trace/span IDs into structured logs when OpenTelemetry is active.
|
|
||||||
- **Telemetry:** External tool calls (Chromium, LibreOffice, PDF engines, webhooks, downloads) must create OTEL spans with `trace.SpanKindClient` and `semconv.ServerAddress("toolname")`. Use `gotenberg.Tracer()` and `gotenberg.Meter()` for traces and metrics respectively.
|
|
||||||
- **No business logic in `cmd/`:** The `cmd/gotenberg/` package is strictly for wiring and startup.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Review Checklist
|
|
||||||
|
|
||||||
### Backward Compatibility
|
|
||||||
|
|
||||||
- [ ] No existing CLI flags renamed or removed
|
|
||||||
- [ ] No existing environment variables renamed or removed
|
|
||||||
- [ ] No existing API form fields renamed or removed
|
|
||||||
- [ ] No existing HTTP endpoints changed or removed
|
|
||||||
- [ ] No changes to default values that alter existing behavior
|
|
||||||
- [ ] Deprecated flags have both old and new names registered, with `fs.MarkDeprecated()`
|
|
||||||
|
|
||||||
If any of these are violated, the change **must** be flagged as a breaking change.
|
|
||||||
|
|
||||||
### Linting Standards
|
|
||||||
|
|
||||||
The `.golangci.yml` enforces strict rules including: `gosec`, `govet`, `errcheck`, `staticcheck`, `dupl`, `bodyclose`, `exhaustive`, `errname`, `sloglint`, `gocritic`, and more. Zero linting errors are permitted.
|
|
||||||
|
|
||||||
Formatters enforce `gci`, `gofmt`, `gofumpt`, `goimports` with import ordering:
|
|
||||||
|
|
||||||
1. Standard library
|
|
||||||
2. Third-party packages
|
|
||||||
3. `github.com/gotenberg/gotenberg/v8`
|
|
||||||
|
|
||||||
Three groups separated by blank lines.
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
|
|
||||||
- Errors are wrapped with context: `fmt.Errorf("description: %w", err)`. No swallowed errors.
|
|
||||||
- No business logic in `cmd/`.
|
|
||||||
- No panics in production code paths.
|
|
||||||
- Input is validated defensively.
|
|
||||||
- New features belong in the correct module (or justify a new one).
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- Every exported function, type, constant, and variable has a GoDoc comment starting with its name.
|
|
||||||
- New packages include a `doc.go` file.
|
|
||||||
- `README.md` is not modified unless explicitly requested.
|
|
||||||
|
|
||||||
### Definition of Done
|
|
||||||
|
|
||||||
A change is ready to merge only when:
|
|
||||||
|
|
||||||
1. Code compiles: `go build ./...`
|
|
||||||
2. Code is formatted: `make fmt`
|
|
||||||
3. All linters pass: `make lint` and `make lint-prettier`
|
|
||||||
4. Integration tests pass: `make test-integration` (at minimum, the relevant `TAGS`)
|
|
||||||
5. Unit tests pass: `make test-unit`
|
|
||||||
6. All exported symbols and new packages have compliant GoDoc
|
|
||||||
7. Bruno collection is updated (if routes were added or modified)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Scoped Guidelines
|
|
||||||
|
|
||||||
Detailed guidelines for specific areas of the codebase live in their own `AGENTS.md` files:
|
|
||||||
|
|
||||||
- [`test/integration/AGENTS.md`](test/integration/AGENTS.md) — Integration test framework, Gherkin step reference, available tags, and how to write new tests.
|
|
||||||
- [`.bruno/AGENTS.md`](.bruno/AGENTS.md) — Bruno API collection structure, `.bru` file format, conventions, and route update checklist.
|
|
||||||
- [`pkg/modules/pdfengines/AGENTS.md`](pkg/modules/pdfengines/AGENTS.md) — How to add new PDF engine features (Makefile variable and flag).
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Claude Code — Gotenberg
|
|
||||||
|
|
||||||
Read [AGENTS.md](AGENTS.md) first. It contains everything: core principles, project layout, coding standards, the mandatory 4-step workflow (Plan → Implement → Test → Review), integration test reference, review checklist, and Bruno collection guidelines.
|
|
||||||
+146
-16
@@ -1,6 +1,6 @@
|
|||||||
# Contributing to Gotenberg
|
# Contributing to Gotenberg
|
||||||
|
|
||||||
Thank you for your interest in contributing to Gotenberg! This guide will help you get started.
|
**Gotenberg** is a Docker-based API for converting documents to PDF. It is a widely used production dependency. Stability and backward compatibility are paramount. When in doubt about whether a change is breaking, flag it rather than assuming it's safe.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ Thank you for your interest in contributing to Gotenberg! This guide will help y
|
|||||||
|
|
||||||
- Go (see version in `go.mod`)
|
- Go (see version in `go.mod`)
|
||||||
- Docker
|
- Docker
|
||||||
- Node.js (see version in `.node-version`) — for Prettier linting
|
- Node.js (see version in `.node-version`), for Prettier linting
|
||||||
- [golangci-lint](https://golangci-lint.run/) v2+
|
- [golangci-lint](https://golangci-lint.run/) v2+
|
||||||
|
|
||||||
### Build and Run
|
### Build and Run
|
||||||
@@ -43,7 +43,13 @@ make test-integration TAGS="merge,split"
|
|||||||
|
|
||||||
## Submitting a Pull Request
|
## Submitting a Pull Request
|
||||||
|
|
||||||
Before opening a PR, verify:
|
For non-trivial changes, outline your approach before writing code. Open an issue or draft PR describing:
|
||||||
|
|
||||||
|
- What needs to change and why.
|
||||||
|
- The proposed solution, with enough detail to implement (files to modify, interface changes, form fields, etc.).
|
||||||
|
- Which integration test tags will be affected and what new scenarios are needed.
|
||||||
|
|
||||||
|
Before opening (or marking ready) a PR, verify:
|
||||||
|
|
||||||
1. Code compiles: `make build`
|
1. Code compiles: `make build`
|
||||||
2. Code is formatted: `make fmt` and `make prettify`
|
2. Code is formatted: `make fmt` and `make prettify`
|
||||||
@@ -51,24 +57,148 @@ Before opening a PR, verify:
|
|||||||
4. Integration tests pass: `make test-integration` (at minimum, the relevant tags)
|
4. Integration tests pass: `make test-integration` (at minimum, the relevant tags)
|
||||||
5. Unit tests pass: `make test-unit`
|
5. Unit tests pass: `make test-unit`
|
||||||
6. All exported symbols and new packages have GoDoc comments
|
6. All exported symbols and new packages have GoDoc comments
|
||||||
|
7. Bruno collection is updated (if routes were added or modified)
|
||||||
|
|
||||||
|
Review your changes against the [Review Checklist](#review-checklist) before submitting.
|
||||||
|
|
||||||
### Guidelines
|
### Guidelines
|
||||||
|
|
||||||
- **Conventional Commits.** Commit messages must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification (e.g., `feat(chromium): add screenshot endpoint`, `fix(api): handle empty body`).
|
|
||||||
- **One thing per PR.** Keep features, bug fixes, and refactoring in separate PRs.
|
- **One thing per PR.** Keep features, bug fixes, and refactoring in separate PRs.
|
||||||
- **Backward compatibility matters.** Do not rename or remove existing CLI flags, environment variables, or API form fields without discussion.
|
- **Backward compatibility matters.** Do not rename or remove existing CLI flags, environment variables, or API form fields without discussion.
|
||||||
- **Integration tests first.** When adding a feature or route, start by writing the Gherkin scenario in `test/integration/features/`.
|
- **Integration tests first.** When adding a feature or route, start by writing the Gherkin scenario in `test/integration/features/`. See [`test/integration/README.md`](test/integration/README.md) for the full reference.
|
||||||
- **Logging uses `gotenberg.Logger(mod)`** with context-aware calls (`*Context` variants).
|
- **Unit tests** when applicable: table-driven tests in `*_test.go` files using mocks from `pkg/gotenberg/mocks.go`.
|
||||||
- **External operations have OTEL traces** with appropriate SpanKind and semconv attributes.
|
|
||||||
- **No business logic in `cmd/`.** All logic belongs in `pkg/`.
|
|
||||||
|
|
||||||
## Detailed Guidelines
|
### Commit Conventions
|
||||||
|
|
||||||
The [`AGENTS.md`](AGENTS.md) files contain comprehensive guidelines used by both human contributors and AI-assisted tools:
|
If committing, follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
||||||
|
|
||||||
| File | What it covers |
|
```
|
||||||
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
<type>(<scope>): <description>
|
||||||
| [`AGENTS.md`](AGENTS.md) | Core principles, mandatory workflow, project layout, coding patterns, module system, Makefile reference, review checklist |
|
```
|
||||||
| [`test/integration/AGENTS.md`](test/integration/AGENTS.md) | Integration test framework (Godog/Gherkin), available tags, step reference, how to write new tests |
|
|
||||||
| [`.bruno/AGENTS.md`](.bruno/AGENTS.md) | Bruno API collection structure, `.bru` file format, conventions, route update checklist |
|
Common types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `ci`, `build`. The scope should match the module or area of the change (e.g., `chromium`, `pdfengines`, `api`).
|
||||||
| [`pkg/modules/pdfengines/AGENTS.md`](pkg/modules/pdfengines/AGENTS.md) | How to add new PDF engine features (Makefile variable and flag) |
|
|
||||||
|
Stage only the files related to the change. Do not use `git add -A` or `git add .`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
- **Backward compatibility is law.** Never modify existing CLI flags, environment variables, or API form fields unless explicitly instructed to perform a breaking change. Flag any breaking change immediately.
|
||||||
|
- **Defensive programming.** Assume input is malformed. Handle errors explicitly. Never panic.
|
||||||
|
- **Atomic commits.** One feature or fix per PR. Isolate refactoring from feature work.
|
||||||
|
- **Idiomatic Go.** Follow "Effective Go" principles. All exported symbols must have GoDoc comments starting with their name.
|
||||||
|
|
||||||
|
## Project Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/gotenberg/ → Entry point only (wiring/startup). No business logic.
|
||||||
|
pkg/gotenberg/ → Core module system, interfaces, utilities, mocks.
|
||||||
|
pkg/modules/ → Feature modules (api, chromium, libreoffice, pdfengines, etc.).
|
||||||
|
pkg/standard/ → Wires all standard modules together via imports.
|
||||||
|
test/integration/ → Gherkin feature files + Go test infrastructure.
|
||||||
|
build/ → Dockerfile, fonts, Chromium config.
|
||||||
|
.bruno/ → Bruno API collection (mirrors every route).
|
||||||
|
```
|
||||||
|
|
||||||
|
Key interfaces live in `pkg/gotenberg/`: `Module`, `Provisioner`, `Validator`, `Debuggable`. Every module implements `Descriptor()` and self-registers. When adding features, determine if they belong in an existing module or require a new one.
|
||||||
|
|
||||||
|
## Codebase Navigation
|
||||||
|
|
||||||
|
- Start with `pkg/gotenberg/` for core interfaces and `pkg/modules/` for feature implementations.
|
||||||
|
- The integration test infrastructure in `test/integration/scenario/` is well-structured. Read `scenario.go` and `containers.go` to understand the Gherkin step definitions before writing new tests.
|
||||||
|
- Mocks for all major interfaces are in `pkg/gotenberg/mocks.go`. Use them for unit tests rather than creating new ones.
|
||||||
|
- Import ordering is enforced: standard library, third-party, then `github.com/gotenberg/gotenberg/v8`, separated by blank lines.
|
||||||
|
- When making changes, run only the relevant integration test tag rather than the full suite (40min timeout).
|
||||||
|
- Telemetry infrastructure lives in `pkg/gotenberg/telemetry.go` (global Logger, Tracer, Meter) and `pkg/gotenberg/internal/` (log handlers, OTEL SDK init). HTTP semantic conventions are in `pkg/gotenberg/semconv/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Makefile: the Only Build Interface
|
||||||
|
|
||||||
|
All build and verification tasks go through the Makefile. Do not run `go` commands directly unless debugging a specific package.
|
||||||
|
|
||||||
|
| Command | Purpose | When to use |
|
||||||
|
| ----------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||||
|
| `make build` | Build the Docker image | Before integration tests, or to verify compilation |
|
||||||
|
| `make run` | Run Gotenberg container via `docker compose` | Manual testing. Flags are configured via Makefile variables and compose.yaml |
|
||||||
|
| `make telemetry` | Start OpenTelemetry collector and OpenObserve | When testing telemetry locally |
|
||||||
|
| `make down` | Stop all compose containers | After manual testing |
|
||||||
|
| `make fmt` | Format Go code (`go fix`, `golangci-lint fmt`, `go mod tidy`) | Before every commit |
|
||||||
|
| `make lint` | Lint Go code (strict `.golangci.yml` config) | Before every commit. Zero errors permitted |
|
||||||
|
| `make lint-prettier` | Lint non-Go files (Markdown, YAML, etc.) with Prettier | Before every commit |
|
||||||
|
| `make prettify` | Format non-Go files (Markdown, YAML, etc.) with Prettier | Before every commit |
|
||||||
|
| `make test-unit` | Run unit tests (`go test -race ./...`) | After code changes to `pkg/` |
|
||||||
|
| `make test-integration` | Run integration tests (Gherkin/Godog, 40min timeout) | After any feature or route change |
|
||||||
|
| `make godoc` | Serve GoDoc at `localhost:6060` | To verify documentation |
|
||||||
|
|
||||||
|
## Module System
|
||||||
|
|
||||||
|
Gotenberg uses a self-registering module architecture inspired by CaddyServer. Each module:
|
||||||
|
|
||||||
|
- Lives in `pkg/modules/<name>/`
|
||||||
|
- Implements the `gotenberg.Module` interface (at minimum `Descriptor()`)
|
||||||
|
- May also implement `gotenberg.Provisioner`, `gotenberg.Validator`, or `gotenberg.Debuggable`
|
||||||
|
- Self-registers via `init()` and is wired through `pkg/standard/`
|
||||||
|
|
||||||
|
When adding a feature, first determine if it belongs in an existing module. Only create a new module if the feature represents a genuinely separate concern.
|
||||||
|
|
||||||
|
## Coding Patterns
|
||||||
|
|
||||||
|
- **Error handling:** Always wrap errors with context using `fmt.Errorf("description: %w", err)`. Never swallow errors silently.
|
||||||
|
- **Import ordering:** Enforced by `gci`: standard library, then third-party, then `github.com/gotenberg/gotenberg/v8`. Three groups separated by blank lines.
|
||||||
|
- **Mocks:** Comprehensive mock implementations for all major interfaces live in `pkg/gotenberg/mocks.go`. Use these for unit tests.
|
||||||
|
- **Logging:** Use `gotenberg.Logger(mod)` to get the module's slog logger during `Provision()`. All log calls must be context-aware: `logger.DebugContext(ctx, msg)`, `logger.InfoContext(ctx, msg)`, `logger.ErrorContext(ctx, msg)`. This propagates trace/span IDs into structured logs when OpenTelemetry is active.
|
||||||
|
- **Telemetry:** External tool calls (Chromium, LibreOffice, PDF engines, webhooks, downloads) must create OTEL spans with `trace.SpanKindClient` and `semconv.ServerAddress("toolname")`. Use `gotenberg.Tracer()` and `gotenberg.Meter()` for traces and metrics respectively.
|
||||||
|
- **No business logic in `cmd/`:** The `cmd/gotenberg/` package is strictly for wiring and startup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
### Backward Compatibility
|
||||||
|
|
||||||
|
- [ ] No existing CLI flags renamed or removed
|
||||||
|
- [ ] No existing environment variables renamed or removed
|
||||||
|
- [ ] No existing API form fields renamed or removed
|
||||||
|
- [ ] No existing HTTP endpoints changed or removed
|
||||||
|
- [ ] No changes to default values that alter existing behavior
|
||||||
|
- [ ] Deprecated flags have both old and new names registered, with `fs.MarkDeprecated()`
|
||||||
|
|
||||||
|
If any of these are violated, the change **must** be flagged as a breaking change.
|
||||||
|
|
||||||
|
### Linting Standards
|
||||||
|
|
||||||
|
The `.golangci.yml` enforces strict rules including: `gosec`, `govet`, `errcheck`, `staticcheck`, `dupl`, `bodyclose`, `exhaustive`, `errname`, `sloglint`, `gocritic`, and more. Zero linting errors are permitted.
|
||||||
|
|
||||||
|
Formatters enforce `gci`, `gofmt`, `gofumpt`, `goimports` with import ordering:
|
||||||
|
|
||||||
|
1. Standard library
|
||||||
|
2. Third-party packages
|
||||||
|
3. `github.com/gotenberg/gotenberg/v8`
|
||||||
|
|
||||||
|
Three groups separated by blank lines.
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
|
||||||
|
- Errors are wrapped with context: `fmt.Errorf("description: %w", err)`. No swallowed errors.
|
||||||
|
- No business logic in `cmd/`.
|
||||||
|
- No panics in production code paths.
|
||||||
|
- Input is validated defensively.
|
||||||
|
- New features belong in the correct module (or justify a new one).
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Every exported function, type, constant, and variable has a GoDoc comment starting with its name.
|
||||||
|
- New packages include a `doc.go` file.
|
||||||
|
- `README.md` is not modified unless explicitly requested.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scoped Guidelines
|
||||||
|
|
||||||
|
Detailed guidelines for specific areas of the codebase:
|
||||||
|
|
||||||
|
- [`test/integration/README.md`](test/integration/README.md): Integration test framework, Gherkin step reference, available tags, and how to write new tests.
|
||||||
|
- [`.bruno/README.md`](.bruno/README.md): Bruno API collection structure, `.bru` file format, conventions, and route update checklist.
|
||||||
|
- [`pkg/modules/pdfengines/README.md`](pkg/modules/pdfengines/README.md): How to add new PDF engine features (Makefile variable and flag).
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
# Gemini — Gotenberg
|
|
||||||
|
|
||||||
Read [AGENTS.md](AGENTS.md) first. It contains everything: core principles, project layout, coding standards, the mandatory 4-step workflow (Plan → Implement → Test → Review), integration test reference, review checklist, and Bruno collection guidelines.
|
|
||||||
+11
-23
@@ -2,40 +2,28 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Please ensure to keep your environment up to date and use only the latest version of Gotenberg.
|
Only the latest version of Gotenberg receives security updates and patches. Keep your environment up to date.
|
||||||
Security updates and patches will be applied only to the most recent version.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
Your help in identifying vulnerabilities in our project is much appreciated.
|
If you discover a security vulnerability, do not publish it publicly. Send details via email to _neuhart [dot] julien [at] gmail [dot] com_ with the subject indicating a Gotenberg security vulnerability report.
|
||||||
We take all reports regarding security seriously.
|
|
||||||
|
|
||||||
If you discover a security vulnerability, please refrain from publishing it publicly.
|
Include:
|
||||||
Instead, kindly send us the details via email to _neuhart [dot] julien [at] gmail [dot] com_.
|
|
||||||
|
|
||||||
In the subject of your email, please indicate that it's a security vulnerability report for Gotenberg.
|
|
||||||
In your message, please include:
|
|
||||||
|
|
||||||
- A detailed description of the vulnerability.
|
- A detailed description of the vulnerability.
|
||||||
- The steps to reproduce the issue.
|
- Steps to reproduce the issue.
|
||||||
- Any potential impact of the vulnerability on the users or system.
|
- Any potential impact on users or the system.
|
||||||
|
|
||||||
Please remember that this process is done in a _'best-effort'_ manner.
|
This process is handled on a _'best-effort'_ basis. Response speed may vary depending on severity and available resources.
|
||||||
This means we strive to respond and act as quickly as possible, but the speed may vary depending on the severity of
|
|
||||||
the issue and our resources.
|
|
||||||
|
|
||||||
Thank you in advance for helping to keep our project safe!
|
|
||||||
|
|
||||||
## Disclosure Policy
|
## Disclosure Policy
|
||||||
|
|
||||||
Once we have received your vulnerability report, we will work to validate and reproduce the issue.
|
Once a vulnerability report is received and confirmed:
|
||||||
If we can confirm the vulnerability, we will proceed to:
|
|
||||||
|
|
||||||
- Work on a fix and a release timeline.
|
- A fix and release timeline will be prepared.
|
||||||
- Notify you when the fix has been implemented and released.
|
- You will be notified when the fix is released.
|
||||||
- Credit you for discovering the vulnerability (unless you request anonymity).
|
- You will be credited for the discovery (unless you request anonymity).
|
||||||
- Please note that we will do our best to keep you informed about the progress towards resolving the issue.
|
|
||||||
|
|
||||||
## Comments on this Policy
|
## Comments on this Policy
|
||||||
|
|
||||||
If you have suggestions on how this process could be improved, please submit a pull request.
|
If you have suggestions on how this process could be improved, submit a pull request.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Integration Tests
|
# Integration Tests
|
||||||
|
|
||||||
- **Framework:** Gherkin (BDD) via [Godog](https://github.com/cucumber/godog), with `testcontainers-go` for Docker orchestration.
|
- **Framework:** Gherkin (BDD) via [Godog](https://github.com/cucumber/godog), with `testcontainers-go` for Docker orchestration.
|
||||||
- **Feature files:** `test/integration/features/*.feature` — one file per endpoint or capability.
|
- **Feature files:** `test/integration/features/*.feature`, one file per endpoint or capability.
|
||||||
- **Test infrastructure:** `test/integration/scenario/` — Go step definitions, container management, HTTP helpers, PDF validation.
|
- **Test infrastructure:** `test/integration/scenario/`, Go step definitions, container management, HTTP helpers, PDF validation.
|
||||||
- **Entry point:** `test/integration/main_test.go` (build tag: `integration`).
|
- **Entry point:** `test/integration/main_test.go` (build tag: `integration`).
|
||||||
- **Test data:** `test/integration/testdata/`
|
- **Test data:** `test/integration/testdata/`
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ make test-integration PLATFORM=linux/arm64 # Force a specific platform
|
|||||||
|
|
||||||
- `I make a "(GET|HEAD)" request to Gotenberg at the "<endpoint>" endpoint`
|
- `I make a "(GET|HEAD)" request to Gotenberg at the "<endpoint>" endpoint`
|
||||||
- `I make a "(GET|HEAD)" request to Gotenberg at the "<endpoint>" endpoint with the following header(s):` (table: name | value)
|
- `I make a "(GET|HEAD)" request to Gotenberg at the "<endpoint>" endpoint with the following header(s):` (table: name | value)
|
||||||
- `I make a "(POST)" request to Gotenberg at the "<endpoint>" endpoint with the following form data and header(s):` (table: name | value | kind — where kind is `file`, `field`, or `header`)
|
- `I make a "(POST)" request to Gotenberg at the "<endpoint>" endpoint with the following form data and header(s):` (table: name | value | kind, where kind is `file`, `field`, or `header`)
|
||||||
- `I make <N> concurrent "(POST)" requests to Gotenberg at the "<endpoint>" endpoint with the following form data and header(s):` (same table format)
|
- `I make <N> concurrent "(POST)" requests to Gotenberg at the "<endpoint>" endpoint with the following form data and header(s):` (same table format)
|
||||||
- `I wait for the asynchronous request to the webhook`
|
- `I wait for the asynchronous request to the webhook`
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ make test-integration PLATFORM=linux/arm64 # Force a specific platform
|
|||||||
- `the (response|webhook request) cookie "<name>" should be "<value>"`
|
- `the (response|webhook request) cookie "<name>" should be "<value>"`
|
||||||
- `the (response|webhook request) body should match string:` (docstring)
|
- `the (response|webhook request) body should match string:` (docstring)
|
||||||
- `the (response|webhook request) body should contain string:` (docstring)
|
- `the (response|webhook request) body should contain string:` (docstring)
|
||||||
- `the (response|webhook request) body should match JSON:` (docstring — use `"ignore"` for dynamic values like timestamps)
|
- `the (response|webhook request) body should match JSON:` (docstring, use `"ignore"` for dynamic values like timestamps)
|
||||||
- `the webhook event should match JSON:` (docstring — use `"ignore"` for dynamic values; polls for up to 5s)
|
- `the webhook event should match JSON:` (docstring, use `"ignore"` for dynamic values; polls for up to 5s)
|
||||||
- `there should be <N> PDF(s) in the (response|webhook request)`
|
- `there should be <N> PDF(s) in the (response|webhook request)`
|
||||||
- `there should be the following file(s) in the (response|webhook request):` (table of filenames)
|
- `there should be the following file(s) in the (response|webhook request):` (table of filenames)
|
||||||
- `the "<name>" PDF should have <N> page(s)`
|
- `the "<name>" PDF should have <N> page(s)`
|
||||||
Reference in New Issue
Block a user