Skip to content

Architecture Manual

This document describes the architecture of Snackbox: its component structure and deployment topology. The product requirements that drive these decisions are defined in REQUIREMENTS.md.

Snackbox aims to be fully compliant with the 12-factor app methodology. See 12FACTOR.md for the current compliance evaluation.

Components

Component View

graph TD
    Client([Client])

    subgraph server["server · :8080 (Go net/http)"]
        MW["Middleware\nCORS → Logging → Max Body"]
        Router["Router\n(Auth · Rate Limit applied per route)"]
        AuthH["Auth Handler"]
        HealthH["Health Handler"]
        ResourceH["Resource Handlers"]
        Repos["Repository\nTagRepo · PageRepo · PostRepo · UserRepo · MediaRepo"]
    end

    subgraph metricsMux["metricsMux · :9091 (Go net/http)"]
        MetricsH["Metrics Handler\n(Prometheus registry)"]
    end

    subgraph storage["Storage"]
        SQLite[("SQLite (file)")]
        Disk[("Storage (disk)")]
    end

    Client --> MW
    MW --> Router
    Router --> AuthH
    Router --> HealthH
    Router --> ResourceH
    HealthH --> SQLite
    ResourceH --> Repos
    Repos --> SQLite
    ResourceH --> Disk

The binary is structured in strict layers. Each layer only calls the layer directly below it. This enforces the requirement that business logic must not appear in the router or middleware:

Layer Packages Responsibility
Entry point cmd/server Wires all components, starts HTTP servers, handles OS signals
Middleware internal/middleware CORS, auth (JWT), logging, rate-limit, max-body
Router internal/router Registers all routes, applies middleware chain
Handlers internal/handlers Parses requests, calls repositories, writes responses
Repositories internal/repository SQL queries against SQLite
Storage SQLite file + filesystem Persistent state

A second HTTP server runs on METRICS_ADDR (default :9091) and exposes only GET /metrics. It is wired directly in cmd/server/main.go and shares no middleware with the main API. This satisfies the requirement that the metrics endpoint must not be exposed on the public API port.

Bootstrap

On every startup internal/bootstrap runs pending SQL migrations from MIGRATIONS_PATH and, if no admin user exists, creates one from the ADMIN_NAME / ADMIN_EMAIL / ADMIN_PASSWORD environment variables. This satisfies the requirement that migrations are applied automatically on startup.

Configuration

All runtime configuration is loaded by internal/config from environment variables, with an optional .env file as a fallback. See the Administrator Manual for the full reference.

Deployment

Deployment View

flowchart TD
    Client([Client])
    Prometheus([Prometheus])
    RP["Reverse Proxy\nnginx · Caddy · …"]

    subgraph host["Container / Host"]
        API["Snackbox · :8080 · API\n/usr/local/bin/snackbox"]
        Metrics["Snackbox · :9091 · Metrics\n/usr/local/bin/snackbox"]
        DB[("Database\n$DATABASE_PATH")]
        Media[("Media Storage\n$STORAGE_PATH")]
    end

    Client -->|"80/TCP"| RP
    RP -->|"8080/TCP"| API
    Prometheus -->|"9091/TCP"| Metrics
    API --> DB
    API --> Media

Snackbox is deployed as a single process behind a reverse proxy. The reverse proxy (nginx, Caddy, or similar) handles TLS termination and forwards requests to the API port. The metrics port is kept on loopback or an internal monitoring network. See Deployment Constraints for platform and resource requirements.

Port Default Exposure
LISTEN_ADDR :8080 Via reverse proxy (public)
METRICS_ADDR :9091 Internal / loopback only

Persistent state lives in two locations:

Path Content
DATABASE_PATH SQLite database file
STORAGE_PATH Uploaded media files

Both paths should reside on the same volume so that a single backup covers all state. See the Administrator Manual for deployment guides (systemd and Docker).

Tools and Frameworks

Tool / Library Purpose
Go 1.26 Primary language
net/http HTTP server (standard library, no framework)
mattn/go-sqlite3 SQLite driver (CGO)
golang-jwt/jwt JWT signing and validation
prometheus/client_golang Prometheus metrics
golang.org/x/time/rate Token-bucket rate limiter
golangci-lint Static analysis
hurl End-to-end API integration tests

Dependencies and Licensing

Snackbox is released under the BSD-3-Clause License. All direct and transitive Go module dependencies use MIT, BSD-3-Clause, or Apache-2.0 — all of which are compatible with BSD-3-Clause outbound licensing and impose no copyleft or viral obligations.

Notable: mattn/go-sqlite3 bundles the SQLite C amalgamation, which is public domain and carries no license obligations.

Software Bill of Materials (SBOM)

Package Version License
github.com/golang-jwt/jwt/v5 v5.3.1 MIT
github.com/mattn/go-sqlite3 v1.14.34 MIT
golang.org/x/crypto v0.48.0 BSD-3-Clause
golang.org/x/time v0.15.0 BSD-3-Clause
golang.org/x/sys v0.41.0 BSD-3-Clause
github.com/beorn7/perks v1.0.1 MIT
github.com/cespare/xxhash/v2 v2.3.0 MIT
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 BSD-3-Clause
github.com/prometheus/client_golang v1.23.2 Apache-2.0
github.com/prometheus/client_model v0.6.2 Apache-2.0
github.com/prometheus/common v0.66.1 Apache-2.0
go.yaml.in/yaml/v2 v2.4.2 Apache-2.0
google.golang.org/protobuf v1.36.8 BSD-3-Clause
github.com/kr/text v0.2.0 MIT

Regenerating the Report

Install go-licenses and run it from the repository root:

go install github.com/google/go-licenses@latest
$(go env GOPATH)/bin/go-licenses report ./...

This prints one line per dependency with its name, license URL, and SPDX identifier. Update the table above whenever go.mod changes.