## Summary Homogenize all 23 ADRs to a single canonical header format, and rewrite `adr/README.md` to match the actual state of the corpus. This is **Tâche 7** of the ARCODANGE Phase 1 migration (Claude Code → Mistral Vibe). Independent from PR #17 (Tâche 6 — restructure AGENTS.md) — both can merge in any order. No code changes; only documentation. ## Changes ### 1. Homogenize 21 ADR headers (commit `db09d0a`) The audit (Tâche 6 Phase A, Mistral intent-router agent, 2026-05-02) had identified **3 inconsistent header formats** : - **F1** — list bullets (`* Status:` / `* Date:` / `* Deciders:`) : 11 ADRs (0001-0008, 0011, 0014, 0023) - **F2** — bold fields (`**Status:**` / `**Date:**` / `**Authors:**`) : 9 ADRs (0009, 0010, 0012, 0013, 0015, 0016, 0017, 0018, 0019) - **F3** — dedicated section (`## Status\n**Value** ✅`) : 5 ADRs (0020, 0021, 0022, 0024, 0025) Plus mixed metadata names (Authors / Deciders / Decision Date / Implementation Date / Implementation Status / Last Updated) and decorative emojis on status values made the corpus hard to scan or template against. **Canonical format adopted** (see `adr/README.md` for full template) : ```markdown # NN. Title **Status:** <Proposed | Accepted | Implemented | Partially Implemented | Approved | Rejected | Deferred | Deprecated | Superseded by ADR-NNNN> **Date:** YYYY-MM-DD **Authors:** Name(s) [optional **Field:** ... lines] ## Context... ``` **Transformations applied** (via `/tmp/homogenize-adrs.py` script, 23 files scanned, 21 modified — 0010 and 0012 were already conform) : - F1 list bullets → bold fields - F2 cleanup : `**Deciders:**` → `**Authors:**`, strip status emojis - F3 sections : `## Status\n**Value** ✅` → `**Status:** Value` (single line) - Strip decorative emojis from `**Status:**` and `**Implementation Status:**` - Convert `* Last Updated:` / `* Implementation Status:` / `* Decision Drivers:` / `* Decision Date:` to bold - Date typo fix : `2024-04-XX` → `2026-04-XX` for ADRs 0018, 0019 (off-by-2-years in original) - Normalize multiple blank lines after header (max 1) **ADR body content is preserved unchanged.** Only headers transformed. ### 2. Rewrite `adr/README.md` (commit `d64ab02`) Previous README had multiple inconsistencies : - Index table listed wrong titles for ADRs 0010-0021 (looked like an aspirational forecast that never matched reality — e.g. "0011 = Trunk-Based Development" but real 0011 is absent and Trunk-Based Development is actually 0017) - Listed entries for ADRs 0011 (validation library) and 0014 (gRPC) but **these files do not exist** in the repo - 0024 (BDD Test Organization) was missing from the detail list - Template still showed the obsolete F1 format (`* Status:`) - Decorative emojis on every status entry Rewrite : - Index table **regenerated from actual file contents** (title from H1, status from `**Status:**` line) — emoji-free, accurate - Notes that 0011 / 0014 are not currently in use (reserved) - Updated template block matches the canonical format - Status Legend extended with `Approved`, `Partially Implemented`, `Deferred` - Added note that 0026 is the next free number for new ADRs ## Test plan - [x] All 23 ADRs follow `**Status:**` / `**Date:**` / `**Authors:**` (verified via grep) - [x] No more occurrences of `* Status:` (F1) or `## Status` (F3) in any ADR header - [x] No more emojis on `**Status:**` lines - [x] `adr/README.md` index links resolve to existing files (no more 0011 / 0014 dead links) - [x] Pre-commit hooks pass (`go mod tidy`, `go fmt`, `swag fmt`) ## Migration context Part of Phase 1 of the ARCODANGE migration from Claude Code to Mistral Vibe. Tâche 7 of the curriculum. Independent from PR #17 (which restructures `AGENTS.md`). The two PRs touch disjoint files — no merge conflict expected when both are merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) (Opus 4.7, 1M context). Mistral Vibe (intent-router agent / mistral-medium-3.5) did the original audit identifying the 3 formats during Tâche 6 Phase A. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Mistral Vibe (devstral-2 / mistral-medium-3.5) Reviewed-on: #18 Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
16 KiB
18. User Management and Authentication System
Date: 2026-04-06 Status: Proposed Authors: Product Owner Decision Drivers: Security, User Personalization, Admin Functionality
Context
The dance-lessons-coach application currently lacks user management and authentication capabilities. To provide personalized experiences and administrative functions, we need to implement a secure user authentication system with PostgreSQL persistence.
Decision
We will implement a user management and authentication system with the following characteristics:
Core Features
-
User Model
- Username-based identification (no email/personal info)
- Password authentication with secure hashing
- User profile fields: description and current goal
- Admin flag for privileged users
-
Authentication System
- JWT-based authentication
- Secure password hashing (bcrypt)
- Session management
- Admin master password for non-persisted admin access
-
Password Reset Workflow
- Admin-assisted password reset (no email/phone required)
- Allow password reset flag for users
- Unauthenticated password reset endpoint for flagged users
-
Integration Points
- Greet service personalization based on authenticated user
- Admin-only endpoints for user management
- BDD test coverage for all authentication flows
- CI/CD pipeline updates for new dependencies
Technical Implementation
Database Schema (PostgreSQL)
CREATE TABLE users (
id SERIAL PRIMARY KEY,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
deleted_at TIMESTAMP WITH TIME ZONE,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
description TEXT,
current_goal TEXT,
is_admin BOOLEAN DEFAULT FALSE,
allow_password_reset BOOLEAN DEFAULT FALSE,
last_login TIMESTAMP WITH TIME ZONE
);
Technology Stack
- ORM: GORM (for PostgreSQL integration) - aligns with existing interface-based design
- Authentication: JWT with HS256 signing - stateless, scalable
- Password Hashing: bcrypt - industry standard for password storage
- Validation: go-playground/validator - consistent with existing validation approach
- Database: PostgreSQL (containerized) - production-ready database
- Configuration: Viper integration - consistent with existing config management
- Logging: Zerolog integration - consistent with existing logging approach
- Telemetry: OpenTelemetry support - consistent with existing observability
Architecture Alignment
The user management system follows the established dance-lessons-coach patterns:
-
Interface-based Design:
type UserRepository interface { CreateUser(user *User) error GetUserByUsername(username string) (*User, error) // ... other methods } type AuthService interface { Authenticate(username, password string) (*User, error) GenerateJWT(user *User) (string, error) ValidateJWT(token string) (*User, error) } -
Context-aware Services:
func (s *AuthService) Authenticate(ctx context.Context, username, password string) (*User, error) { log.Trace().Ctx(ctx).Str("username", username).Msg("Authenticating user") // ... authentication logic } -
Configuration Integration:
type AuthConfig struct { JWTSecret string `mapstructure:"jwt_secret"` JWTExpiration time.Duration `mapstructure:"jwt_expiration"` AdminUsername string `mapstructure:"admin_username"` AdminMasterPassword string `mapstructure:"admin_master_password"` } -
Chi Router Integration:
func (h *AuthHandler) RegisterRoutes(router chi.Router) { router.Post("/register", h.handleRegister) router.Post("/login", h.handleLogin) // ... other routes }
Security Considerations
- Password Storage: bcrypt with work factor 12
- JWT Security:
- 30-minute expiration for access tokens
- Secure random signing key
- HTTPS-only cookies
- Secret Rotation: Multiple valid secrets with retention policy (see Issue #8)
- Admin Access:
- Master password from environment variable
- Non-persisted admin user
- Full access to user management endpoints
- Password Reset Control: Only admins can flag users for reset
- Password Reset Security:
- Admin-Only Flagging: Only authenticated admins can set
allow_password_resetflag - Flag-Based Access: Unauthenticated reset only works for admin-flagged users
- Automatic Flag Clearing: Flag is cleared after successful password reset
- No Self-Service: Users cannot flag themselves or others for reset
- Admin-Only Flagging: Only authenticated admins can set
- Rate Limiting: On authentication endpoints (3 attempts/hour for password reset)
- Input Validation: Strict username validation (alphanumeric, 3-50 chars)
API Endpoints
Public Endpoints
POST /api/v1/auth/register- User registrationPOST /api/v1/auth/login- User loginPOST /api/v1/auth/reset-password- Password reset (for flagged users)
Authenticated Endpoints
GET /api/v1/users/me- Get current user profilePUT /api/v1/users/me- Update current user profilePUT /api/v1/users/me/password- Change own password
Admin-Only Endpoints
GET /api/v1/admin/users- List all usersPOST /api/v1/admin/users/{username}/allow-reset- Allow password resetDELETE /api/v1/admin/users/{username}- Delete user
Integration with Existing Services
Greet Service Enhancement
The authentication system integrates seamlessly with the existing greet service by leveraging Go's context package:
// Updated greet service with authentication support
func (s *Service) Greet(ctx context.Context, name string) string {
log.Trace().Ctx(ctx).Str("name", name).Msg("Greet function called")
// Extract authenticated username from context using existing auth package
if username := auth.GetUsernameFromContext(ctx); username != "" {
log.Trace().Ctx(ctx).Str("authenticated_user", username).Msg("Using authenticated username")
return "Hello " + username + "!"
}
// Fallback to original behavior for backward compatibility
if name == "" {
return "Hello world!"
}
return "Hello " + name + "!"
}
Authentication Middleware
The system includes Chi middleware for JWT validation:
func (s *AuthService) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Extract and validate JWT token
token := auth.ExtractTokenFromRequest(r)
if token == "" {
next.ServeHTTP(w, r)
return // Continue without authentication
}
// Validate token and extract user
if user, err := s.ValidateJWT(ctx, token); err == nil {
// Add user to context for downstream services
ctx = auth.SetUserInContext(ctx, user)
r = r.WithContext(ctx)
}
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Server Integration
The authentication middleware is added to the Chi router stack:
// In server.go
func (s *Server) getAllMiddlewares() []func(http.Handler) http.Handler {
middlewares := []func(http.Handler) http.Handler{
middleware.StripSlashes,
middleware.Recoverer,
s.authService.Middleware, // Add auth middleware
}
if s.withOTEL {
middlewares = append(middlewares, func(next http.Handler) http.Handler {
return otelhttp.NewHandler(next, "")
})
}
return middlewares
}
Configuration Extension
The existing Config struct is extended with authentication settings:
// In config.go
type AuthConfig struct {
JWTSecret string `mapstructure:"jwt_secret"`
JWTExpiration time.Duration `mapstructure:"jwt_expiration"`
AdminUsername string `mapstructure:"admin_username"`
AdminMasterPassword string `mapstructure:"admin_master_password"`
}
type DatabaseConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
Name string `mapstructure:"name"`
SSLMode string `mapstructure:"ssl_mode"`
}
// Extended Config struct
type Config struct {
Server ServerConfig `mapstructure:"server"`
Shutdown ShutdownConfig `mapstructure:"shutdown"`
Logging LoggingConfig `mapstructure:"logging"`
Telemetry TelemetryConfig `mapstructure:"telemetry"`
API APIConfig `mapstructure:"api"`
Auth AuthConfig `mapstructure:"auth"`
Database DatabaseConfig `mapstructure:"database"`
}
Consequences
Positive
- Personalized Experience: Users see their username in greetings
- Admin Capabilities: Secure administrative functions
- Password Recovery: Admin-assisted workflow without contact info
- Security: Proper authentication and authorization
- Extensibility: Foundation for future user-based features
Negative
- Increased Complexity: Additional dependencies and configuration
- Database Requirement: PostgreSQL container needed for development
- Migration Complexity: Existing tests need updates
- CI/CD Changes: Pipeline needs adjustment for new dependencies
- Performance Impact: Authentication middleware adds overhead
Neutral
- Learning Curve: Team needs to learn GORM and JWT
- Testing Overhead: Additional BDD scenarios required
- Documentation Needs: Comprehensive API documentation required
Alternatives Considered
Alternative 1: No Authentication
- Pros: Simpler, no database needed
- Cons: No personalization, no admin functions
- Rejected: Doesn't meet product requirements
Alternative 2: Session-based Auth
- Pros: Traditional approach, well-understood
- Cons: State management complexity, scaling issues
- Rejected: JWT provides better scalability
Alternative 3: OAuth/OIDC
- Pros: Industry standard, delegation to identity providers
- Cons: Complex setup, external dependencies
- Rejected: Overkill for current requirements
Alternative 4: Pure SQL (no ORM)
- Pros: No ORM overhead, direct control
- Cons: More boilerplate, manual query building
- Rejected: GORM provides good balance of control and convenience
Implementation Plan
This implementation builds upon the completed phases and follows the established dance-lessons-coach patterns.
Phase 10: User Management Foundation (Next Phase)
Objective: Establish database models and basic user management
-
Add Dependencies:
github.com/golang-jwt/jwt/v5for JWT authenticationgolang.org/x/cryptofor bcrypt password hashinggorm.io/gormandgorm.io/driver/postgresfor ORM
-
Create User Package:
pkg/user/models.go- User model and GORM repositorypkg/user/repository.go- Interface-based repositorypkg/user/service.go- User management service
-
Database Setup:
- Add PostgreSQL container to
docker-compose.yml - Create database migration scripts
- Implement GORM database connection
- Add PostgreSQL container to
-
Configuration Extension:
- Extend
Configstruct withAuthConfigandDatabaseConfig - Add environment variable bindings with
DLC_prefix - Update
LoadConfig()function
- Extend
Phase 11: Authentication System
Objective: Implement secure authentication with JWT
-
Auth Service:
pkg/auth/service.go- JWT generation/validationpkg/auth/middleware.go- Chi authentication middlewarepkg/auth/context.go- Context utilities for user data
-
Authentication Endpoints:
POST /api/v1/auth/register- User registrationPOST /api/v1/auth/login- User loginPOST /api/v1/auth/refresh- Token refresh
-
Password Security:
- Implement bcrypt password hashing (work factor 12)
- Add password validation rules
- Implement secure password comparison
-
Admin Authentication:
- Master password configuration
- Non-persisted admin user
- Admin middleware for privileged endpoints
Phase 12: Integration & Personalization
Objective: Integrate authentication with existing services
-
Greet Service Enhancement:
- Update
pkg/greet/greet.goto check authenticated username - Maintain backward compatibility
- Add context-based username extraction
- Update
-
User Profile Endpoints:
GET /api/v1/users/me- Get current user profilePUT /api/v1/users/me- Update profile (description, goal)PUT /api/v1/users/me/password- Change password
-
Admin Endpoints:
GET /api/v1/admin/users- List all usersPOST /api/v1/admin/users/{username}/allow-reset- Allow password resetDELETE /api/v1/admin/users/{username}- Delete user
Phase 13: Password Reset & Testing
Objective: Implement password reset workflow and comprehensive testing
-
Password Reset Workflow:
POST /api/v1/auth/reset-password- Unauthenticated reset for flagged users- Admin flag management
- Rate limiting for reset endpoints
-
BDD Test Scenarios:
- User registration and login
- Personalized greetings for authenticated users
- Admin password reset workflow
- Error handling and validation
-
Unit & Integration Tests:
- Password hashing/verification
- JWT token generation/validation
- Repository methods
- Authentication middleware
Phase 14: CI/CD & Documentation
Objective: Update pipeline and create comprehensive documentation
-
CI/CD Updates:
- Add PostgreSQL service to CI environment
- Update dependency management
- Add authentication test suite
- Implement security scanning
-
Documentation:
- Update
AGENTS.mdwith new architecture - Create user management wiki page
- Update API documentation with Swagger
- Add configuration examples
- Update
-
Deployment Preparation:
- Create database migration guide
- Update Docker configuration
- Add environment variable documentation
- Create rollback plan
Alignment with Existing Phases
This implementation builds upon the completed phases:
- Phase 1-3: Uses existing Go 1.26.1, Chi router, Zerolog, and interface-based design
- Phase 5: Extends Viper configuration management
- Phase 6: Integrates with graceful shutdown patterns
- Phase 7: Maintains OpenTelemetry compatibility
- Phase 8: Follows existing build system patterns
- Phase 9: Preserves trace-level logging approach
Backward Compatibility
The implementation maintains full backward compatibility:
- Greet Service: Falls back to original behavior when no authentication
- API Endpoints: Existing
/api/v1/greet/*endpoints unchanged - Configuration: All existing config options preserved
- Logging: Maintains existing Zerolog integration
- Telemetry: OpenTelemetry continues to work unchanged
Success Metrics
- Security: No authentication bypass vulnerabilities
- Performance: <50ms auth middleware overhead
- Reliability: 99.9% uptime for auth endpoints
- Adoption: 80% of API calls authenticated within 3 months
- Satisfaction: User feedback on personalization features
Open Questions
- Should we implement refresh tokens for longer sessions?
- What should be the maximum session duration?
- Should we add IP-based rate limiting for auth endpoints?
- What username characters should be allowed beyond alphanumeric?
- Should we implement account lockout after failed attempts?
Future Considerations
- Multi-factor Authentication: For enhanced security
- OAuth Integration: For third-party identity providers
- User Activity Logging: For audit trails
- Password Strength Meter: For better user experience
- Account Recovery: Email/phone-based recovery options
- JWT Secret Rotation: Implement secret persistence and rotation mechanism (Issue #8)
References
Approved by: [Product Owner] Approval Date: [To be determined] Implementation Target: Q2 2024