ActionPhase Route Tester Skill
Purpose
This skill provides patterns for testing authenticated routes in ActionPhase using JWT Bearer token authentication with the Go backend.
When to Use This Skill
- •Testing new API endpoints
- •Validating route functionality after changes
- •Debugging authentication issues
- •Testing POST/PUT/DELETE operations
- •Verifying request/response data
- •End-to-end API testing
- •Integration testing before E2E tests
ActionPhase Authentication Overview
ActionPhase uses:
- •JWT Bearer tokens (Authorization header)
- •Token lifetime: 15 minutes (access token)
- •Refresh tokens: 7 days (stored in database sessions)
- •Token storage: Frontend stores in memory + localStorage
- •Backend: Go with Chi router + JWT middleware
See: /docs/adrs/003-authentication-strategy.md for complete details
Testing Methods
Method 1: api-test.sh (RECOMMENDED)
The api-test.sh script handles authentication and provides convenient commands for testing.
Location: backend/scripts/api-test.sh
Quick Start
# 1. Login and save token ./backend/scripts/api-test.sh login-player # 2. Test endpoints ./backend/scripts/api-test.sh games ./backend/scripts/api-test.sh game 164 ./backend/scripts/api-test.sh characters 164
Available Commands
Authentication:
./api-test.sh login [username] # Login as any user (default: TestPlayer1) ./api-test.sh login-gm # Login as TestGM ./api-test.sh login-player # Login as TestPlayer1 ./api-test.sh test-token # Verify current token is valid
API Endpoints:
./api-test.sh health # Check backend health ./api-test.sh status # Complete status check ./api-test.sh games # List all games ./api-test.sh game [id] # Get game details (default: 164) ./api-test.sh characters [game_id] # Get characters (default: 164) ./api-test.sh posts [game_id] # Get posts (default: 164) ./api-test.sh comments <post_id> # Get comments for post
Create Operations:
./api-test.sh create-post [game_id] [character_id] [content] ./api-test.sh create-comment <post_id> [character_id] [content]
Feature Testing:
./api-test.sh test-mentions # End-to-end mention testing
What the Script Does
- •Logs in via
/api/v1/auth/loginwith test credentials - •Extracts JWT token from response
- •Saves token to
/tmp/api-token.txt - •Uses token in
Authorization: Bearer <token>header for all requests - •Parses responses with
jqfor readability
Script Output
The script outputs:
- •Colored status indicators (✅/❌)
- •JSON responses formatted with jq
- •Error messages if requests fail
- •Token validation results
Method 2: Manual curl with Token
Use the token saved by api-test.sh for manual testing:
# Get the token TOKEN=$(cat /tmp/api-token.txt) # Use in curl requests curl -s -H "Authorization: Bearer $TOKEN" \ http://localhost:3000/api/v1/games | jq '.'
Manual curl Patterns
GET Request:
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/games/164" | jq '.'
POST Request:
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"title": "New Game", "description": "Test game"}' \
"http://localhost:3000/api/v1/games" | jq '.'
PUT Request:
curl -s -X PUT \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"title": "Updated Title"}' \
"http://localhost:3000/api/v1/games/164" | jq '.'
DELETE Request:
curl -s -X DELETE \ -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/games/164" | jq '.'
Common Testing Patterns
Test New API Endpoint
# 1. Login first ./backend/scripts/api-test.sh login-player # 2. Test the endpoint curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/your-new-endpoint" | jq '.' # 3. Verify response structure # 4. Check database changes if applicable
Test Character Creation Flow
# 1. Login as player
./backend/scripts/api-test.sh login-player
# 2. Create character
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"game_id": 164,
"name": "Test Character",
"character_sheet": {"class": "Warrior", "level": 1}
}' \
"http://localhost:3000/api/v1/characters" | jq '.'
# 3. Verify in database
# 4. Login as GM and test approval workflow
./backend/scripts/api-test.sh login-gm
Test Phase Transition
# Login as GM
./backend/scripts/api-test.sh login-gm
# Advance phase
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"game_id": 164}' \
"http://localhost:3000/api/v1/phases/advance" | jq '.'
# Verify phase changed
./backend/scripts/api-test.sh game 164 | jq '.current_phase'
Test Private Messages
# Login as Player 1
./backend/scripts/api-test.sh login TestPlayer1
# Send message to Player 2
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"recipient_character_id": 1320,
"content": "Test private message"
}' \
"http://localhost:3000/api/v1/games/164/messages/private" | jq '.'
# Login as Player 2 and check messages
./backend/scripts/api-test.sh login TestPlayer2
./backend/scripts/api-test.sh posts 164
Test with Query Parameters
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/games/164/posts?limit=10&offset=0" | jq '.'
Test Credentials
Available Test Users:
| Username | Password | Role |
|---|---|---|
| TestGM | testpassword123 | Game Master |
| TestPlayer1 | testpassword123 | Player |
| TestPlayer2 | testpassword123 | Player |
| TestPlayer3 | testpassword123 | Player |
Test Game: Game ID 164 (use this for testing)
See: .claude/context/TEST_DATA.md for complete test fixture documentation
API Structure
Base URL
http://localhost:3000/api/v1
Route Structure
All routes follow REST conventions:
/api/v1/{resource}
/api/v1/{resource}/{id}
/api/v1/{resource}/{id}/{sub-resource}
Examples:
- •
/api/v1/games- List games - •
/api/v1/games/164- Get game 164 - •
/api/v1/games/164/characters- List characters in game 164 - •
/api/v1/games/164/posts- List posts in game 164
Authentication Endpoints
POST /api/v1/auth/login # Login (returns JWT) POST /api/v1/auth/logout # Logout GET /api/v1/auth/me # Get current user POST /api/v1/auth/refresh # Refresh access token
Main Resource Endpoints
Games:
GET /api/v1/games # List games
POST /api/v1/games # Create game (GM only)
GET /api/v1/games/{id} # Get game details
PUT /api/v1/games/{id} # Update game (GM only)
DELETE /api/v1/games/{id} # Delete game (GM only)
Characters:
GET /api/v1/games/{game_id}/characters # List characters
POST /api/v1/characters # Create character
GET /api/v1/characters/{id} # Get character
PUT /api/v1/characters/{id} # Update character
POST /api/v1/characters/{id}/approve # Approve (GM only)
POST /api/v1/characters/{id}/reject # Reject (GM only)
Messaging:
GET /api/v1/games/{game_id}/posts # Common room posts
POST /api/v1/games/{game_id}/posts # Create post
GET /api/v1/games/{game_id}/posts/{id}/comments # Get comments
POST /api/v1/games/{game_id}/posts/{id}/comments # Create comment
GET /api/v1/games/{game_id}/messages/private # Private messages
POST /api/v1/games/{game_id}/messages/private # Send private message
Phases:
POST /api/v1/phases/advance # Advance phase (GM only)
GET /api/v1/games/{game_id}/phases/current # Get current phase
See: .claude/reference/API_DOCUMENTATION.md for complete API reference
Testing Checklist
Before testing a route:
- • Backend server is running (
just dev) - • Database is migrated (
just migrate) - • Test fixtures are loaded (if needed)
- • You have a valid token (
./api-test.sh login-player) - • You know the full route path
- • You know the HTTP method (GET/POST/PUT/DELETE)
- • You have the request body prepared (if POST/PUT)
- • You know the expected response structure
- • You can verify changes (database, logs, etc.)
Verifying Database Changes
After testing routes that modify data:
# Connect to PostgreSQL PGPASSWORD=example psql -h localhost -U postgres -d actionphase # Check specific tables actionphase=# SELECT * FROM games WHERE id = 164; actionphase=# SELECT * FROM characters WHERE game_id = 164; actionphase=# SELECT * FROM posts WHERE game_id = 164 ORDER BY created_at DESC LIMIT 5; actionphase=# SELECT * FROM sessions WHERE username = 'TestPlayer1'; # Or use justfile command just psql
Quick queries:
-- Latest posts SELECT id, character_id, content, created_at FROM posts WHERE game_id = 164 ORDER BY created_at DESC LIMIT 10; -- Character mentions SELECT p.id, p.content, p.mentioned_character_ids FROM posts p WHERE game_id = 164 AND mentioned_character_ids IS NOT NULL ORDER BY created_at DESC; -- Current phase SELECT id, title, current_phase, phase_number FROM games WHERE id = 164;
Debugging Failed Tests
401 Unauthorized
Possible causes:
- •No token provided
- •Token expired (15 minute lifetime)
- •Invalid token format
- •JWT secret mismatch
Solutions:
# Check if backend is running curl http://localhost:3000/health # Get a fresh token ./backend/scripts/api-test.sh login-player # Verify token works ./backend/scripts/api-test.sh test-token # Check token format (should start with "eyJ") cat /tmp/api-token.txt
403 Forbidden
Possible causes:
- •User lacks required permissions
- •Not the GM for GM-only routes
- •Not the owner of the resource
- •Character not approved yet
Solutions:
# For GM-only routes, login as GM ./backend/scripts/api-test.sh login-gm # Check user info ./backend/scripts/api-test.sh test-token # Verify ownership in database just psql
404 Not Found
Possible causes:
- •Incorrect URL
- •Resource doesn't exist
- •Route not implemented yet
- •Typo in endpoint path
Solutions:
# Check route exists in backend/pkg/http/root.go grep -r "your-route" backend/pkg/http/ # Verify resource exists just psql # Then: SELECT * FROM games WHERE id = 164; # Check server logs # (server should print route registrations on startup)
500 Internal Server Error
Possible causes:
- •Database connection issue
- •Missing required fields
- •Validation error
- •Application panic/error
Solutions:
# Check server logs in terminal # Backend prints detailed error logs with correlation IDs # Check database is running docker ps | grep postgres # Verify request body structure # Compare with models in backend/pkg/core/models.go # Check correlation ID in error response # Search logs for that correlation ID
Testing Workflow
1. Unit Tests → 2. API Tests → 3. Manual Tests → 4. E2E Tests
This skill covers steps 2 and 3.
Step-by-Step Testing Flow
- •Write/modify backend code
- •Run unit tests:
just test-mocks - •Start backend:
just dev - •Test API with curl/api-test.sh ← This skill
- •Verify in database:
just psql - •Test in UI manually
- •Write E2E tests: Only after API works
See: .claude/context/TESTING.md for complete testing strategy
Integration with Other Tools
Use with Test Fixtures
# Load test fixtures ./backend/pkg/db/test_fixtures/apply_e2e.sh # Now test with known data ./backend/scripts/api-test.sh game 164 ./backend/scripts/api-test.sh characters 164
Use Before E2E Tests
# 1. Test API endpoint works ./backend/scripts/api-test.sh create-post 164 1319 "Test content" # 2. Verify response structure is correct # 3. NOW write Playwright test # The API endpoint is confirmed working
Use with justfile Commands
# justfile integrates api-test.sh just api-login # Login as player just api-login-gm # Login as GM just api-games # List games just api-game 164 # Get game 164
Environment Variables
# Override API base URL API_BASE_URL=http://localhost:3000 ./backend/scripts/api-test.sh games # Use different port API_BASE_URL=http://localhost:8080 ./backend/scripts/api-test.sh health
Common Scenarios
Scenario 1: Testing a New POST Endpoint
# 1. Start backend
just dev
# 2. Login
./backend/scripts/api-test.sh login-player
# 3. Test endpoint
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"field": "value"}' \
"http://localhost:3000/api/v1/your-endpoint" | jq '.'
# 4. Verify in database
just psql
# Then: SELECT * FROM your_table ORDER BY created_at DESC LIMIT 1;
# 5. Test error cases
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"invalid": "data"}' \
"http://localhost:3000/api/v1/your-endpoint" | jq '.'
# Should return 400 with validation error
Scenario 2: Testing Permission-Based Access
# Test as Player (should fail) ./backend/scripts/api-test.sh login-player curl -s -X POST \ -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/phases/advance" | jq '.' # Should return 403 # Test as GM (should succeed) ./backend/scripts/api-test.sh login-gm curl -s -X POST \ -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \ "http://localhost:3000/api/v1/phases/advance" | jq '.' # Should return 200
Scenario 3: End-to-End Feature Test
# Complete workflow test
echo "=== Testing Character Creation & Approval ==="
# 1. Player creates character
./backend/scripts/api-test.sh login-player
CHAR=$(curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"game_id": 164,
"name": "Test Character",
"character_sheet": {"class": "Mage"}
}' \
"http://localhost:3000/api/v1/characters")
CHAR_ID=$(echo "$CHAR" | jq -r '.id')
echo "Created character: $CHAR_ID"
# 2. GM approves character
./backend/scripts/api-test.sh login-gm
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/characters/$CHAR_ID/approve" | jq '.'
# 3. Verify character is approved
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/characters/$CHAR_ID" | jq '.status'
# Should return "approved"
echo "✅ Character workflow complete"
Key Files
- •Testing script:
backend/scripts/api-test.sh - •API routes:
backend/pkg/http/root.go - •Handler implementations:
backend/pkg/*/api.go - •Test fixtures:
backend/pkg/db/test_fixtures/*.sql - •justfile: Development commands that wrap api-test.sh
Related Skills & Context
- •backend-dev-guidelines - Patterns for implementing API endpoints
- •database-operations - Database schema and query patterns
- •authentication - JWT authentication details
- •test-fixtures - Test data setup and usage
Context Files:
- •
.claude/context/TESTING.md- Testing strategy - •
.claude/context/TEST_DATA.md- Test fixtures reference - •
.claude/context/ARCHITECTURE.md- Request flow - •
.claude/reference/API_DOCUMENTATION.md- Complete API reference
Skill Status: COMPLETE ✅
Authentication: JWT Bearer tokens ✅
Testing Script: backend/scripts/api-test.sh ✅
Integration: Works with test fixtures, justfile, E2E tests ✅