passion-dev
Passion climbing training app development. Use for: adding handlers, modifying DB models, creating templates, understanding project architecture, running/testing the app, YAML import features.
Install
mkdir -p .claude/skills/passion-dev && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15037" && unzip -o skill.zip -d .claude/skills/passion-dev && rm skill.zipInstalls to .claude/skills/passion-dev
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Passion climbing training app development. Use for: adding handlers, modifying DB models, creating templates, understanding project architecture, running/testing the app, YAML import features.About this skill
Passion Development
Passion is a climbing training web application built with Go, HTMX, and Tailwind CSS. It manages session templates, training cycles, exercise libraries, and guided workout runs.
Architecture
- Go 1.25 with
chirouter,gormORM (SQLite),goldmarkmarkdown,golang-jwtauth - Server-side rendered HTML templates with HTMX for interactivity
- Single binary with embedded static assets
Project Structure
cmd/passion/main.go – Entry point, config loading, DB init, graceful shutdown
config/config.go – 12-factor config: YAML file + env overrides
db/models.go – GORM model definitions (all entities)
db/store.go – Store struct, AutoMigrate
db/seed.go – Dev seed data
db/yaml_import.go – Startup YAML catalog import (exercises + templates)
http/server/core.go – Server struct, template parsing, routing, middleware
http/server/auth.go – JWT auth, login/signup handlers
http/server/dashboard.go – Dashboard handler (week view, scheduled sessions)
http/server/templates.go – Session template CRUD, activity/exercise management
http/server/exercise_library.go – Library exercise CRUD
http/server/training_cycles.go – Training cycle CRUD + session generation
http/server/runs.go – Guided run player (complete/skip exercises)
http/server/form_helpers.go – Shared form parsing (formInt, formFloat)
http/server/errors.go – Centralized error response helper
http/server/template_color.go – Color normalization for template cards
http/server/time_helpers.go – Date/time utilities
http/server/youtube_embed.go – YouTube URL → embed conversion
http/server/markdown.go – Markdown preview endpoint
templates/ – Go HTML templates (pages, fragments, layouts)
static/passion.css – Custom CSS (Tailwind loaded via CDN)
catalog/ – YAML exercise/template definitions for import
Key Conventions
Handler Pattern
All HTTP handlers are methods on *Server. Pattern:
func (s *Server) handleFoo(w http.ResponseWriter, r *http.Request) {
ownerID, ok := s.currentUserID(r)
if !ok {
s.unauthorizedRedirect(w, r)
return
}
// ... business logic with s.store.DB ...
// Full page: s.renderPage(w, PageData{...})
// HTMX fragment: s.renderFragment(w, "fragment_name", data)
}
HTMX Redirects
After successful POST mutations, set HX-Redirect header + w.WriteHeader(http.StatusOK):
w.Header().Set("HX-Redirect", "/target-path")
w.WriteHeader(http.StatusOK)
Error Responses
- Client errors (4xx):
http.Error(w, "human message", http.StatusBadRequest) - Server errors (5xx):
s.serverError(w, r, err)— logs internally, returns generic message - Never expose GORM/internal error messages to the client
Form Parsing
Use shared helpers from form_helpers.go:
sets := formInt(r, "sets")
weight := formFloat(r, "weight_kg")
Database Models
- All entities have
OwnerID uintfor multi-user scoping - Always filter queries by
owner_idfor authorization - Use
gorm.Model(provides ID, CreatedAt, UpdatedAt, DeletedAt) - Exercise kinds:
"reps_and_sets"(default),"session","exercise_catalog" - Media is stored in
ExerciseMediarows (polymorphic: ExerciseID or LibraryExerciseID)
Templates (HTML)
- Layouts:
templates/layouts/base.htmlwraps all pages - Fragments:
templates/fragments/for HTMX partial responses - Use
{{ .Field }}Go template syntax - HTMX attributes:
hx-post,hx-target,hx-swap
Config
Config loads from YAML then env vars override (12-factor). Key env vars:
PASSION_ADDR– listen addressPASSION_DB_PATH– SQLite file pathPASSION_SEED– enable dev seedingPASSION_JWT_SECRET– JWT signing keyPASSION_DEV_AUTH_BYPASS– skip auth in development
Build & Run
make run # go run ./cmd/passion
make build # go build ./...
make watch # hot-reload with air
go test ./... # run all tests
go vet ./... # static analysis
Testing
- Tests use standard
testingpackage - Config tests use
t.TempDir()+t.Setenv()for isolation - HTTP handler tests use
httptest.NewRecorder()+httptest.NewRequest() - DB tests create in-memory SQLite via
NewSqlite(":memory:")