# 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))
}
```