112 lines
4.5 KiB
Markdown
112 lines
4.5 KiB
Markdown
|
|
# CLAUDE.md
|
||
|
|
|
||
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
|
|
||
|
|
## 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`.
|