- Update navigation labels from "My Account" to "Dashboard" and "Login" to "Sign in", updating tests accordingly. - Redesign settings forms into structured sections with improved spacing and layout. - Add CSS styles for tabs, small buttons, and responsive settings sections to enhance the user experience.
4.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
Go Executable:
/home/linuxbrew/.linuxbrew/bin/go
Run dev server:
# 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):
cd backend
go run ./cmd/warpbox
Run all tests:
cd backend
go test ./...
Run a single test or package:
cd backend
go test ./libs/services/... -run TestDeleteTokenVerification
go test ./libs/handlers/... -v
Build:
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:
- Creates
web.Renderer(template engine) - Creates
UploadService(opens bbolt DB, createsfiles/anddb/dirs) - Creates
AuthService(reuses same*bbolt.DB) - Creates
SettingsService(reuses same*bbolt.DB) - Starts background jobs via
jobs.StartAll - Creates
handlers.Appwith all services - Registers all routes on a
http.ServeMux - 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 theboxesbucket. - 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.jsonon 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.