Ctrl K
ComunidadGuías…

docs/ARCHITECTURE.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Architecture Documentation

## Overview

ActaLog is a mobile-first **Progressive Web App (PWA)** built using Clean Architecture principles with a Go backend and Vue.js frontend. The system is designed to be modular, testable, scalable, and works offline-first with automatic synchronization.

## Architecture Pattern

We follow **Clean Architecture** (also known as Hexagonal Architecture or Ports and Adapters), which provides:

- **Independence from frameworks**: Business logic doesn't depend on external libraries
- **Testability**: Business rules can be tested without UI, database, or external dependencies
- **Independence from UI**: UI can change without affecting business logic
- **Independence from database**: Can swap databases without changing business rules
- **Independence from external services**: Business rules don't know about the outside world

## System Architecture

```mermaid
graph TB
    subgraph "Client Layer"
        Web[Web Browser]
        Mobile[Mobile Browser]
        Installed[Installed PWA]
    end

    subgraph "PWA Layer"
        SW[Service Worker]
        IDB[(IndexedDB)]
        Cache[Cache Storage]
        Manifest[Web App Manifest]
    end

    subgraph "Presentation Layer"
        VueApp[Vue.js Application]
        Vuetify[Vuetify Components]
        OfflineUtil[Offline Storage Utils]
    end

    subgraph "API Layer"
        Router[HTTP Router]
        Middleware[Middleware Stack]
        Handlers[HTTP Handlers]
    end

    subgraph "Business Logic Layer"
        Services[Services/Use Cases]
        Domain[Domain Models]
    end

    subgraph "Data Layer"
        Repos[Repositories]
        DB[(Database)]
    end

    subgraph "Infrastructure"
        Auth[JWT Authentication]
        Logger[Structured Logging]
        Telemetry[OpenTelemetry]
    end

    Web --> SW
    Mobile --> SW
    Installed --> SW
    SW --> VueApp
    SW --> Cache
    VueApp --> Vuetify
    VueApp --> OfflineUtil
    OfflineUtil --> IDB
    VueApp --> Router
    Router --> Middleware
    Middleware --> Handlers
    Handlers --> Services
    Services --> Domain
    Services --> Repos
    Repos --> DB
    Middleware --> Auth
    Middleware --> Logger
    Services --> Telemetry
```

## Directory Structure

```
actalog/
├── cmd/
│   └── actalog/           # Application entry point
│       └── main.go
├── internal/              # Private application code
│   ├── domain/           # Business entities and interfaces
│   │   ├── user.go
│   │   ├── workout.go
│   │   └── movement.go
│   ├── repository/       # Data access implementations
│   │   ├── user_repo.go
│   │   ├── workout_repo.go
│   │   └── movement_repo.go
│   ├── service/          # Business logic/use cases
│   │   ├── user_service.go
│   │   ├── workout_service.go
│   │   └── movement_service.go
│   └── handler/          # HTTP handlers
│       ├── user_handler.go
│       ├── workout_handler.go
│       └── movement_handler.go
├── pkg/                   # Public, reusable packages
│   ├── auth/             # Authentication utilities
│   ├── middleware/       # HTTP middleware
│   ├── utils/            # Utility functions
│   └── version/          # Version information
├── api/                   # API definitions
│   ├── rest/             # REST API routes
│   └── models/           # API request/response models
├── configs/              # Configuration management
│   └── config.go
├── test/                 # Tests
│   ├── unit/            # Unit tests
│   └── integration/     # Integration tests
├── web/                  # Frontend application
│   ├── public/          # Static assets
│   └── src/             # Vue.js source code
├── docs/                # Documentation
├── design/              # Design assets
└── migrations/          # Database migrations
```

## Layer Responsibilities

### 1. Domain Layer (`internal/domain/`)

**Responsibility**: Contains business entities and repository interfaces

- Pure Go structs representing business concepts
- Repository interfaces (defined here, implemented elsewhere)
- No external dependencies
- The heart of the application

**Core Entities** (Showing planned v0.3.0 schema - not yet implemented):

