# Solution Design Document

## Validation Checklist

- [x] All required sections are complete
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] All context sources are listed with relevance ratings
- [x] Project commands are discovered from actual project files
- [x] Constraints → Strategy → Design → Implementation path is logical
- [x] Architecture pattern is clearly stated with rationale
- [x] Every component in diagram has directory mapping
- [x] Every interface has specification
- [x] Error handling covers all error types
- [x] Quality requirements are specific and measurable
- [x] Every quality requirement has test coverage
- [x] **All architecture decisions confirmed by user** (ADR-1, ADR-2, ADR-3 explicitly confirmed)
- [x] Component names consistent across diagrams
- [x] A developer could implement from this design

---

## Constraints

**CON-1 Technical Platform**
- PHP 8.x with Slim 2.6.2 framework and Twig 1.44.8 templating
- MySQL databases with multi-store architecture (central `kiosk_buykiosk` + per-store `kiosk_{typeNum}`)
- Redis for caching and session management
- Ably for real-time WebSocket communication
- Browser support: Chrome, Safari, Firefox (latest two versions)
- Mobile-responsive admin dashboard (tablet-friendly for on-floor access)

**CON-2 Coding Standards & Deployment**
- PSR-4 autoloading for all new classes under `BuyerKiosk\` namespace
- Follow existing controller/service/model patterns in codebase
- Database migrations via JSON migration files in `userfrosting/migrations/input/`
- No external dependencies beyond existing (Twilio/Vonage, Ably, Redis, OpenAI)
- Deployment via existing `./deploy.sh` pipeline

**CON-3 Security & Permissions**
- UserFrosting permission model integration with new permissions:
  - `uri_events` - View event dashboard and details
  - `uri_events_manage` - Create, edit, delete events
  - `uri_events_templates` - Create and edit store-specific templates
  - `uri_events_templates_global` - Create and edit global templates (corporate only)
  - `uri_events_reports` - View event performance reports
- Store isolation: Users can only access events for stores in their `checkStoreGroup()`
- All event changes logged with timestamp and user for audit trail

**CON-4 Integration Constraints**
- Must not break existing backstock, SMS, signage, Comeback Cash, task, or notes functionality
- Tight coupling: Event deletion cascades to all linked integrations
- Slide tagging system (Phase 0) must be completed before event management features can use tag-based slide selection

## Implementation Context

**IMPORTANT**: You MUST read and analyze ALL listed context sources to understand constraints, patterns, and existing architecture.

### Required Context Sources

- ICO-1 Internal Documentation
```yaml
# PRD for this feature
- doc: docs/specs/004-unified-event-management/product-requirements.md
  relevance: CRITICAL
  why: "Source of all business requirements and acceptance criteria"

# Existing patterns documentation
- doc: docs/patterns/psr4-autoloading.md
  relevance: HIGH
  why: "All new classes must follow PSR-4 autoloading conventions"

- doc: docs/patterns/namespace-structure.md
  relevance: HIGH
  why: "Namespace hierarchy reference for new classes"

# System documentation
- doc: docs/systems/authentication-flow.md
  relevance: MEDIUM
  why: "Permission and session handling patterns"

- doc: docs/features/workspace-queue.md
  relevance: MEDIUM
  why: "Workspace UI patterns and integration points"
```

- ICO-2 Backstock Events System (Integration Pattern Reference)
```yaml
- file: userfrosting/src/BuyerKiosk/Backstock/Event.php
  relevance: HIGH
  why: "Core event entity pattern - phase lifecycle model to follow"

- file: userfrosting/src/BuyerKiosk/Backstock/EventService.php
  relevance: HIGH
  why: "Event service orchestration pattern"

- file: userfrosting/src/BuyerKiosk/Backstock/Controllers/EventController.php
  relevance: MEDIUM
  why: "API endpoint patterns for events"

- file: userfrosting/routes/groups/backstock.php
  relevance: MEDIUM
  sections: [lines 663-795 for event routes]
  why: "Route definition patterns"
```

- ICO-3 SMS Marketing System
```yaml
- file: userfrosting/src/BuyerKiosk/SellerMarketing/SmsQueue.php
  relevance: HIGH
  why: "Central queue pattern for SMS integration"

- file: userfrosting/src/BuyerKiosk/SellerMarketing/SellerMarketingTriggerProcessor.php
  relevance: HIGH
  why: "Trigger processing and customer matching patterns"

- file: userfrosting/src/BuyerKiosk/SellerMarketing/Controllers/SellerMarketingController.php
  relevance: MEDIUM
  why: "SMS API endpoint patterns"
```

- ICO-4 Digital Signage System
```yaml
- file: userfrosting/src/BuyerKiosk/DigitalSign/LoopItem.php
  relevance: HIGH
  why: "Slide scheduling with startDate/expireDate pattern"

- file: userfrosting/src/BuyerKiosk/DigitalSign/Controllers/SlideScheduleController.php
  relevance: HIGH
  why: "Cron-based activation/deactivation pattern"

- file: userfrosting/src/BuyerKiosk/DigitalSign/Constants.php
  relevance: MEDIUM
  why: "Slide type constants and defaults"
```

- ICO-5 Comeback Cash System
```yaml
- file: userfrosting/src/BuyerKiosk/ComebackCash/Models/Event.php
  relevance: HIGH
  why: "Earning/redemption window pattern"

- file: userfrosting/src/BuyerKiosk/ComebackCash/Services/EventService.php
  relevance: HIGH
  why: "Event lifecycle management with conflict resolution"

- file: userfrosting/src/BuyerKiosk/ComebackCash/Services/ComebackCashAbly.php
  relevance: MEDIUM
  why: "Ably real-time broadcast pattern"
```

- ICO-6 Task System
```yaml
- file: userfrosting/src/BuyerKiosk/Core/Task.php
  relevance: HIGH
  why: "Task entity with scheduling and recurrence"

- file: userfrosting/src/BuyerKiosk/Workbook/TaskCompletion.php
  relevance: MEDIUM
  why: "Completion tracking pattern"

- file: userfrosting/src/BuyerKiosk/Workbook/Controllers/TasksApiController.php
  relevance: MEDIUM
  why: "Task API patterns"
```

- ICO-7 Notes System
```yaml
- file: userfrosting/src/BuyerKiosk/Workbook/Note.php
  relevance: HIGH
  why: "Note entity with date-based visibility"

- file: userfrosting/src/BuyerKiosk/Workbook/NoteManager.php
  relevance: MEDIUM
  why: "Note management service pattern"
```

### Implementation Boundaries

- **Must Preserve**:
  - All existing backstock event functionality (`bsEvents` tables and classes)
  - All existing SMS marketing trigger and blast functionality
  - All existing digital signage slide management and scheduling
  - All existing Comeback Cash event and coupon functionality
  - All existing task and notes functionality
  - Existing API endpoints - no breaking changes to existing consumers
  - Store database isolation patterns

- **Can Modify**:
  - Add `eventId` foreign key columns to: `tasks`, `workbook_notes`
  - Add new tag tables for digital signage slides
  - Add new junction tables for event-to-integration linking
  - Extend existing controllers with new event-related endpoints
  - Add new routes for event management

- **Must Not Touch**:
  - POS API endpoints (used by external systems)
  - Core buy/sell transaction processing
  - Customer and employee tables (except adding event-related foreign keys to related tables)
  - Loyalty points system
  - QuickBooks/Shopify integrations

### External Interfaces

#### System Context Diagram

```mermaid
graph TB
    subgraph Users
        SM[Store Manager]
        DM[District Manager]
        SA[Store Associate]
    end

    subgraph "Event Management System"
        EH[Event Hub]
        ED[Event Dashboard]
        ET[Event Templates]
    end

    subgraph "Integrated Systems"
        BS[Backstock Events]
        SMS[SMS Marketing]
        DS[Digital Signage]
        CC[Comeback Cash]
        TK[Tasks]
        NT[Notes]
    end

    subgraph "External Services"
        ABLY[Ably Real-time]
        TWILIO[Twilio/Vonage SMS]
    end

    subgraph "Data Stores"
        CENTRAL[(Central DB<br/>kiosk_buykiosk)]
        STORE[(Store DB<br/>kiosk_{typeNum})]
        REDIS[(Redis Cache)]
    end

    SM --> ED
    DM --> ED
    SA --> TK
    SA --> NT

    ED --> EH
    EH --> BS
    EH --> SMS
    EH --> DS
    EH --> CC
    EH --> TK
    EH --> NT

    EH --> STORE
    ET --> CENTRAL
    SMS --> TWILIO
    EH --> ABLY
    DS --> ABLY
    EH --> REDIS
```

#### Interface Specifications

```yaml
# Inbound Interfaces (what calls this system)
inbound:
  - name: "Admin Web Interface"
    type: HTTPS
    format: REST JSON
    authentication: Session (UserFrosting)
    data_flow: "Event CRUD, integration configuration, dashboard views"
    permissions: uri_events, uri_events_manage

  - name: "Workbook Web Interface"
    type: HTTPS
    format: REST JSON
    authentication: Session (UserFrosting)
    data_flow: "Staff task views, event notes, task completion"
    permissions: task-lists access

# Outbound Interfaces (what this system calls)
outbound:
  - name: "Ably Real-time"
    type: WebSocket
    format: JSON
    authentication: API Key ($_ENV['ABLY_KEY'])
    data_flow: "Event updates broadcast to connected clients"
    criticality: HIGH

  - name: "SMS Queue (Twilio/Vonage)"
    type: Internal Queue
    format: seller_marketing_queue table
    authentication: N/A (internal)
    data_flow: "Scheduled SMS messages for event campaigns"
    criticality: MEDIUM

# Data Interfaces
data:
  - name: "Central Database (kiosk_buykiosk)"
    type: MySQL
    connection: PDO via dbConnectByName()
    data_flow: "Event templates, global slide library, corporate configuration"
    tables: eventTemplates, eventTemplate_Integrations, corpSlides, corpSlide_Tags

  - name: "Store Database (kiosk_{typeNum})"
    type: MySQL
    connection: PDO via dbConnectByName($store->getDbName())
    data_flow: "Store events, integrations, tasks, notes, slides"
    tables: events, event_integrations, dsSlides, dsSlide_Tags, tasks, workbook_notes

  - name: "Redis Cache"
    type: Redis
    connection: Redis client
    data_flow: "Event dashboard caching, session data"
```

### Cross-Component Boundaries (if applicable)

- **API Contracts**:
  - Existing POS APIs (Comeback Cash, mobile) must not change
  - Internal workspace APIs can be extended but not broken
  - Ably channel message formats must be backward compatible

- **Shared Resources**:
  - Central database: Event templates shared across all stores
  - Redis: Shared cache namespace with store-prefixed keys
  - SMS queue: Central `seller_marketing_queue` shared by all stores
  - Ably channels: Per-store channels (`{typeNum}`) for real-time updates

- **Breaking Change Policy**:
  - New columns with defaults - backward compatible
  - New tables - no impact on existing systems
  - Foreign key additions with SET NULL on delete - safe cascade
  - API changes: Add new endpoints, don't modify existing response structures

### Project Commands

```bash
# Component: BuyerKiosk Web Application
Location: /Users/rvanvuren/Projects/buyerkiosk-web

## Environment Setup
Install Dependencies: cd userfrosting && composer install
Environment Variables: Copy .env.example to .env and configure
Start Development: Apache/nginx + PHP-FPM (existing server setup)

# Testing Commands
Unit Tests: ./test.sh
Full Deploy (includes tests): ./deploy.sh

