# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Important Nots Do not take screenshots yourself, ask the user to take screenshots of your visual changes if you want to so that you can verify them. ## Commands **Go Executable:** ```bash /home/linuxbrew/.linuxbrew/bin/go ``` **Run dev server:** ```bash # First-time setup: copy the env template cp scripts/env/dev.env.example scripts/env/dev.env # Edit scripts/env/dev.env to set WARPBOX_ADMIN_TOKEN and other values, then: ./scripts/run/dev.sh ``` **Run directly (one-off):** ```bash cd backend go run ./cmd/warpbox ``` **Run all tests:** ```bash cd backend go test ./... ``` **Run a single test or package:** ```bash cd backend go test ./libs/services/... -run TestDeleteTokenVerification go test ./libs/handlers/... -v ``` **Build:** ```bash cd backend go build ./cmd/warpbox ``` ## Architecture Warpbox is a self-hosted file-sharing app. All code lives under `backend/`. There is no frontend build step — the server renders Go templates and serves static assets directly. ### Startup flow `cmd/warpbox/main.go` → `config.Load()` → `httpserver.New()` → `server.ListenAndServe()` `httpserver.New()` wires everything together: 1. Creates `web.Renderer` (template engine) 2. Creates `UploadService` (opens bbolt DB, creates `files/` and `db/` dirs) 3. Creates `AuthService` (reuses same `*bbolt.DB`) 4. Creates `SettingsService` (reuses same `*bbolt.DB`) 5. Starts background jobs via `jobs.StartAll` 6. Creates `handlers.App` with all services 7. Registers all routes on a `http.ServeMux` 8. Wraps the mux in middleware chain: `Recoverer → RequestID → SecurityHeaders → Gzip → Logger` ### Services The three services share a single bbolt database. Each owns distinct buckets: | Service | Buckets | |---|---| | `UploadService` | `boxes` | | `AuthService` | `users`, `user_emails`, `sessions`, `invites`, `collections` | | `SettingsService` | `settings`, `usage` | `UploadService` owns the DB handle. `AuthService` and `SettingsService` receive `uploadService.DB()`. ### Data model - **Box** — one upload session. Has expiry, optional download limit, optional password (SHA-256 salted hash), optional owner (`OwnerID`), optional collection. Stored as JSON in the `boxes` bucket. - **File** — belongs to a Box. Stored on disk as `data/files/{boxID}/@each@{fileID}.ext`. Thumbnails at `@thumb@{fileID}.jpg`. - Box metadata is also written to `data/files/{boxID}/.warpbox.box.json` on every save. - **User** passwords are hashed with argon2id. Session tokens are SHA-256 hashed before storage. - **Delete tokens** for anonymous boxes are one-time random IDs, stored only as a SHA-256 hash. ### Handlers `handlers.App` holds all three services plus config, logger, and renderer. `RegisterRoutes` maps every URL pattern. Handler files are split by concern: `upload.go`, `download.go`, `dashboard.go` (user `/app`), `admin.go`, `auth.go`, `manage.go`, `pages.go`. ### Upload policy enforcement `SettingsService` stores per-day usage records keyed by `ip:{ip}:{date}` or `user:{userID}:{date}`. The upload handler (`handlers/upload.go`) checks these against `UploadPolicySettings` before accepting a multipart form. Admins bypass all per-upload and daily limits. ### Background jobs `jobs.StartAll` launches goroutines for: - **Cleanup** (`WARPBOX_CLEANUP_ENABLED`): deletes expired boxes and boxes that hit their download limit. - **Thumbnails** (`WARPBOX_THUMBNAIL_ENABLED`): generates JPEG thumbnails for image/video files that don't have one yet. ### Configuration All config comes from env vars via `config.Load()`. The dev script sources `scripts/env/dev.env`. `WARPBOX_BASE_URL` is required and must not be empty. Size values accept an optional `MB`/`Mb` suffix and support fractions (e.g. `0.5` = 512 KiB). ### Logging Structured JSONL logs go to `data/logs/{YYYY-MM-DD}.log` via `log/slog`. Every log entry includes `source` (e.g. `"user-upload"`, `"admin"`) and `severity` fields. User-activity events include a numeric `code` field (e.g. `2001` = upload complete, `2101` = box deleted). ### Template rendering `web.Renderer` parses all templates from `backend/templates/` at startup using `html/template`. Page data is passed as `web.PageData`. The base layout is `templates/layouts/base.html`. The current logged-in user is injected into every page render via `a.currentPublicUser(r)`. ## First-run bootstrap On a fresh `data/` directory, visit `/register` to create the first admin account. After bootstrap, normal registration is closed. Admins create invite links from `/admin/users`. The `WARPBOX_ADMIN_TOKEN` env var provides emergency fallback access at `/admin/login`.