```go
// User represents a system user
type User struct {
    ID            int64
    Email         string
    PasswordHash  string
    Name          string
    Birthday      *time.Time
    ProfileImage  string
    Role          string
    CreatedAt     time.Time
    UpdatedAt     time.Time
    UpdatedBy     *int64
    LastLoginAt   *time.Time
}

// WOD represents a predefined CrossFit workout
type WOD struct {
    ID          int64
    Name        string
    Source      string // CrossFit, Other Coach, Self-recorded
    Type        string // Benchmark, Hero, Girl, Notables, Games, Endurance, Self-created
    Regime      string // EMOM, AMRAP, Fastest Time, etc.
    ScoreType   string // Time, Rounds+Reps, Max Weight
    Description string
    URL         string
    Notes       string
    CreatedBy   *int64
    CreatedAt   time.Time
    UpdatedAt   time.Time
    UpdatedBy   *int64
}

// StrengthMovement represents an exercise/movement
type StrengthMovement struct {
    ID           int64
    Name         string
    MovementType string // weightlifting, cardio, gymnastics
    Description  string
    CreatedBy    *int64
    CreatedAt    time.Time
    UpdatedAt    time.Time
    UpdatedBy    *int64
}

// Workout represents a workout template (reusable)
type Workout struct {
    ID        int64
    Name      string
    Notes     string
    CreatedAt time.Time
    UpdatedAt time.Time
    UpdatedBy *int64
}

// UserWorkout links a user to a workout on a specific date
type UserWorkout struct {
    ID          int64
    UserID      int64
    WorkoutID   int64
    WorkoutDate time.Time
    Notes       string
    CreatedAt   time.Time
    UpdatedAt   time.Time
}

// WorkoutWOD links a workout to a WOD with scoring
type WorkoutWOD struct {
    ID         int64
    WorkoutID  int64
    WODID      int64
    ScoreValue string
    OrderIndex int
    CreatedAt  time.Time
    UpdatedAt  time.Time
}

// WorkoutStrength links a workout to a strength movement with details
type WorkoutStrength struct {
    ID         int64
    WorkoutID  int64
    StrengthID int64
    Weight     *float64
    Sets       *int
    Reps       *int
    Notes      string
    OrderIndex int
    CreatedAt  time.Time
    UpdatedAt  time.Time
}

// UserSetting stores user preferences
type UserSetting struct {
    ID                      int64
    UserID                  int64
    NotificationPreferences string
    DataExportFormat        string
    Theme                   string
    CreatedAt               time.Time
    UpdatedAt               time.Time
}

// AuditLog records significant actions
type AuditLog struct {
    ID        int64
    UserID    *int64
    Action    string
    Details   string
    Timestamp time.Time
}

// Repository Interfaces
type UserRepository interface {
    Create(user *User) error
    GetByID(id int64) (*User, error)
    GetByEmail(email string) (*User, error)
    Update(user *User) error
}

type WODRepository interface {
    Create(wod *WOD) error
    GetByID(id int64) (*WOD, error)
    GetByName(name string) (*WOD, error)
    List(filters map[string]interface{}) ([]*WOD, error)
    Update(wod *WOD) error
}

type StrengthMovementRepository interface {
    Create(movement *StrengthMovement) error
    GetByID(id int64) (*StrengthMovement, error)
    ListByType(movementType string) ([]*StrengthMovement, error)
}

type UserWorkoutRepository interface {
    Create(userWorkout *UserWorkout) error
    GetByUserAndDate(userID int64, date time.Time) ([]*UserWorkout, error)
    GetByDateRange(userID int64, start, end time.Time) ([]*UserWorkout, error)
}

// ... and more repository interfaces
```

### 2. Repository Layer (`internal/repository/`)

**Responsibility**: Implements data access interfaces defined in domain

- Implements repository interfaces from domain layer
- Handles database queries and data mapping
- Isolates persistence logic
- Can be easily swapped (e.g., SQLite to PostgreSQL)

### 3. Service Layer (`internal/service/`)

**Responsibility**: Contains business logic and use cases

- Orchestrates business workflows
- Uses repositories for data access
- Validates business rules
- Transaction management
- Independent of delivery mechanism (HTTP, gRPC, etc.)

### 4. Handler Layer (`internal/handler/`)

**Responsibility**: HTTP request/response handling

- Receives HTTP requests
- Validates input
- Calls service layer
- Formats responses
- Error handling and status codes

### 5. API Layer (`api/`)

**Responsibility**: API contracts and routing

- REST endpoint definitions
- Request/response models (DTOs)
- API versioning
- Route configuration

## Data Flow

```mermaid
sequenceDiagram
    participant Client
    participant Handler
    participant Service
    participant Repository
    participant Database

    Client->>Handler: HTTP Request
    Handler->>Handler: Validate Input
    Handler->>Service: Call Business Logic
    Service->>Service: Apply Business Rules
    Service->>Repository: Data Operation
    Repository->>Database: SQL Query
    Database-->>Repository: Result
    Repository-->>Service: Domain Model
    Service-->>Handler: Result
    Handler->>Handler: Format Response
    Handler-->>Client: HTTP Response
```