# Database Operations
Database Migrations: php userfrosting/migrations/migrate.php
Migration Input Files: userfrosting/migrations/input/*.json

# Cron Jobs (relevant to events)
SMS Processing: php tasker/process-sms-triggers.php --all-stores
Slide Scheduling: php tasker/process-slide-schedule.php
Event Phase Updates: php tasker/process-event-phases.php (NEW)

# Development Server
Local URL: https://dev2.buyerkiosk.com (existing)
Debug: Chrome DevTools MCP connection available
```

## Solution Strategy

### Architecture Pattern: Central Event Hub with Adapter-Based Integration

The Unified Event Management system uses a **hub-and-spoke architecture** where a central Event Hub orchestrates connections to existing systems through dedicated integration adapters.

```
                    ┌─────────────────────┐
                    │    Event Hub        │
                    │  (Central Entity)   │
                    └─────────┬───────────┘
                              │
        ┌─────────┬───────────┼───────────┬─────────┬─────────┐
        ▼         ▼           ▼           ▼         ▼         ▼
   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
   │Backstock│ │   SMS   │ │ Signage │ │Comeback │ │  Tasks  │ │  Notes  │
   │ Adapter │ │ Adapter │ │ Adapter │ │  Cash   │ │ Adapter │ │ Adapter │
   └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘
        │          │          │          │          │          │
        ▼          ▼          ▼          ▼          ▼          ▼
   [bsEvents] [SMS Queue] [dsLoop]   [ccEvents]  [tasks]  [notes]
```

### Integration Approach

Each existing system connects to the Event Hub through a dedicated **Integration Adapter** that:
1. **Translates** event dates to system-specific configurations
2. **Creates** linked records in the target system
3. **Cascades** changes when the event is modified or deleted
4. **Reports** status back to the Event Dashboard

### Justification

This approach was selected because:
1. **Preserves existing systems**: Each integrated system continues to function independently
2. **Loose-to-tight coupling**: Adapters isolate complexity while maintaining tight cascade behavior
3. **Incremental delivery**: Each integration can be built and tested independently
4. **Template reusability**: Templates store adapter configurations that auto-populate on event creation
5. **Follows existing patterns**: Mirrors how Backstock already works with categories and progress tracking

### Key Technical Decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| **Event Storage** | New `events` table (separate from bsEvents) | Clean separation; bsEvents can be linked via adapter |
| **Phase Lifecycle** | 5-phase model (upcoming → build_up → active → wind_down → completed) | Matches existing bsEvents pattern; proven effective |
| **Date Handling** | Store dates in UTC, display in store timezone | Consistent with existing systems |
| **Integration Linking** | Junction table `event_integrations` | Flexible N:M relationship with cascade delete |
| **Template Storage** | Central DB for global templates, store DB for store templates | Supports corporate + franchise + store hierarchy |
| **Cascade Behavior** | Tight coupling - event deletion removes all integrations | User-confirmed simplicity over flexibility |
| **Tag System** | New `dsSlide_Tags` table with many-to-many relationship | Required for tag-based slide selection in events |

## Building Block View

### Components

```mermaid
graph TB
    subgraph "Presentation Layer"
        UI[Event Dashboard UI]
        WUI[Workbook UI]
        API[REST API Controllers]
    end

    subgraph "Business Logic Layer"
        ES[EventService]
        TS[TemplateService]
        IS[IntegrationService]

        subgraph "Integration Adapters"
            BA[BackstockAdapter]
            SA[SmsAdapter]
            DA[SignageAdapter]
            CA[ComebackCashAdapter]
            TA[TaskAdapter]
            NA[NoteAdapter]
        end
    end

    subgraph "Domain Layer"
        E[Event Entity]
        T[Template Entity]
        I[Integration Entity]
        TAG[SlideTag Entity]
    end

    subgraph "Data Layer"
        ER[EventRepository]
        TR[TemplateRepository]
        IR[IntegrationRepository]

        subgraph "Existing Repositories"
            BSR[BackstockEventRepo]
            SMSR[SmsQueueRepo]
            DSR[SignageRepo]
            CCR[ComebackCashRepo]
            TKR[TaskRepo]
            NTR[NoteRepo]
        end
    end

    UI --> API
    WUI --> API
    API --> ES
    API --> TS
    ES --> IS
    IS --> BA
    IS --> SA
    IS --> DA
    IS --> CA
    IS --> TA
    IS --> NA

    ES --> E
    TS --> T
    IS --> I

    ES --> ER
    TS --> TR
    IS --> IR

    BA --> BSR
    SA --> SMSR
    DA --> DSR
    CA --> CCR
    TA --> TKR
    NA --> NTR
```

### Directory Map

**Component**: Event Management Core
```
userfrosting/src/BuyerKiosk/
├── EventManagement/                          # NEW: Event management module
│   ├── Models/
│   │   ├── Event.php                         # NEW: Central event entity
│   │   ├── EventTemplate.php                 # NEW: Template entity
│   │   └── EventIntegration.php              # NEW: Integration link entity
│   ├── Services/
│   │   ├── EventService.php                  # NEW: Event lifecycle management
│   │   ├── TemplateService.php               # NEW: Template CRUD and application
│   │   ├── IntegrationService.php            # NEW: Integration orchestration
│   │   └── EventPhaseProcessor.php           # NEW: Cron-based phase updates
│   ├── Adapters/
│   │   ├── IntegrationAdapterInterface.php   # NEW: Adapter contract
│   │   ├── BackstockAdapter.php              # NEW: Links to bsEvents
│   │   ├── SmsAdapter.php                    # NEW: Creates SMS blasts/triggers
│   │   ├── SignageAdapter.php                # NEW: Schedules slides
│   │   ├── ComebackCashAdapter.php           # NEW: Creates ccEvents
│   │   ├── TaskAdapter.php                   # NEW: Creates event tasks
│   │   └── NoteAdapter.php                   # NEW: Creates event notes
│   ├── Controllers/
│   │   ├── EventApiController.php            # NEW: REST API for events (admin)
│   │   ├── EventMobileApiController.php      # NEW: Mobile API for events
│   │   ├── EventPageController.php           # NEW: Admin page rendering
│   │   ├── TemplateApiController.php         # NEW: Template management API
│   │   └── EventReportController.php         # NEW: Reporting endpoints
│   └── EventManagementFactory.php            # NEW: Service factory/DI
```

**Component**: Slide Tagging (Phase 0 Prerequisite)
```
userfrosting/src/BuyerKiosk/
├── DigitalSign/
│   ├── Models/
│   │   └── SlideTag.php                      # NEW: Tag entity
│   ├── Services/
│   │   └── SlideTagService.php               # NEW: Tag management
│   └── Controllers/
│       └── SlideController.php               # MODIFY: Add tag endpoints
```

**Component**: Routes
```
userfrosting/routes/
├── event-management/
│   ├── api.php                               # NEW: Event REST API routes (admin)
│   ├── mobile-api.php                        # NEW: Event Mobile API routes
│   └── pages.php                             # NEW: Admin page routes
├── groups/
│   └── digitalsign.php                       # MODIFY: Add tag endpoints
```

**Component**: Templates
```
userfrosting/templates/themes/default/
├── admin/
│   └── event-management/
│       ├── dashboard.html                    # NEW: Event dashboard
│       ├── event-form.html                   # NEW: Create/edit event
│       ├── event-detail.html                 # NEW: Event detail view
│       ├── timeline.html                     # NEW: Event timeline view
│       └── templates.html                    # NEW: Template management
├── workspace/partials/
│   └── event-indicator.html                  # NEW: Staff event awareness
```

**Component**: Frontend JavaScript
```
public_html/js/
├── admin/
│   └── event-management/
│       ├── event-dashboard.js                # NEW: Dashboard interactions
│       ├── event-form.js                     # NEW: Form handling
│       ├── event-timeline.js                 # NEW: Timeline visualization
│       └── template-manager.js               # NEW: Template UI
├── workspace/modules/
│   └── event-indicator.js                    # NEW: Staff event display
```

**Component**: Database Migrations
```
userfrosting/migrations/input/
├── 20251210_001_slide_tags.json              # NEW: Phase 0 - Slide tagging
├── 20251210_002_events_core.json             # NEW: Core events table
├── 20251210_003_event_integrations.json      # NEW: Integration linking
├── 20251210_004_event_templates.json         # NEW: Template tables
├── 20251210_005_task_event_fk.json           # NEW: Add eventId to tasks
├── 20251210_006_notes_event_fk.json          # NEW: Add eventId to notes
├── 20251210_007_bsevents_event_fk.json       # NEW: Add eventId to bsEvents
├── 20251210_008_sms_blast_event_fk.json      # NEW: Add eventId to SMS blasts
├── 20251210_009_sms_trigger_event_fk.json    # NEW: Add eventId to SMS triggers
├── 20251210_010_dsloop_event_fk.json         # NEW: Add eventId to dsLoop
├── 20251210_011_ccevents_event_fk.json       # NEW: Add eventId to ccEvents
└── 20251210_012_event_calendar_tokens.json   # NEW: Calendar token table for iCal feeds
```

**Component**: Cron Jobs
```
tasker/
├── process-event-phases.php                  # NEW: Update event phases
└── process-slide-schedule.php                # MODIFY: Include tag-based logic
```

### Interface Specifications

#### Interface Documentation References

```yaml
interfaces:
  - name: "UserFrosting Session Authentication"
    doc: docs/systems/authentication-flow.md
    relevance: CRITICAL
    why: "All event management routes use session-based auth"

  - name: "Ably Real-time Messaging"
    doc: External - https://ably.com/docs
    relevance: HIGH
    why: "Event updates broadcast to connected clients"

  - name: "Existing Integration Systems"
    docs:
      - docs/features/backstock.md
      - docs/features/seller-marketing-overview.md
      - docs/specs/003-comeback-cash/solution-design.md
    relevance: HIGH
    why: "Must integrate with these existing systems"
```

#### Data Storage Changes

##### Phase 0: Slide Tagging (Store Database)

```yaml
Table: dsSlide_Tags (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  slideId: INT UNSIGNED NOT NULL  # FK to dsSlides.id
  tag: VARCHAR(50) NOT NULL
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  UNIQUE KEY: uk_slide_tag (slideId, tag)
  INDEX: idx_tag (tag)
  FOREIGN KEY: fk_slide REFERENCES dsSlides(id) ON DELETE CASCADE

Table: corpSlide_Tags (NEW - Global Database)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  slideId: INT UNSIGNED NOT NULL  # FK to corpSlides.id
  tag: VARCHAR(50) NOT NULL
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  UNIQUE KEY: uk_slide_tag (slideId, tag)
  INDEX: idx_tag (tag)
  FOREIGN KEY: fk_corpslide REFERENCES corpSlides(id) ON DELETE CASCADE

Table: hbSlide_Tags (NEW - Global Database)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  slideId: INT UNSIGNED NOT NULL  # FK to hbSlides.id
  tag: VARCHAR(50) NOT NULL
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  UNIQUE KEY: uk_slide_tag (slideId, tag)
  INDEX: idx_tag (tag)
  FOREIGN KEY: fk_hbslide REFERENCES hbSlides(id) ON DELETE CASCADE
```

##### Core Event Tables (Store Database)

```yaml
Table: events (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  templateId: INT UNSIGNED NULL  # FK to eventTemplates (global DB) if created from template
  sourceEventId: INT UNSIGNED NULL  # FK to events - if duplicated from another event
  name: VARCHAR(100) NOT NULL
  description: TEXT NULL
  eventType: ENUM('season', 'holiday', 'sale', 'custom') NOT NULL
  year: YEAR NOT NULL
  startDate: DATE NOT NULL
  endDate: DATE NOT NULL
  buildUpDays: INT UNSIGNED DEFAULT 14
  windDownDays: INT UNSIGNED DEFAULT 7
  status: ENUM('draft', 'scheduled', 'active', 'completed', 'cancelled', 'archived') DEFAULT 'draft'
  previousStatus: VARCHAR(20) NULL  # Stores status before archiving (for unarchive)
  phase: ENUM('upcoming', 'build_up', 'active', 'wind_down', 'completed') DEFAULT 'upcoming'
  color: VARCHAR(7) NULL  # Hex color
  icon: VARCHAR(50) NULL
  isRecurring: TINYINT(1) DEFAULT 0
  archivedAt: TIMESTAMP NULL  # When event was archived
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  updated_at: TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP
  createdBy: INT UNSIGNED NULL  # FK to employees
  INDEX: idx_status (status)
  INDEX: idx_year (year)
  INDEX: idx_dates (startDate, endDate)
  INDEX: idx_type (eventType)
  INDEX: idx_archived (archivedAt)  # For filtering archived events

Table: event_integrations (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  eventId: INT UNSIGNED NOT NULL
  integrationType: ENUM('backstock', 'sms_blast', 'sms_trigger', 'signage', 'comeback_cash', 'task', 'note') NOT NULL
  foreignId: INT UNSIGNED NOT NULL  # ID in the target system
  config: JSON NULL  # Integration-specific configuration
  status: ENUM('pending', 'active', 'completed', 'failed') DEFAULT 'pending'
  relativeDays: INT NULL  # Days relative to event start (negative = before)
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  FOREIGN KEY: fk_event REFERENCES events(id) ON DELETE CASCADE
  INDEX: idx_event (eventId)
  INDEX: idx_type (integrationType)
  UNIQUE KEY: uk_event_integration (eventId, integrationType, foreignId)

Table: event_audit_log (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  eventId: INT UNSIGNED NOT NULL
  action: VARCHAR(50) NOT NULL  # created, updated, activated, cancelled, archived, duplicated, etc.
  details: JSON NULL
  employeeId: INT UNSIGNED NULL
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  FOREIGN KEY: fk_audit_event REFERENCES events(id) ON DELETE CASCADE
  INDEX: idx_event (eventId)

Table: event_calendar_tokens (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  employeeId: INT UNSIGNED NOT NULL  # FK to employees
  token: VARCHAR(64) NOT NULL  # Unique token for iCal feed
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  expires_at: TIMESTAMP NULL  # Token expiration (NULL = never expires)
  last_accessed: TIMESTAMP NULL  # Last time feed was accessed
  UNIQUE KEY: uk_token (token)
  INDEX: idx_employee (employeeId)
  Notes:
    - One token per employee per store
    - Token embedded in iCal feed URL
    - Can be regenerated (invalidates old token)
```

##### Template Tables (Global Database - kiosk_buykiosk)

```yaml
Table: eventTemplates (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  name: VARCHAR(100) NOT NULL
  description: TEXT NULL
  eventType: ENUM('season', 'holiday', 'sale', 'custom') NOT NULL
  scope: ENUM('global', 'franchise', 'store') DEFAULT 'global'
  storeType: VARCHAR(10) NULL  # Filter by store type (ou, pa, wi, etc.)
  defaultBuildUpDays: INT UNSIGNED DEFAULT 14
  defaultWindDownDays: INT UNSIGNED DEFAULT 7
  color: VARCHAR(7) NULL
  icon: VARCHAR(50) NULL
  isActive: TINYINT(1) DEFAULT 1
  created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  updated_at: TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP
  INDEX: idx_scope (scope)
  INDEX: idx_type (eventType)
  INDEX: idx_storetype (storeType)

Table: eventTemplate_Integrations (NEW)
  id: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  templateId: INT UNSIGNED NOT NULL
  integrationType: ENUM('backstock', 'sms_blast', 'sms_trigger', 'signage', 'comeback_cash', 'task', 'note') NOT NULL
  config: JSON NOT NULL  # Template configuration for this integration type
  relativeDays: INT NULL  # Days relative to event start
  isOptional: TINYINT(1) DEFAULT 0  # Can user remove this integration?
  sortOrder: INT UNSIGNED DEFAULT 0
  FOREIGN KEY: fk_template REFERENCES eventTemplates(id) ON DELETE CASCADE
  INDEX: idx_template (templateId)
```

##### Modifications to Existing Tables (Store Database)

**Purpose**: Add `eventId` column to all integration target tables to:
1. Mark records as "created by event system"
2. Show visual indicators in UI ("Part of Summer Sale event")
3. Warn users before deleting event-managed records
4. Enable reverse lookup from any record back to its parent event

```yaml
Table: tasks
  ADD COLUMN: eventId INT UNSIGNED NULL AFTER taskGroup
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_task_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Summer Sale" badge on task card

Table: workbook_notes
  ADD COLUMN: eventId INT UNSIGNED NULL AFTER id
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_note_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Created by Black Friday" indicator

Table: bsEvents (Backstock Events)
  ADD COLUMN: eventId INT UNSIGNED NULL
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_bs_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Managed by Summer Sale" banner on backstock event

Table: seller_marketing_blasts (SMS Blasts)
  ADD COLUMN: eventId INT UNSIGNED NULL
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_blast_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Part of Holiday Campaign" badge

Table: seller_marketing_triggers (SMS Triggers)
  ADD COLUMN: eventId INT UNSIGNED NULL
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_trigger_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show event association indicator

Table: dsLoop (Digital Signage Loop Items)
  ADD COLUMN: eventId INT UNSIGNED NULL
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_loop_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Added by Spring Sale" on slide in loop

Table: ccEvents (Comeback Cash Events)
  ADD COLUMN: eventId INT UNSIGNED NULL
  ADD INDEX: idx_eventId (eventId)
  ADD FOREIGN KEY: fk_cc_event REFERENCES events(id) ON DELETE SET NULL
  # UI: Show "📅 Linked to Memorial Day Sale" on CC event
```

##### Event-Managed Record Deletion Warning

When a user attempts to delete a record that has `eventId IS NOT NULL`:

```yaml
Warning Dialog:
  title: "This record is managed by an event"
  message: "This {recordType} was created by the '{eventName}' event.
            Deleting it will remove it from the event's integrations."
  options:
    - "Delete anyway" (removes record, updates event_integrations)
    - "Go to event" (navigate to parent event)
    - "Cancel"
```

#### Internal API Changes

##### Event Management API

```yaml
# Event CRUD
Endpoint: List Events
  Method: GET
  Path: /api/:typeNum/events
  Auth: Session + uri_events permission
  Query Parameters:
    year: INT (optional, filter by year)
    status: STRING (optional, filter by status)
    eventType: STRING (optional, filter by type)
  Response:
    success: true
    events: Array<Event>
    total: INT

Endpoint: Get Event
  Method: GET
  Path: /api/:typeNum/events/:eventId
  Auth: Session + uri_events permission
  Response:
    success: true
    event: Event (with integrations)

Endpoint: Create Event
  Method: POST
  Path: /api/:typeNum/events
  Auth: Session + uri_events_manage permission
  Request:
    name: STRING (required, max 100)
    eventType: ENUM (required)
    startDate: DATE (required, YYYY-MM-DD)
    endDate: DATE (required, YYYY-MM-DD)
    description: TEXT (optional)
    buildUpDays: INT (optional, default 14)
    windDownDays: INT (optional, default 7)
    color: STRING (optional, hex)
    icon: STRING (optional)
    isRecurring: BOOLEAN (optional)
    integrations: Array<IntegrationConfig> (optional)
  Response:
    success: true
    event: Event

Endpoint: Update Event
  Method: PUT
  Path: /api/:typeNum/events/:eventId
  Auth: Session + uri_events_manage permission
  Request: (same as create, all optional)
  Response:
    success: true
    event: Event
    recalculatedIntegrations: BOOLEAN

Endpoint: Delete Event
  Method: DELETE
  Path: /api/:typeNum/events/:eventId
  Auth: Session + uri_events_manage permission
  Response:
    success: true
    cascadeDeleted: Object (count of deleted integrations by type)

Endpoint: Activate Event
  Method: POST
  Path: /api/:typeNum/events/:eventId/activate
  Auth: Session + uri_events_manage permission
  Response:
    success: true
    event: Event
    integrationsActivated: INT

Endpoint: Cancel Event
  Method: POST
  Path: /api/:typeNum/events/:eventId/cancel
  Auth: Session + uri_events_manage permission
  Response:
    success: true
    event: Event
    integrationsCancelled: INT

Endpoint: Duplicate Event
  Method: POST
  Path: /api/:typeNum/events/:eventId/duplicate
  Auth: Session + uri_events_manage permission
  Description: Creates a copy of an existing event with new dates
  Request:
    name: STRING (optional, defaults to "{original name} (Copy)")
    startDate: DATE (required)
    endDate: DATE (required)
    includeIntegrations: BOOLEAN (optional, default true)
  Response:
    success: true
    event: Event (the new duplicated event)
    integrationsCreated: INT
  Notes:
    - All integration configurations are copied
    - Integration foreignIds are NEW (creates new records in target systems)
    - Relative days are preserved and recalculated for new dates
    - Original event is unchanged
    - Useful for "run last year's event again"

Endpoint: Archive Event
  Method: POST
  Path: /api/:typeNum/events/:eventId/archive
  Auth: Session + uri_events_manage permission
  Description: Soft-deletes an event (can be restored)
  Response:
    success: true
    event: Event (with status: 'archived')
  Notes:
    - Integrations are deactivated but NOT deleted
    - Event no longer appears in default lists
    - Can be restored via unarchive endpoint
    - Archived events still visible in reports/history

Endpoint: Unarchive Event
  Method: POST
  Path: /api/:typeNum/events/:eventId/unarchive
  Auth: Session + uri_events_manage permission
  Description: Restores an archived event
  Response:
    success: true
    event: Event (with status restored to previous state)
  Notes:
    - Integrations remain in their current state (not auto-reactivated)
    - User must manually reactivate if needed

Endpoint: Permanently Delete Event
  Method: DELETE
  Path: /api/:typeNum/events/:eventId/permanent
  Auth: Session + uri_events_manage permission
  Description: Hard-deletes an archived event (cannot be undone)
  Request:
    confirm: BOOLEAN (required, must be true)
  Response:
    success: true
    cascadeDeleted: Object
  Notes:
    - Only works on archived events
    - Requires explicit confirmation
    - Cascades to all integrations (hard delete)

# Conflict Detection
Endpoint: Check Event Conflicts
  Method: POST
  Path: /api/:typeNum/events/check-conflicts
  Auth: Session + uri_events permission
  Description: Validates event dates and integrations for conflicts before create/update
  Request:
    eventId: INT (optional, exclude this event from conflict check - for updates)
    startDate: DATE (required)
    endDate: DATE (required)
    eventType: ENUM (required)
    integrations: Array<IntegrationConfig> (optional)
  Response:
    success: true
    hasConflicts: BOOLEAN
    conflicts: Array<Conflict>
    warnings: Array<Warning>
  Conflict:
    type: ENUM (date_overlap, comeback_cash_conflict, resource_conflict)
    severity: ENUM (error, warning)
    message: STRING
    conflictingEventId: INT (if applicable)
    conflictingEventName: STRING (if applicable)
    details: Object
  Warning:
    type: ENUM (past_integration_date, short_buildup, overlapping_slides)
    message: STRING
    suggestion: STRING
  ConflictTypes:
    - date_overlap: "Another {eventType} event overlaps these dates"
    - comeback_cash_conflict: "Comeback Cash event conflicts with existing CC event"
    - resource_conflict: "Slides/SMS templates already scheduled"
    - past_integration_date: "Integration scheduled for date in the past"
    - short_buildup: "Build-up period is less than recommended"

# Post-Event Reports
Endpoint: Get Event Report
  Method: GET
  Path: /api/:typeNum/events/:eventId/report
  Auth: Session + uri_events_reports permission
  Description: Comprehensive post-event performance report
  Response:
    success: true
    report: EventReport
  EventReport:
    event: EventSummary
    period:
      startDate: DATE
      endDate: DATE
      totalDays: INT
      buildUpDays: INT
      activeDays: INT
      windDownDays: INT

    # Sales Performance
    sales:
      totalRevenue: DECIMAL
      totalBuys: INT
      avgBuyValue: DECIMAL
      itemsBought: INT
      uniqueCustomers: INT
      newCustomers: INT
      returningCustomers: INT
      dailyAvgSales: DECIMAL
      peakDay: DATE
      peakDaySales: DECIMAL

    # Year-over-Year Comparison
    comparison:
      previousEventId: INT
      previousYear: INT
      revenueChange: FLOAT (%)
      buysChange: FLOAT (%)
      customersChange: FLOAT (%)
      avgBuyValueChange: FLOAT (%)

    # Integration Performance
    integrations:
      backstock:
        enabled: BOOLEAN
        categoriesProcessed: INT
        itemsProcessed: INT
        completionRate: FLOAT (%)
      sms:
        enabled: BOOLEAN
        blastsSent: INT
        totalRecipients: INT
        deliveryRate: FLOAT (%)
        clickRate: FLOAT (%)
        triggersSent: INT
      comebackCash:
        enabled: BOOLEAN
        couponsIssued: INT
        couponsRedeemed: INT
        redemptionRate: FLOAT (%)
        totalCouponValue: DECIMAL
        redeemedValue: DECIMAL
      signage:
        enabled: BOOLEAN
        slidesDisplayed: INT
        totalImpressions: INT
      tasks:
        enabled: BOOLEAN
        tasksCreated: INT
        tasksCompleted: INT
        completionRate: FLOAT (%)
        avgCompletionTime: STRING

    # Top Performers
    topItems: Array<{itemName, quantity, revenue}>
    topCategories: Array<{categoryName, quantity, revenue}>
    topEmployees: Array<{employeeName, buys, revenue}>

    generatedAt: TIMESTAMP

Endpoint: Export Event Report
  Method: GET
  Path: /api/:typeNum/events/:eventId/report/export
  Auth: Session + uri_events_reports permission
  Query Parameters:
    format: ENUM (pdf, csv, xlsx) - default pdf
  Description: Download event report in specified format
  Response:
    Content-Type: application/pdf | text/csv | application/vnd.openxmlformats...
    Content-Disposition: attachment; filename="event-report-{eventId}.{format}"

Endpoint: Email Event Report
  Method: POST
  Path: /api/:typeNum/events/:eventId/report/email
  Auth: Session + uri_events_reports permission
  Request:
    recipients: Array<STRING> (email addresses)
    format: ENUM (pdf, csv) - default pdf
    includeMessage: STRING (optional custom message)
  Response:
    success: true
    sentTo: Array<STRING>

Endpoint: Compare Events
  Method: GET
  Path: /api/:typeNum/events/compare
  Auth: Session + uri_events_reports permission
  Query Parameters:
    eventIds: STRING (comma-separated event IDs, max 4)
  Description: Side-by-side comparison of multiple events
  Response:
    success: true
    events: Array<EventSummary>
    comparison:
      metrics: Array<MetricComparison>
    MetricComparison:
      metric: STRING
      values: Array<{eventId, value}>
      winner: INT (eventId with best value)

# Calendar Export
Endpoint: Get iCal Feed URL
  Method: GET
  Path: /api/:typeNum/events/calendar/feed-url
  Auth: Session + uri_events permission
  Description: Returns a unique, authenticated URL for iCal subscription
  Response:
    success: true
    feedUrl: STRING (unique URL with auth token)
    expiresAt: TIMESTAMP (token expiration)
  Notes:
    - URL contains embedded auth token for calendar apps
    - Token is long-lived but can be regenerated
    - Feed includes all non-archived events

Endpoint: Get iCal Feed (Public with Token)
  Method: GET
  Path: /api/calendar/:typeNum/events.ics
  Query Parameters:
    token: STRING (required, auth token from feed-url endpoint)
  Auth: Token-based (no session required)
  Description: Returns iCal format feed for calendar subscription
  Response:
    Content-Type: text/calendar
    Body: iCal formatted event data
  iCal Event Fields:
    - SUMMARY: Event name
    - DTSTART/DTEND: Event dates
    - DESCRIPTION: Event description + integration summary
    - CATEGORIES: Event type
    - COLOR: Event color (if supported)
    - URL: Link to event detail in admin
    - VALARM: Reminder for build-up start

Endpoint: Export Single Event to iCal
  Method: GET
  Path: /api/:typeNum/events/:eventId/calendar
  Auth: Session + uri_events permission
  Description: Download single event as .ics file
  Response:
    Content-Type: text/calendar
    Content-Disposition: attachment; filename="{event-name}.ics"

Endpoint: Regenerate Calendar Token
  Method: POST
  Path: /api/:typeNum/events/calendar/regenerate-token
  Auth: Session + uri_events permission
  Description: Invalidates old feed URL and generates new token
  Response:
    success: true
    feedUrl: STRING (new URL)
    previousTokenInvalidated: BOOLEAN

# Integration Management
Endpoint: Add Integration
  Method: POST
  Path: /api/:typeNum/events/:eventId/integrations
  Auth: Session + uri_events_manage permission
  Request:
    integrationType: ENUM (required)
    config: JSON (required, type-specific)
    relativeDays: INT (optional)
  Response:
    success: true
    integration: EventIntegration
    foreignRecord: Object (created record in target system)

Endpoint: Remove Integration
  Method: DELETE
  Path: /api/:typeNum/events/:eventId/integrations/:integrationId
  Auth: Session + uri_events_manage permission
  Response:
    success: true
    cascadeDeleted: BOOLEAN

# Template API
Endpoint: List Templates
  Method: GET
  Path: /api/:typeNum/events/templates
  Auth: Session + uri_events permission
  Query Parameters:
    scope: ENUM (optional, filter by scope)
    eventType: STRING (optional)
  Response:
    success: true
    templates: Array<EventTemplate>

Endpoint: Create Event from Template
  Method: POST
  Path: /api/:typeNum/events/from-template
  Auth: Session + uri_events_manage permission
  Request:
    templateId: INT (required)
    startDate: DATE (required)
    endDate: DATE (required)
    name: STRING (optional, override template name)
  Response:
    success: true
    event: Event (with populated integrations)

Endpoint: Save Event as Template
  Method: POST
  Path: /api/:typeNum/events/:eventId/save-as-template
  Auth: Session + uri_events_templates permission
  Request:
    name: STRING (required)
    description: STRING (optional)
  Response:
    success: true
    template: EventTemplate

# Dashboard & Reporting
Endpoint: Event Dashboard
  Method: GET
  Path: /api/:typeNum/events/dashboard
  Auth: Session + uri_events permission
  Response:
    success: true
    activeEvents: Array<Event>
    upcomingEvents: Array<Event>
    metrics: Object (summary stats)

Endpoint: Event Timeline
  Method: GET
  Path: /api/:typeNum/events/timeline
  Auth: Session + uri_events permission
  Query Parameters:
    months: INT (optional, default 3)
  Response:
    success: true
    timeline: Array<TimelineEntry>

Endpoint: Event Report
  Method: GET
  Path: /api/:typeNum/events/:eventId/report
  Auth: Session + uri_events_reports permission
  Response:
    success: true
    report: EventReport
```

##### Slide Tagging API (Phase 0)

```yaml
Endpoint: Get Slide Tags
  Method: GET
  Path: /api/:typeNum/digitalsign/slides/:slideId/tags
  Auth: Session + store access
  Response:
    success: true
    tags: Array<STRING>

Endpoint: Update Slide Tags
  Method: PUT
  Path: /api/:typeNum/digitalsign/slides/:slideId/tags
  Auth: Session + uri_store_settings permission
  Request:
    tags: Array<STRING> (max 10 tags, each max 50 chars)
  Response:
    success: true
    tags: Array<STRING>

Endpoint: Search Slides by Tags
  Method: GET
  Path: /api/:typeNum/digitalsign/slides/by-tags
  Auth: Session + store access
  Query Parameters:
    tags: STRING (comma-separated)
    source: ENUM (optional: store, corporate, hipbone)
  Response:
    success: true
    slides: Array<Slide>

Endpoint: Get All Tags
  Method: GET
  Path: /api/:typeNum/digitalsign/tags
  Auth: Session + store access
  Response:
    success: true
    tags: Array<{tag: STRING, count: INT}>
```

##### Mobile API - Event Management

Mobile API follows existing patterns from `docs/api/MOBILE_API.md`. All endpoints use JWT authentication.

```yaml
# Event List & Dashboard
Endpoint: Get Active Events (Mobile Dashboard)
  Method: GET
  Path: /api/mobile/:typeNum/events/active
  Auth: JWT + store access
  Description: Returns currently active and upcoming events for mobile dashboard
  Response:
    success: true
    activeEvents: Array<EventSummary>  # Events in active phase
    upcomingEvents: Array<EventSummary>  # Events in upcoming/build_up phase
    todaysTasks: Array<Task>  # Event-related tasks due today
  EventSummary:
    id: INT
    name: STRING
    eventType: STRING
    phase: STRING
    status: STRING
    startDate: DATE
    endDate: DATE
    color: STRING
    icon: STRING
    daysUntilStart: INT (negative if already started)
    integrationCount: INT

Endpoint: List Events (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events
  Auth: JWT + store access
  Query Parameters:
    year: INT (optional, default current year)
    status: STRING (optional)
    limit: INT (optional, default 20)
    offset: INT (optional, default 0)
  Response:
    success: true
    events: Array<EventSummary>
    total: INT
    hasMore: BOOLEAN

Endpoint: Get Event Detail (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId
  Auth: JWT + store access
  Response:
    success: true
    event: Event (full detail)
    integrations: Array<IntegrationSummary>
    timeline: Array<TimelineEntry>  # Visual timeline data
  IntegrationSummary:
    id: INT
    type: STRING
    status: STRING
    label: STRING  # Human-readable description
    scheduledDate: DATE
    foreignId: INT
    canNavigate: BOOLEAN  # Can user tap to view in app?

# Event CRUD (Mobile)
Endpoint: Create Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events
  Auth: JWT + uri_events_manage permission
  Request:
    name: STRING (required)
    eventType: ENUM (required)
    startDate: DATE (required)
    endDate: DATE (required)
    description: TEXT (optional)
    buildUpDays: INT (optional)
    windDownDays: INT (optional)
    templateId: INT (optional, create from template)
  Response:
    success: true
    event: Event

Endpoint: Update Event (Mobile)
  Method: PUT
  Path: /api/mobile/:typeNum/events/:eventId
  Auth: JWT + uri_events_manage permission
  Request:
    name: STRING (optional)
    description: TEXT (optional)
    startDate: DATE (optional)
    endDate: DATE (optional)
    buildUpDays: INT (optional)
    windDownDays: INT (optional)
  Response:
    success: true
    event: Event
    integrationsUpdated: INT  # Count of cascaded updates

Endpoint: Delete Event (Mobile)
  Method: DELETE
  Path: /api/mobile/:typeNum/events/:eventId
  Auth: JWT + uri_events_manage permission
  Response:
    success: true
    cascadeDeleted: Object

Endpoint: Activate Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/activate
  Auth: JWT + uri_events_manage permission
  Response:
    success: true
    event: Event
    integrationsActivated: INT

Endpoint: Cancel Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/cancel
  Auth: JWT + uri_events_manage permission
  Response:
    success: true
    event: Event

# Integration Management (Mobile)
Endpoint: Get Integration Types (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/integration-types
  Auth: JWT + store access
  Description: Returns available integration types with configuration schemas
  Response:
    success: true
    types: Array<IntegrationType>
  IntegrationType:
    type: STRING
    label: STRING
    description: STRING
    icon: STRING
    configSchema: Object  # JSON Schema for config

Endpoint: Add Integration (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/integrations
  Auth: JWT + uri_events_manage permission
  Request:
    integrationType: ENUM (required)
    config: JSON (required)
    relativeDays: INT (optional)
  Response:
    success: true
    integration: IntegrationSummary

Endpoint: Remove Integration (Mobile)
  Method: DELETE
  Path: /api/mobile/:typeNum/events/:eventId/integrations/:integrationId
  Auth: JWT + uri_events_manage permission
  Response:
    success: true

# Templates (Mobile - Read Only)
Endpoint: List Templates (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/templates
  Auth: JWT + store access
  Response:
    success: true
    templates: Array<TemplateSummary>
  TemplateSummary:
    id: INT
    name: STRING
    eventType: STRING
    scope: STRING
    integrationCount: INT
    description: STRING

Endpoint: Get Template Detail (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/templates/:templateId
  Auth: JWT + store access
  Response:
    success: true
    template: EventTemplate
    integrations: Array<TemplateIntegration>

# Quick Actions (Mobile)
Endpoint: Get Event Quick Actions
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/actions
  Auth: JWT + store access
  Description: Returns available actions based on event state and user permissions
  Response:
    success: true
    actions: Array<QuickAction>
  QuickAction:
    action: STRING (activate, cancel, edit, delete, duplicate, view_tasks)
    label: STRING
    enabled: BOOLEAN
    disabledReason: STRING (if disabled)
    confirmRequired: BOOLEAN
    confirmMessage: STRING

# Push Notifications (Mobile)
Endpoint: Update Push Preferences
  Method: PUT
  Path: /api/mobile/:typeNum/events/notifications/preferences
  Auth: JWT + store access
  Request:
    eventReminders: BOOLEAN  # Notify before event starts
    phaseChanges: BOOLEAN  # Notify on phase transitions
    taskReminders: BOOLEAN  # Notify for event-related tasks
    reminderDays: INT  # Days before event to send reminder
  Response:
    success: true
    preferences: Object

# Event Statistics (Mobile) - Real-time metrics during active events
Endpoint: Get Event Statistics
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/stats
  Auth: JWT + store access
  Description: Returns real-time performance metrics for an active event
  Response:
    success: true
    event: EventSummary
    stats: EventStats
    comparison: EventComparison (if previous year data exists)
    lastUpdated: TIMESTAMP
  EventStats:
    # Sales Metrics (from buys during event period)
    totalSales: DECIMAL
    totalBuys: INT
    avgBuyValue: DECIMAL
    itemsBought: INT
    uniqueCustomers: INT

    # Backstock Metrics (if backstock integration active)
    backstockProgress: FLOAT (0-100%)
    categoriesCompleted: INT
    categoriesTotal: INT
    itemsProcessed: INT
    itemsRemaining: INT

    # SMS Metrics (if SMS integration active)
    smsBlastsSent: INT
    smsDelivered: INT
    smsClicked: INT (if tracking enabled)
    triggersSent: INT

    # Comeback Cash Metrics (if CC integration active)
    couponsIssued: INT
    couponsRedeemed: INT
    couponValue: DECIMAL
    redemptionRate: FLOAT (0-100%)

    # Task Metrics
    tasksTotal: INT
    tasksCompleted: INT
    taskCompletionRate: FLOAT (0-100%)

    # Signage Metrics
    slidesActive: INT
    slideImpressions: INT (if tracking available)

  EventComparison:
    previousEventId: INT
    previousEventName: STRING
    previousYear: INT
    salesChange: FLOAT (percentage +/-)
    buysChange: FLOAT (percentage +/-)
    customersChange: FLOAT (percentage +/-)

Endpoint: Get Event Statistics Summary (Dashboard Card)
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/stats/summary
  Auth: JWT + store access
  Description: Lightweight stats for dashboard cards (faster response)
  Response:
    success: true
    summary:
      totalSales: DECIMAL
      totalBuys: INT
      taskProgress: STRING ("5/8 completed")
      backstockProgress: STRING ("75% complete")
      daysRemaining: INT
      trend: ENUM (up, down, flat)  # Compared to same point last year

Endpoint: Get Event Statistics History
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/stats/history
  Auth: JWT + store access
  Query Parameters:
    metric: ENUM (sales, buys, customers, redemptions)
    granularity: ENUM (hourly, daily) - default daily
  Description: Time-series data for charts
  Response:
    success: true
    metric: STRING
    granularity: STRING
    dataPoints: Array<DataPoint>
  DataPoint:
    timestamp: DATETIME
    value: DECIMAL
    previousYearValue: DECIMAL (if available)

Endpoint: Get Live Event Feed
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/feed
  Auth: JWT + store access
  Query Parameters:
    limit: INT (default 20)
    since: TIMESTAMP (for polling)
  Description: Real-time activity feed for event
  Response:
    success: true
    activities: Array<ActivityItem>
    hasMore: BOOLEAN
  ActivityItem:
    id: INT
    type: ENUM (sale, coupon_issued, coupon_redeemed, task_completed, sms_sent, phase_change)
    timestamp: DATETIME
    description: STRING
    value: DECIMAL (if applicable)
    employeeName: STRING (if applicable)
    metadata: Object
```

##### Template CRUD API (Admin + Mobile)

```yaml
# Full Template Management
Endpoint: Create Template
  Method: POST
  Path: /api/:typeNum/events/templates
  Auth: Session + uri_events_templates permission
  Request:
    name: STRING (required)
    description: TEXT (optional)
    eventType: ENUM (required)
    scope: ENUM (global requires uri_events_templates_global)
    defaultBuildUpDays: INT (optional, default 14)
    defaultWindDownDays: INT (optional, default 7)
    color: STRING (optional)
    icon: STRING (optional)
    integrations: Array<TemplateIntegrationConfig> (optional)
  Response:
    success: true
    template: EventTemplate

Endpoint: Update Template
  Method: PUT
  Path: /api/:typeNum/events/templates/:templateId
  Auth: Session + uri_events_templates permission
  Request: (same as create, all optional)
  Response:
    success: true
    template: EventTemplate

Endpoint: Delete Template
  Method: DELETE
  Path: /api/:typeNum/events/templates/:templateId
  Auth: Session + uri_events_templates permission
  Response:
    success: true

Endpoint: Add Integration to Template
  Method: POST
  Path: /api/:typeNum/events/templates/:templateId/integrations
  Auth: Session + uri_events_templates permission
  Request:
    integrationType: ENUM (required)
    config: JSON (required)
    relativeDays: INT (optional)
    isOptional: BOOLEAN (optional, default false)
  Response:
    success: true
    integration: TemplateIntegration

Endpoint: Update Template Integration
  Method: PUT
  Path: /api/:typeNum/events/templates/:templateId/integrations/:integrationId
  Auth: Session + uri_events_templates permission
  Request:
    config: JSON (optional)
    relativeDays: INT (optional)
    isOptional: BOOLEAN (optional)
  Response:
    success: true
    integration: TemplateIntegration

Endpoint: Remove Integration from Template
  Method: DELETE
  Path: /api/:typeNum/events/templates/:templateId/integrations/:integrationId
  Auth: Session + uri_events_templates permission
  Response:
    success: true

Endpoint: Duplicate Template
  Method: POST
  Path: /api/:typeNum/events/templates/:templateId/duplicate
  Auth: Session + uri_events_templates permission
  Request:
    name: STRING (required, new template name)
    scope: ENUM (optional, defaults to original scope)
  Response:
    success: true
    template: EventTemplate
```

##### Mobile API - Additional Features

```yaml
# Event Duplication (Mobile)
Endpoint: Duplicate Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/duplicate
  Auth: JWT + uri_events_manage permission
  Request:
    name: STRING (optional)
    startDate: DATE (required)
    endDate: DATE (required)
    includeIntegrations: BOOLEAN (optional, default true)
  Response:
    success: true
    event: MobileEventSummary
    integrationsCreated: INT

# Archive/Restore (Mobile)
Endpoint: Archive Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/archive
  Auth: JWT + uri_events_manage permission
  Response:
    success: true
    event: MobileEventSummary

Endpoint: Unarchive Event (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/unarchive
  Auth: JWT + uri_events_manage permission
  Response:
    success: true
    event: MobileEventSummary

Endpoint: List Archived Events (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/archived
  Auth: JWT + uri_events permission
  Response:
    success: true
    events: Array<MobileEventSummary>

# Conflict Detection (Mobile)
Endpoint: Check Conflicts (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/check-conflicts
  Auth: JWT + uri_events permission
  Request:
    eventId: INT (optional, for update checks)
    startDate: DATE (required)
    endDate: DATE (required)
    eventType: ENUM (required)
  Response:
    success: true
    hasConflicts: BOOLEAN
    conflictCount: INT
    conflicts: Array<MobileConflict>
    warnings: Array<MobileWarning>
  MobileConflict:
    type: STRING
    severity: STRING
    message: STRING
    eventName: STRING (if overlapping)
  MobileWarning:
    type: STRING
    message: STRING

# Reports (Mobile - Simplified)
Endpoint: Get Event Report Summary (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/report
  Auth: JWT + uri_events_reports permission
  Description: Simplified report optimized for mobile display
  Response:
    success: true
    report: MobileReportSummary
  MobileReportSummary:
    eventName: STRING
    dates: {startDate, endDate}
    sales:
      totalRevenue: DECIMAL
      totalBuys: INT
      avgBuyValue: DECIMAL
    comparison:
      revenueChange: FLOAT (% vs same period last year)
      trend: ENUM (up, down, flat)
    topMetrics:
      - label: STRING
        value: STRING
        icon: STRING
    integrationStatus:
      backstock: {enabled, completionRate}
      sms: {enabled, deliveryRate}
      comebackCash: {enabled, redemptionRate}
      tasks: {enabled, completionRate}

Endpoint: Email Event Report (Mobile)
  Method: POST
  Path: /api/mobile/:typeNum/events/:eventId/report/email
  Auth: JWT + uri_events_reports permission
  Request:
    recipients: Array<STRING>
    format: ENUM (pdf, csv) - default pdf
  Response:
    success: true
    sentTo: Array<STRING>

# Calendar Export (Mobile)
Endpoint: Get Calendar Feed URL (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/calendar/feed-url
  Auth: JWT + uri_events permission
  Response:
    success: true
    feedUrl: STRING
    qrCode: STRING (base64 PNG for easy sharing)

Endpoint: Add Event to Device Calendar (Mobile)
  Method: GET
  Path: /api/mobile/:typeNum/events/:eventId/calendar
  Auth: JWT + uri_events permission
  Description: Returns data for native calendar integration
  Response:
    success: true
    calendarEvent:
      title: STRING
      startDate: DATETIME
      endDate: DATETIME
      allDay: BOOLEAN
      notes: STRING
      url: STRING
      reminders: Array<{minutes: INT}>
```

#### Application Data Models

```pseudocode
ENTITY: Event (NEW)
  FIELDS:
    id: INT (auto-increment)
    templateId: INT (nullable, reference to source template)
    sourceEventId: INT (nullable, reference to duplicated-from event)
    name: STRING (max 100)
    description: TEXT (nullable)
    eventType: ENUM('season', 'holiday', 'sale', 'custom')
    year: YEAR
    startDate: DATE
    endDate: DATE
    buildUpDays: INT (default 14)
    windDownDays: INT (default 7)
    status: ENUM('draft', 'scheduled', 'active', 'completed', 'cancelled', 'archived')
    previousStatus: STRING (nullable, stores status before archiving)
    phase: ENUM('upcoming', 'build_up', 'active', 'wind_down', 'completed')
    color: STRING (nullable, hex)
    icon: STRING (nullable)
    isRecurring: BOOLEAN (default false)
    archivedAt: TIMESTAMP (nullable, when event was archived)
    createdBy: INT (nullable, employee ID)
    created_at: TIMESTAMP
    updated_at: TIMESTAMP (nullable)

  BEHAVIORS:
    + create(data): Event
    + getById(id): Event
    + update(data): Event
    + delete(): void (cascades to integrations)
    + activate(): void (schedules all integrations)
    + cancel(): void (cancels all integrations)
    + archive(): void (soft delete, deactivates integrations)
    + unarchive(): void (restores to previousStatus)
    + permanentDelete(): void (hard delete, only when archived)
    + duplicate(newStartDate, newEndDate, includeIntegrations): Event
    + getCurrentPhase(): ENUM (calculated from dates)
    + getBuildUpStartDate(): DATE (startDate - buildUpDays)
    + getWindDownEndDate(): DATE (endDate + windDownDays)
    + isArchived(): BOOLEAN
    + getSourceEvent(): Event (nullable, if duplicated)
    + toArray(): array
    + fromRow(row): Event

ENTITY: EventIntegration (NEW)
  FIELDS:
    id: INT
    eventId: INT (FK to events)
    integrationType: ENUM('backstock', 'sms_blast', 'sms_trigger', 'signage', 'comeback_cash', 'task', 'note')
    foreignId: INT (ID in target system)
    config: JSON (nullable, integration-specific)
    status: ENUM('pending', 'active', 'completed', 'failed')
    relativeDays: INT (nullable, days from event start)
    created_at: TIMESTAMP

  BEHAVIORS:
    + create(data): EventIntegration
    + getByEventId(eventId): Array<EventIntegration>
    + activate(): void (triggers adapter)
    + deactivate(): void (cancels in target system)
    + delete(): void (cascades to target system)
    + getAdapter(): IntegrationAdapterInterface

ENTITY: EventTemplate (NEW - Global DB)
  FIELDS:
    id: INT
    name: STRING (max 100)
    description: TEXT (nullable)
    eventType: ENUM
    scope: ENUM('global', 'franchise', 'store')
    storeType: STRING (nullable, filter)
    defaultBuildUpDays: INT
    defaultWindDownDays: INT
    color: STRING (nullable)
    icon: STRING (nullable)
    isActive: BOOLEAN
    created_at: TIMESTAMP
    updated_at: TIMESTAMP

  BEHAVIORS:
    + getById(id): EventTemplate
    + listByScope(scope, storeType): Array<EventTemplate>
    + createEventFromTemplate(startDate, endDate, store): Event
    + saveEventAsTemplate(event, name): EventTemplate

ENTITY: SlideTag (NEW)
  FIELDS:
    id: INT
    slideId: INT (FK to dsSlides/corpSlides/hbSlides)
    tag: STRING (max 50)
    created_at: TIMESTAMP

  BEHAVIORS:
    + addTag(slideId, tag): SlideTag
    + removeTag(slideId, tag): void
    + getTagsForSlide(slideId): Array<STRING>
    + setTags(slideId, tags): void (replaces all)
    + searchByTags(tags, source): Array<Slide>
    + getAllTags(): Array<{tag, count}>

ENTITY: EventCalendarToken (NEW)
  FIELDS:
    id: INT (auto-increment)
    employeeId: INT (FK to employees)
    token: STRING (64 chars, unique)
    created_at: TIMESTAMP
    expires_at: TIMESTAMP (nullable, NULL = never expires)
    last_accessed: TIMESTAMP (nullable)

  BEHAVIORS:
    + generateToken(employeeId): EventCalendarToken
    + getByToken(token): EventCalendarToken (validates not expired)
    + regenerate(): EventCalendarToken (invalidates old, creates new)
    + getFeedUrl(typeNum): STRING (full iCal URL with token)
    + recordAccess(): void (updates last_accessed)

SERVICE: ConflictChecker (NEW)
  PURPOSE: Validates events and integrations for scheduling conflicts

  BEHAVIORS:
    + checkConflicts(eventData, excludeEventId?): ConflictResult
    + checkDateOverlaps(startDate, endDate, eventType, excludeEventId?): Array<Conflict>
    + checkComebackCashConflicts(startDate, endDate): Array<Conflict>
    + checkResourceConflicts(integrations, startDate, endDate): Array<Conflict>
    + validateIntegrationDates(integrations, eventStartDate): Array<Warning>

  ConflictResult:
    hasConflicts: BOOLEAN
    conflicts: Array<Conflict>
    warnings: Array<Warning>

SERVICE: EventReportGenerator (NEW)
  PURPOSE: Generates comprehensive post-event performance reports

  BEHAVIORS:
    + generateReport(eventId): EventReport
    + getSalesMetrics(eventId): SalesMetrics
    + getYearOverYearComparison(eventId): ComparisonMetrics
    + getIntegrationPerformance(eventId): IntegrationMetrics
    + exportToPdf(eventId): Binary
    + exportToCsv(eventId): Binary
    + exportToXlsx(eventId): Binary
    + emailReport(eventId, recipients, format): void
    + compareEvents(eventIds): ComparisonReport

SERVICE: EventDuplicator (NEW)
  PURPOSE: Creates deep copies of events with all integrations

  BEHAVIORS:
    + duplicate(eventId, newDates, includeIntegrations): Event
    + copyIntegrations(sourceEvent, targetEvent): Array<EventIntegration>
    + recalculateRelativeDays(sourceEvent, targetEvent, integrations): void

ENTITY: Task (MODIFIED)
  FIELDS:
    + eventId: INT (nullable, FK to events, NEW)

  BEHAVIORS:
    + getByEventId(eventId): Array<Task> (NEW)
    ~ delete(): void (SET NULL on event FK)

ENTITY: Note (MODIFIED)
  FIELDS:
    + eventId: INT (nullable, FK to events, NEW)

  BEHAVIORS:
    + getByEventId(eventId): Array<Note> (NEW)
    ~ delete(): void (SET NULL on event FK)
```

#### Integration Points

```yaml
# Internal Integration Adapters (Event Hub to Existing Systems)
#
# IMPORTANT: All adapters set eventId on target records for traceability.
# This enables:
#   - UI indicators showing "Created by {eventName}"
#   - Delete warnings when user tries to remove event-managed records
#   - Reverse lookup from any record to its parent event

BackstockAdapter:
  target_system: bsEvents (Backstock Events)
  integration_type: "Create/link backstock event record"
  operations:
    - create: "Creates bsEvents record with event dates AND sets eventId"
    - link: "Links existing bsEvent_Categories to unified event"
    - sync_dates: "Updates bsEvents dates when unified event dates change"
    - delete: "Deletes linked bsEvents record (cascade)"
  data_flow:
    - event.id → bsEvents.eventId (marks as event-managed)
    - bsEvents.id → event_integrations.foreignId
    - event.startDate → bsEvents.startDate
    - event.endDate → bsEvents.endDate
    - event.buildUpDays → bsEvents.buildUpDays
    - event.categories → bsEvent_Categories

SmsAdapter:
  target_system: seller_marketing_queue + seller_marketing_blasts/triggers
  integration_type: "Schedule SMS campaigns relative to event dates"
  operations:
    - create_blast: "Creates seller_marketing_blasts with calculated send date AND sets eventId"
    - create_trigger: "Creates seller_marketing_triggers active during event period AND sets eventId"
    - update_dates: "Recalculates send dates when event dates change"
    - cancel: "Sets blast status to 'cancelled', deactivates triggers"
  data_flow:
    - event.id → blast.eventId / trigger.eventId (marks as event-managed)
    - relativeDays + event.startDate → blast.scheduled_at
    - event.startDate/endDate → trigger.start_date/expire_date
    - config.messageId → blast/trigger.message_id

SignageAdapter:
  target_system: dsLoop + digitalSignSchedule
  integration_type: "Schedule slide display during event period"
  operations:
    - add_slides: "Adds slides to dsLoop with event dates as start/expire AND sets eventId"
    - add_by_tags: "Finds slides matching tags and adds to loop with eventId"
    - update_dates: "Updates dsLoop and digitalSignSchedule when event changes"
    - remove: "Removes slides from dsLoop, cleans up digitalSignSchedule"
  data_flow:
    - event.id → dsLoop.eventId (marks as event-managed)
    - config.slideIds → dsLoop entries
    - config.tags → slide lookup → dsLoop entries
    - event.startDate → dsLoop.startDate
    - event.endDate → dsLoop.expireDate

ComebackCashAdapter:
  target_system: ccEvents (Comeback Cash)
  integration_type: "Create promotional coupon events linked to unified event"
  operations:
    - create: "Creates ccEvents with earning/redemption windows AND sets eventId"
    - update_dates: "Syncs earning/redemption dates with event timeline"
    - cancel: "Cancels ccEvents, handles active coupons gracefully"
  data_flow:
    - event.id → ccEvents.eventId (marks as event-managed)
    - config.side → ccEvents.side (buy/sales)
    - config.earningType → ccEvents.earning_type
    - event dates + relativeDays → ccEvents earning/redemption windows

TaskAdapter:
  target_system: tasks + taskGroups
  integration_type: "Create event-specific tasks with relative scheduling"
  operations:
    - create: "Creates tasks with eventId FK, creates task group if needed"
    - calculate_dates: "Converts relativeDays to actual due dates"
    - update_dates: "Recalculates task dates when event dates change"
    - delete: "Deletes tasks linked to event (or SET NULL based on config)"
  data_flow:
    - event.id → tasks.eventId (marks as event-managed)
    - config.taskName → tasks.taskName
    - relativeDays + event.startDate → tasks.startDate
    - "Event: {eventName}" → taskGroups.groupName

NoteAdapter:
  target_system: workbook_notes
  integration_type: "Create scheduled staff announcements for event"
  operations:
    - create: "Creates notes with eventId FK and visibility dates"
    - update_dates: "Syncs note visibility with event timeline"
    - delete: "Deletes notes linked to event"
  data_flow:
    - event.id → workbook_notes.eventId (marks as event-managed)
    - config.content → workbook_notes.content
    - config.title → workbook_notes.title
    - event.startDate + relativeDays → workbook_notes.startDate
    - config.isManagerOnly → workbook_notes.isManagerOnly
    - config.isPinned → workbook_notes.isPinned

# External Services

Ably:
  purpose: "Real-time event updates to connected clients"
  channel: "{typeNum}" (store-specific)
  events_published:
    - event.created: {eventId, eventName}
    - event.updated: {eventId, changes}
    - event.activated: {eventId}
    - event.cancelled: {eventId}
    - event.phase_changed: {eventId, oldPhase, newPhase}
  integration_pattern: "Fire-and-forget with graceful failure handling"
```

### Implementation Examples

#### Example: Event Phase Calculation

**Why this example**: Phase calculation is central to the event lifecycle and must be consistent across all components.

```php
/**
 * Calculate the current phase of an event based on today's date
 * Phase determines what actions are available and how integrations behave
 */
