Commit graph

7 commits

Author SHA1 Message Date
1fc42bf1b2 feat: add packaging, deployment, error pages, and project docs
Phase 7 — Polish:
- Error page template with styled 404/403/500 pages
- Error rendering helper on Renderer

Phase 8 — Packaging & Deployment:
- Containerfile: multi-stage build, non-root user, health check,
  OCI labels with build date and git revision
- Makefile: build, test, cross-compile, deb, rpm, container,
  tarballs, checksums targets
- nfpm.yaml: .deb and .rpm package config
- systemd service: hardened with NoNewPrivileges, ProtectSystem,
  ProtectHome, PrivateTmp, RestrictSUIDSGID
- Default environment file with commented examples
- postinstall/preremove scripts (shellcheck validated)
- compose.yaml: example Podman/Docker Compose
- Caddyfile.example: subdomain, subpath, and remote proxy configs
- CHANGELOG.md for release notes
- CLAUDE.md with architecture, conventions, and quick reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:34:32 +02:00
395b1b7523 fix: address security and quality issues from code review
Security fixes:
- Fix XSS in Atom feed: escape user-supplied URLs in HTML content
- Wrap signup request approval in a transaction to prevent
  partial state on crash (user created but request still pending)
- Stop leaking internal error messages to admin UI
- Add request body size limit on API import endpoint
- Log SetMustResetPassword errors instead of silently discarding

Correctness fixes:
- Handle errors from API fave update/delete instead of returning
  success on failure
- Use actual data timestamp for feed <updated> instead of
  time.Now() (improves HTTP caching)
- Replace hardcoded 10000 export limit with named constant
  (maxExportFaves = 100000)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:19:44 +02:00
fe4c751289 feat: add JSON REST API under /api/v1/
Phase 6 — JSON API:
- POST /api/v1/auth/login — returns session token
- POST /api/v1/auth/logout
- GET/POST /api/v1/faves — list own faves (paginated), create fave
- GET/PUT/DELETE /api/v1/faves/{id} — get, update, delete fave
- GET /api/v1/tags?q= — search tags
- GET /api/v1/users/{username} — public profile
- GET /api/v1/users/{username}/faves — public faves (paginated)
- GET /api/v1/export/json — export own faves
- POST /api/v1/import — import faves from JSON

All endpoints return JSON. Auth via session cookie (same as web UI).
Privacy-aware: private faves hidden from non-owners.
Respects profile visibility settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:13:23 +02:00
4e9db3f995 feat: add Atom feeds and JSON/CSV import/export
Phase 5 — Feeds & Import/Export:
- Atom feeds: global (/feed.xml), per-user (/u/{name}/feed.xml),
  per-tag (/tags/{name}/feed.xml). Uses gorilla/feeds.
- JSON export: all user's faves with tags, pretty-printed
- CSV export: standard format with header row
- JSON import: validates and creates faves with tags
- CSV import: flexible column mapping from header row
- Import/export pages with format documentation
- Feed items include enclosure for images, author info
- Limited-visibility profiles excluded from feeds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:11:44 +02:00
13aec5be6e feat: add admin panel with user, tag, and signup management
Phase 4 — Admin Panel:
- Admin dashboard with user/fave/pending-request counts
- User management: create with temp password, reset password,
  enable/disable accounts (prevents self-disable)
- Tag management: rename and delete tags
- Signup request management: approve (creates user with
  must-reset-password) and reject pending requests
- Site settings: site name, description, signup mode
  (open/requests/closed)
- All admin routes require both login and admin role
- SignupRequest model and full store (create, list pending,
  approve with user creation, reject)
- SetMustResetPassword method on UserStore for admin password resets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:09:30 +02:00
2cbbb20278 feat: add profiles, public views, settings, and code quality fixes
Phase 3 — Profiles & Public Views:
- Public profile page (/u/{username}) with OG meta tags
- User settings page (display name, bio, visibility, default privacy)
- Avatar upload with image processing
- Password change from settings (verifies current password)
- Home page shows public fave feed for logged-in users
- Must-reset-password guard redirects to /reset-password
- Profile visibility: public (full) or limited (username only)

Code quality improvements from /simplify review:
- Fix signup request persistence bug (was silently discarding data)
- Fix health check to use configured listen address, not hardcoded :8080
- Add rate limiter cleanup goroutine (was leaking memory)
- Extract shared helpers: ClearSessionCookie, IsSecureRequest, scanTags,
  scanUserFrom (scanner interface), SignupRequestStore
- Replace hand-rolled joinPlaceholders with strings.Join
- Remove dead _method hidden field, redundant devMode field
- Simplify rate-limited route registration (remove double-mux)
- Log previously-swallowed errors (session delete, image delete)
- Stop leaking internal error messages to users in image upload

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:01:41 +02:00
fc1f7259c5 feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.

Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed

Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages

Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00