# 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.go` — `Store` 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).