class Event {
    public function getCurrentPhase(): string {
        $today = new DateTime('today', new DateTimeZone($this->store->getTimezone()));

        $buildUpStart = (clone $this->startDate)->modify("-{$this->buildUpDays} days");
        $windDownEnd = (clone $this->endDate)->modify("+{$this->windDownDays} days");

        if ($today < $buildUpStart) {
            return 'upcoming';
        } elseif ($today >= $buildUpStart && $today < $this->startDate) {
            return 'build_up';
        } elseif ($today >= $this->startDate && $today <= $this->endDate) {
            return 'active';
        } elseif ($today > $this->endDate && $today <= $windDownEnd) {
            return 'wind_down';
        } else {
            return 'completed';
        }
    }

    public function getBuildUpStartDate(): DateTime {
        return (clone $this->startDate)->modify("-{$this->buildUpDays} days");
    }

    public function getWindDownEndDate(): DateTime {
        return (clone $this->endDate)->modify("+{$this->windDownDays} days");
    }
}
```

#### Example: Integration Adapter Interface

**Why this example**: All adapters must follow this contract for consistent behavior and cascade handling.

```php
/**
 * Contract for all integration adapters
 * Each adapter translates Event operations to target system operations
 */
interface IntegrationAdapterInterface {
    /**
     * Create a linked record in the target system
     * @param Event $event The unified event
     * @param array $config Integration-specific configuration from template
     * @return int The foreign ID of the created record
     * @throws IntegrationException On failure
     */
    public function create(Event $event, array $config): int;