## Dependency Rule

Dependencies can only point inward:

```
Handlers → Services → Domain ← Repositories
```

- **Domain** has no dependencies
- **Services** depend only on Domain
- **Repositories** depend only on Domain
- **Handlers** depend on Services and Domain

## Key Design Patterns

### 1. Dependency Injection

All dependencies are injected through constructors:

```go
type UserService struct {
    userRepo domain.UserRepository
}

func NewUserService(repo domain.UserRepository) *UserService {
    return &UserService{userRepo: repo}
}
```

### 2. Repository Pattern

Data access is abstracted through interfaces:

```go
// Domain defines the interface
type UserRepository interface {
    GetByID(id int64) (*User, error)
}

// Repository implements it
type PostgresUserRepository struct { ... }
func (r *PostgresUserRepository) GetByID(id int64) (*User, error) { ... }
```

### 3. Interface Segregation

Small, focused interfaces instead of large ones:

```go
type UserReader interface {
    GetByID(id int64) (*User, error)
}

type UserWriter interface {
    Create(user *User) error
}
```

## Technology Stack

### Backend
- **Language**: Go 1.21+
- **Web Framework**: Standard library `net/http` + gorilla/mux or chi
- **Database**: SQLite (dev), PostgreSQL (prod)
- **ORM/Query Builder**: sqlx or raw SQL
- **Authentication**: JWT with golang-jwt
- **Password Hashing**: bcrypt
- **Observability**: OpenTelemetry
- **Testing**: Go standard testing + testify

### Frontend (PWA)
- **Framework**: Vue.js 3
- **UI Library**: Vuetify 3
- **State Management**: Pinia
- **HTTP Client**: Axios
- **Build Tool**: Vite 6
- **PWA Plugin**: vite-plugin-pwa
- **Service Worker**: Workbox 7
- **Offline Storage**: IndexedDB (native browser API)
- **Testing**: Vitest + Vue Test Utils

