diff --git a/User-Story-Implementation-Workflow.-.md b/User-Story-Implementation-Workflow.-.md new file mode 100644 index 0000000..a51cb7b --- /dev/null +++ b/User-Story-Implementation-Workflow.-.md @@ -0,0 +1,648 @@ +# User Management and Authentication System + +## Overview + +The DanceLessonsCoach user management and authentication system provides secure user authentication, personalized experiences, and administrative capabilities. This document describes the system architecture, API endpoints, and integration points. + +## Architecture + +```mermaid +graph TD + A[Client] -->|HTTP Request| B[Authentication Middleware] + B -->|Valid Token| C[Authorized Endpoints] + B -->|Invalid Token| D[401 Unauthorized] + C --> E[Greet Service] + C --> F[User Profile Service] + C --> G[Admin Service] + E -->|Personalized Response| A + F -->|User Data| H[PostgreSQL] + G -->|Admin Operations| H +``` + +## Core Components + +### 1. User Model + +**Database Schema:** +```sql +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 +); +``` + +**Fields:** +- `username`: Unique identifier (3-50 alphanumeric characters) +- `password_hash`: bcrypt-hashed password +- `description`: User's personal description +- `current_goal`: User's current dance learning goal +- `is_admin`: Administrative privileges flag +- `allow_password_reset`: Flag for password reset eligibility + +### 2. Authentication Service + +**Features:** +- JWT token generation and validation +- bcrypt password hashing (work factor 12) +- 30-minute token expiration +- Secure cookie-based token storage +- Admin master password authentication + +**Environment Variables:** +```bash +# JWT Configuration +DLC_JWT_SECRET="your-secure-random-secret-key" +DLC_JWT_EXPIRATION="30m" + +# Admin Configuration +DLC_ADMIN_USERNAME="admin" +DLC_ADMIN_MASTER_PASSWORD="secure-master-password" + +# Database Configuration +DLC_DB_HOST="localhost" +DLC_DB_PORT="5432" +DLC_DB_USER="dancecoach" +DLC_DB_PASSWORD="secure-password" +DLC_DB_NAME="dance_lessons_coach" +DLC_DB_SSL_MODE="disable" +``` + +## API Endpoints + +### Authentication Endpoints + +#### POST `/api/v1/auth/register` +**Request:** +```json +{ + "username": "john_doe", + "password": "securePassword123!" +} +``` + +**Response (201 Created):** +```json +{ + "id": 1, + "username": "john_doe", + "created_at": "2024-04-06T10:00:00Z", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Validation Rules:** +- `username`: Required, 3-50 chars, alphanumeric only +- `password`: Required, min 8 chars + +#### POST `/api/v1/auth/login` +**Request:** +```json +{ + "username": "john_doe", + "password": "securePassword123!" +} +``` + +**Response (200 OK):** +```json +{ + "id": 1, + "username": "john_doe", + "is_admin": false, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "expires_at": "2024-04-06T10:30:00Z" +} +``` + +#### POST `/api/v1/auth/reset-password` +**Request (for flagged users only):** +```json +{ + "username": "john_doe", + "new_password": "newSecurePassword456!" +} +``` + +**Response (200 OK):** +```json +{ + "message": "Password reset successfully" +} +``` + +### User Profile Endpoints + +#### GET `/api/v1/users/me` +**Headers:** +``` +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Response (200 OK):** +```json +{ + "id": 1, + "username": "john_doe", + "description": "Dance enthusiast learning salsa", + "current_goal": "Master basic salsa steps", + "created_at": "2024-04-06T10:00:00Z", + "last_login": "2024-04-06T10:15:00Z" +} +``` + +#### PUT `/api/v1/users/me` +**Request:** +```json +{ + "description": "Passionate dancer learning multiple styles", + "current_goal": "Prepare for salsa competition" +} +``` + +**Response (200 OK):** +```json +{ + "id": 1, + "username": "john_doe", + "description": "Passionate dancer learning multiple styles", + "current_goal": "Prepare for salsa competition", + "updated_at": "2024-04-06T10:30:00Z" +} +``` + +#### PUT `/api/v1/users/me/password` +**Request:** +```json +{ + "current_password": "securePassword123!", + "new_password": "evenMoreSecurePassword456!" +} +``` + +**Response (200 OK):** +```json +{ + "message": "Password updated successfully" +} +``` + +### Admin Endpoints + +#### GET `/api/v1/admin/users` +**Headers:** +``` +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +X-Admin-Key: master-admin-key +``` + +**Response (200 OK):** +```json +{ + "users": [ + { + "id": 1, + "username": "john_doe", + "is_admin": false, + "allow_password_reset": false, + "created_at": "2024-04-06T10:00:00Z" + }, + { + "id": 2, + "username": "jane_smith", + "is_admin": true, + "allow_password_reset": true, + "created_at": "2024-04-05T15:30:00Z" + } + ], + "total": 2 +} +``` + +#### POST `/api/v1/admin/users/{username}/allow-reset` +**Headers:** +``` +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +X-Admin-Key: master-admin-key +``` + +**Response (200 OK):** +```json +{ + "message": "Password reset allowed for user john_doe" +} +``` + +#### DELETE `/api/v1/admin/users/{username}` +**Headers:** +``` +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +X-Admin-Key: master-admin-key +``` + +**Response (200 OK):** +```json +{ + "message": "User john_doe deleted successfully" +} +``` + +## Integration with Greet Service + +### Current Behavior +``` +GET /api/v1/greet/John +Response: {"message": "Hello John!"} +``` + +### New Behavior with Authentication +``` +GET /api/v1/greet +Headers: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +Response: {"message": "Hello john_doe!"} +``` + +**Implementation:** +```go +func (s *Service) Greet(ctx context.Context, name string) string { + // Extract authenticated username from context + username := auth.GetUsernameFromContext(ctx) + + if username != "" { + return "Hello " + username + "!" + } + + // Fallback to original behavior + if name == "" { + return "Hello world!" + } + return "Hello " + name + "!" +} +``` + +## Password Reset Workflow + +```mermaid +sequenceDiagram + participant User + participant Admin + participant System + participant Database + + User->>System: Forgot password (no auth) + System-->>User: 403 Forbidden + + User->>Admin: Request password reset + Admin->>System: POST /api/v1/admin/users/john_doe/allow-reset + System->>Database: Set allow_password_reset = true + Database-->>System: Success + System-->>Admin: 200 OK + + User->>System: POST /api/v1/auth/reset-password + System->>Database: Check allow_password_reset flag + Database-->>System: Flag is true + System->>Database: Update password_hash + Database-->>System: Success + System->>Database: Set allow_password_reset = false + System-->>User: 200 OK +``` + +## Security Considerations + +### Password Storage +- **Algorithm:** bcrypt with work factor 12 +- **Implementation:** `golang.org/x/crypto/bcrypt` +- **Salt:** Automatic per-password salt + +### JWT Security +- **Algorithm:** HS256 with secure random key +- **Expiration:** 30 minutes (configurable) +- **Storage:** HTTP-only, Secure cookies +- **Claims:** User ID, username, admin flag, expiration + +### Rate Limiting +- **Authentication Endpoints:** 5 requests per minute per IP +- **Password Reset:** 3 attempts per hour per user +- **Implementation:** Chi middleware + +### Input Validation +- **Username:** 3-50 alphanumeric characters +- **Password:** Minimum 8 characters +- **Description/Goal:** Maximum 500 characters + +## Error Handling + +### Standard Error Format +```json +{ + "error": "error_code", + "message": "Human-readable message", + "details": [ + { + "field": "username", + "message": "Username must be at least 3 characters" + } + ] +} +``` + +### Common Error Codes +- `auth_invalid_credentials`: Invalid username/password +- `auth_token_expired`: JWT token expired +- `auth_token_invalid`: Invalid JWT token +- `auth_unauthorized`: Missing or invalid authorization +- `validation_failed`: Input validation failed +- `user_not_found`: User does not exist +- `user_exists`: Username already taken +- `password_reset_not_allowed`: User not flagged for reset +- `admin_required`: Admin privileges required + +## Database Setup + +### Docker Compose +```yaml +version: '3.8' + +services: + postgres: + image: postgres:15-alpine + container_name: dance-lessons-coach-db + environment: + POSTGRES_USER: dancecoach + POSTGRES_PASSWORD: secure-password + POSTGRES_DB: dance_lessons_coach + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U dancecoach"] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + postgres_data: +``` + +### Database Migration +```bash +# Initialize database +go run cmd/server/main.go migrate + +# Run migrations +goose -dir migrations/postgres up +``` + +## Testing Strategy + +### Unit Tests +- Password hashing/verification +- JWT token generation/validation +- User model validation +- Repository methods + +### Integration Tests +- Authentication flow +- Authorization middleware +- Database operations +- Password reset workflow + +### BDD Tests +```gherkin +Feature: User Authentication + Scenario: Successful user registration + Given I am not authenticated + When I register with valid credentials + Then I should receive a JWT token + And my user account should be created + + Scenario: Successful login + Given I have a registered account + When I login with correct credentials + Then I should receive a JWT token + And the token should expire in 30 minutes + + Scenario: Personalized greeting for authenticated user + Given I am authenticated as "john_doe" + When I request the default greeting + Then the response should be "{"message":"Hello john_doe!"}" +``` + +## CI/CD Integration + +### New Dependencies +```bash +# Add to go.mod +require ( + github.com/golang-jwt/jwt/v5 v5.0.0 + golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa + gorm.io/gorm v1.25.0 + gorm.io/driver/postgres v1.5.0 +) +``` + +### Pipeline Changes +1. Add PostgreSQL service to CI environment +2. Run database migrations before tests +3. Include authentication tests in test suite +4. Add security scanning for dependencies + +## Deployment Considerations + +### Configuration +```yaml +# config.yaml +database: + host: localhost + port: 5432 + user: dancecoach + password: secure-password + name: dance_lessons_coach + ssl_mode: disable + +auth: + jwt_secret: your-secure-random-secret-key + jwt_expiration: 30m + admin_username: admin + admin_master_password: secure-master-password +``` + +### Environment Variables +```bash +# Database +export DLC_DB_HOST="localhost" +export DLC_DB_PORT="5432" +export DLC_DB_USER="dancecoach" +export DLC_DB_PASSWORD="secure-password" +export DLC_DB_NAME="dance_lessons_coach" +export DLC_DB_SSL_MODE="disable" + +# Authentication +export DLC_JWT_SECRET="your-secure-random-secret-key" +export DLC_JWT_EXPIRATION="30m" +export DLC_ADMIN_USERNAME="admin" +export DLC_ADMIN_MASTER_PASSWORD="secure-master-password" +``` + +## Monitoring and Observability + +### Metrics +- `auth_login_success_total`: Successful logins +- `auth_login_failure_total`: Failed login attempts +- `auth_register_total`: User registrations +- `auth_token_issued_total`: JWT tokens issued +- `user_active_total`: Active users + +### Logging +- Authentication attempts (success/failure) +- Password changes +- Admin operations +- Rate limiting events + +### Alerts +- Multiple failed login attempts +- Admin account modifications +- Unusual password reset activity + +## Future Enhancements + +### Short-term (Next 3 Months) +1. **Refresh Tokens:** Long-lived refresh tokens with rotation +2. **Rate Limiting:** IP-based rate limiting for auth endpoints +3. **Password Strength:** Enforce stronger password requirements +4. **Account Lockout:** Temporary lockout after failed attempts + +### Medium-term (Next 6 Months) +1. **Multi-factor Authentication:** TOTP or backup codes +2. **User Activity Logging:** Comprehensive audit trails +3. **Session Management:** View and revoke active sessions +4. **Password Expiration:** Enforce periodic password changes + +### Long-term (Future) +1. **OAuth Integration:** Google, Facebook, Apple sign-in +2. **Social Features:** User profiles, followers, messaging +3. **Role-Based Access:** Fine-grained permissions +4. **User Preferences:** Theme, language, notifications + +## Troubleshooting + +### Common Issues + +**Issue:** Authentication fails with valid credentials +- **Check:** Password hash comparison logic +- **Check:** JWT secret key configuration +- **Check:** Database connection + +**Issue:** Password reset not working +- **Check:** User has `allow_password_reset` flag set +- **Check:** Admin has set the flag correctly +- **Check:** Rate limiting not blocking requests + +**Issue:** Personalized greeting not showing username +- **Check:** Authentication middleware is properly configured +- **Check:** JWT token is valid and not expired +- **Check:** Context contains username after authentication + +## Migration Guide + +### From No Authentication to User System + +1. **Add Dependencies:** + ```bash + go get github.com/golang-jwt/jwt/v5 + go get golang.org/x/crypto + go get gorm.io/gorm + go get gorm.io/driver/postgres + ``` + +2. **Update Configuration:** + - Add database configuration + - Add JWT configuration + - Add admin configuration + +3. **Update Server:** + - Add authentication middleware + - Add user repository initialization + - Add auth routes + +4. **Update Greet Service:** + - Modify to check for authenticated username + - Maintain backward compatibility + +5. **Update Tests:** + - Add authentication scenarios + - Update existing tests for new behavior + - Add BDD tests for user management + +6. **Update CI/CD:** + - Add PostgreSQL to test environment + - Update test scripts + - Add security scanning + +## References + +- [GORM Documentation](https://gorm.io/) +- [JWT RFC 7519](https://tools.ietf.org/html/rfc7519) +- [bcrypt Documentation](https://pkg.go.dev/golang.org/x/crypto/bcrypt) +- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) +- [Chi Router Middleware](https://github.com/go-chi/chi) + +## Appendix + +### Username Validation Regex +```go +var usernameRegex = regexp.MustCompile(`^[a-zA-Z0-9]{3,50}$`) +``` + +### Password Hashing Example +```go +import "golang.org/x/crypto/bcrypt" + +func HashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 12) + return string(bytes), err +} + +func CheckPasswordHash(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} +``` + +### JWT Token Example +```go +import ( + "github.com/golang-jwt/jwt/v5" + "time" +) + +type Claims struct { + UserID uint `json:"user_id"` + Username string `json:"username"` + IsAdmin bool `json:"is_admin"` + jwt.RegisteredClaims +} + +func GenerateJWT(user *User, secret string, expiration time.Duration) (string, error) { + claims := &Claims{ + UserID: user.ID, + Username: user.Username, + IsAdmin: user.IsAdmin, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiration)), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString([]byte(secret)) +} +```