    /**
     * Update the linked record when event dates change
     * @param Event $event The updated event
     * @param EventIntegration $integration The integration record
     * @throws IntegrationException On failure
     */
    public function syncDates(Event $event, EventIntegration $integration): void;

    /**
     * Activate the integration (start/schedule in target system)
     * @param EventIntegration $integration
     * @throws IntegrationException On failure
     */
    public function activate(EventIntegration $integration): void;

    /**
     * Deactivate/cancel the integration in target system
     * @param EventIntegration $integration
     * @throws IntegrationException On failure
     */
    public function deactivate(EventIntegration $integration): void;

    /**
     * Delete the linked record (cascade from event deletion)
     * @param EventIntegration $integration
     * @throws IntegrationException On failure
     */
    public function delete(EventIntegration $integration): void;

    /**
     * Get status information from the target system
     * @param EventIntegration $integration
     * @return array Status details for dashboard display
     */
    public function getStatus(EventIntegration $integration): array;
}
```

#### Example: Relative Date Calculation for Integrations

**Why this example**: Templates use relative dates that must be converted to actual dates at event creation.

```php
/**
 * Calculate actual dates from relative days configuration
 * Negative values = before event start
 * Positive values = after event start
 * Zero = on event start date
 */
class IntegrationService {
    public function calculateIntegrationDate(Event $event, int $relativeDays): DateTime {
        $baseDate = clone $event->getStartDate();

        if ($relativeDays === 0) {
            return $baseDate;
        }

        $modifier = $relativeDays > 0 ? "+{$relativeDays} days" : "{$relativeDays} days";
        return $baseDate->modify($modifier);
    }

    /**
     * Create all integrations from a template
     */
    public function createFromTemplate(Event $event, EventTemplate $template): array {
        $createdIntegrations = [];

        foreach ($template->getIntegrations() as $templateIntegration) {
            $adapter = $this->getAdapter($templateIntegration['type']);

            // Apply relative date calculation
            $config = $templateIntegration['config'];
            if (isset($templateIntegration['relativeDays'])) {
                $config['scheduledDate'] = $this->calculateIntegrationDate(
                    $event,
                    $templateIntegration['relativeDays']
                );
            }

            // Create the integration via adapter
            $foreignId = $adapter->create($event, $config);

            // Record the integration link
            $integration = new EventIntegration([
                'eventId' => $event->getId(),
                'integrationType' => $templateIntegration['type'],
                'foreignId' => $foreignId,
                'config' => json_encode($config),
                'relativeDays' => $templateIntegration['relativeDays'] ?? null,
                'status' => 'pending'
            ]);
            $integration->save($this->db);

            $createdIntegrations[] = $integration;
        }

        return $createdIntegrations;
    }
}
```

#### Example: Cascade Delete with Transaction

**Why this example**: Event deletion must cascade to all integrations atomically with proper cleanup.

```php
/**
 * Delete event and cascade to all integrations
 * Uses transaction to ensure atomic operation
 */
class EventService {
    public function deleteEvent(int $eventId): array {
        $event = $this->getEventById($eventId);
        if (!$event) {
            throw new NotFoundException("Event not found: {$eventId}");
        }

        $cascadeResults = [
            'backstock' => 0,
            'sms_blast' => 0,
            'sms_trigger' => 0,
            'signage' => 0,
            'comeback_cash' => 0,
            'task' => 0,
            'note' => 0
        ];

        $this->db->beginTransaction();

        try {
            // Get all integrations for this event
            $integrations = EventIntegration::getByEventId($this->db, $eventId);

            // Delete each integration via its adapter (cascades to target system)
            foreach ($integrations as $integration) {
                $adapter = $this->integrationService->getAdapter($integration->getIntegrationType());
                $adapter->delete($integration);
                $integration->delete($this->db);
                $cascadeResults[$integration->getIntegrationType()]++;
            }

            // Log audit trail
            $this->auditLog($eventId, 'deleted', [
                'eventName' => $event->getName(),
                'cascadeResults' => $cascadeResults
            ]);

            // Delete the event record
            $event->delete($this->db);

            $this->db->commit();

            // Broadcast deletion via Ably
            $this->ably->publish('event.deleted', [
                'eventId' => $eventId,
                'eventName' => $event->getName()
            ]);

            return $cascadeResults;

        } catch (\Exception $e) {
            $this->db->rollBack();
            $this->log->error("Event deletion failed: " . $e->getMessage());
            throw new IntegrationException("Failed to delete event: " . $e->getMessage());
        }
    }
}
```

## Runtime View

### Primary Flow: Create Event from Template

1. Manager navigates to Event Management dashboard
2. Manager clicks "Create Event" and selects "From Template"
3. System displays template library (filtered by store type)
4. Manager selects template and adjusts dates
5. System auto-populates all integration configurations
6. Manager reviews and customizes integrations
7. Manager confirms and activates event
8. System creates all linked records across integrated systems

```mermaid
sequenceDiagram
    actor Manager
    participant UI as Event Dashboard
    participant API as EventApiController
    participant ES as EventService
    participant TS as TemplateService
    participant IS as IntegrationService
    participant Adapters as Integration Adapters
    participant DB as Store Database
    participant Ably as Ably Real-time

    Manager->>UI: Select template, set dates
    UI->>API: POST /events/from-template
    API->>API: Validate permissions
    API->>TS: getTemplate(templateId)
    TS-->>API: EventTemplate
    API->>ES: createEvent(data)
    ES->>DB: BEGIN TRANSACTION
    ES->>DB: INSERT INTO events
    DB-->>ES: eventId

    loop For each template integration
        ES->>IS: createIntegration(event, config)
        IS->>Adapters: adapter.create(event, config)
        Adapters->>DB: Create target system record
        DB-->>Adapters: foreignId
        Adapters-->>IS: foreignId
        IS->>DB: INSERT INTO event_integrations
    end

    ES->>DB: INSERT INTO event_audit_log
    ES->>DB: COMMIT
    ES->>Ably: publish('event.created')
    ES-->>API: Event with integrations
    API-->>UI: JSON Response
    UI-->>Manager: Show event dashboard
```

### Secondary Flow: Event Activation

1. Cron job runs every hour (or manual trigger)
2. System finds events where current date is in build_up or active phase
3. System activates pending integrations based on their relative dates
4. Integrations create/schedule records in target systems
5. Dashboard updates to show active status

```mermaid
sequenceDiagram
    participant Cron as EventPhaseProcessor
    participant ES as EventService
    participant IS as IntegrationService
    participant Adapters as Integration Adapters
    participant DB as Store Database
    participant Ably as Ably Real-time

    Cron->>ES: processPhaseUpdates()
    ES->>DB: SELECT events WHERE phase needs update
    DB-->>ES: Events needing update

    loop For each event
        ES->>ES: calculateCurrentPhase()
        alt Phase changed
            ES->>DB: UPDATE events SET phase = newPhase
            ES->>IS: activatePendingIntegrations(event)

            loop For pending integrations
                IS->>Adapters: adapter.activate(integration)
                Adapters->>DB: Update target system
                IS->>DB: UPDATE event_integrations SET status = 'active'
            end

            ES->>DB: INSERT INTO event_audit_log
            ES->>Ably: publish('event.phase_changed')
        end
    end
```

### Error Handling

| Error Type | Handling Strategy | User Feedback |
|------------|-------------------|---------------|
| **Validation Error** | Return 400 with specific field errors | "Event name is required", "End date must be after start date" |
| **Permission Denied** | Return 403, log attempt | "You don't have permission to manage events" |
| **Integration Failure** | Rollback transaction, log error | "Failed to create SMS campaign: [specific reason]" |
| **Conflict** | Return 409 with conflict details | "An event of this type is already active during these dates" |
| **Not Found** | Return 404 | "Event not found" |
| **Ably Failure** | Log and continue (non-blocking) | No user feedback (graceful degradation) |
| **Database Error** | Rollback, log, return 500 | "An error occurred. Please try again." |

### Complex Logic: Event Date Change Cascade

When event dates are modified, all integration dates must be recalculated:

```
ALGORITHM: Recalculate Integration Dates
INPUT: event (with new dates), integrations[]
OUTPUT: updated integrations with new calculated dates

1. FOR each integration in integrations:
   a. IF integration.relativeDays IS NOT NULL:
      i. newScheduledDate = event.startDate + integration.relativeDays
      ii. IF newScheduledDate IN PAST:
          - WARN: "Integration scheduled date is in the past"
          - OPTION: Skip or execute immediately
      iii. ELSE:
          - adapter.syncDates(event, integration)
          - UPDATE integration dates in target system
   b. ELSE:
      - Integration uses absolute dates (event start/end)
      - adapter.syncDates(event, integration)

2. IF any integration already executed (SMS sent, etc.):
   a. WARN user: "Some integrations have already executed"
   b. List affected integrations
   c. Cannot undo executed actions

3. LOG all date changes to audit trail
4. BROADCAST 'event.updated' via Ably
```

### Complex Logic: Template to Event Conversion

```
ALGORITHM: Create Event from Template
INPUT: template, startDate, endDate, store
OUTPUT: event with populated integrations

1. CREATE event record:
   - Copy template fields (name, type, buildUpDays, windDownDays, color, icon)
   - Set startDate, endDate from user input
   - Set year = YEAR(startDate)
   - Set templateId = template.id
   - Set status = 'draft'
   - Calculate initial phase

2. FOR each template_integration in template.integrations:
   a. RESOLVE relative dates:
      - actualDate = startDate + template_integration.relativeDays
   b. VALIDATE configuration:
      - Check referenced resources exist (slides, categories, etc.)
      - WARN if resources missing
   c. CREATE integration record (status = 'pending')
   d. CALL adapter.create(event, config):
      - Creates record in target system
      - Returns foreignId
   e. STORE foreignId in event_integrations

3. IF any integration creation fails:
   a. ROLLBACK entire transaction
   b. RETURN error with specific failure

4. LOG creation to audit trail
5. RETURN event with integrations array
```

## Deployment View

### Single Application Deployment

This feature deploys as part of the existing BuyerKiosk monolithic PHP application. No new infrastructure is required.

- **Environment**: Existing LAMP stack (Linux, Apache, MySQL, PHP 8.x)
- **Server**: Production web servers (existing)
- **Database**:
  - Central DB: `kiosk_buykiosk` (templates, global slides)
  - Store DBs: `kiosk_{typeNum}` (events, integrations, local slides)
- **Dependencies**:
  - Existing: Ably (real-time), Redis (caching), MySQL
  - No new external services required

### Configuration Requirements

```yaml
# Existing environment variables (already configured)
ABLY_KEY: [existing] - Real-time event broadcasts
REDIS_HOST: [existing] - Session and cache storage

# New permissions to add to UserFrosting
permissions:
  - uri_events: "Access Event Management dashboard"
  - uri_events_manage: "Create, edit, delete events"
  - uri_events_templates: "Manage store-level templates"
  - uri_events_templates_global: "Manage global templates (corporate only)"
  - uri_events_reports: "View event performance reports"

# New cron job (add to crontab)
cron:
  - schedule: "0 * * * *"  # Every hour
    command: "php /path/to/tasker/process-event-phases.php"
    description: "Update event phases and activate scheduled integrations"