### Infrastructure
- **Containerization**: Docker + Docker Compose
- **Database**: MariaDB/PostgreSQL/SQLite
- **Web Server**: Nginx (optional reverse proxy)
- **Migrations**: golang-migrate
- **HTTPS**: Required for PWA (Let's Encrypt)

## PWA Architecture

ActaLog is built as a Progressive Web App, providing native app-like experience with offline capabilities.

### PWA Core Components

```mermaid
graph LR
    subgraph "PWA Components"
        Manifest[Web App Manifest]
        SW[Service Worker]
        Cache[Cache API]
        IDB[IndexedDB]
        Sync[Background Sync]
    end

    subgraph "User Experience"
        Install[Install Prompt]
        Offline[Offline Mode]
        Updates[Auto Updates]
        Fast[Fast Loading]
    end

    Manifest --> Install
    SW --> Offline
    SW --> Updates
    Cache --> Fast
    IDB --> Offline
    Sync --> Offline
```

### 1. Web App Manifest

**Location**: Auto-generated by vite-plugin-pwa

**Configuration** (in `vite.config.js`):
```javascript
manifest: {
  name: 'ActaLog - CrossFit Workout Tracker',
  short_name: 'ActaLog',
  description: 'Track your CrossFit workouts...',
  theme_color: '#2c3657',
  background_color: '#ffffff',
  display: 'standalone',
  icons: [...]
}
```

**Capabilities**:
- Installable to home screen on iOS, Android, and desktop
- Custom splash screen with theme colors
- Standalone display mode (no browser UI)
- Portrait orientation for mobile

### 2. Service Worker (Workbox)

**Auto-generated by vite-plugin-pwa with Workbox strategies**

**Caching Strategies**:

1. **CacheFirst** (Static Assets)
   - Fonts (Google Fonts, Material Design Icons)
   - CSS, JS bundles
   - Images and icons
   - Used for rarely-changing resources

2. **NetworkFirst** (API Data)
   - API responses with 5-minute cache fallback
   - 10-second network timeout
   - Falls back to cache if offline

3. **Precaching**
   - All build assets automatically precached
   - Updated on new deployment

### 3. Offline Storage (IndexedDB)

**Implementation**: `src/utils/offlineStorage.js`

**Object Stores**:
- `workouts` - Cached workout data
- `movements` - Cached movement library
- `pendingSync` - Queue for offline operations

**Workflow**:
```mermaid
sequenceDiagram
    participant User
    participant App
    participant IDB as IndexedDB
    participant Network
    participant API

    User->>App: Log workout (offline)
    App->>IDB: Save to local DB
    App->>IDB: Add to sync queue
    App-->>User: Workout saved locally

    Note over App: Connection restored

    App->>IDB: Get pending sync items
    IDB-->>App: Pending workouts
    App->>API: POST /api/workouts
    API-->>App: 201 Created
    App->>IDB: Remove from sync queue
    App->>IDB: Mark as synced
```

**Key Functions**:
- `saveWorkoutOffline()` - Save workout when offline
- `getWorkoutsOffline()` - Retrieve cached workouts
- `syncWithServer()` - Sync pending operations
- `markWorkoutSynced()` - Update sync status

### 4. Offline-First Strategy

**Data Flow**:
1. **Always try network first** for fresh data
2. **Cache successful responses** for offline access
3. **Use cached data** when offline
4. **Queue write operations** for background sync
5. **Sync automatically** when connection restored

**Network Detection**:
```javascript
// Listen for online/offline events
window.addEventListener('online', syncWithServer)
window.addEventListener('offline', showOfflineNotice)

// Check current status
if (navigator.onLine) {
  // Online - normal operation
} else {
  // Offline - use cache
}
```

### 5. Update Strategy

**Auto-update with user notification**:
- Service worker checks for updates on page load
- New version silently downloaded in background
- User prompted to reload when critical updates available
- Seamless updates without app store delays

**Update Flow**:
```javascript
registerSW({
  onNeedRefresh() {
    // Notify user of update
    if (confirm('New version available. Reload?')) {
      updateSW(true)
    }
  }
})
```

### PWA Checklist

✅ Web App Manifest with complete metadata
✅ Service Worker for offline functionality
✅ HTTPS in production (required for PWA)
✅ Responsive design (mobile-first)
✅ Fast loading with cache strategies
✅ Offline page/graceful degradation
✅ Add to home screen capability
✅ App icons (72px - 512px)
✅ Background sync for offline operations
⏳ Push notifications (future enhancement)

### Performance Optimizations

1. **Code Splitting**: Lazy-load routes and components
2. **Asset Optimization**: Compress images, minify CSS/JS
3. **Precaching**: Critical resources cached on install
4. **Runtime Caching**: API responses cached intelligently
5. **IndexedDB**: Efficient local data storage

### Browser Support

- **Chrome/Edge**: Full support (Desktop & Mobile)
- **Safari**: Full support iOS 11.3+ (with limitations on install prompt)
- **Firefox**: Full support (Desktop & Android)
- **Samsung Internet**: Full support
- **Opera**: Full support

**Graceful Degradation**:
- Works as regular web app in older browsers
- Progressive enhancement for modern browsers
- No broken functionality in non-PWA browsers

## Audit Logging Architecture

### Comprehensive Audit Trail System

ActaLog implements a complete audit logging system that tracks all data modifications across the application. This provides accountability, compliance support, and troubleshooting capabilities.

### Audit Logging Design Patterns

**1. Service Layer Integration**
- Audit logging is implemented at the service layer, not in repositories or handlers
- Every service that modifies data accepts an `auditLogRepo` in its constructor
- Services inject user context (userID, userEmail) into audit logs

**2. Conditional Logging**
```go
if s.auditLogRepo != nil {
    details, _ := json.Marshal(map[string]interface{}{
        "entity_id":   entity.ID,
        "entity_name": entity.Name,
        "created_by":  userEmail,
    })
    detailsStr := string(details)
    _ = s.auditLogRepo.Create(&domain.AuditLog{
        UserID:       &userID,
        TargetUserID: &targetUserID,
        EventType:    domain.EventEntityCreated,
        Details:      &detailsStr,
        CreatedAt:    time.Now(),
    })
}
```

**3. Fire-and-Forget Pattern**
- Audit log failures never block primary operations
- Audit logging uses fire-and-forget (errors ignored with `_`)
- Primary business operations succeed even if audit logging fails

**4. Change Tracking for Updates**
```go
// Store old values before update
oldName := entity.Name
oldValue := entity.Value

// Perform update
entity.Name = newName
entity.Value = newValue

// Log with before/after comparison
details, _ := json.Marshal(map[string]interface{}{
    "entity_id": entity.ID,
    "changes": map[string]interface{}{
        "name_old":  oldName,
        "name_new":  entity.Name,
        "value_old": oldValue,
        "value_new": entity.Value,
    },
})
```

**5. User Attribution**
- `UserID`: The user who performed the action
- `TargetUserID`: The user who was affected by the action (for user management operations)
- `userEmail`: Stored in details JSON for human-readable logs

**6. Admin Operation Tracking**
```go
details, _ := json.Marshal(map[string]interface{}{
    "entity_id":    entity.ID,
    "admin_update": true,  // Flag for admin operations
    "updated_by":   adminEmail,
})
```

### Logged Operations by Entity

**Movements**
- `movement_created` - New movement creation (custom and standard)
- `movement_updated` - Movement attribute updates
- `movement_deleted` - Movement deletion

**WODs**
- `wod_created` - New WOD creation
- `wod_updated` - WOD attribute updates
- `wod_deleted` - WOD deletion

**Workout Templates**
- `workout_template_created` - New template creation with movements/WODs
- `workout_template_updated` - Template modifications
- `workout_template_deleted` - Template deletion

**User Workouts**
- `user_workout_logged` - User logs a workout
- `user_workout_updated` - User edits a logged workout
- `user_workout_deleted` - User deletes a workout

**User Management**
- `profile_updated` - User profile changes (name, email, birthday)
- `user_settings_updated` - Settings changes (theme, units, preferences)
- `user_created` - User registration
- `user_disabled` - User account disabled
- `user_enabled` - User account enabled
- `user_role_changed` - Role changes (user ↔ admin)
- `user_deleted` - User account deletion

**Organizations** (v0.14.0)
- `organization_created` - Organization creation
- `organization_updated` - Organization updates
- `organization_deleted` - Organization deletion
- `user_organization_added` - User added to organization
- `user_organization_removed` - User removed from organization

**Subscriptions** (v0.14.0)
- `subscription_created` - Subscription creation
- `subscription_cancelled` - Subscription cancellation
- `subscription_marked_paid` - Payment recorded
- `subscription_marked_unpaid` - Payment reversed

### Audit Log Data Structure

```go
type AuditLog struct {
    ID           int64      `json:"id"`
    UserID       *int64     `json:"user_id"`        // Who performed action
    TargetUserID *int64     `json:"target_user_id"` // Who was affected
    EventType    string     `json:"event_type"`     // Event constant
    Details      *string    `json:"details"`        // JSON-encoded context
    CreatedAt    time.Time  `json:"created_at"`     // Timestamp
}
```

**Details JSON Schema** (varies by event type):
```json
{
    "entity_id": 123,
    "entity_name": "Back Squat",
    "entity_type": "movement",
    "created_by": "user@example.com",
    "admin_update": false,
    "changes": {
        "name_old": "Back Squat",
        "name_new": "Barbell Back Squat",
        "type_old": "weightlifting",
        "type_new": "weightlifting"
    }
}
```

### Admin Audit Log UI

**Admin Data Change Logs View** (`/admin/data-change-logs`)
- Filterable by entity type, operation, user email
- Paginated table showing all audit events
- Detailed dialog showing full before/after JSON
- Changed fields diff table for updates
- Color-coded operations and entity types

**Use Cases:**
- Compliance and accountability tracking
- Troubleshooting data issues
- User action history review
- Security incident investigation
- Admin operation auditing

### Performance Considerations

1. **Asynchronous Logging**: Audit logs written synchronously but don't block operations
2. **No Transactions**: Audit logs in separate operations (may fail independently)
3. **Indexing**: `audit_logs` table indexed on `event_type`, `user_id`, `target_user_id`, `created_at`
4. **Cleanup**: Admin API endpoint for deleting old audit logs (retention policy)

### Security Considerations

- Audit logs are immutable once created (no update/delete from application)
- Only admins can view audit logs via API
- Sensitive data (passwords) never logged
- IP addresses optional (privacy consideration)
- GDPR compliance: Audit logs included in user data exports

### Implementation Checklist

✅ Domain layer: Event type constants defined
✅ Repository layer: AuditLogRepository implemented for all databases
✅ Service layer: All CRUD services inject and use auditLogRepo
✅ Handler layer: All handlers extract userEmail from JWT context
✅ Initialization: All services initialized with auditLogRepo in main.go
✅ Admin UI: Complete audit log viewing and filtering interface
✅ Testing: All services tested with and without audit logging enabled

---

## Backup and Restore Architecture

### Overview

ActaLog provides a comprehensive backup and restore system that supports multiple restore modes for flexible data management. The system uses a JSON-based backup format with schema metadata for cross-database compatibility.

### Backup Format

Backups are stored as ZIP files containing:
- `metadata.json` - Backup metadata (version, timestamp, database info, record counts)
- `schema_metadata.json` - Database schema information for type-aware restoration
- `{table_name}.json` - JSON export of each table's data

### Restore Modes

The restore system supports three modes for handling existing data:

```mermaid
graph TB
    subgraph "Restore Modes"
        Replace[Replace Mode<br>DELETE all → INSERT all]
        Merge[Merge Mode<br>UPDATE existing → INSERT new]
        Skip[Skip Mode<br>INSERT only non-existing]
    end

    subgraph "Natural Key Matching"
        Users[Users: email]
        Movements[Movements: name]
        WODs[WODs: name]
        Orgs[Organizations: name]
        Workouts[User Workouts: user_id + date + name]
    end

    Merge --> Users
    Merge --> Movements
    Merge --> WODs
    Merge --> Orgs
    Merge --> Workouts
    Skip --> Users
    Skip --> Movements
    Skip --> WODs
    Skip --> Orgs
    Skip --> Workouts
```

**1. Replace Mode** (Default)
- Deletes all existing data in each table
- Inserts all records from backup
- Fastest but destructive
- Use for clean restores to fresh database

**2. Merge Mode**
- Matches records by natural key (not ID)
- Updates existing records with backup data
- Inserts new records that don't exist
- Preserves records not in backup
- ID remapping for foreign key integrity

**3. Skip Mode**
- Matches records by natural key
- Skips records that already exist
- Only inserts new records
- Safest for incremental imports
- ID remapping for foreign key integrity

### Natural Key Matching Strategy

Records are matched by business keys rather than database IDs:

| Table | Natural Key | Match Strategy |
|-------|-------------|----------------|
| users | email | Exact match |
| movements | name | Exact match |
| wods | name | Exact match |
| organizations | name | Exact match |
| user_workouts | user_id + workout_date + workout_name | Composite match |
| workout_movements | workout_id + movement_id + order_index | Composite (after remap) |
| workout_wods | workout_id + wod_id + order_index | Composite (after remap) |
| user_settings | user_id | After user remap |
| notifications | - | Additive only (skip) |
| audit_logs | - | Additive only (skip) |

### ID Remapping

When using merge or skip mode, IDs may differ between backup and target database. The system maintains ID mappings:

```go
type idMappings struct {
    users         map[int64]int64  // backup_id -> target_id
    movements     map[int64]int64
    wods          map[int64]int64
    organizations map[int64]int64
    workouts      map[int64]int64
    userWorkouts  map[int64]int64
}
```

**Remapping Flow:**
1. Restore parent tables first (users, movements, wods, organizations)
2. Build ID mapping for each matched/inserted record
3. Restore child tables using remapped foreign keys
4. Update FK references before insert/update

### Restore Result

The API returns detailed statistics:

```json
{
  "mode": "merge",
  "tables_restored": 21,
  "records_created": 16,
  "records_updated": 50,
  "records_skipped": 0,
  "errors": []
}
```

### API Usage

```bash
# Replace mode (default)
curl -X POST /api/admin/backups/{filename}/restore \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"confirm": true}'

# Merge mode
curl -X POST /api/admin/backups/{filename}/restore \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"confirm": true, "mode": "merge"}'

# Skip mode
curl -X POST /api/admin/backups/{filename}/restore \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"confirm": true, "mode": "skip"}'
```

### Import Duplicate Handling

All import services support duplicate detection and handling:

| Import Type | Skip Duplicates | Update Duplicates | Detection Key |
|-------------|-----------------|-------------------|---------------|
| WOD Import | ✅ | ✅ | name |
| Movement Import | ✅ | ✅ | name |
| User Workout Import | ✅ | ✅ | user_id + date + name |
| Wodify Import | ✅ | ✅ | workout date |

**Import Options:**
```bash
# Skip duplicates (keep existing)
curl -X POST /api/import/wods/confirm \
  -F "file=@wods.csv" \
  -F "skip_duplicates=true"

# Update duplicates (overwrite existing)
curl -X POST /api/import/wods/confirm \
  -F "file=@wods.csv" \
  -F "update_duplicates=true"
```

### Security Considerations

- Only admin users can create, restore, or delete backups
- Backup files stored in configurable directory (default: `./backups`)
- Security-sensitive tables (refresh_tokens, password_resets) are skipped during merge/skip
- Audit logs are append-only (never overwritten)
- All restore operations are logged to audit trail

### Implementation Files

- `internal/domain/backup.go` - RestoreMode type, RestoreResult struct, BackupService interface
- `internal/service/backup_service.go` - Full backup/restore implementation with merge/skip logic
- `internal/handler/backup_handler.go` - REST API endpoints
- `internal/service/import_service.go` - Import duplicate handling
- `internal/service/wodify_import_service.go` - Wodify-specific import logic

---

## Security Architecture

### Authentication Flow

```mermaid
sequenceDiagram
    participant Client
    participant API
    participant AuthService
    participant UserRepo
    participant DB

    Client->>API: POST /api/auth/login
    API->>AuthService: Authenticate(email, password)
    AuthService->>UserRepo: GetByEmail(email)
    UserRepo->>DB: SELECT user
    DB-->>UserRepo: User data
    UserRepo-->>AuthService: User
    AuthService->>AuthService: Verify password (bcrypt)
    AuthService->>AuthService: Generate JWT
    AuthService-->>API: JWT token
    API-->>Client: {token, user}

    Note over Client,API: Subsequent requests
    Client->>API: GET /api/workouts (Authorization: Bearer token)
    API->>API: Validate JWT
    API->>API: Extract user ID
    API->>WorkoutService: GetUserWorkouts(userID)
```

### Security Measures

1. **Password Security**: Bcrypt with cost factor 12+
2. **SQL Injection Prevention**: Parameterized queries only
3. **XSS Prevention**: Input sanitization and output encoding
4. **CSRF Protection**: CSRF tokens for state-changing operations
5. **Rate Limiting**: Token bucket algorithm
6. **TLS/SSL**: Required in production
7. **CORS**: Configurable allowed origins
8. **Input Validation**: Strict validation at all entry points

## Defense-in-Depth Pattern

The protected-user system (v1.3.0) introduced a four-layer defense pattern that's worth using as a reference for future security-critical features:

- **L1 — HTTP middleware:** Request-level rejection. Catches every HTTP-level write attempt.
- **L2 — Service-layer guard:** Catches in-process callers (cron, jobs, internal APIs) that bypass the HTTP path.
- **L3 — Database trigger:** Catches direct DB access (raw SQL, connection-pool bypass, rogue migrations).
- **L4 — Audit logging:** Tagged at the rejecting layer (not the layer traversed). Single event per attempt.

Plus a **boot-time invariant** that fails closed if any layer is broken.

Each layer is independently sufficient. See `docs/security/PROTECTED_USERS.md` for the complete reference implementation; see `docs/security/THREAT_MODEL.md` for the broader threat coverage map.

## Observability

### Three Pillars

1. **Logs**: Structured JSON logging with correlation IDs
2. **Metrics**: Request latency, throughput, error rates
3. **Traces**: Distributed tracing with OpenTelemetry

### Key Metrics

- Request duration (p50, p95, p99)
- Request rate (requests/second)
- Error rate (errors/second)
- Database query duration
- Active connections
- Memory usage

## Testing Strategy

### Test Pyramid

```
       /\
      /  \  E2E Tests (Few)
     /____\
    /      \ Integration Tests (Some)
   /________\
  /          \ Unit Tests (Many)
 /____________\
```

### Test Types

1. **Unit Tests** (`test/unit/`): Test individual functions/methods
2. **Integration Tests** (`test/integration/`): Test component interactions
3. **E2E Tests**: Test complete user workflows

### Test Practices

- Table-driven tests for multiple scenarios
- Mocking external dependencies
- Test coverage > 80%
- Parallel test execution where safe
- Test isolation (no shared state)

## Deployment Architecture

### Production Deployment (Docker)

ActaLog uses a **single-port architecture** for production deployments:

```mermaid
graph TB
    subgraph "Client Layer"
        Browser[Web Browser]
        Mobile[Mobile Browser]
        PWA[Installed PWA]
    end

    subgraph "Docker Container (Port 8080)"
        GoApp[Go Application]
        StaticFiles[Static Files<br>/app/web/dist]

        subgraph "Routes"
            APIRoutes[/api/* - API Endpoints]
            Uploads[/uploads/* - User Files]
            Frontend[/* - Frontend SPA]
        end
    end

    subgraph "Data Layer"
        DB[(Database<br>SQLite/PostgreSQL/MariaDB)]
        UploadsVol[Uploads Volume]
        DataVol[Data Volume]
    end

    Browser --> GoApp
    Mobile --> GoApp
    PWA --> GoApp

    GoApp --> APIRoutes
    GoApp --> Uploads
    GoApp --> Frontend

    Frontend --> StaticFiles
    APIRoutes --> DB
    Uploads --> UploadsVol
    DB -.-> DataVol
```

**Key Design Points:**

1. **Single Port (8080)**: All traffic (frontend + backend) served from one port
2. **Static File Serving**: Go serves pre-built frontend static files from `/app/web/dist`
3. **Route Priority**: API routes match first, then uploads, then frontend catch-all
4. **SPA Routing**: Non-existent paths serve `index.html` for Vue Router
5. **No Node.js in Production**: Frontend built during Docker image creation
6. **Volume Management**:
   - `/app/data` - Database files (SQLite) or config
   - `/app/uploads` - User-uploaded files (avatars, etc.)

**Implementation:** See `cmd/actalog/main.go:418-436` for static file serving logic.

### Multi-Instance Production (Scalable)

For high-availability deployments:

```mermaid
graph LR
    subgraph "Production Environment"
        LB[Load Balancer/Nginx]
        App1[ActaLog Container 1<br>Port 8080]
        App2[ActaLog Container 2<br>Port 8080]
        DB[(PostgreSQL<br>Shared Database)]
        Uploads[Shared Uploads<br>NFS/S3]
        Cache[(Redis<br>Future)]
    end

    Client[Clients] --> LB
    LB --> App1
    LB --> App2
    App1 --> DB
    App2 --> DB
    App1 --> Uploads
    App2 --> Uploads
    App1 -.-> Cache
    App2 -.-> Cache
```

**Scaling Considerations:**
- Use PostgreSQL or MariaDB (not SQLite) for shared database
- Mount shared uploads volume or use object storage (S3)
- Load balancer handles TLS termination
- Each container independently serves frontend + API

## Performance Considerations

1. **Database Indexing**: Proper indexes on frequently queried columns
2. **Connection Pooling**: Reuse database connections
3. **Caching Strategy**:
   - Service Worker cache for static assets
   - IndexedDB for offline data
   - Redis for session data (future)
4. **Pagination**: Limit result sets with offset/limit
5. **Lazy Loading**: Load related data on demand
6. **Compression**: gzip compression for API responses
7. **PWA Precaching**: Critical resources cached on app install
8. **Code Splitting**: Lazy-load routes and components

## Future Enhancements

1. **Push Notifications**: Web Push API for workout reminders and achievements
2. **gRPC API**: For enhanced performance on mobile devices
3. **GraphQL**: Flexible querying for complex data requirements
4. **Event Sourcing**: Audit trail and temporal queries
5. **Microservices**: Split into smaller services as needed
6. **Real-time Updates**: WebSockets for live workout tracking
7. **Advanced PWA Features**:
   - Periodic background sync for data refresh
   - Web Share API for workout sharing
   - File System Access API for bulk data operations
   - Badging API for unsynced workout notifications

## Version History

- **v0.3.0**: Planned database schema redesign (documented but not yet implemented)
- **v0.2.0-beta**: Multi-database support, workout logging backend (current version)
- **v0.1.0**: Initial schema and architecture implementation (current schema)

## Notes on Planned v0.3.0 Schema

**Status:** Documented design, not yet implemented in codebase.

The database schema redesign is documented to better represent the logical data model:

**Key Architectural Changes:**
1. **Workouts as Templates**: Workouts are now reusable templates rather than user-specific instances
2. **WOD Entity**: New first-class entity for CrossFit WODs with comprehensive metadata
3. **Junction Tables**: Proper many-to-many relationships via junction tables (user_workouts, workout_wods, workout_strength)
4. **Audit Trail**: Built-in audit logging for accountability and troubleshooting
5. **User Settings**: Separate table for user preferences

**Impact on Application Layers:**
- **Domain Layer**: New entities (WOD, StrengthMovement, UserWorkout, etc.) require new repository interfaces
- **Service Layer**: Business logic must handle template-based workouts and user instances separately
- **API Layer**: Endpoints need refactoring to support new workflow (create template → log user workout)
- **Frontend**: UI must distinguish between workout templates and user workout logs

**Migration Strategy (When Implemented):**
- Database migrations will transform existing data from v0.1.0 schema to v0.3.0
- Existing user workouts will be converted to the new template + user_workout structure
- Standard WODs and movements will be seeded during migration