# Bamort Development Instructions READ THIS FILE CAREFULLY AND COMPLETE BEFORE STARTING DEVELOPMENT! Bamort is a role-playing game character management system (MOAM replacement) with a Go backend and Vue.js frontend. ## Project Overview - **Repository**: github.com:Bardioc26/bamort.git - **Architecture**: Monorepo with separate backend/frontend in Docker containers - **Backend**: Go 1.25 + Gin framework + GORM + MariaDB - **Frontend**: Vue 3 + Vite + i18n - **Development**: Docker Compose with live-reload (Air for Go, Vite HMR for Vue) ## Backend Architecture (`backend/`) ### Module Structure Every backend module must contain exactly these files: | File | Required | Content | |---|---|---| | `handlers.go` | yes | All HTTP handler functions for the module (Gin controllers)| | `routes.go` | yes | Route definitions; calls `RegisterRoutes` | | `register.go` | yes | `init()` — registers routes, models, and migrations with the application | | `model.go` | yes | GORM entity definitions owned by this module | | `*_test.go` | yes | At least one test file; more files allowed by sub-domain | | `database.go` | when needed | Module-specific DB query helpers | Handler files may be split by sub-domain (e.g. `lerncost_handler.go`, `share_handlers.go`) when `handlers.go` grows large. The split files stay in the same package. **Models**: each module defines its own GORM entities in `model.go`. The shared `models/` package contains only types that are referenced across multiple modules. **Configuration**: `config.Cfg` loaded from env vars — `ENVIRONMENT`, `DATABASE_TYPE`, `TEMPLATES_DIR`, etc. ### Route Ownership Map New endpoints must be added to the module that owns their prefix. the prefixes can be foundin the routes.go files. Use `RequireAdmin()` or `RequireMaintainer()` middleware on sub-routes that need elevated roles — never check roles inside a handler. ### Module Dependencies Modules should be self contained as far as possible. If a module needs to reference another module's data, it should import that module's package and use its exported functions — do not duplicate logic or data structures. If this means circular references, consider whether the shared logic should be moved to a common package (e.g. `utils/` or `models/`) of an exeption for duplicating logic or data structures must be made. ### Testing Requirements - **NEVER** create test files with `main()` — always use `_test.go` - **ALWAYS** call `setupTestEnvironment(t)` at the top of every test function - Use `testutils.SetupTestDB()` for any test that touches the database (creates an isolated SQLite DB) - Test character ID 18 (Fanjo Vetrani) is pre-seeded in the test DB **Every handler must have tests covering:** 1. Happy path — expected 2xx response with correct body 2. Error / not-found path — expected 4xx response 3. Unauthorized access — expected 401 (no token) or 403 (wrong role) for protected routes Use `t.Run("scenario", ...)` subtests when a handler has multiple input variants. Group related scenarios in one table-driven test rather than writing separate top-level test functions. ### Role Checking Roles in ascending order: `standard` < `maintainer` < `admin`. - `user.RequireAdmin()` — allows only `admin`; returns 403 for all other roles - `user.RequireMaintainer()` — allows `maintainer` and `admin`; returns 403 otherwise - **Apply these as Gin middleware in `routes.go` on a sub-group — never read the role inside a handler** ```go func RegisterRoutes(r *gin.RouterGroup) { group := r.Group("/maintenance") group.GET("/skills", listSkills) // all authenticated users protected := group.Group("") protected.Use(user.RequireMaintainer()) protected.POST("/skills", createSkill) // maintainer + admin only } ``` ### API Patterns - Protected routes under `/api` prefix require JWT — `user.AuthMiddleware()` is applied globally - Use `respondWithError(c, status, message)` for all error responses ## Docker Development Workflow ### Verify Containers ```bash docker ps | grep bamort-backend-dev # Must be running before testing ``` ### Container Names & Ports - `bamort-backend-dev`: Go API at http://localhost:8180 (Air live-reload) - `bamort-frontend-dev`: Vue at http://localhost:5173 (Vite HMR) - `bamort-mariadb-dev`: MariaDB at localhost:3306 - `bamort-phpmyadmin-dev`: http://localhost:8082 ### Rebuild After Dockerfile Changes ```bash cd /data/dev/bamort docker-compose -f docker/docker-compose.dev.yml build bamort-backend-dev docker-compose -f docker/docker-compose.dev.yml up -d bamort-backend-dev ``` ### View Logs ```bash docker logs bamort-backend-dev --tail=50 docker logs bamort-frontend-dev --tail=20 ``` ## Testing Commands ### Backend Tests ```bash cd /data/dev/bamort/backend go test -v ./pdfrender/ -run TestExportCharacterToPDF go test -v ./character/ ``` ### Frontend - HMR auto-reloads on file save - Check browser console and `docker logs bamort-frontend-dev` ## Debugging & Bugfixing Both Docker containers are always running. Use them directly — no restart needed. **Read live logs (Air/Vite output, compile errors, runtime panics):** ```bash docker logs bamort-backend-dev -f --tail=50 docker logs bamort-frontend-dev -f --tail=20 ``` **Test API endpoints directly:** ```bash # Public — no token needed curl -s http://localhost:8180/api/public/version # Authenticated — copy token from browser DevTools → Application → localStorage → 'token' curl -s -H "Authorization: Bearer " http://localhost:8180/api/characters ``` **Inspect database:** phpMyAdmin at http://localhost:8082 **Backend test failures** run against an isolated SQLite DB (`testutils.SetupTestDB()`) — they are independent of the running MariaDB container. **Air** recompiles the backend automatically on file save — compile errors appear immediately in `docker logs bamort-backend-dev`. **Vite HMR** reloads the frontend on file save — build errors appear in `docker logs bamort-frontend-dev` and the browser console. ## PDF Rendering Module (`pdfrender/`) - Uses `chromedp` for HTML→PDF (requires Chromium in Docker) - Templates in `templates/Default_A4_Quer/` (page1_stats.html, page2_play.html, etc.) - Continuation pages auto-generated for overflow (page1.2_stats.html pattern) - Test with character ID 18: generates 4 pages + continuations if needed - Template capacity defined in HTML comments: `` ## Common Patterns ### Error Handling (Backend) ```go if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ``` ## Critical Rules 1. **NEVER** write example/demo code - only production code 2. **NEVER** create test files with `main()` - use `_test.go` 3. **ALWAYS** check `docker ps` before assuming containers are running 4. **ALWAYS** use TDD: write failing test first, then implement 5. **ALWAYS** use KISS principle: simplest solution that works ## File-Specific Instructions Load additional instructions for specific file types: - Go files: See `.github/instructions/go.instructions.md` - Vue files: See `.github/instructions/vue.instructions.md` - CSS files: See `.github/instructions/css.instructions.md` - JS files: See `.github/instructions/js.instructions.md`