```

### Deployment Order

1. **Phase 0: Slide Tagging** (prerequisite)
   ```
   a. Run migration: 20251210_001_slide_tags.json
   b. Deploy SlideTag model and service classes
   c. Deploy slide tag API endpoints
   d. Update digital sign UI for tag management
   e. Verify: Tag CRUD operations work for all slide types
   ```

2. **Phase 1: Core Event Tables**
   ```
   a. Run migrations in order:
      - 20251210_002_events_core.json
      - 20251210_003_event_integrations.json
      - 20251210_004_event_templates.json
   b. Deploy EventManagement module (models, services, adapters)
   c. Deploy API controllers and routes
   d. Add permissions to UserFrosting
   e. Verify: Event CRUD works, no integrations yet
   ```

3. **Phase 2: FK Modifications & Integrations**
   ```
   a. Run migrations:
      - 20251210_005_task_event_fk.json
      - 20251210_006_notes_event_fk.json
   b. Enable integration adapters
   c. Deploy admin dashboard UI
   d. Add cron job for phase processing
   e. Verify: Full event with integrations works end-to-end
   ```

4. **Phase 3: Templates & Reporting**
   ```
   a. Seed initial event templates (global)
   b. Deploy template management UI
   c. Deploy reporting endpoints and UI
   d. Verify: Template-based event creation works
   ```

### Rollback Strategy

| Phase | Rollback Procedure |
|-------|-------------------|
| **Phase 0** | Remove tag tables, revert SlideController changes |
| **Phase 1** | Drop events/event_integrations tables, remove routes |
| **Phase 2** | Remove eventId FKs, disable adapters |
| **Phase 3** | Remove template data, disable template UI |

**Safe Rollback Notes**:
- All new tables can be dropped without affecting existing functionality
- FK additions are nullable with SET NULL on delete (safe to remove)
- Existing systems continue to function independently if Event Management is disabled
- No breaking changes to existing APIs

### Performance Considerations

```yaml
Expected Load:
  - Events per store: 10-50 active events/year
  - Dashboard requests: ~100/day per store
  - Integration operations: Peak at event creation (~6 per event)
  - Phase processor: Runs hourly, processes ~100 events/minute

Response Time Targets:
  - Dashboard load: < 500ms
  - Event CRUD: < 1s
  - Integration creation (all 6): < 3s
  - Template application: < 2s

Caching Strategy:
  - Dashboard metrics: Redis, 5-minute TTL
  - Event list: Redis, 1-minute TTL (invalidate on changes)
  - Templates: Redis, 1-hour TTL
  - No caching for write operations
```

## User Interface Specification

### Navigation & Access

The Event Management system lives in the **Admin section** of the application, accessible via a dedicated sidebar menu item. This is intentionally separate from the Workspace/Workbook area to maintain clear separation between operational tools (workspace) and planning/management tools (admin).

```
Admin Sidebar
├── Store Settings
├── Employee Management
├── ...
├── 📅 Event Management    ← NEW
│   ├── Events Dashboard   (default view)
│   ├── Event Templates
│   ├── Reports
│   └── Archive
└── ...
```

**Permission Mapping**:
| Menu Item | Required Permission | Notes |
|-----------|---------------------|-------|
| Events Dashboard | `uri_events` | View-only access to event list and details |
| Event Templates | `uri_events_templates` | Create/edit store templates |
| Reports | `uri_events_reports` | View event performance reports |
| Archive | `uri_events` | View archived events (restore requires `uri_events_manage`) |
| Create/Edit Events | `uri_events_manage` | Required for any modification actions |

### Route Structure

```
/admin/:typeNum/events                    → Dashboard (Kanban view)
/admin/:typeNum/events/list               → List view
/admin/:typeNum/events/create             → Create wizard
/admin/:typeNum/events/:eventId           → Event detail page
/admin/:typeNum/events/:eventId/edit      → Edit wizard
/admin/:typeNum/events/:eventId/duplicate → Duplicate wizard (pre-filled)
/admin/:typeNum/events/templates          → Template management
/admin/:typeNum/events/reports            → Reports dashboard
/admin/:typeNum/events/reports/:eventId   → Single event report
/admin/:typeNum/events/archive            → Archived events
```

---

### UI-1: Events Dashboard (Kanban View)

The primary view for event management. Shows events organized by status in a Kanban board layout.

#### Wireframe

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  📅 Event Management                                    [+ Create Event]  ⚙️    │
├─────────────────────────────────────────────────────────────────────────────────┤
│  [Kanban View] [List View]     🔍 Search...     [Filter ▼]  [Date Range ▼]     │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  ┌─ DRAFT (3) ──────┐  ┌─ SCHEDULED (5) ────┐  ┌─ ACTIVE (2) ──────┐          │
│  │                  │  │                    │  │                    │          │
│  │ ┌──────────────┐ │  │ ┌──────────────┐  │  │ ┌──────────────┐  │          │
│  │ │ 🏷️ Black     │ │  │ │ 🎄 Holiday   │  │  │ │ 🍂 Fall Sale │  │          │
│  │ │ Friday 2025  │ │  │ │ Sale 2025    │  │  │ │              │  │          │
│  │ │              │ │  │ │              │  │  │ │ ● ACTIVE     │  │          │
│  │ │ Nov 28-Dec 1 │ │  │ │ Dec 15-25    │  │  │ │ Oct 1-31     │  │          │
│  │ │              │ │  │ │              │  │  │ │              │  │          │
│  │ │ 📦 🔔 📺 💵  │ │  │ │ 📦 🔔 📺     │  │  │ │ 📦 🔔 📺 💵  │  │          │
│  │ │ ▔▔ ▔▔ ▔▔ ▔▔ │ │  │ │ ▔▔ ▔▔ ▔▔     │  │  │ │ ▔▔ ▔▔ ▔▔ ▔▔ │  │          │
│  │ └──────────────┘ │  │ └──────────────┘  │  │ └──────────────┘  │          │
│  │                  │  │                    │  │                    │          │
│  │ ┌──────────────┐ │  │ ┌──────────────┐  │  │ ┌──────────────┐  │          │
│  │ │ 🎃 Halloween │ │  │ │ 🎊 New Year  │  │  │ │ 📱 Phone     │  │          │
│  │ │ Clearance    │ │  │ │ Blowout      │  │  │ │ Launch       │  │          │
│  │ │              │ │  │ │              │  │  │ │              │  │          │
│  │ │ Oct 25-31    │ │  │ │ Dec 26-Jan 2 │  │  │ │ ● BUILD UP   │  │          │
│  │ │              │ │  │ │              │  │  │ │ Nov 1-15     │  │          │
│  │ │ 📦 📺       │ │  │ │ 📦 🔔 📺 💵  │  │  │ │              │  │          │
│  │ └──────────────┘ │  │ └──────────────┘  │  │ │ 📦 🔔        │  │          │
│  │ ...              │  │ ...               │  │ └──────────────┘  │          │
│  └──────────────────┘  └────────────────────┘  └────────────────────┘          │
│                                                                                 │
│  ┌─ COMPLETED (12) ─┐  ┌─ CANCELLED (1) ───┐                                   │
│  │                  │  │                    │                                   │
│  │ ┌──────────────┐ │  │ ┌──────────────┐  │    Legend:                        │
│  │ │ 🎒 Back to   │ │  │ │ ❌ Summer    │  │    📦 Backstock  🔔 SMS           │
│  │ │ School       │ │  │ │ Clearance    │  │    📺 Signage    💵 ComebackCash  │
│  │ │              │ │  │ │              │  │    📋 Tasks      📝 Notes         │
│  │ │ ✓ COMPLETED  │ │  │ │ CANCELLED    │  │                                   │
│  │ │ Aug 1-Sep 5  │ │  │ │ Jul 1-15     │  │                                   │
│  │ └──────────────┘ │  │ └──────────────┘  │                                   │
│  └──────────────────┘  └────────────────────┘                                   │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Event Card Components

```
┌────────────────────────────────────────┐
│ 🏷️ Event Name                    [⋮]  │  ← Emoji from template/custom + overflow menu
│                                        │
│ ○ Phase Badge (if applicable)          │  ← Shows current phase: BUILD UP, ACTIVE, WIND DOWN
│                                        │
│ 📅 Nov 28 - Dec 1, 2025               │  ← Date range
│                                        │
│ ┌──┬──┬──┬──┬──┬──┐                   │  ← Integration icons (filled = active, outline = configured but not active)
│ │📦│🔔│📺│💵│📋│📝│                   │
│ └──┴──┴──┴──┴──┴──┘                   │
│                                        │
│ ⚠️ 1 conflict detected                 │  ← Conflict warning (if any)
└────────────────────────────────────────┘
```

**Card Overflow Menu (⋮)**:
- View Details
- Edit Event
- Duplicate Event
- ---
- Archive Event (for completed/cancelled)
- Cancel Event (for scheduled/active)
- Delete Draft (for drafts only)

#### Kanban Columns

| Column | Events Shown | Visual Style | Drag Target |
|--------|--------------|--------------|-------------|
| **Draft** | `status = 'draft'` | Gray header | Can drag TO scheduled |
| **Scheduled** | `status = 'scheduled'` | Blue header | Can drag TO draft (back to editing) |
| **Active** | `status = 'active'` | Green header | No drag (system controlled) |
| **Completed** | `status = 'completed'` | Dark header | Can drag TO archive |
| **Cancelled** | `status = 'cancelled'` | Red header | Can drag TO archive |

**Note**: Archived events are NOT shown on the Kanban board - they have their own dedicated page.

#### Phase Badges (for Active Events Only)

Active events display their current phase with color coding:

| Phase | Badge | Color |
|-------|-------|-------|
| `upcoming` | Not shown (shouldn't be active) | - |
| `build_up` | `● BUILD UP` | Yellow |
| `active` | `● ACTIVE` | Green |
| `wind_down` | `● WIND DOWN` | Orange |
| `completed` | `✓ COMPLETED` | Gray |

#### Filter Options

```
┌─────────────────────────────────────┐
│ Filter Events                    ✕  │
├─────────────────────────────────────┤
│ Date Range                          │
│ ○ All Events                        │
│ ○ This Month                        │
│ ○ Next 30 Days                      │
│ ○ This Quarter                      │
│ ○ Custom: [____] to [____]          │
├─────────────────────────────────────┤
│ Integrations (check to filter)      │
│ ☑ 📦 Backstock Events              │
│ ☑ 🔔 SMS Campaigns                 │
│ ☑ 📺 Digital Signage               │
│ ☑ 💵 Comeback Cash                 │
│ ☑ 📋 Tasks                         │
│ ☑ 📝 Notes                         │
├─────────────────────────────────────┤
│ Created By                          │
│ [All Users              ▼]          │
├─────────────────────────────────────┤
│ [Apply Filters]  [Clear All]        │
└─────────────────────────────────────┘
```

---

### UI-2: Events List View

Alternative table-based view for users who prefer traditional list layouts or need to see more events at once.

#### Wireframe

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  📅 Event Management                                    [+ Create Event]  ⚙️    │
├─────────────────────────────────────────────────────────────────────────────────┤
│  [Kanban View] [List View]     🔍 Search...     [Filter ▼]  [Date Range ▼]     │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ □  Event Name          Start      End        Status     Phase    Actions  │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  🍂 Fall Sale        Oct 1      Oct 31     ACTIVE     ● ACTIVE  [⋮]    │ │
│  │    📦 🔔 📺 💵                                                            │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  📱 Phone Launch     Nov 1      Nov 15     ACTIVE     ● BUILD UP [⋮]   │ │
│  │    📦 🔔         ⚠️ 1 conflict                                            │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  🎄 Holiday Sale     Dec 15     Dec 25     SCHEDULED  -          [⋮]   │ │
│  │    📦 🔔 📺                                                               │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  🏷️ Black Friday     Nov 28     Dec 1      DRAFT      -          [⋮]   │ │
│  │    📦 🔔 📺 💵                                                            │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  🎊 New Year         Dec 26     Jan 2      SCHEDULED  -          [⋮]   │ │
│  │    📦 🔔 📺 💵                                                            │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Showing 1-5 of 23 events                          [< Previous]  [Next >]      │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Bulk Actions (when items selected)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  ☑ 3 events selected    [Archive Selected]  [Cancel Selected]  [Clear]         │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Sortable Columns

| Column | Sortable | Default |
|--------|----------|---------|
| Event Name | Yes | - |
| Start Date | Yes | ▼ (ascending, upcoming first) |
| End Date | Yes | - |
| Status | Yes | - |
| Phase | No | - |
| Actions | No | - |

---

### UI-3: Event Creation Wizard

A step-by-step wizard for creating events. Each step represents either core event details or an integration configuration.

#### Wizard Flow Overview

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                                                                                 │
│   ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐   │
│   │  1  │───▶│  2  │───▶│  3  │───▶│  4  │───▶│  5  │───▶│  6  │───▶│  7  │   │
│   └─────┘    └─────┘    └─────┘    └─────┘    └─────┘    └─────┘    └─────┘   │
│    Event     Backstock    SMS      Signage   Comeback    Tasks     Review     │
│    Basics    📦          🔔        📺        Cash 💵     📋        ✓          │
│                                                                                 │
│   Required   Optional    Optional  Optional  Optional   Optional   Required   │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

**Step Indicator States**:
- ○ Not visited (outline)
- ◐ In progress (half-filled)
- ● Completed (filled)
- ⊘ Skipped (crossed out)

#### Step 1: Event Basics (Required)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 1 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ○ Backstock  ○ SMS  ○ Signage  ○ Comeback Cash  ○ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  Start from Template (Optional)                                                │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔍 Search templates...                                            [▼]    │ │
│  │ ├─ 🏪 Store Templates                                                    │ │
│  │ │   └─ 🎃 Halloween Sale                                                 │ │
│  │ │   └─ 🦃 Thanksgiving Special                                           │ │
│  │ ├─ 🏢 Corporate Templates                                                │ │
│  │ │   └─ 🏷️ Standard Sale Event                                           │ │
│  │ │   └─ 🎄 Holiday Season Package                                         │ │
│  │ └─ ➕ Start from Scratch                                                 │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  Event Name *                                                                   │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ Fall Clearance Sale                                                       │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Event Emoji                        Event Color                                │
│  ┌─────────────────┐                ┌─────────────────┐                        │
│  │ 🍂 [Change]     │                │ ███ Orange [▼]  │                        │
│  └─────────────────┘                └─────────────────┘                        │
│                                                                                 │
│  Start Date *                       End Date *                                  │
│  ┌─────────────────┐                ┌─────────────────┐                        │
│  │ 📅 Oct 1, 2025  │                │ 📅 Oct 31, 2025 │                        │
│  └─────────────────┘                └─────────────────┘                        │
│                                                                                 │
│  Description                                                                    │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ Seasonal clearance event to move fall inventory before holiday stock      │ │
│  │ arrives. Focus on apparel and outdoor items.                              │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ⚠️ Date Conflict Detected                                                     │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ This event overlaps with "Phone Launch Event" (Nov 1-15).                 │ │
│  │ Shared integrations may cause conflicts if both events are active.        │ │
│  │ [View Details]                                                            │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                              [Cancel]    [Next: Backstock →]   │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 2: Backstock Integration (Optional)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 2 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ◐ Backstock  ○ SMS  ○ Signage  ○ Comeback Cash  ○ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  📦 Backstock Event                                      [Skip This Step →]   │
│                                                                                 │
│  Create a backstock event to apply special pricing rules during this event.    │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable Backstock Event                                                      │
│                                                                                 │
│  Event Type                                                                     │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ ○ Standard Sale                                                           │ │
│  │ ● Clearance Event                                                         │ │
│  │ ○ BOGO Promotion                                                          │ │
│  │ ○ Category Discount                                                       │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Pricing Rules                                                                  │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ Discount: [25]% off  ○ All items  ● Tagged items only                    │ │
│  │                                                                           │ │
│  │ Category Filter:     [Fall/Winter Apparel        ▼]                      │ │
│  │                                                                           │ │
│  │ ☑ Apply floor price protection                                           │ │
│  │ ☑ Exclude already-discounted items                                       │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Activation                                                                     │
│  ○ Activate when event starts                                                  │
│  ○ Activate during build-up phase (3 days before)                             │
│  ● Custom activation: [Oct 1, 2025] at [6:00 AM]                              │
│                                                                                 │
│  End Behavior                                                                   │
│  ○ Deactivate when event ends                                                  │
│  ● Deactivate during wind-down phase (1 day before end)                       │
│  ○ Custom deactivation: [________] at [____]                                  │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Skip]    [Next: SMS Campaigns →]     │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 3: SMS Campaigns (Optional)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 3 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ● Backstock  ◐ SMS  ○ Signage  ○ Comeback Cash  ○ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  🔔 SMS Campaigns                                        [Skip This Step →]   │
│                                                                                 │
│  Configure SMS blast messages and automated triggers for this event.           │
│                                                                                 │
│  ─────────────────────────── SMS BLASTS ──────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable SMS Blasts                                                           │
│                                                                                 │
│  ┌─ Blast #1: Pre-Event Announcement ────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  Audience: [All Opted-In Customers    ▼]        Est. Recipients: 2,847   │ │
│  │                                                                           │ │
│  │  Message:                                                                 │ │
│  │  ┌─────────────────────────────────────────────────────────────────────┐ │ │
│  │  │ 🍂 FALL CLEARANCE starts tomorrow! Up to 50% off seasonal items.   │ │ │
│  │  │ Visit us at {store_address}. Reply STOP to opt out.                │ │ │
│  │  └─────────────────────────────────────────────────────────────────────┘ │ │
│  │  Characters: 142/160                                                      │ │
│  │                                                                           │ │
│  │  Send Date: ○ Event start  ● Custom: [Sep 30, 2025] at [10:00 AM]       │ │
│  │                                                                           │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  [+ Add Another Blast]                                                         │
│                                                                                 │
│  ─────────────────────── SMS TRIGGERS ────────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable Event-Specific Triggers                                              │
│                                                                                 │
│  ┌─ Trigger: Post-Purchase Follow-up ────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  Trigger Event: [Customer completes purchase      ▼]                     │ │
│  │  Delay:         [24] hours after trigger                                 │ │
│  │                                                                           │ │
│  │  Message:                                                                 │ │
│  │  ┌─────────────────────────────────────────────────────────────────────┐ │ │
│  │  │ Thanks for shopping our Fall Clearance, {first_name}! Your         │ │ │
│  │  │ receipt is ready. Questions? Call us at {store_phone}.             │ │ │
│  │  └─────────────────────────────────────────────────────────────────────┘ │ │
│  │                                                                           │ │
│  │  Active: During event dates only                                         │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  [+ Add Another Trigger]                                                       │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Skip]    [Next: Signage →]           │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 4: Digital Signage (Optional)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 4 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ● Backstock  ● SMS  ◐ Signage  ○ Comeback Cash  ○ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  📺 Digital Signage                                      [Skip This Step →]   │
│                                                                                 │
│  Select slides to display during this event.                                   │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable Event Signage                                                        │
│                                                                                 │
│  Slide Selection Method                                                        │
│  ○ Select specific slides                                                      │
│  ● Select by tags                                                              │
│  ○ Use template default                                                        │
│                                                                                 │
│  Selected Tags:  [Fall] [Sale] [Clearance]  [+ Add Tag]                       │
│                                                                                 │
│  Matching Slides Preview:                                                      │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐                           │
│  │ │ 🍂      │ │ 🏷️      │ │ 50%     │ │ SALE    │                           │
│  │ │ FALL    │ │ PRICES  │ │ OFF     │ │ ENDS    │                           │
│  │ │ SALE    │ │ SLASHED │ │         │ │ SOON    │                           │
│  │ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤                           │
│  │ │ 15 sec  │ │ 15 sec  │ │ 10 sec  │ │ 10 sec  │                           │
│  │ └─────────┘ └─────────┘ └─────────┘ └─────────┘                           │
│  │                                                                            │
│  │ 4 slides selected • Total loop time: 50 seconds                           │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  Display Phases                                                                │
│  ☑ Show during build-up phase                                                 │
│  ☑ Show during active phase                                                   │
│  ☐ Show during wind-down phase                                                │
│                                                                                 │
│  Priority: [Normal ▼]  (Higher priority slides show first in loop)            │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Skip]    [Next: Comeback Cash →]     │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 5: Comeback Cash (Optional)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 5 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ● Backstock  ● SMS  ● Signage  ◐ Comeback Cash  ○ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  💵 Comeback Cash Promotion                              [Skip This Step →]   │
│                                                                                 │
│  Configure promotional coupons issued during this event.                       │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable Comeback Cash                                                        │
│                                                                                 │
│  Coupon Configuration                                                          │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  Coupon Value:  $[10] off purchase of $[50] or more                      │ │
│  │                                                                           │ │
│  │  Issue Condition:                                                         │ │
│  │  ○ Every purchase                                                         │ │
│  │  ● Purchases over $[25]                                                   │ │
│  │  ○ Every Nth purchase: [___]                                             │ │
│  │                                                                           │ │
│  │  Redemption Window:                                                       │ │
│  │  Coupons valid: [7] days after event ends                                │ │
│  │  Expiration date: Nov 7, 2025 (calculated)                               │ │
│  │                                                                           │ │
│  │  ☑ Allow stacking with other promotions                                  │ │
│  │  ☐ Limit one per customer                                                │ │
│  │                                                                           │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Coupon Message Preview:                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │  ┌─────────────────────────────────────────────┐                         │ │
│  │  │  🎉 COMEBACK CASH                           │                         │ │
│  │  │  $10 OFF your next purchase of $50+        │                         │ │
│  │  │  Valid through: Nov 7, 2025                │                         │ │
│  │  │  Code: [Auto-generated at issue]           │                         │ │
│  │  └─────────────────────────────────────────────┘                         │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Skip]    [Next: Tasks →]             │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 6: Tasks (Optional)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 6 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ● Backstock  ● SMS  ● Signage  ● Comeback Cash  ◐ Tasks  ○ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  📋 Event Tasks                                          [Skip This Step →]   │
│                                                                                 │
│  Create tasks that should be completed before, during, or after the event.     │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  ☑ Enable Event Tasks                                                          │
│                                                                                 │
│  ┌─ Pre-Event Tasks ─────────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  □ Set up clearance section displays              Due: Sep 29  [@John]   │ │
│  │  □ Print and post sale signage                    Due: Sep 30  [@Team]   │ │
│  │  □ Brief staff on promotion details               Due: Sep 30  [@Sarah]  │ │
│  │                                                                           │ │
│  │  [+ Add Pre-Event Task]                                                   │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ┌─ During-Event Tasks ──────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  □ Restock clearance items daily                  Recurring: Daily        │ │
│  │  □ Monitor competitor pricing                     Due: Oct 15  [@Manager] │ │
│  │                                                                           │ │
│  │  [+ Add During-Event Task]                                                │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ┌─ Post-Event Tasks ────────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  □ Remove sale signage                            Due: Nov 1   [@Team]   │ │
│  │  □ Return unsold items to regular floor           Due: Nov 2   [@John]   │ │
│  │  □ Complete event performance review              Due: Nov 5   [@Manager]│ │
│  │                                                                           │ │
│  │  [+ Add Post-Event Task]                                                  │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Skip]    [Next: Review →]            │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Step 7: Review & Create (Required)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Create Event                                           Step 7 of 7            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│  ● Event Basics  ● Backstock  ● SMS  ● Signage  ⊘ Comeback Cash  ● Tasks  ◐ Review │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  ✓ Review Your Event                                                           │
│                                                                                 │
│  ┌─ 🍂 Fall Clearance Sale ──────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  Dates: October 1 - October 31, 2025  (31 days)                          │ │
│  │  Description: Seasonal clearance event to move fall inventory...          │ │
│  │                                                          [Edit Basics]    │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ┌─ Integrations Summary ────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  ✓ 📦 Backstock Event                                      [Edit]        │ │
│  │    • Clearance Event - 25% off tagged items                              │ │
│  │    • Activates: Oct 1 at 6:00 AM                                         │ │
│  │                                                                           │ │
│  │  ✓ 🔔 SMS Campaigns                                        [Edit]        │ │
│  │    • 1 blast scheduled (Sep 30, 10:00 AM)                                │ │
│  │    • 1 trigger configured (Post-purchase follow-up)                       │ │
│  │                                                                           │ │
│  │  ✓ 📺 Digital Signage                                      [Edit]        │ │
│  │    • 4 slides selected by tags: Fall, Sale, Clearance                    │ │
│  │    • Display during: build-up, active phases                             │ │
│  │                                                                           │ │
│  │  ⊘ 💵 Comeback Cash                                        [Add]         │ │
│  │    • Skipped                                                              │ │
│  │                                                                           │ │
│  │  ✓ 📋 Tasks                                                [Edit]        │ │
│  │    • 3 pre-event, 2 during-event, 3 post-event tasks                     │ │
│  │                                                                           │ │
│  │  📝 Notes                                                  [Add Note]    │ │
│  │    • No notes added                                                       │ │
│  │                                                                           │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ⚠️ Warnings                                                                   │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │  • Date overlap with "Phone Launch Event" (Nov 1-15) - both events       │ │
│  │    use Backstock integration                                              │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Create As:                                                                    │
│  ○ Draft - Save for later editing                                             │
│  ● Scheduled - Ready to activate on start date                                │
│                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                              [← Back]    [Save as Draft]    [Create Event →]   │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### UI-4: Event Detail Page

The detail page shows comprehensive information about a single event. The layout adapts based on event status and phase.

#### Header Section (All States)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  [← Back to Events]                                                             │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  🍂 Fall Clearance Sale                                                        │
│  ════════════════════════════════════════════════════════════════════════════  │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────┐           │
│  │  STATUS        PHASE           DATES                           │           │
│  │  ● ACTIVE      ● ACTIVE        Oct 1 - Oct 31, 2025           │           │
│  │                                (Day 15 of 31)                  │           │
│  └─────────────────────────────────────────────────────────────────┘           │
│                                                                                 │
│  [Edit Event]  [Duplicate]  [View Report]  [⋮ More Actions]                    │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Phase Timeline (Active Events)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Event Timeline                                                                 │
│                                                                                 │
│  Sep 28        Oct 1                              Oct 30      Oct 31           │
│     │            │                                   │          │              │
│     ▼            ▼                                   ▼          ▼              │
│  ═══════════════════════════════════════════════════════════════════          │
│  │ BUILD │████████████████████████████████████████████│ WIND │                │
│  │  UP   │              A C T I V E                   │ DOWN │                │
│  ═══════════════════════════════════════════════════════════════════          │
│                              ▲                                                  │
│                              │                                                  │
│                           TODAY                                                 │
│                          Oct 15                                                 │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Integration Status Cards

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Integrations                                                                   │
│                                                                                 │
│  ┌─ 📦 Backstock Event ─────────────────┐  ┌─ 🔔 SMS Campaigns ───────────────┐ │
│  │                                      │  │                                  │ │
│  │  Status: ● ACTIVE                    │  │  Blasts: 1 sent, 0 scheduled    │ │
│  │  Type: Clearance (25% off)           │  │  Triggers: 1 active             │ │
│  │  Items affected: 847                 │  │  Messages sent: 2,847           │ │
│  │  Revenue: $12,450                    │  │  Opt-outs: 12 (0.4%)            │ │
│  │                                      │  │                                  │ │
│  │  [View Backstock Event →]            │  │  [View Campaign Details →]       │ │
│  └──────────────────────────────────────┘  └──────────────────────────────────┘ │
│                                                                                 │
│  ┌─ 📺 Digital Signage ─────────────────┐  ┌─ 📋 Tasks ───────────────────────┐ │
│  │                                      │  │                                  │ │
│  │  Status: ● ACTIVE                    │  │  Completed: 5 of 8              │ │
│  │  Slides: 4 in rotation              │  │  Overdue: 1                      │ │
│  │  Display hours: 156                 │  │  Upcoming: 2                     │ │
│  │                                      │  │                                  │ │
│  │  [Preview Slides →]                  │  │  [View All Tasks →]             │ │
│  └──────────────────────────────────────┘  └──────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### State-Specific Display Variations

**Draft Event Detail**:
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Status: DRAFT                                                                  │
│                                                                                 │
│  ⚠️ This event is still being configured.                                      │
│                                                                                 │
│  Completion Checklist:                                                         │
│  ✓ Basic details configured                                                    │
│  ✓ Backstock event configured                                                  │
│  ○ SMS campaigns not configured                                                │
│  ✓ Signage configured                                                          │
│  ○ No tasks added                                                              │
│                                                                                 │
│  [Continue Editing]                    [Schedule Event]                         │
└─────────────────────────────────────────────────────────────────────────────────┘
```

