✂️ Cutter is a tiny URL shortener built with Go, HTMX, and SQLite.
The goal is to showcase how I approach end-to-end backend development: clean layering, explicit naming conventions and development tooling.
- Domain (
internal/domain/link) – contains the bussiness logic. - Application (
internal/app) – orchestrates use cases through handlers that consume DTO commands/results. Policies are injected here before touching repositories. - Interface (
internal/interface/http) – exposes an HTMX-powered web UI and REST endpoints built on a small router (pkg/amigo) plus Tailwind/templ templates. - Infrastructure (
internal/infra) – SQLite persistence generated viasqlc, logger setup, and dependency wiring. - Packaging – multi-stage Dockerfile producing a distroless image; docker compose (with
.envsupport) starts the API plus any backing services.
- Go 1.25, HTMX UI components powered by a-h/templ, and tailwindcss build pipeline.
- SQLite persistence via
sqlc. - Migrations done with
goose. - Embedded static assets (
static/) served throughgo:embed. - Makefile-driven workflow (generate templates, build CSS, run server, docker compose up).
- Naming convention (Command/Handler/Result) enforced across handlers.
- Go >= 1.25
- Develop environment is provided through
flake.nix+.envrcusingdirenv. - Go tool dependencies (templ, goose, sqlc) are declared in
go.mod.
make init # Generate templates, css, sqlc code
make serve # Run the app with all assets up to date
make watch # Auto-rebuild on file changes
make build # Compile the Go binary into ./bin/cutter
make up # docker compose up --build with project name cutter- Commands (
CreateLinkCommand,VisitLinkCommand, …) are DTOs that capture the input for a use case. - Handlers (
CreateLinkHandler,VisitLinkHandler, …) execute the use case via aHandlemethod and orchestrate repositories, policies and other services. - Results (
CreateLinkResult, …) hold the data returned by handlers. - Policies (e.g.
link.CreatePolicy) capture domain rules such as URL validation or expiration defaults so that the domain stays consistent and reusable.
- pkg/amigo – a custom HTTP toolkit I’m evolving to offer a “friendly API” (hence the name “amigo”) developer experience, inspired by frameworks like FastAPI. It currently powers routing, middleware, and static delivery and will keep growing.