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>
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, routerhandlers/store.go—Storestruct holds DB, SpotifyAuth, ClaudeClient, Auth, etc. Passed to all handlershandlers/handle_*.go— REST handlers grouped by domaingraph/schema/*.graphql— GraphQL schema files (source of truth)graph/*.resolvers.go— resolver implementations (one per schema file,follow-schemalayout)graph/generated.go— auto-generated by gqlgen, do not editgraph/model/models_gen.go— auto-generated GraphQL models, do not editmodels/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, homeDatasrc/views/— page components (Home, Admin, CV, Notes, Bookmarks, shrines)src/components/— reusable UI components
Key Patterns
- GraphQL models vs GORM models:
gqlgen.ymlmaps GraphQL types directly to GORM models inbackend/models. Thegraph/model/package has only generated input/payload types. - Auth flow: Login sets
access_token(24h) andrefresh_token(365h) as HTTP-only cookies.AuthMiddlewarevalidates tokens and injects user into Gin context.AuthContextMiddlewarepasses Gin context into GraphQL resolver context. - Spotify tokens: Persisted to
/backend/token/spotify_token.jsoninside 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.DeletedAtfield).