**Scheduled Event Detail**:
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Status: SCHEDULED                    Starts in: 15 days                        │
│                                                                                 │
│  📅 Countdown to Event                                                         │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │        15          0           0            0                              │
│  │       DAYS       HOURS       MINS         SECS                             │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  Pre-Event Checklist:                                                          │
│  ☐ Set up clearance section displays (Due: Sep 29)                             │
│  ☐ Print and post sale signage (Due: Sep 30)                                   │
│  ☐ Brief staff on promotion details (Due: Sep 30)                              │
│                                                                                 │
│  [Edit Event]    [Cancel Event]                                                │
└─────────────────────────────────────────────────────────────────────────────────┘
```

**Completed Event Detail**:
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  Status: ✓ COMPLETED                  Ended: 5 days ago                         │
│                                                                                 │
│  📊 Quick Stats                                                                │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │   $45,230        847          2,847         +12%                           │
│  │   Revenue       Items        SMS Sent       vs Last Year                    │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  [View Full Report]    [Duplicate for Next Year]    [Archive]                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### UI-5: Event Reports Page

#### Reports Dashboard

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  📊 Event Reports                                                               │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  [All Events ▼]    [Date Range: Last 12 Months ▼]    [Export CSV]              │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  Overview Metrics                                                               │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │                                                                             │
│  │   23              $234,500         +15%              8.2                    │
│  │   Events          Total Revenue    vs Prior Year    Avg Days               │
│  │   Completed                                                                 │
│  │                                                                             │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  Revenue by Event                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │  ████████████████████████████████████████  Black Friday 2024    $52,300    │
│  │  ███████████████████████████              Holiday Sale 2024     $41,200    │
│  │  ████████████████████                     Back to School        $32,100    │
│  │  ██████████████                           Summer Clearance      $24,500    │
│  │  ████████████                             Spring Sale           $21,800    │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  Event Performance Table                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ Event Name         Dates           Revenue    Items    YoY     Actions    │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ Black Friday 2024  Nov 28-Dec 1    $52,300    1,247   +18%    [View]     │ │
│  │ Holiday Sale 2024  Dec 15-25       $41,200    982     +12%    [View]     │ │
│  │ Back to School     Aug 1-Sep 5     $32,100    756     +8%     [View]     │ │
│  │ Summer Clearance   Jun 15-Jul 4    $24,500    623     -3%     [View]     │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

#### Single Event Report

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  📊 Event Report: 🍂 Fall Clearance Sale                                       │
│  October 1 - October 31, 2024                                                  │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  [← Back to Reports]                              [Export PDF]  [Export CSV]   │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  Key Metrics                                                                   │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │                                                                             │
│  │   $45,230         847           312          $145                          │
│  │   Total           Items         Transactions  Avg Transaction              │
│  │   Revenue         Sold                                                     │
│  │                                                                             │
│  │   +12%            +8%           +15%          -3%                          │
│  │   vs Last Year    vs Last Year  vs Last Year  vs Last Year                 │
│  │                                                                             │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  ┌─ Daily Revenue Chart ────────────────────────────────────────────────────┐  │
│  │                                                                          │  │
│  │  $3k │                    ▄                                              │  │
│  │      │              ▄     █                                              │  │
│  │  $2k │        ▄     █     █  ▄                                          │  │
│  │      │  ▄  ▄  █  ▄  █  ▄  █  █  ▄                                       │  │
│  │  $1k │  █  █  █  █  █  █  █  █  █  ▄  ▄                                  │  │
│  │      │  █  █  █  █  █  █  █  █  █  █  █                                  │  │
│  │   $0 └──────────────────────────────────────────────────────────────     │  │
│  │       Oct 1    Oct 8    Oct 15   Oct 22   Oct 29                         │  │
│  │                                                                          │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                 │
│  Integration Performance                                                       │
│  ┌─────────────────────────────────────────────────────────────────────────────┐
│  │                                                                             │
│  │  📦 Backstock                          🔔 SMS                              │
│  │  ─────────────────────                 ────────────────────                 │
│  │  Items activated: 847                  Messages sent: 2,847                │
│  │  Items sold: 623 (74%)                 Open rate: 42%                      │
│  │  Revenue: $38,450                      Click rate: 8%                      │
│  │  Avg discount: 22%                     Conversions: 127                    │
│  │                                                                             │
│  │  📺 Signage                            💵 Comeback Cash                    │
│  │  ─────────────────────                 ────────────────────                 │
│  │  Slides displayed: 4                   Coupons issued: N/A                 │
│  │  Display hours: 744                    (Not configured)                    │
│  │  Impressions: ~12,400                                                      │
│  │                                                                             │
│  └─────────────────────────────────────────────────────────────────────────────┘
│                                                                                 │
│  Year-over-Year Comparison                                                     │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ Metric              This Year    Last Year    Change                      │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ Revenue             $45,230      $40,383      +$4,847 (+12%)             │ │
│  │ Items Sold          847          784          +63 (+8%)                   │ │
│  │ Transactions        312          271          +41 (+15%)                  │ │
│  │ Avg Transaction     $145         $149         -$4 (-3%)                   │ │
│  │ Event Duration      31 days      28 days      +3 days                     │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### UI-6: Archive Page

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  🗄️ Archived Events                                                            │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  🔍 Search archived events...            [Date Range ▼]    [Year: 2024 ▼]     │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │ □  Event Name          Dates              Archived On    Actions          │ │
│  ├───────────────────────────────────────────────────────────────────────────┤ │
│  │ □  🎃 Halloween 2023   Oct 25-31, 2023    Jan 15, 2024   [Restore] [⋮]   │ │
│  │ □  🎄 Holiday 2023     Dec 15-25, 2023    Feb 1, 2024    [Restore] [⋮]   │ │
│  │ □  ❌ Summer (Cancelled) Jun 1-15, 2023   Jun 2, 2023    [Restore] [⋮]   │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Showing 1-3 of 15 archived events                                             │
│                                                                                 │
│  ⚠️ Archived events are retained for 2 years. Events older than 2 years       │
│     will be permanently deleted.                                               │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  Bulk Actions (with selection):                                                │
│  [Restore Selected]    [Permanently Delete]                                    │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### UI-7: Template Management

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│  📋 Event Templates                                         [+ Create Template] │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  [Store Templates]  [Corporate Templates]                                      │
│                                                                                 │
│  ─────────────────────────────────────────────────────────────────────────────  │
│                                                                                 │
│  Store Templates (3)                                                           │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  ┌──────────────────────┐  ┌──────────────────────┐  ┌──────────────────┐│ │
│  │  │ 🎃 Halloween Sale    │  │ 🦃 Thanksgiving      │  │ 📱 Product       ││ │
│  │  │                      │  │                      │  │ Launch           ││ │
│  │  │ Integrations:        │  │ Integrations:        │  │                  ││ │
│  │  │ 📦 🔔 📺            │  │ 📦 🔔 💵            │  │ Integrations:    ││ │
│  │  │                      │  │                      │  │ 📦 🔔 📺 📋     ││ │
│  │  │ Used: 3 times        │  │ Used: 2 times        │  │                  ││ │
│  │  │                      │  │                      │  │ Used: 1 time     ││ │
│  │  │ [Use]  [Edit]  [⋮]  │  │ [Use]  [Edit]  [⋮]  │  │ [Use] [Edit] [⋮]││ │
│  │  └──────────────────────┘  └──────────────────────┘  └──────────────────┘│ │
│  │                                                                           │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  Corporate Templates (5)                                            🔒 Locked  │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │                                                                           │ │
│  │  ┌──────────────────────┐  ┌──────────────────────┐                      │ │
│  │  │ 🏷️ Standard Sale    │  │ 🎄 Holiday Season    │   ...                │ │
│  │  │ 🔒                   │  │ 🔒                   │                      │ │
│  │  │ Corporate template   │  │ Corporate template   │                      │ │
│  │  │                      │  │                      │                      │ │
│  │  │ [Use]  [View]        │  │ [Use]  [View]        │                      │ │
│  │  └──────────────────────┘  └──────────────────────┘                      │ │
│  │                                                                           │ │
│  └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### Responsive Behavior

The Event Management UI uses a **hybrid responsive approach** that transforms from horizontal Kanban columns on wide screens to a swimlane card layout on narrow screens.

#### Breakpoint Summary

| Breakpoint | Kanban View | List View | Wizard |
|------------|-------------|-----------|--------|
| Desktop (≥1200px) | 5 horizontal columns | Full table | Side-by-side layout |
| Tablet (992-1199px) | 3 columns + horizontal scroll | Condensed table | Stacked layout |
| Small Tablet (768-991px) | Swimlane cards (vertical) | Condensed table | Stacked layout |
| Mobile (≤767px) | Swimlane cards (compact) | Card view | Full-width steps |

#### Desktop: Full Horizontal Kanban (≥1200px)

All 5 status columns visible side-by-side. Drag-and-drop between columns enabled.

```
┌─────────────────────────────────────────────────────────────────────────────────────┐
│  📅 Event Management                                      [+ Create Event]  ⚙️      │
├─────────────────────────────────────────────────────────────────────────────────────┤
│  [Kanban View] [List View]       🔍 Search...       [Filter ▼]  [Date Range ▼]     │
├─────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                     │
│  ┌─ DRAFT ────┐  ┌─ SCHEDULED ─┐  ┌─ ACTIVE ────┐  ┌─ COMPLETED ┐  ┌─ CANCELLED ┐ │
│  │            │  │             │  │             │  │            │  │            │  │
│  │  ┌──────┐  │  │  ┌──────┐   │  │  ┌──────┐   │  │  ┌──────┐  │  │  ┌──────┐  │  │
│  │  │ Card │  │  │  │ Card │   │  │  │ Card │   │  │  │ Card │  │  │  │ Card │  │  │
│  │  └──────┘  │  │  └──────┘   │  │  └──────┘   │  │  └──────┘  │  │  └──────┘  │  │
│  │  ┌──────┐  │  │  ┌──────┐   │  │  ┌──────┐   │  │            │  │            │  │
│  │  │ Card │  │  │  │ Card │   │  │  │ Card │   │  │            │  │            │  │
│  │  └──────┘  │  │  └──────┘   │  │  └──────┘   │  │            │  │            │  │
│  │            │  │             │  │             │  │            │  │            │  │
│  └────────────┘  └─────────────┘  └─────────────┘  └────────────┘  └────────────┘  │
│                                                                                     │
└─────────────────────────────────────────────────────────────────────────────────────┘
```

#### Tablet: Partial Columns with Scroll (992-1199px)

3 columns visible with horizontal scroll to access remaining columns. Scroll indicators show more content.

```
┌───────────────────────────────────────────────────────────────┐
│  📅 Event Management                    [+ Create]  ⚙️        │
├───────────────────────────────────────────────────────────────┤
│  [Kanban] [List]     🔍 Search...          [Filter ▼]        │
├───────────────────────────────────────────────────────────────┤
│                                                          ▶    │  ← scroll indicator
│  ┌─ DRAFT (3) ────┐  ┌─ SCHEDULED (5) ─┐  ┌─ ACTIVE (2) ──┐  │
│  │                │  │                 │  │               │  │
│  │  ┌──────────┐  │  │  ┌──────────┐   │  │  ┌──────────┐ │  │
│  │  │ 🏷️ Black │  │  │  │ 🎄 Holiday│   │  │  │ 🍂 Fall  │ │  │
│  │  │ Friday   │  │  │  │ Sale     │   │  │  │ Sale     │ │  │
│  │  │ Nov 28   │  │  │  │ Dec 15   │   │  │  │ ● ACTIVE │ │  │
│  │  │ 📦🔔📺💵 │  │  │  │ 📦🔔📺   │   │  │  │ 📦🔔📺💵 │ │  │
│  │  └──────────┘  │  │  └──────────┘   │  │  └──────────┘ │  │
│  │  ┌──────────┐  │  │  ┌──────────┐   │  │               │  │
│  │  │ 🎃 Hallo │  │  │  │ 🎊 New   │   │  │               │  │
│  │  │ ween    │  │  │  │ Year     │   │  │               │  │
│  │  └──────────┘  │  │  └──────────┘   │  │               │  │
│  └────────────────┘  └─────────────────┘  └───────────────┘  │
│                                                               │
│  ◀ COMPLETED (12)  •  CANCELLED (1) ▶                        │  ← hidden columns hint
└───────────────────────────────────────────────────────────────┘
```

#### Small Tablet & Mobile: Swimlane Cards (≤991px)

Transforms to a **single-column vertical layout** with status headers as swimlane dividers. All events visible in one scrollable view, grouped by status.

**Key Features**:
- Status headers are sticky while scrolling within that section
- Collapsed sections show count badge, tap to expand
- "Jump to" floating button for quick navigation between sections
- Cards are full-width for easy touch targets

```
┌─────────────────────────────────────────────┐
│  📅 Event Management        [+]  🔍  ≡     │
├─────────────────────────────────────────────┤
│  [Filter: All ▼]  [Date: All Time ▼]       │
├─────────────────────────────────────────────┤
│                                             │
│  ══════════════════════════════════════════ │
│  ● ACTIVE (2)                          [−] │  ← tap to collapse
│  ══════════════════════════════════════════ │
│                                             │
│  ┌─────────────────────────────────────────┐│
│  │ 🍂 Fall Clearance Sale                  ││
│  │                                         ││
│  │ ● ACTIVE  •  Day 15 of 31              ││
│  │ Oct 1 - Oct 31, 2025                   ││
│  │                                         ││
│  │ 📦 🔔 📺 💵                             ││
│  │                                    [⋮]  ││
│  └─────────────────────────────────────────┘│
│                                             │
│  ┌─────────────────────────────────────────┐│
│  │ 📱 Phone Launch Event                   ││
│  │                                         ││
│  │ ● BUILD UP  •  Starts in 2 days        ││
│  │ Nov 1 - Nov 15, 2025                   ││
│  │                                         ││
│  │ 📦 🔔         ⚠️ 1 conflict             ││
│  │                                    [⋮]  ││
│  └─────────────────────────────────────────┘│
│                                             │
│  ══════════════════════════════════════════ │
│  ○ SCHEDULED (5)                       [+] │  ← collapsed, tap to expand
│  ══════════════════════════════════════════ │
│                                             │
│  ══════════════════════════════════════════ │
│  ○ DRAFT (3)                           [+] │
│  ══════════════════════════════════════════ │
│                                             │
│  ══════════════════════════════════════════ │
│  ✓ COMPLETED (12)                      [+] │
│  ══════════════════════════════════════════ │
│                                             │
│  ══════════════════════════════════════════ │
│  ✗ CANCELLED (1)                       [+] │
│  ══════════════════════════════════════════ │
│                                             │
│         ┌─────────────────────┐             │
│         │ ↑ Jump to section   │             │  ← floating action button
│         └─────────────────────┘             │
│                                             │
└─────────────────────────────────────────────┘
```

#### Expanded Swimlane Section

When user taps to expand a collapsed section:

```
│  ══════════════════════════════════════════ │
│  ○ SCHEDULED (5)                       [−] │  ← now expanded
│  ══════════════════════════════════════════ │
│                                             │
│  ┌─────────────────────────────────────────┐│
│  │ 🎄 Holiday Sale 2025                    ││
│  │                                         ││
│  │ Starts in 45 days                       ││
│  │ Dec 15 - Dec 25, 2025                  ││
│  │                                         ││
│  │ 📦 🔔 📺                                ││
│  │                                    [⋮]  ││
│  └─────────────────────────────────────────┘│
│                                             │
│  ┌─────────────────────────────────────────┐│
│  │ 🏷️ Black Friday 2025                    ││
│  │                                         ││
│  │ Starts in 23 days                       ││
│  │ Nov 28 - Dec 1, 2025                   ││
│  │                                         ││
│  │ 📦 🔔 📺 💵                             ││
│  │                                    [⋮]  ││
│  └─────────────────────────────────────────┘│
│                                             │
│  ┌─────────────────────────────────────────┐│
│  │ 🎊 New Year Blowout                     ││
│  │ ...                                     ││
│  └─────────────────────────────────────────┘│
│                                             │
│  + 2 more events                           │  ← if many events, show "load more"
│                                             │
```

#### Mobile Card Compact Mode (≤480px)

Even more condensed for small phones:

```
┌───────────────────────────────┐
│ 📅 Events         [+] 🔍 ≡   │
├───────────────────────────────┤
│ ● ACTIVE (2)              [−]│
├───────────────────────────────┤
│ ┌───────────────────────────┐│
│ │ 🍂 Fall Clearance Sale    ││
│ │ ● ACTIVE • Oct 1-31       ││
│ │ 📦🔔📺💵              [⋮] ││
│ └───────────────────────────┘│
│ ┌───────────────────────────┐│
│ │ 📱 Phone Launch           ││
│ │ ● BUILD UP • Nov 1-15     ││
│ │ 📦🔔  ⚠️               [⋮] ││
│ └───────────────────────────┘│
├───────────────────────────────┤
│ ○ SCHEDULED (5)           [+]│
├───────────────────────────────┤
│ ○ DRAFT (3)               [+]│
├───────────────────────────────┤
│ ✓ COMPLETED (12)          [+]│
├───────────────────────────────┤
│ ✗ CANCELLED (1)           [+]│
└───────────────────────────────┘
```

#### Swimlane Interaction Behaviors

| Gesture/Action | Behavior |
|----------------|----------|
| Tap section header | Expand/collapse section |
| Tap event card | Navigate to event detail |
| Long-press card | Show quick actions menu |
| Swipe card left | Reveal archive/cancel action (context-dependent) |
| Tap [⋮] menu | Show full actions dropdown |
| Tap "Jump to" FAB | Show section picker overlay |
| Pull down | Refresh events list |

#### Section Default States

| Section | Default State | Rationale |
|---------|---------------|-----------|
| Active | Expanded | Most important - what's happening now |
| Scheduled | Expanded | What's coming up |
| Draft | Collapsed | Work in progress, less urgent |
| Completed | Collapsed | Historical, reference only |
| Cancelled | Collapsed | Rare, usually not needed |

#### CSS Implementation Notes

```css
/* Breakpoint variables */
:root {
  --bp-mobile: 480px;
  --bp-tablet-sm: 768px;
  --bp-tablet: 992px;
  --bp-desktop: 1200px;
}

