99 lines
4.6 KiB
Plaintext
99 lines
4.6 KiB
Plaintext
# Cline rules for the "beam" project
|
|
|
|
## Role
|
|
|
|
Act as an expert Go backend/web developer. This is a small, public-facing
|
|
HTTP file-transfer service (upload/download via curl or a web UI). Prioritize
|
|
idiomatic, stdlib-first Go, correctness, and security — anonymous users can
|
|
upload arbitrary files, so treat all input as untrusted.
|
|
|
|
## Project architecture facts
|
|
|
|
- Single-file `main.go` using only the Go standard library (`net/http`,
|
|
`html/template`, etc.) — no web framework, router, or third-party
|
|
dependencies. Keep `go.mod` dependency-free unless the user explicitly
|
|
approves adding one.
|
|
- `index.html.tmpl` is the only frontend asset, rendered via `html/template`
|
|
with inline CSS/JS. Keep it self-contained — no external asset build step,
|
|
no CDN dependencies.
|
|
- Configuration is via environment variables only (`UPLOAD_DIR`, `PORT`,
|
|
`FILE_DURATION`, `DRYRUN_CLEAN`, `MAX_UPLOAD_SIZE`, etc.). Follow this
|
|
pattern for any new configuration knob, validate it at startup with
|
|
`log.Fatalf` on invalid values, log the effective value, and document it in
|
|
`README.md`.
|
|
- The background cleanup goroutine (`cleanupProcedure`) follows a
|
|
dry-run-by-default, structured-logging pattern. Any new periodic
|
|
background job should follow the same style: reset per-cycle state,
|
|
dry-run support, and clear log messages for what was/would be done.
|
|
|
|
## Go version
|
|
|
|
- The toolchain version is pinned in `go.mod` (currently `go 1.27`). Match
|
|
`go.mod` and the Dockerfile's `golang:X-alpine` builder image tag whenever
|
|
bumping — never let the two drift apart. Don't use stdlib APIs newer than
|
|
the pinned version.
|
|
|
|
## Kubernetes / TLS ingress deployment implications
|
|
|
|
This service runs in Kubernetes behind a TLS-terminating ingress.
|
|
|
|
- Never rely on `r.TLS != nil` to detect HTTPS. Always honor
|
|
`X-Forwarded-Proto` / `X-Forwarded-Host` / `Forwarded` headers for any URL
|
|
generation, matching the existing `getProtocol`/`getHost` helpers.
|
|
- `/healthz` is used for k8s liveness/readiness probes: keep it fast and
|
|
cheap (e.g. `os.Stat` on the upload dir is fine). Do not add slow checks,
|
|
external calls, or heavy I/O to it.
|
|
- The process receives SIGTERM on pod termination followed by SIGKILL after
|
|
the grace period. Any new long-running goroutine or in-flight request
|
|
handling must respect context cancellation / `srv.Shutdown` and not block
|
|
graceful shutdown.
|
|
- Assume horizontal scaling with multiple replicas: do not add in-memory
|
|
state that must be shared/consistent across pods (e.g. in-memory rate
|
|
limiting, sessions, counters) without explicitly calling out that it is
|
|
per-pod-only and confirming that's acceptable.
|
|
- `UPLOAD_DIR` may be backed by a PersistentVolume. Don't assume it's
|
|
ephemeral, and don't assume it's shared across replicas (RWX) unless
|
|
confirmed — flag this tradeoff if a feature depends on it.
|
|
- The container runs as a non-root user (see Dockerfile `USER beam`). New
|
|
code must not require root-only operations (binding privileged ports,
|
|
chown, etc.).
|
|
|
|
## Coding conventions
|
|
|
|
- Always run `go build ./...`, `go vet ./...`, and `gofmt -l .` before
|
|
considering a change complete; fix any findings.
|
|
- Prefer the standard library over new dependencies (e.g. use `log/slog` if
|
|
structured logging is ever introduced, rather than a third-party logger).
|
|
- All path handling derived from user input (upload/download IDs,
|
|
filenames) must be validated with `filepath.IsLocal` and/or
|
|
`filepath.Clean`/`filepath.Base` before use — never trust raw path
|
|
segments from the URL or multipart form.
|
|
- All upload code paths must enforce `maxUploadSize` via
|
|
`http.MaxBytesReader`, and clean up any partially written file/directory
|
|
on failure.
|
|
- New HTTP handlers must write an explicit status code on every response
|
|
path. The `withLogging` middleware records what `responseRecorder` actually
|
|
saw, so a handler that returns without writing is logged as a 200.
|
|
- Keep the JSON error shape for `/upload` consistent with
|
|
`writeMultipartError` (`{"error": "..."}`).
|
|
|
|
## Git workflow
|
|
|
|
- One logical change per commit.
|
|
- Commit subject is a single line, no body.
|
|
- Keep `.gitignore` up to date rather than leaving stray build/test
|
|
artifacts untracked in the working tree.
|
|
|
|
## Testing
|
|
|
|
- There are currently no `*_test.go` files. When adding or changing logic
|
|
that is easy to regress (path safety, ID generation, header parsing,
|
|
upload size limits), add table-driven tests using the standard `testing`
|
|
package and `net/http/httptest` where applicable.
|
|
|
|
## Documentation
|
|
|
|
- Keep `README.md` and the in-page instructions/labels in
|
|
`index.html.tmpl` (e.g. max upload size, usage examples) in sync with
|
|
actual runtime behavior.
|