apistockdocs
v0.4 GitHub apistock.dev
Technical/Architecture

Services and libraries

Everything apistock depends on, grouped by role: what it is, why it was chosen, where it's used, what problem it solves, what would happen without it, and how it's set up. Versions are the ones pinned in the repository's go.mod files and compose files when this page was written; the files are the source of truth.

The dependency rules behind this list (ADR-0019): the core library (apistock.dev) may only depend on the standard library, the OpenTelemetry API and golang.org/x; everything heavier lives in a module that an app imports only if it uses it. internal/archtest fails the build when core gains another dependency.

Runtime services#

What a Full app talks to while it runs.

PostgreSQL#

What The relational database
Why The only required service (ADR-0005). It stores application data, users and sessions, runtime settings, the job queue (River), the audit log and release records, so a production app needs nothing else: no Redis, no message broker
Where modules/postgres (pool, transactions, migrations), every repository, modules/settings, modules/jobs, modules/auditpg, modules/releases
Version postgres:18 in compose.yaml; CI tests against the same image
Without it A Full app doesn't start: DATABASE_URL is required
Setup Development: aps dev or docker compose up -d --wait. Production: any managed PostgreSQL; set DATABASE_URL and run cmd/migrate before each release. Always in Docker locally, never installed on the machine (ADR-0028)

Email provider: Resend or SMTP#

What Delivers email: Resend through its HTTP API (modules/mail/resend), or any SMTP server (modules/mail/smtp, standard library net/smtp)
Why Sign-up codes, password resets and security alerts must reach real inboxes with SPF and DKIM (ADR-0025, ADR-0037)
Where internal/app/infra_mail.go builds the sender; the apistock.mail.send job worker calls it
Without it Production refuses to start without credentials; users can't verify their email or reset passwords
Setup aps add mail; email guide

Google and Apple#

External identity providers for sign-in, used only when configured. Endpoints: Google accounts.google.com (authorization), oauth2.googleapis.com (token) and Google's JWKS; Apple appleid.apple.com (/auth/authorize, /auth/token, /auth/keys, /auth/revoke). See authentication.

An OTLP backend (optional)#

Any OpenTelemetry-compatible collector or vendor receives traces and metrics when OTEL_EXPORTER_OTLP_ENDPOINT is set. Without it, telemetry stays in-process and logs still carry trace IDs.

Development services#

Run by aps dev from the app's compose.yaml. None of them run in production.

Mailpit#

What A fake email server with a web inbox (mailpit.axllent.org)
Why Every flow that sends email (sign-up, reset, alerts) must be testable locally without a provider account and without emailing real people by mistake
Where compose.yaml service mailpit (axllent/mailpit:v1.27), SMTP on 127.0.0.1:1025, inbox on http://127.0.0.1:8025. The app sends to it when MAIL_DELIVERY is mailpit (the development default), through MAILPIT_SMTP_ADDR
How it works It accepts any message over SMTP without authentication and stores it; the web UI and its HTTP API (/api/v1/messages, /api/v1/search) show them. Tests read codes from that API
Without it Development email sends fail and retry; nobody can finish sign-up locally. The app still starts
Production Refused: MAIL_DELIVERY=mailpit is for development
Setup Nothing: aps dev starts it. Ports: MAILPIT_SMTP_PORT, MAILPIT_WEB_PORT. The repository's own compose.yaml runs another instance on 51025 and 58025 for library tests

Grafana LGTM#

What grafana/otel-lgtm:0.33.0: Grafana with Loki, Tempo and Prometheus-compatible storage and an OpenTelemetry collector, in one container
Why To see traces, metrics and logs locally with no setup
Where compose.yaml service grafana, profile observability; aps dev --observability starts it and sets OTEL_EXPORTER_OTLP_ENDPOINT
Without it Nothing breaks; telemetry isn't exported
Setup aps dev --observability, then http://127.0.0.1:3000

Docker and Docker Compose#

Run the services above, with health checks (pg_isready, mailpit readyz) that docker compose up --wait waits for. The Dockerfile builds production images (golang:1.26 builder, gcr.io/distroless/static-debian12:nonroot runtime with /api and /migrate).

Core Go libraries#

Imported by generated apps through the apistock modules.

