* introduced central package registry by package init function * dynamic registration of routes, model, migrations and initializers. * setting a docker compose project name to prevent shutdown of other containers with the same (composer)name * ai documentation * app template * Create tests for ALL API entpoints in ALL packages Based on current data. Ensure that all API endpoints used in frontend are tested. These tests are crucial for the next refactoring tasks. * adopting agent instructions for a more consistent coding style * added desired module layout and debugging information * Fix All Failing tests All failing tests are fixed now that makes the refactoring more easy since all tests must pass * restored routes for maintenance * added common translations * added new tests for API Endpoint * Merge branch 'separate_business_logic' * added lern and skill improvement cost editing * Set Docker image tag when building to prevent rebuild when nothing has changed * add and remove PP for Weaponskill fixed * add and remove PP for same named skills fixed * add new task
7.1 KiB
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:
- Happy path — expected 2xx response with correct body
- Error / not-found path — expected 4xx response
- 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 onlyadmin; returns 403 for all other rolesuser.RequireMaintainer()— allowsmaintainerandadmin; returns 403 otherwise- Apply these as Gin middleware in
routes.goon a sub-group — never read the role inside a handler
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
/apiprefix require JWT —user.AuthMiddleware()is applied globally - Use
respondWithError(c, status, message)for all error responses
Docker Development Workflow
Verify Containers
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:3306bamort-phpmyadmin-dev: http://localhost:8082
Rebuild After Dockerfile Changes
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
docker logs bamort-backend-dev --tail=50
docker logs bamort-frontend-dev --tail=20
Testing Commands
Backend Tests
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):
docker logs bamort-backend-dev -f --tail=50
docker logs bamort-frontend-dev -f --tail=20
Test API endpoints directly:
# 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 <token>" 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
chromedpfor 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:
<!-- MaxItems: 58 -->
Common Patterns
Error Handling (Backend)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
Critical Rules
- NEVER write example/demo code - only production code
- NEVER create test files with
main()- use_test.go - ALWAYS check
docker psbefore assuming containers are running - ALWAYS use TDD: write failing test first, then implement
- 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