Files
web_server/CLAUDE.md
Adam French 2becda2bd8
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 39s
Add CLAUDE.md and update frontend README
Add Claude Code guidance file with build commands, architecture overview,
and key patterns. Replace default Vite scaffold README with project-specific
documentation including dev proxy config and deployment notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 00:37:19 +00:00

3.4 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 nginx/vue && npm run dev

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

Frontend build

cd nginx/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 (nginx/vue/): Vue 3 SPA with Vite, Tailwind CSS v4, Pinia stores, Vue Router. Served as static files through Nginx.

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).