/* Layout modes */
@media (min-width: 1200px) {
  .event-kanban { display: flex; flex-direction: row; }
  .kanban-column { flex: 1; min-width: 220px; }
}

@media (min-width: 992px) and (max-width: 1199px) {
  .event-kanban { display: flex; overflow-x: auto; }
  .kanban-column { flex: 0 0 300px; }
}

@media (max-width: 991px) {
  .event-kanban { display: block; }  /* Swimlane mode */
  .kanban-column { width: 100%; margin-bottom: 0; }
  .swimlane-header { position: sticky; top: 0; z-index: 10; }
}
```

---

### Accessibility Requirements

| Requirement | Implementation |
|-------------|----------------|
| Keyboard Navigation | Full tab navigation through all interactive elements |
| Screen Reader | ARIA labels on all icons, status badges, and interactive elements |
| Color Contrast | WCAG AA compliance (4.5:1 for text, 3:1 for UI elements) |
| Focus Indicators | Visible focus rings on all interactive elements |
| Status Announcements | ARIA live regions for status changes and notifications |

### Icon Legend Reference

| Icon | Integration | Filled State | Outline State |
|------|-------------|--------------|---------------|
| 📦 | Backstock | Configured & Active | Configured but Inactive |
| 🔔 | SMS Campaigns | Active/Sent | Scheduled |
| 📺 | Digital Signage | Displaying | Configured |
| 💵 | Comeback Cash | Issuing | Configured |
| 📋 | Tasks | Has Active Tasks | Has Completed/Future Tasks |
| 📝 | Notes | Has Notes | No Notes |

## Cross-Cutting Concepts

### Pattern Documentation

```yaml
# Existing patterns used in this feature
- pattern: docs/patterns/psr4-autoloading.md
  relevance: CRITICAL
  why: "All new EventManagement classes must follow PSR-4 autoloading"

- pattern: docs/patterns/namespace-structure.md
  relevance: HIGH
  why: "New classes organized under BuyerKiosk\\EventManagement namespace"

# New patterns created for this feature
- pattern: "Integration Adapter Pattern" (INLINE)
  relevance: CRITICAL
  why: "Standardizes how Event Hub connects to existing systems"

- pattern: "Relative Date Scheduling Pattern" (INLINE)
  relevance: HIGH
  why: "Consistent handling of integration scheduling relative to event dates"
```

### System-Wide Patterns

#### Security

- **Authentication**: UserFrosting session-based auth (existing)
- **Authorization**: Permission-based access control
  - `uri_events` - Read access to events
  - `uri_events_manage` - Write access to events
  - `uri_events_templates` / `uri_events_templates_global` - Template management
  - `uri_events_reports` - Reporting access
- **Store Isolation**: `checkStoreGroup($typeNum)` enforced on all operations
- **Data Protection**: No PII stored in event tables; customer data accessed only via existing systems

#### Error Handling

```php
// Global error handling strategy
class EventManagementException extends \Exception {}
class ValidationException extends EventManagementException {}
class IntegrationException extends EventManagementException {}
class NotFoundException extends EventManagementException {}

// Controller error handling pattern
try {
    $result = $service->operation();
    return json_encode(['success' => true, 'data' => $result]);
} catch (ValidationException $e) {
    return json_encode(['success' => false, 'error' => $e->getMessage()], 400);
} catch (NotFoundException $e) {
    return json_encode(['success' => false, 'error' => 'Not found'], 404);
} catch (IntegrationException $e) {
    $this->log->error("Integration error: " . $e->getMessage());
    return json_encode(['success' => false, 'error' => 'Integration failed'], 500);
}
```

#### Logging & Auditing

- **Audit Trail**: All event changes logged to `event_audit_log`
  - Who: employeeId from session
  - What: action type (created, updated, deleted, activated, cancelled)
  - When: timestamp
  - Details: JSON payload of changes
- **Application Logging**: Existing PHP error logging for system errors
- **Real-time Updates**: Ably broadcasts for client synchronization

### Implementation Patterns

#### Code Patterns and Conventions

```yaml
Naming Conventions:
  - Classes: PascalCase (Event, EventService, BackstockAdapter)
  - Methods: camelCase (getById, createFromTemplate)
  - Database Tables: snake_case (event_integrations, event_audit_log)
  - API Routes: kebab-case (/events/from-template)
  - Constants: UPPER_SNAKE_CASE (EVENT_TYPE_SEASON)

File Organization:
  - Models: Entity classes with DB methods (save, delete, toArray, fromRow)
  - Services: Business logic orchestration
  - Controllers: HTTP request handling, validation, response formatting
  - Adapters: Integration-specific translation layer

Coding Standards:
  - PHP 8.x typed properties and return types
  - Constructor property promotion where appropriate
  - Dependency injection via factory methods
  - Avoid static methods except for factory patterns
```

#### State Management Patterns

```php
// Event lifecycle state management
class Event {
    // Status represents user intent
    private string $status; // draft, scheduled, active, completed, cancelled

    // Phase represents temporal state (auto-calculated)
    private string $phase; // upcoming, build_up, active, wind_down, completed

    // Phase is derived, not stored
    public function getCurrentPhase(): string {
        return $this->calculatePhaseFromDates();
    }

    // Status transitions must be validated
    public function activate(): void {
        if ($this->status !== 'scheduled' && $this->status !== 'draft') {
            throw new ValidationException("Cannot activate event in {$this->status} status");
        }
        $this->status = 'active';
    }
}
```

#### Integration Patterns

```php
// Adapter factory pattern
class IntegrationService {
    private array $adapters = [];

    public function getAdapter(string $type): IntegrationAdapterInterface {
        if (!isset($this->adapters[$type])) {
            $this->adapters[$type] = match($type) {
                'backstock' => new BackstockAdapter($this->db, $this->store),
                'sms_blast', 'sms_trigger' => new SmsAdapter($this->db, $this->store),
                'signage' => new SignageAdapter($this->db, $this->store),
                'comeback_cash' => new ComebackCashAdapter($this->db, $this->store),
                'task' => new TaskAdapter($this->db, $this->store),
                'note' => new NoteAdapter($this->db, $this->store),
                default => throw new \InvalidArgumentException("Unknown adapter: {$type}")
            };
        }
        return $this->adapters[$type];
    }
}

// Fire-and-forget pattern for Ably broadcasts
class EventAbly {
    public function broadcast(string $eventType, array $data): void {
        try {
            $this->ably->channel($this->typeNum)->publish($eventType, $data);
        } catch (\Exception $e) {
            // Log but don't fail the operation
            $this->log->warning("Ably broadcast failed: " . $e->getMessage());
        }
    }
}
```

#### Component Structure Pattern

```php
// Controller structure following existing patterns
class EventApiController {
    private EventService $eventService;
    private IntegrationService $integrationService;
    private $app;

    public function __construct($app) {
        $this->app = $app;
        $factory = new EventManagementFactory($app);
        $this->eventService = $factory->getEventService();
        $this->integrationService = $factory->getIntegrationService();
    }

    // Standard action method structure
    public function createEvent() {
        // 1. Permission check
        if (!$this->app->user->checkAccess('uri_events_manage')) {
            $this->app->notAuthorized();
            return;
        }

        // 2. Store isolation
        $typeNum = $this->app->request->params('typeNum');
        if (!$this->app->user->checkStoreGroup($typeNum)) {
            $this->app->notAuthorized();
            return;
        }

        // 3. Input validation
        $data = $this->validateEventInput($this->app->request->getBody());

        // 4. Business logic via service
        $event = $this->eventService->createEvent($typeNum, $data);

        // 5. Response
        echo json_encode(['success' => true, 'event' => $event->toArray()]);
    }
}
```

#### Data Processing Pattern

```php
// Service layer business logic flow
class EventService {
    public function createEventFromTemplate(
        string $typeNum,
        int $templateId,
        array $overrides
    ): Event {
        // 1. VALIDATE: Input and preconditions
        $template = $this->templateService->getById($templateId);
        if (!$template) {
            throw new NotFoundException("Template not found");
        }

        $this->validateDateRange($overrides['startDate'], $overrides['endDate']);

        // 2. AUTHORIZE: Already handled in controller

        // 3. TRANSFORM: Template to event data
        $eventData = $this->transformTemplateToEvent($template, $overrides);

        // 4. EXECUTE: Business logic with transaction
        $this->db->beginTransaction();
        try {
            $event = Event::create($this->db, $eventData);

            // Create all integrations from template
            $integrations = $this->integrationService->createFromTemplate($event, $template);

            // 5. PERSIST: Audit trail
            $this->auditLog($event->getId(), 'created_from_template', [
                'templateId' => $templateId,
                'integrationCount' => count($integrations)
            ]);

            $this->db->commit();
        } catch (\Exception $e) {
            $this->db->rollBack();
            throw $e;
        }

        // 6. RESPOND: Return complete event
        $event->setIntegrations($integrations);
        $this->ably->broadcast('event.created', ['eventId' => $event->getId()]);

        return $event;
    }
}
```

#### Error Handling Pattern

```php
// Error classification and handling
class EventService {
    public function updateEvent(int $eventId, array $data): Event {
        try {
            $event = $this->getEventById($eventId);
            if (!$event) {
                throw new NotFoundException("Event not found: {$eventId}");
            }

            // Validation errors - user can fix
            if (isset($data['endDate']) && $data['endDate'] < $data['startDate']) {
                throw new ValidationException("End date must be after start date");
            }

            // Business rule errors - conditional
            if ($event->getStatus() === 'completed') {
                throw new ValidationException("Cannot modify completed events");
            }

            // Execute update
            $event->update($this->db, $data);

            // Cascade date changes to integrations
            if (isset($data['startDate']) || isset($data['endDate'])) {
                $this->cascadeDateChanges($event);
            }

            return $event;

        } catch (ValidationException | NotFoundException $e) {
            // Rethrow user-facing errors
            throw $e;
        } catch (\PDOException $e) {
            // Log system errors, return generic message
            $this->log->error("Database error updating event {$eventId}: " . $e->getMessage());
            throw new IntegrationException("Failed to update event. Please try again.");
        }
    }
}
```

### Integration Points

- **Connection Points**:
  - Backstock: Links via `event_integrations.foreignId` → `bsEvents.id`
  - SMS: Creates records in `seller_marketing_blasts` and `seller_marketing_triggers`
  - Signage: Adds entries to `dsLoop` with event dates
  - Comeback Cash: Creates `ccEvents` with earning/redemption windows
  - Tasks: Creates `tasks` with `eventId` FK
  - Notes: Creates `workbook_notes` with `eventId` FK

- **Data Flow**:
  - IN: Event configuration from UI → stored in `events` table
  - OUT: Integration records created in respective system tables
  - SYNC: Date changes cascade via adapters to all linked records

- **Events** (Ably Broadcasts):
  - `event.created` - New event created
  - `event.updated` - Event details changed
  - `event.activated` - Event status set to active
  - `event.cancelled` - Event cancelled
  - `event.phase_changed` - Phase transitioned (cron-triggered)
  - `event.deleted` - Event and integrations removed

## Architecture Decisions

- [x] **ADR-1 Event Hub Architecture**: New Central Event Hub
  - **Choice**: Create a new `events` table as a central entity separate from existing bsEvents
  - **Alternatives Considered**:
    - Extend bsEvents: Would have entangled backstock-specific logic with general event management
    - Distributed events: Each system manages own events - no central coordination
  - **Rationale**: Clean separation allows unified event management without impacting existing backstock functionality. Backstock becomes one integration among many rather than the core.
  - **Trade-offs**: Requires adapter to link new events to existing bsEvents; some data duplication
  - **User confirmed**: ✅ Yes

- [x] **ADR-2 Slide Tagging Prerequisite**: Include in this SDD as Phase 0
  - **Choice**: Add slide tagging capability as Phase 0 of this feature
  - **Alternatives Considered**:
    - Separate project: Would delay event management delivery
    - Skip tagging: Events would need to specify individual slides, not categories
  - **Rationale**: Tag-based slide selection is essential for practical event management. Corporate can create slides tagged "summer-sale" that automatically activate for summer events.
  - **Trade-offs**: Increases scope of this feature; tagging must ship before event signage integration works
  - **User confirmed**: ✅ Yes

- [x] **ADR-3 Integration Coupling**: Tight Coupling with Cascade Delete
  - **Choice**: Event deletion cascades to all linked integrations (backstock events, SMS, slides, tasks, notes, etc.)
  - **Alternatives Considered**:
    - Loose coupling: Preserve integrations when event deleted - would leave orphaned records
    - Selective cascade: Let user choose per-integration - more complex UX
  - **Rationale**: Events are the source of truth for their integrations. Deleting an event should cleanly remove all associated promotional materials.
  - **Trade-offs**: No recovery of integrations after event deletion; must warn user before delete
  - **User confirmed**: ✅ Yes

- [x] **ADR-4 Template Storage**: Global DB for Templates, Store DB for Events
  - **Choice**: Store event templates in central database (`kiosk_buykiosk`), store events in store databases (`kiosk_{typeNum}`)
  - **Alternatives Considered**:
    - All in store DB: Templates couldn't be shared across stores
    - All in central DB: Would violate store isolation pattern
  - **Rationale**: Enables corporate to create global templates that any store can use, while keeping actual event data isolated per store for security and performance.
  - **Trade-offs**: Cross-database queries not possible; templates must be copied to event on creation
  - **User confirmed**: ✅ Implicit (follows existing multi-DB pattern)

- [x] **ADR-5 Phase vs Status Model**: Dual-track lifecycle
  - **Choice**: Events have both a `status` (user intent) and `phase` (temporal state)
  - **Alternatives Considered**:
    - Single field: Would mix user actions with time-based state
    - No phase tracking: Would require recalculating phase on every access
  - **Rationale**: Status captures what the user wants (draft, scheduled, active, cancelled). Phase captures where we are in the event timeline (upcoming, build_up, active, wind_down, completed). Both are needed for proper event management.
  - **Trade-offs**: Two fields to maintain; cron job needed to update phase
  - **User confirmed**: ✅ Implicit (matches bsEvents pattern)

- [x] **ADR-6 Adapter Pattern**: Dedicated adapter per integration type
  - **Choice**: Create separate adapter classes for each integrated system implementing common interface
  - **Alternatives Considered**:
    - Switch statements: Hard to maintain as integrations grow
    - Generic adapter: Would require complex configuration
  - **Rationale**: Each integrated system has unique requirements. Dedicated adapters encapsulate system-specific logic while presenting uniform interface to EventService.
  - **Trade-offs**: More classes to create and maintain; changes to integrated systems may require adapter updates
  - **User confirmed**: ✅ Implicit (standard design pattern)

## Quality Requirements

### Performance

| Metric | Target | Measurement |
|--------|--------|-------------|
| **Dashboard Load** | < 500ms | Time to first meaningful paint |
| **Event List API** | < 200ms | 95th percentile response time |
| **Event Creation** | < 1s | Including up to 6 integrations |
| **Template Application** | < 2s | Full event with all integrations |
| **Integration Cascade** | < 3s | All 6 adapters creating records |
| **Phase Processor** | < 100 events/min | Cron job throughput |

**Caching Requirements**:
- Dashboard metrics cached 5 minutes in Redis
- Event lists cached 1 minute with invalidation on write
- Templates cached 1 hour (rarely change)

### Usability

| Requirement | Specification |
|-------------|---------------|
| **Dashboard Overview** | View all active/upcoming events at a glance |
| **One-Click Templates** | Create fully-configured event from template in ≤3 clicks |
| **Integration Status** | Visual indicators for each integration's status (pending/active/failed) |
| **Date Conflict Warning** | Alert when event dates overlap with existing events of same type |
| **Bulk Operations** | Activate/cancel multiple events at once |
| **Timeline View** | Visual calendar showing event phases and overlaps |
| **Mobile-Friendly** | Dashboard usable on tablet for on-floor access |

### Security

| Requirement | Implementation |
|-------------|----------------|
| **Authentication** | UserFrosting session-based authentication (existing) |
| **Authorization** | Permission-based access control with 5 granular permissions |
| **Store Isolation** | Events only accessible to users with store group access |
| **Audit Trail** | All changes logged with user, timestamp, and details |
| **Input Validation** | Server-side validation of all inputs; XSS prevention |
| **CSRF Protection** | Token validation on all state-changing operations |
| **Data Protection** | No PII stored directly in event tables |

### Reliability

| Requirement | Specification |
|-------------|---------------|
| **Data Integrity** | Transactional operations for event+integration creation |
| **Cascade Safety** | Integration failures roll back entire operation |
| **Graceful Degradation** | Ably failures don't block event operations |
| **Recovery** | Events can be re-activated after cancellation |
| **Idempotency** | Phase processor handles duplicate runs safely |
| **Backup** | Events included in standard database backups |

### Availability

| Metric | Target |
|--------|--------|
| **System Uptime** | 99.5% (follows existing application SLA) |
| **Cron Reliability** | Phase processor runs every hour ± 5 minutes |
| **Real-time Updates** | Ably broadcasts within 2 seconds of change |

## Risks and Technical Debt

### Known Technical Issues

| Issue | Impact | Mitigation |
|-------|--------|------------|
| **Digital signage lacks tagging** | Cannot select slides by category for events | Phase 0 adds tagging prerequisite |
| **SMS blast scheduling is timezone-sensitive** | Scheduled times may shift if store timezone changes | Store timezone at time of scheduling |
| **Comeback Cash event conflicts** | ccEvents already has conflict detection | Integrate with existing conflict check in adapter |
| **Task recurrence complexity** | Existing task recurrence doesn't support event-relative dates | Event tasks are one-time; don't use recurrence |
| **Multi-DB transaction limitations** | Cannot span transaction across central + store DBs | Template copy happens before store transaction |

### Technical Debt

| Debt Item | Severity | Recommendation |
|-----------|----------|----------------|
| **bsEvents tight coupling** | MEDIUM | Current backstock has mixed concerns. Event Management creates clean separation; don't replicate patterns |
| **SMS blast vs trigger distinction** | LOW | Two similar models for different use cases. Keep separate; SMS adapter handles both |
| **LoopItem expiration logic** | LOW | Signage expiration is complex. Adapter should call existing methods, not reimplement |
| **Inconsistent date handling** | MEDIUM | Some tables use DATE, others DATETIME. Event tables use DATE for consistency |
| **No soft delete pattern** | MEDIUM | Most tables use hard delete. Events use hard delete with audit log for recovery info |

### Implementation Gotchas

| Gotcha | Details | How to Handle |
|--------|---------|---------------|
| **Timezone calculations** | Event dates are stored as DATE (no time). Phase calculations must use store timezone. | Always create DateTime with store timezone before comparisons |
| **Build-up can be in past** | If event starts tomorrow with 14-day build-up, build-up started 13 days ago | Phase calculation handles this; integrations scheduled in past execute immediately |
| **Cascade delete order** | FKs with CASCADE may fire before adapter cleanup | Delete via adapters first, then let FK cascade on event delete |
| **Template integration IDs** | Templates store integration *configurations*, not foreignIds | foreignId populated during event creation, not stored in template |
| **Ably channel naming** | Store channel is just `{typeNum}`, not prefixed | Follow existing Ably patterns in codebase |
| **JSON config validation** | Integration configs are JSON blobs - easy to have schema drift | Define and validate config schemas per integration type |
| **Phase vs status confusion** | Users may expect "active" status to mean phase is "active" | UI should clearly separate "Event Status" from "Current Phase" |
| **Cron overlap** | If phase processor takes >1 hour, next run may overlap | Add lock file or use single-instance cron pattern |

### Risks

| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| **R1: Integration complexity** | MEDIUM | HIGH | Build each adapter incrementally; test in isolation before integration |
| **R2: Data migration for existing events** | LOW | MEDIUM | New system is additive; existing bsEvents continue to work standalone |
| **R3: User adoption** | MEDIUM | MEDIUM | Template library with pre-built events lowers adoption barrier |
| **R4: Scope creep** | HIGH | MEDIUM | Clear phase boundaries; defer nice-to-haves to future versions |
| **R5: Performance at scale** | LOW | LOW | Expected volume is modest (10-50 events/store/year); optimize if needed |
| **R6: Integration breakage** | MEDIUM | HIGH | Adapters must not modify integrated system's core behavior; only link data |

### New Technical Debt (Accepted)

| Debt Created | Reason | Future Resolution |
|--------------|--------|-------------------|
| **Dual event systems** | bsEvents continues parallel to new events table | Future: Migrate bsEvents to use Event Hub as source of truth |
| **Template duplication** | Template configs copied to event, not referenced | Acceptable: Events are independent; template changes shouldn't affect existing events |
| **No undo/redo** | Delete is permanent (with audit log) | Future: Add soft delete or archive functionality if needed |

## Test Specifications

### Critical Test Scenarios

**Scenario 1: Create Event from Template**
```gherkin
Given: A user with uri_events_manage permission
And: A global template "Summer Sale" exists with SMS, signage, and task integrations
And: The user has access to store "ou00"
When: The user creates an event from "Summer Sale" template
And: Sets start date to "2025-07-01" and end date to "2025-07-14"
Then: An event is created in the store database
And: An SMS blast is scheduled for June 30 (day -1)
And: Signage slides tagged "summer-sale" are added to the loop
And: A task "Set up Summer Sale display" is created
And: All integrations link back to the event via event_integrations
And: An audit log entry records the creation
And: An Ably broadcast is sent on the store channel
```

**Scenario 2: Event Date Change Cascades**
```gherkin
Given: An active event "Black Friday" with start date "2025-11-28"
And: The event has 3 integrations (backstock, SMS, signage)
When: The user changes the start date to "2025-11-27"
Then: The backstock event's startDate is updated
And: The SMS blast's scheduled_at is recalculated
And: The signage slides' startDate is updated
And: All changes happen in a single transaction
And: An audit log entry records the date change
```

**Scenario 3: Event Deletion Cascade**
```gherkin
Given: An event "Holiday Clearance" with 5 integrations
And: Integrations include: backstock, 2 SMS blasts, signage, and tasks
When: The user deletes the event
Then: A confirmation dialog shows what will be deleted
And: All linked bsEvents records are deleted
And: All linked SMS blasts are cancelled/deleted
And: All linked slides are removed from the loop
And: All linked tasks are deleted (not just unlinked)
And: The event record is deleted
And: Cascade counts are returned to the user
And: An audit log entry records the deletion details
```

**Scenario 4: Phase Transition via Cron**
```gherkin
Given: An event "Spring Sale" with:
  - startDate: tomorrow
  - buildUpDays: 7
  - current phase: "build_up"
