Files
tanabata/README.md
T
H1K0 b470782e97 docs(project): add README with reverse-proxy and quick-start guide
Root README covering the stack, quick start, and dev commands, plus a Reverse
proxy (nginx) section: client_max_body_size for large uploads, forwarded headers
feeding the rate limiter, and buffering-off for streaming large media.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:52:09 +03:00

99 lines
3.7 KiB
Markdown

# Tanabata File Manager
A multi-user, tag-based web file manager for images and video. Go + Gin backend
(Clean Architecture, pgx, goose migrations), SvelteKit SPA frontend, PostgreSQL,
JWT auth — shipped as a single Docker image that serves both the API and the
built SPA on one port.
## Documentation
- [`openapi.yaml`](openapi.yaml) — full REST API specification
- [`docs/DEPLOY.md`](docs/DEPLOY.md) — production deploy (Gitea Actions → host)
- [`docs/GO_PROJECT_STRUCTURE.md`](docs/GO_PROJECT_STRUCTURE.md) — backend architecture
- [`docs/FRONTEND_STRUCTURE.md`](docs/FRONTEND_STRUCTURE.md) — frontend architecture
- [`.env.example`](.env.example) — every configuration variable, documented
## Quick start
```bash
cp .env.example .env # then edit the secrets (JWT_SECRET, ADMIN_PASSWORD, …)
docker compose up -d --build
```
By default this runs the app plus a bundled PostgreSQL container
(`COMPOSE_PROFILES=with-db`). To point at a Postgres already on the host, set
`COMPOSE_PROFILES=` empty and aim `DATABASE_URL` at `host.docker.internal`. See
[`.env.example`](.env.example) for the full matrix.
The app is published on **127.0.0.1** only and expects a reverse proxy in front
(see below). The default port is **42776** — the sum of the Unicode code points
of 七夕.
## Reverse proxy (nginx)
The container publishes its port on loopback (`127.0.0.1:${APP_PORT}:42776` in
[`docker-compose.yml`](docker-compose.yml)), so a reverse proxy on the host
terminates TLS and forwards to it. Three settings matter for this app:
1. **`client_max_body_size`** — uploads go up to `MAX_UPLOAD_BYTES` (500 MiB by
default). nginx caps request bodies at **1 MiB** out of the box, so without
this every large upload fails with `413`.
2. **Forwarded headers** — the app trusts `X-Forwarded-For` only from the hops in
`TRUSTED_PROXIES` (default: loopback + Docker bridge ranges) and keys its
login/refresh rate limiter on the resulting client IP. If the proxy doesn't
send the header, every request looks like it comes from the proxy and shares
one rate-limit bucket.
3. **Streaming for big media** — turning request/response buffering off lets
large uploads stream straight to the app and lets video range-seeks work
without nginx spooling whole files to disk first.
```nginx
server {
listen 443 ssl;
server_name tanabata.example.com;
# ssl_certificate / ssl_certificate_key ... (e.g. from certbot)
# Match MAX_UPLOAD_BYTES (500 MiB default); nginx defaults to 1m → 413.
client_max_body_size 512m;
location / {
proxy_pass http://127.0.0.1:42776; # APP_PORT
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Stream large uploads/downloads instead of buffering to disk; keeps
# video range-seek responsive. Scope these to file/preview locations
# instead if you'd rather keep buffering for small JSON responses.
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
```
If you run the app **without** a proxy and want it reachable on the LAN, drop the
`127.0.0.1:` prefix from the `ports` line in
[`docker-compose.yml`](docker-compose.yml) and adjust `TRUSTED_PROXIES`
accordingly.
## Development
```bash
# Backend
cd backend
go run ./cmd/server # dev server
go test ./... # all tests
# Frontend
cd frontend
npm run dev # Vite dev server
npm run build # production build
npm run generate:types # regenerate API types from openapi.yaml
```