Files
web_server/CLAUDE.md
Adam French d3d3269d49
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 4m58s
Extract Vue frontend into separate container and add stp_wasm crate
Move Vue app from nginx/vue/ to top-level vue/ with its own Dockerfile,
update docker-compose configs and nginx proxy to serve from the new
container, and add initial Rust WASM crate (stp_wasm). Also fix .gitignore
to exclude Rust target/ directories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 16:40:45 +00:00

3.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Build & Run Commands

Full stack (dev mode, HTTP only)

docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build

Dev mode seeds the database with test data (SEED_DB=true) and disables certbot/SSL. Visit http://localhost.

Full stack (production, HTTPS)

docker compose up --build

Frontend only (hot reload)

cd vue && npm run dev

Vite dev server proxies /api to localhost:8080, /gitea to localhost:3000, /radio to localhost:8000.

Frontend build

cd vue && npm run build

Regenerate GraphQL (after editing schema files)

cd backend && go run github.com/99designs/gqlgen generate

This regenerates graph/generated.go and graph/model/models_gen.go. Resolver implementations in *.resolvers.go files are preserved.

Architecture

Dockerized multi-service personal website self-hosted on a Raspberry Pi.

Backend (backend/): Go with Gin router. GraphQL API via gqlgen at POST /api/graphql. REST endpoints for auth, file uploads, Spotify OAuth, and WebSockets. GORM for PostgreSQL with auto-migrations (no separate migration files). JWT auth stored in HTTP-only cookies.

Frontend (vue/): Vue 3 SPA with Vite, Tailwind CSS v4, Pinia stores, Vue Router. Built in a separate container; assets served through Nginx (production) or proxied to Vite dev server (dev mode).

Nginx (nginx/): Reverse proxy + SPA server. Config is templated (nginx.conf.template) and selected at runtime by entrypoint.sh based on DEV_MODE and certificate presence. Rate limiting on login (5/min), API (30/sec), uploads (5/min).

Backend Structure

  • main.go — entry point: wires up DB, services, router
  • handlers/store.goStore struct holds DB, SpotifyAuth, ClaudeClient, Auth, etc. Passed to all handlers
  • handlers/handle_*.go — REST handlers grouped by domain
  • graph/schema/*.graphql — GraphQL schema files (source of truth)
  • graph/*.resolvers.go — resolver implementations (one per schema file, follow-schema layout)
  • graph/generated.go — auto-generated by gqlgen, do not edit
  • graph/model/models_gen.go — auto-generated GraphQL models, do not edit
  • models/models.go — GORM database models (User, Post, Message, Activity, Favorite, Rowing)
  • services/ — database init, JWT auth, WebSocket server, Spotify OAuth, Gitea feed, Claude client, DB seeding

Frontend Structure

  • src/graphql.js — thin axios-based GraphQL client (POST /api/graphql)
  • src/stores/ — Pinia stores for auth, posts, favorites, activities, songs, messages, homeData
  • src/views/ — page components (Home, Admin, CV, Notes, Bookmarks, shrines)
  • src/components/ — reusable UI components

Key Patterns

  • GraphQL models vs GORM models: gqlgen.yml maps GraphQL types directly to GORM models in backend/models. The graph/model/ package has only generated input/payload types.
  • Auth flow: Login sets access_token (24h) and refresh_token (365h) as HTTP-only cookies. AuthMiddleware validates tokens and injects user into Gin context. AuthContextMiddleware passes Gin context into GraphQL resolver context.
  • Spotify tokens: Persisted to /backend/token/spotify_token.json inside the container, surviving restarts.
  • Gitea feed: Backend proxies and caches (1 min TTL) the Gitea activity feed API.
  • All GORM models use soft delete (gorm.DeletedAt field).