When: The phase processor cron runs after startDate
Then: The event phase changes to "active"
And: Any pending integrations for day 0 are activated
And: An Ably broadcast is sent with phase change
```

**Scenario 5: Permission Denied**
```gherkin
Given: A user with only uri_events permission (read-only)
And: The user can view the event dashboard
When: The user attempts to create a new event
Then: A 403 Forbidden response is returned
And: No event is created
And: An access denied message is shown
```

**Scenario 6: Invalid Date Range**
```gherkin
Given: A user creating a new event
When: The user sets end date before start date
Then: A validation error is returned immediately
And: The error message specifies "End date must be after start date"
And: No event is created
And: The user can correct and resubmit
```

**Scenario 7: Integration Failure Rollback**
```gherkin
Given: A user creating an event with signage and SMS integrations
And: The SMS system is temporarily unavailable
When: The event creation is attempted
Then: The event creation fails
And: No partial event record exists
And: No signage changes were made
And: An error message indicates "Failed to create SMS campaign"
And: The user can retry when SMS is available
```

**Scenario 8: Store Isolation**
```gherkin
Given: User A with access to store "ou00"
And: User B with access to store "pa00"
And: An event "Summer Sale" exists in store "ou00"
When: User B attempts to view the event
Then: A 403 Forbidden response is returned
And: The event details are not exposed
```

### Test Coverage Requirements

| Category | Coverage Target | Key Test Areas |
|----------|-----------------|----------------|
| **Business Logic** | 90%+ | Phase calculation, date cascades, template conversion, adapter operations |
| **API Endpoints** | 100% | All event CRUD, integration management, template API |
| **Authorization** | 100% | Permission checks, store isolation, audit logging |
| **Adapters** | 80%+ | Each adapter: create, sync, activate, delete operations |
| **Error Handling** | 100% | Validation errors, integration failures, rollback scenarios |
| **Edge Cases** | Key scenarios | Past dates, overlapping events, empty templates, timezone boundaries |

### Unit Tests

```yaml
EventTest:
  - testPhaseCalculation_UpcomingPhase
  - testPhaseCalculation_BuildUpPhase
  - testPhaseCalculation_ActivePhase
  - testPhaseCalculation_WindDownPhase
  - testPhaseCalculation_CompletedPhase
  - testPhaseCalculation_WithDifferentBuildUpDays
  - testGetBuildUpStartDate
  - testGetWindDownEndDate
  - testStatusTransition_DraftToScheduled
  - testStatusTransition_ScheduledToActive
  - testStatusTransition_ActiveToCancelled
  - testStatusTransition_InvalidTransitionThrows

IntegrationServiceTest:
  - testCalculateIntegrationDate_PositiveRelativeDays
  - testCalculateIntegrationDate_NegativeRelativeDays
  - testCalculateIntegrationDate_ZeroDays
  - testCreateFromTemplate_AllIntegrationsCreated
  - testCreateFromTemplate_TransactionRollbackOnFailure
  - testGetAdapter_ReturnsCorrectAdapterType
  - testGetAdapter_ThrowsOnUnknownType

BackstockAdapterTest:
  - testCreate_CreatesBsEvent
  - testSyncDates_UpdatesBsEventDates
  - testDelete_RemovesBsEvent
  - testActivate_SetsBsEventActive
  - testGetStatus_ReturnsCurrentStatus

SmsAdapterTest:
  - testCreate_Blast_CreatesBlastRecord
  - testCreate_Trigger_CreatesTriggerRecord
  - testSyncDates_RecalculatesScheduledTime
  - testDeactivate_CancelsBlast
  - testDelete_RemovesBlastAndQueue

SlideTagServiceTest:
  - testAddTag_CreatesTagRecord
  - testRemoveTag_DeletesTagRecord
  - testSetTags_ReplacesAllTags
  - testSearchByTags_ReturnsMatchingSlides
  - testSearchByTags_MultipleTagsIntersection
```

### Integration Tests

```yaml
EventApiControllerTest:
  - testListEvents_ReturnsStoreEvents
  - testListEvents_FiltersbyYear
  - testGetEvent_WithIntegrations
  - testCreateEvent_MinimalFields
  - testCreateEvent_WithAllIntegrations
  - testCreateEvent_FromTemplate
  - testUpdateEvent_CascadesDates
  - testDeleteEvent_CascadesIntegrations
  - testActivateEvent_ActivatesIntegrations
  - testCancelEvent_DeactivatesIntegrations

AuthorizationTest:
  - testDenied_WithoutEventPermission
  - testDenied_WrongStoreGroup
  - testAllowed_WithEventManagePermission
  - testAllowed_WithCorrectStoreGroup
  - testTemplateAccess_GlobalRequiresGlobalPermission

SlideTagApiTest:
  - testGetTags_ForSlide
  - testUpdateTags_ReplacesExisting
  - testSearchByTags_StoreSlides
  - testSearchByTags_CorporateSlides
  - testGetAllTags_WithCounts
```

### End-to-End Tests

```yaml
EventWorkflowE2E:
  - testCompleteEventLifecycle:
      1. Create event from template
      2. View on dashboard
      3. Modify dates (verify cascade)
      4. Activate event
      5. Verify integrations active
      6. Wait for phase change (mock time)
      7. Cancel event
      8. Verify integrations cancelled
      9. Delete event
      10. Verify cascade complete

TemplateWorkflowE2E:
  - testTemplateCreationAndUse:
      1. Create store template
      2. Add integrations to template
      3. Create event from template
      4. Verify all integrations populated
      5. Create second event from same template
      6. Verify events are independent
```

---

## Glossary

### Domain Terms

| Term | Definition | Context |
|------|------------|---------|
| **Event** | A promotional period with defined start/end dates that coordinates activities across multiple store systems | Central entity in the Event Hub; not to be confused with JavaScript events |
| **Event Type** | Category of event: season (Spring/Summer/Fall/Winter), holiday, sale, or custom | Used for filtering, templates, and conflict detection |
| **Phase** | Temporal state of an event based on current date: upcoming, build_up, active, wind_down, completed | Auto-calculated; determines what activities are currently relevant |
| **Status** | User-controlled state of an event: draft, scheduled, active, completed, cancelled, archived | Set by user actions; determines if integrations are enabled |
| **Archived** | Soft-deleted state where event is hidden from default views but can be restored | Preserves historical data; integrations deactivated but not deleted |
| **Source Event** | The original event from which a duplicate was created | Tracked via `sourceEventId` FK; enables "run last year's event again" |
| **Conflict** | A scheduling issue that prevents event creation/update (date overlap, resource conflict) | Detected by ConflictChecker; must be resolved before saving |
| **Warning** | A potential issue that doesn't block event creation but should be reviewed | Short build-up period, past dates, overlapping resources |
| **Post-Event Report** | Comprehensive performance analysis generated after an event completes | Includes sales, integrations, YoY comparison |
| **Build-up** | Days before event start when preparation activities occur (default: 14 days) | Tasks, staff notes, and signage may activate during build-up |
| **Wind-down** | Days after event end for cleanup and transition (default: 7 days) | Clearance pricing, final SMS, and task completion |
| **Integration** | A linked record in an external system (backstock, SMS, signage, etc.) controlled by the event | Created via adapters; cascades with event changes |
| **Template** | A reusable event configuration with predefined integrations | Global templates shared across stores; store templates are local |
| **Relative Days** | Scheduling offset from event start date (e.g., -1 = day before, +7 = week after) | Used in templates; converted to actual dates at event creation |
| **Cascade** | Automatic propagation of changes from event to all linked integrations | Date changes cascade; deletion cascades (tight coupling) |
| **Event-Managed Record** | Any record in an integrated system (task, note, slide, SMS, etc.) that has a non-null `eventId` | UI shows badge/indicator; delete warning displayed; links back to parent event |

### Technical Terms

| Term | Definition | Context |
|------|------------|---------|
| **Event Hub** | The central `events` table and EventService that orchestrates all event operations | Core component of the Unified Event Management system |
| **Adapter** | A class implementing IntegrationAdapterInterface that translates event operations to a specific system | BackstockAdapter, SmsAdapter, SignageAdapter, etc. |
| **Integration Service** | Service that manages integration lifecycle across all adapters | Creates, syncs, activates, and deletes integrations |
| **Type Num** | Store identifier pattern like "ou00" or "pa00" | Used for store isolation and database connection |
| **Store DB** | Per-store MySQL database named `kiosk_{typeNum}` | Events and integrations stored here |
| **Central DB** | Shared MySQL database `kiosk_buykiosk` | Templates and global slides stored here |
| **Phase Processor** | Cron job that updates event phases and activates scheduled integrations | Runs hourly via `process-event-phases.php` |
| **Slide Tag** | Keyword label attached to digital signage slides for categorization | Enables tag-based slide selection in events |
| **Calendar Token** | Unique authentication token embedded in iCal feed URLs | Enables calendar app subscription without session auth |
| **iCal Feed** | Standard calendar format export of events for subscription by calendar apps | Token-authenticated; auto-updates when events change |
| **Conflict Checker** | Service that validates event dates and integrations for scheduling conflicts | Runs before create/update; returns conflicts and warnings |
| **Event Duplicator** | Service that creates deep copies of events with all integrations | Preserves relative days; recalculates dates for new period |
| **Report Generator** | Service that compiles post-event performance metrics and exports | Supports PDF, CSV, XLSX formats; includes YoY comparison |

### System Abbreviations

| Abbreviation | Full Form | Context |
|--------------|-----------|---------|
| **bsEvents** | Backstock Events | Existing event system for backstock promotions |
| **ccEvents** | Comeback Cash Events | Promotional coupon event system |
| **dsLoop** | Digital Sign Loop | Table storing slide playback configuration |
| **SMS** | Short Message Service | Text message campaigns via Twilio/Vonage |
| **FK** | Foreign Key | Database relationship constraint |
| **CRUD** | Create, Read, Update, Delete | Standard data operations |
| **ADR** | Architecture Decision Record | Documented architectural decisions |
| **iCal** | iCalendar | Standard format for calendar data interchange (.ics files) |
| **YoY** | Year over Year | Comparison metrics between current and previous year events |

### API Terms

| Term | Definition | Context |
|------|------------|---------|
| **typeNum route param** | Store identifier in URL path: `/:typeNum/events` | All event APIs are scoped to a specific store |
| **Integration Type** | Enum value identifying the target system: `backstock`, `sms_blast`, `sms_trigger`, `signage`, `comeback_cash`, `task`, `note` | Used in `event_integrations.integrationType` |
| **Foreign ID** | The primary key of the linked record in the target system | Stored in `event_integrations.foreignId` |
| **Config JSON** | Integration-specific configuration stored as JSON | Schema varies by integration type |
| **Ably Channel** | Real-time messaging channel for a store (channel name = typeNum) | Used for event update broadcasts |

---

## Appendix A: Future - Centralized Task Orchestrator

> **Note**: This appendix documents a forward-looking architecture requirement identified during the Event Management design. The full orchestrator system will be specified in a **separate dedicated spec (Spec 005)** after Event Management implementation is complete.

### Why This Matters for Event Management

The Event Management system introduces a new scheduled task: **Event Phase Processing**. This task needs to run hourly to:
- Transition events between phases (upcoming → build_up → active → wind_down → completed)
- Activate phase-triggered integrations
- Send phase-change notifications

### Interim Solution (For This Spec)

For the initial Event Management implementation, we will create a **standalone cron script** following existing patterns:

```bash
# Add to crontab
0 * * * * /usr/bin/php /path/to/userfrosting/scripts/process-event-phases.php >> /var/log/event-phases.log 2>&1
```

**Script**: `userfrosting/scripts/process-event-phases.php`
- Processes all stores sequentially
- Updates event phases based on current date
- Activates scheduled integrations
- Logs results to file
- Follows existing script patterns (lock files, error handling)

### Future Orchestrator Requirements (Spec 005)

When we build the centralized orchestrator, it should address these needs identified during Event Management design:

| Requirement | Rationale |
|-------------|-----------|
| **Queue + Worker Pools** | Spawn N specialized workers per task type (SMS, sync, events) |
| **Horizontal Scaling** | Scale workers based on queue depth and load |
| **Task Isolation** | Individual failures don't crash the system |
| **Store Isolation** | Per-store errors don't affect other stores |
| **Dependency Management** | Tasks can depend on other tasks completing first |
| **Conditional Execution** | Only run tasks if store has the required feature/integration |
| **Unified Logging** | Single place to see all scheduled task activity |
| **Alerting** | Notify on failures, timeouts, and unhealthy stores |
| **Admin Dashboard** | Real-time visibility into queues, workers, job status |

### Tasks to Consolidate (Future)

The orchestrator should eventually unify these existing scripts:
- `process-triggers.php` - SMS trigger processing
- `process-sms-queue.php` - SMS queue sending
- `aggregate-store-stats.php` - Statistics aggregation
- `employee-sync.php` - WhenIWork/Homebase sync
- `cc-contact-sync.php` - Constant Contact sync
- `quickbooks-sync-worker.php` - QuickBooks journal entries
- `process-event-phases.php` - **NEW**: Event phase transitions

### Interface Preview

The Event Phase task should be designed to easily migrate to the orchestrator:

```php
// Future-ready task structure
class EventPhaseTask {
    public function execute(?string $typeNum): TaskResult {
        // Process events for a single store
        // Return structured result with metrics
    }

    public function shouldRun(?string $typeNum): bool {
        // Check if store has events feature enabled
    }
}
```

### Reference

When Spec 005 is created, reference this appendix for:
- Initial requirements gathered during Event Management design
- List of existing scripts to consolidate
- High-level architectural direction (queue + worker pools)
- Interface expectations for task implementations
