# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What is kls A URL shortener web service. Users submit a URL, get back a 5-character short code. Visiting `/` redirects to the original URL. Admin routes (POST, /list) are protected with HTTP Basic Auth. ## Build and Run ```bash go build -o kls . ./kls -f /path/to/kls.conf ``` No Makefile, no tests. The binary is `.gitignore`d. ## Configuration Uses `goutils/config` to load a key=value config file (default `~/.config/kls/kls.conf`). Required keys: - `DB_PASSWORD`, `DB_HOST` — no defaults - `HTTP_USER`, `HTTP_PASS` — Basic Auth credentials - `HTTP_ADDR` — bind address Optional (have defaults): `DB_ENGINE` (postgres), `DB_NAME` (kls), `DB_USER` (kls), `DB_PORT` (5432), `HTTP_PORT` (8000). ## Architecture - **`main.go`** — entry point: loads config, connects to DB, starts HTTP server. - **`handler.go`** — HTTP routing and handlers on the `server` struct. Implements `ServeHTTP` directly (no router library). GET requests matching a valid short code bypass auth and redirect; everything else requires Basic Auth. Templates are embedded via `//go:embed`. - **`links/`** — core domain package: - `url.go` — `URL` model, CRUD operations (Store, Lookup, StoreURL, RetrieveURL, FetchAll), URL normalization (strips query/fragment by default), and cleaning logic. Uses squirrel for query building with PostgreSQL dollar placeholders. - `db.go` — PostgreSQL connection setup via pgx/v4 pool. - `alphabet.go` — short code generation: 5 random characters from an unambiguous alphabet (`ABCDEFGHJKMNPQRSTUVWXYZ23456789`, excludes 0/O/1/I/L). `ValidShortCode` regex is used for routing. - **`schema.sql`** — single `urls` table with `id` (UUID), `url`, `nurl` (normalized), `short` (unique), `created_at`. - **`templates/`** — Go HTML templates (`index.tpl` for submit form, `list.tpl` for listing all URLs). ## Key behaviors - **Deduplication**: `StoreURL` checks for an existing normalized URL before creating a new entry. - **URL cleaning**: By default, query strings are stripped. The "rawp" form checkbox preserves the original query string. - **No router**: `server.ServeHTTP` handles all dispatch — check there when adding routes.