Library Version Used in What it does and why Without it
Go standard library 1.26 Everywhere net/http routing (method and wildcard patterns), log/slog, crypto/*, http.CrossOriginProtection, net/smtp. apistock prefers it before any dependency
Huma github.com/danielgtaylor/huma/v2 v2.39.1 modules/openapi, each module's delivery/ Code-first API: Go request and response types become validation, OpenAPI 3.1 and problem+json errors (ADR-0027, spike). Confined to delivery/ Hand-written validation and a spec that drifts from the code
pgx github.com/jackc/pgx/v5 v5.11.0 modules/postgres, repositories, settings, jobs, auditpg, releases PostgreSQL driver and pool, with native types, LISTEN/NOTIFY (live settings) and tracing hooks. Hand-written SQL on it, no ORM (ADR-0032) No database access
goose github.com/pressly/goose/v3 v3.28.0 modules/postgres (postgres.Migrate) Applies SQL migration files in order, under an advisory lock, recording versions Manual schema changes
River github.com/riverqueue/river v0.47.0 modules/jobs Transactional job queue on PostgreSQL: retries, scheduling, a leader for periodic jobs, and enqueueing inside the same transaction as the data (ADR-0033) Email sent inside requests, no retries, a separate broker
github.com/robfig/cron/v3 v3.0.1 modules/jobs Parses 5-field cron schedules of job definitions No cron schedules
OpenTelemetry Go go.opentelemetry.io/otel, SDK, OTLP HTTP exporters, otelhttp v1.46.0 / contrib v0.71.0 Core (trace API only), modules/telemetry, modules/postgres, modules/jobs Traces, metrics and correlated logs; vendor-neutral export (ADR-0007) No tracing; logs without trace IDs
golang.org/x/time v0.16.0 Core ratelimit Token-bucket limiter behind the sign-in rate limit No brute-force protection per IP

Authentication libraries#

All in modules/auth and its subpackages.

Library Version Used in What it does and why
golang.org/x/crypto v0.57.0 modules/auth argon2id password hashing
go-webauthn github.com/go-webauthn/webauthn v0.18.1 modules/auth/passkey WebAuthn registration and assertion verification: attestation formats, origins, RP ID, sign counters (ADR-0044). Security-critical parsing isn't hand-written
github.com/fxamacker/cbor/v2 v2.9.3 modules/auth/passkey/passkeytest CBOR encoding for the software authenticator used in tests
golang.org/x/oauth2 v0.37.0 modules/auth/social OAuth 2.0 authorization code flow with PKCE
go-oidc github.com/coreos/go-oidc/v3 v3.21.0 modules/auth/social Verifies Google and Apple ID tokens: signature from the provider's JWKS, issuer, audience, expiry (ADR-0046)
go-jose github.com/go-jose/go-jose/v4 v4.1.4 modules/auth/social Signs the ES256 Apple client secret; verifies Apple's server-to-server notifications
rsc.io/qr v0.2.0 modules/auth Renders the TOTP otpauth:// URI as a QR code image, so no frontend library is needed

TOTP (RFC 6238) and the AES-GCM keyring are implemented on the standard library in modules/auth.

CLI libraries#

Library Version Used in Why
huh github.com/charmbracelet/huh v1.0.0 cli Interactive prompts with validation, accessible mode (ADR-0035)
golang.org/x/term v0.46.0 cli Detects terminals, reads hidden secrets

Website libraries#

The site/ generator for apistock.dev and docs.apistock.dev (ADR-0049). Not part of apps.

Library Version Why
goldmark v1.8.6 Markdown to HTML with GitHub-flavoured extensions and heading IDs
chroma v2.27.0 Syntax highlighting in code blocks
apistock.dev/modules/openapi/reference this repository Renders the API reference, the same renderer apps serve at /docs

Development and CI tools#

Not imported; run with go run pkg@version or in CI (.github/workflows/).

Tool Version Why
golangci-lint v2.13.2 Lint every module with the repository's .golangci.yml
govulncheck v1.8.0 Known vulnerabilities in dependencies and the Go toolchain
gitleaks CI action Secrets committed by mistake
GoReleaser and cosign release-cli.yml Build, sign and attest aps releases on cli/v* tags
gofmt, go vet Go toolchain Formatting and suspicious code

Testing helpers#

Package What
apistock.dev/modules/postgres/pgtest A fresh database per test, cloned from a migrated template, dropped afterwards; skips without APISTOCK_TEST_DATABASE_URL
apistock.dev/modules/auth/passkey/passkeytest A software WebAuthn authenticator, so passkey flows run in go test
apistock.dev/modules/auth/social/socialtest A fake Google and Apple OpenID provider with signed tokens and notifications
net/http/httptest End-to-end HTTP tests against the app's handler

Deliberately not used#

Not used Instead Why
Redis, Kafka, RabbitMQ PostgreSQL (River, LISTEN/NOTIFY) One required service; jobs commit with data
An ORM, sqlc Hand-written SQL, one file per operation Readable queries, no generated layer (ADR-0032)
A router framework net/http.ServeMux The standard library's patterns are enough
A DI container Constructors in internal/app Wiring you can read and step through (ADR-0004)
JWT sessions Opaque tokens hashed in PostgreSQL Instant revocation, nothing to sign or rotate (ADR-0038)
Testcontainers, embedded PostgreSQL Docker Compose services The same PostgreSQL everywhere (ADR-0028)
Scalar, Swagger UI modules/openapi/reference Same design as the docs site, strict CSP, embedded fonts (ADR-0049)
esc
↑↓ move↵ openesc close