# 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**
- [x] Component names consistent across diagrams
- [x] A developer could implement from this design

---

## Constraints

**CON-1: Framework & Runtime**
- PHP 8.x runtime required
- Slim 2.6.2 framework integration must be preserved
- Composer 2.x for autoloading
- Existing UserFrosting patterns must continue working

**CON-2: Backward Compatibility**
- All 228 existing include statements must be replaceable
- Legacy class references (e.g., `new Store()`) must work during transition via aliases
- External integrations (QuickBooks, FiveStars, Shopify, Twilio, Vonage, Ably) must remain functional
- Test suite must pass throughout migration

**CON-3: Migration Scope**
- 89 files require namespace changes (58 legacy + 31 inconsistent)
- 160 files already PSR-4 compliant (minimal changes)
- Zero downtime required for production

## Implementation Context

### Required Context Sources

```yaml
# Internal documentation and patterns
- doc: docs/patterns/architecture-overview.md
  relevance: HIGH
  why: "Defines current namespace hierarchy and architectural tiers"

- doc: docs/patterns/namespace-structure.md
  relevance: CRITICAL
  why: "Documents all 20+ BuyerKiosk namespaces that must be preserved"

- doc: docs/patterns/model-patterns.md
  relevance: HIGH
  why: "Documents inheritance hierarchies - Store class has 30+ descendants"

- doc: docs/patterns/controller-patterns.md
  relevance: HIGH
  why: "Documents 63 controllers and their namespace patterns"

# Source code files that must be understood
- file: userfrosting/models/BaseModel.php
  relevance: CRITICAL
  why: "Contains 151 include statements to be eliminated"

- file: userfrosting/initialize.php
  relevance: CRITICAL
  why: "Contains 77 include statements to be eliminated"

- file: userfrosting/composer.json
  relevance: CRITICAL
  why: "PSR-4 autoload configuration must be added here"

- file: userfrosting/models/Class/Store.php
  relevance: CRITICAL
  why: "Base class extended by 30+ domain models - must migrate first"

# External documentation
- url: https://www.php-fig.org/psr/psr-4/
  relevance: HIGH
  why: "PSR-4 autoloading standard specification"
```

### Implementation Boundaries

- **Must Preserve**:
  - All existing class functionality
  - Store-based multi-tenant database connections
  - External API integrations
  - Test suite passing

- **Can Modify**:
  - Namespace declarations in all PHP files
  - composer.json autoload configuration
  - BaseModel.php (remove includes, keep utility functions)
  - initialize.php (remove includes, keep bootstrap)

- **Must Not Touch**:
  - Database schemas
  - External API contracts
  - JavaScript/frontend code
  - Twig templates (except `use` statements if any)

### External Interfaces

#### System Context Diagram

```mermaid
graph TB
    BuyerKiosk[BuyerKiosk Application]

    WebUser[Store Employees] --> BuyerKiosk
    MobileApp[Mobile App] --> BuyerKiosk

    BuyerKiosk --> MySQL[(MySQL Multi-Store DBs)]
    BuyerKiosk --> Redis[(Redis Cache)]
    BuyerKiosk --> Ably[Ably Realtime]
    BuyerKiosk --> Twilio[Twilio SMS]
    BuyerKiosk --> Vonage[Vonage SMS]
    BuyerKiosk --> QuickBooks[QuickBooks API]
    BuyerKiosk --> FiveStars[FiveStars API]
    BuyerKiosk --> Shopify[Shopify API]
    BuyerKiosk --> WhenIWork[WhenIWork API]
```

#### Interface Specifications

```yaml
# Data Interfaces (unchanged by refactor)
data:
  - name: "Multi-Store MySQL"
    type: MySQL
    connection: PDO via dbConnectByName()
    pattern: "kiosk_{typeNum}" per store

  - name: "Redis Cache"
    type: Redis
    connection: Predis client
    pattern: Queue caching, session data

# External APIs (unchanged by refactor)
outbound:
  - name: "Twilio/Vonage SMS"
    namespace: BuyerKiosk\SMS
    status: Already PSR-4 compliant

  - name: "QuickBooks"
    namespace: BuyerKiosk\QuickBooks
    status: Already PSR-4 compliant

  - name: "FiveStars"
    namespace: BuyerKiosk\FiveStars
    status: Already PSR-4 compliant
```

### Project Commands

```bash
# Environment Setup
Install Dependencies: cd userfrosting && composer install
Regenerate Autoloader: cd userfrosting && composer dump-autoload

# Testing Commands
Run All Tests: ./test.sh
Run Verbose: ./test.sh --verbose
Run Specific Test: cd userfrosting && php vendor/bin/phpunit tests/Unit/BuyQueueTest.php

# Deployment
Test + Deploy: ./deploy.sh
```

## Solution Strategy

- **Architecture Pattern**: PSR-4 Autoloading with Feature-Based Namespaces
- **Integration Approach**: Phased migration with class aliases for backward compatibility
- **Justification**:
  - PSR-4 is the PHP-FIG standard, enabling IDE support and static analysis
  - Feature-based namespaces (confirmed by user) align with existing directory structure
  - Class aliases provide safe transition without breaking existing code

- **Key Decisions**:
  1. All classes under `BuyerKiosk\` root namespace
  2. Feature-based sub-namespaces (Workbook, Backstock, Core, etc.)
  3. Deprecated aliases for legacy class names
  4. Store class migrates first (30+ dependents)

## Building Block View

### Components

```mermaid
graph TB
    subgraph "Composer Autoloader"
        PSR4[PSR-4 Autoloader]
    end

    subgraph "BuyerKiosk Namespace"
        Core[BuyerKiosk\Core\]
        Workbook[BuyerKiosk\Workbook\]
        Backstock[BuyerKiosk\Backstock\]
        Employee[BuyerKiosk\Employee\]
        Support[BuyerKiosk\Support\]
        Marketing[BuyerKiosk\SellerMarketing\]
        Integrations[BuyerKiosk\QuickBooks\, SMS\, etc.]
    end

    subgraph "Compatibility Layer"
        Aliases[Class Aliases with Deprecation Warnings]
    end

    PSR4 --> Core
    PSR4 --> Workbook
    PSR4 --> Backstock
    PSR4 --> Employee
    PSR4 --> Support
    PSR4 --> Marketing
    PSR4 --> Integrations
    Aliases -.->|deprecated| Core
```

### Directory Map

**New Directory Structure**:
```
userfrosting/
├── src/                                    # NEW: PSR-4 root
│   └── BuyerKiosk/
│       ├── Core/                           # NEW: Legacy root-level models
│       │   ├── Store.php                   # MOVE from models/Class/
│       │   ├── Buy.php                     # MOVE from models/Class/
│       │   ├── BuyQueue.php                # MOVE from models/Class/
│       │   ├── Customer.php                # MOVE from models/Class/
│       │   ├── Employee.php                # MOVE from models/Class/
│       │   ├── Loyalty/                    # NEW: Group loyalty classes
│       │   │   ├── LoyaltyGroup.php
│       │   │   ├── LoyaltyCustomer.php
│       │   │   └── ...
│       │   ├── Robot/                      # NEW: Group robot classes
│       │   │   ├── Robot.php
│       │   │   ├── TriggerRobot.php
│       │   │   └── ...
│       │   └── Controllers/                # NEW: Core controllers
│       │       ├── AccountController.php   # MOVE from controllers/
│       │       ├── UserController.php
│       │       └── ...
│       ├── Workbook/                       # EXISTING (already namespaced)
│       │   ├── TaskListManager.php
│       │   ├── Note.php
│       │   └── Controllers/
│       │       ├── TasksApiController.php
│       │       └── ...
│       ├── Backstock/                      # EXISTING (already namespaced)
│       ├── Employee/                       # EXISTING (already namespaced)
│       ├── Support/                        # EXISTING (already namespaced)
│       ├── SellerMarketing/                # EXISTING (needs standardization)
│       ├── Cash/                           # EXISTING (already namespaced)
│       ├── QuickBooks/                     # EXISTING (already namespaced)
│       ├── SMS/                            # EXISTING (already namespaced)
│       ├── FiveStars/                      # EXISTING (already namespaced)
│       ├── DigitalSign/                    # EXISTING (already namespaced)
│       ├── DailyReport/                    # EXISTING (already namespaced)
│       ├── Sales/                          # EXISTING (already namespaced)
│       ├── Services/                       # NEW: Standalone services
│       │   └── SalesStatsService.php
│       └── Compatibility/                  # NEW: Alias definitions
│           └── LegacyAliases.php
├── models/                                 # DEPRECATED: Will be empty
│   ├── BaseModel.php                       # MODIFY: Remove includes, keep functions
│   └── Class/                              # DEPRECATED: Files move to src/
├── controllers/                            # DEPRECATED: Will be empty
├── composer.json                           # MODIFY: Add PSR-4 config
└── initialize.php                          # MODIFY: Remove includes, load aliases
```

### Composer.json PSR-4 Configuration

```json
{
  "autoload": {
    "psr-4": {
      "BuyerKiosk\\": "src/BuyerKiosk/"
    },
    "files": [
      "src/BuyerKiosk/Compatibility/LegacyAliases.php",
      "models/BaseModel.php"
    ]
  }
}
```

### Interface Specifications

#### Legacy Alias System

```php
<?php
// src/BuyerKiosk/Compatibility/LegacyAliases.php

namespace BuyerKiosk\Compatibility;

/**
 * Deprecated class aliases for backward compatibility.
 * These emit E_USER_DEPRECATED warnings to guide migration.
 */

// Core domain models
class_alias(\BuyerKiosk\Core\Store::class, 'Store');
class_alias(\BuyerKiosk\Core\Buy::class, 'Buy');
class_alias(\BuyerKiosk\Core\BuyQueue::class, 'BuyQueue');
class_alias(\BuyerKiosk\Core\Customer::class, 'Customer');
// ... additional aliases

// Register deprecation handler
spl_autoload_register(function ($class) {
    $legacyClasses = [
        'Store' => \BuyerKiosk\Core\Store::class,
        'Buy' => \BuyerKiosk\Core\Buy::class,
        // ... mapping
    ];

    if (isset($legacyClasses[$class])) {
        @trigger_error(
            sprintf('Class "%s" is deprecated, use "%s" instead.', $class, $legacyClasses[$class]),
            E_USER_DEPRECATED
        );
    }
}, true, true);
```

#### Data Storage Changes

**No database schema changes required.** This refactor only affects PHP class organization, not data storage.

#### Internal API Changes

**No API endpoint changes.** All routes continue to work; only the internal class loading mechanism changes.

### Implementation Examples

#### Example: Migrating Store Class

**Why this example**: Store is the base class with 30+ dependents - demonstrates the migration pattern.

**Before** (`models/Class/Store.php`):
```php
<?php
// No namespace declaration

class Store {
    protected $typeNum;
    protected $db;

    public function __construct($typeNum) {
        $this->typeNum = $typeNum;
        $this->db = dbConnectByName($this->getDbName());
    }

    public function getDbName() {
        return 'kiosk_' . $this->typeNum;
    }
}
```

**After** (`src/BuyerKiosk/Core/Store.php`):
```php
<?php

namespace BuyerKiosk\Core;

class Store {
    protected string $typeNum;
    protected $db;

    public function __construct(string $typeNum) {
        $this->typeNum = $typeNum;
        $this->db = dbConnectByName($this->getDbName());
    }

    public function getDbName(): string {
        return 'kiosk_' . $this->typeNum;
    }
}
```

#### Example: Updating Dependent Class

**Why this example**: Shows how classes extending Store must be updated.

**Before** (`models/Class/Buy.php`):
```php
<?php

class Buy extends Store {
    public function __construct($typeNum, $buyId) {
        parent::__construct($typeNum);
        $this->loadBuy($buyId);
    }
}
```

**After** (`src/BuyerKiosk/Core/Buy.php`):
```php
<?php

namespace BuyerKiosk\Core;

class Buy extends Store {
    public function __construct(string $typeNum, int $buyId) {
        parent::__construct($typeNum);
        $this->loadBuy($buyId);
    }
}
```

#### Example: Updating Use Statements

**Why this example**: Controllers need updated use statements.

**Before**:
```php
<?php

namespace BuyerKiosk\Workbook;

class TasksApiController {
    public function getTasks($typeNum) {
        $store = new \Store($typeNum);  // Legacy reference
    }
}
```

**After**:
```php
<?php

namespace BuyerKiosk\Workbook\Controllers;

use BuyerKiosk\Core\Store;

class TasksApiController {
    public function getTasks(string $typeNum) {
        $store = new Store($typeNum);  // Namespaced reference
    }
}
```

## Runtime View

### Primary Flow: Class Loading

1. Application bootstrap loads `vendor/autoload.php`
2. Composer PSR-4 autoloader registered
3. Legacy aliases registered via `LegacyAliases.php`
4. When code references `new Store()`:
   - Alias system maps to `BuyerKiosk\Core\Store`
   - Deprecation warning emitted (if enabled)
   - PSR-4 autoloader loads `src/BuyerKiosk/Core/Store.php`
5. Class instantiated normally

```mermaid
sequenceDiagram
    participant App as Application
    participant Composer as Composer Autoloader
    participant Aliases as Legacy Aliases
    participant PSR4 as PSR-4 Loader
    participant File as Class File

    App->>Composer: require 'vendor/autoload.php'
    Composer->>Aliases: Load LegacyAliases.php
    Aliases-->>Composer: Register class_alias mappings

    App->>App: new Store($typeNum)
    App->>Aliases: Resolve 'Store'
    Aliases->>Aliases: Emit deprecation warning
    Aliases->>PSR4: Load BuyerKiosk\Core\Store
    PSR4->>File: Load src/BuyerKiosk/Core/Store.php
    File-->>App: Class loaded
```

### Error Handling

- **Class not found**: Composer autoloader throws standard PHP error with full namespace path
- **Deprecation warning**: Legacy alias usage logs warning (suppressible in production)
- **Migration errors**: Test suite catches any broken references immediately

## Deployment View

### Single Application Deployment

- **Environment**: PHP 8.x web server (Apache/Nginx + PHP-FPM)
- **Configuration**:
  - `composer dump-autoload -o` for optimized autoloader
  - No new environment variables required
- **Dependencies**: Composer autoloader (already in use)
- **Performance**: PSR-4 is faster than current classmap for large codebases

### Deployment Strategy

1. **Pre-deployment**: Run `composer dump-autoload` to regenerate autoloader
2. **Staged rollout**: Deploy to staging, run full test suite
3. **Production**: Standard deployment via `./deploy.sh`
4. **Rollback**: Git revert + `composer dump-autoload`

## Cross-Cutting Concepts

### Pattern Documentation

```yaml
# Existing patterns preserved
- pattern: docs/patterns/model-patterns.md
  relevance: CRITICAL
  why: "Store inheritance pattern must be maintained"

- pattern: docs/patterns/controller-patterns.md
  relevance: HIGH
  why: "Controller naming and routing patterns preserved"

# New patterns created
- pattern: docs/patterns/psr4-autoloading.md (NEW)
  relevance: HIGH
  why: "Documents new autoloading configuration and namespace mapping"
```

### System-Wide Patterns

- **Security**: No changes - authentication/authorization unchanged
- **Error Handling**: Deprecation warnings for legacy class usage
- **Performance**: Improved via PSR-4 vs classmap
- **Logging**: Deprecation warnings logged for monitoring migration progress

### Migration Order Pattern

```
PHASE 1: Infrastructure
  1. Create src/BuyerKiosk/ directory structure
  2. Update composer.json with PSR-4 config
  3. Create LegacyAliases.php compatibility layer

PHASE 2: Base Classes (MUST be first)
  1. Store → BuyerKiosk\Core\Store
  2. Robot → BuyerKiosk\Core\Robot\Robot
  3. LoyaltyGroup → BuyerKiosk\Core\Loyalty\LoyaltyGroup
  4. LoyaltyCustomer → BuyerKiosk\Core\Loyalty\LoyaltyCustomer
  5. Nexmo → BuyerKiosk\Core\Nexmo

PHASE 3: Store Dependents (30+ classes)
  - Buy, BuyQueue, Customer, Employee, CompletedBuys, etc.
  - All classes extending Store

PHASE 4: Inheritance Chains
  - Robot descendants (TriggerRobot, MassSMSRobot, MassSMSFinder)
  - Loyalty descendants (LoyaltyTrigger, LoyaltyCoupon, etc.)
  - Nexmo descendants (sendSMS, receiveSMS)

PHASE 5: Standardize Existing Namespaces
  - Fix UserFrosting\SellerMarketing → BuyerKiosk\SellerMarketing
  - Move generic BuyerKiosk\ to feature namespaces

PHASE 6: Controllers
  - Migrate UserFrosting\ controllers → BuyerKiosk\Core\Controllers
  - Standardize all controller namespaces

PHASE 7: Cleanup
  - Remove includes from BaseModel.php
  - Remove includes from initialize.php
  - Delete empty models/Class/ files
```

## Architecture Decisions

- [x] **ADR-1: Feature-Based Namespaces**
  - Choice: Use `BuyerKiosk\Workbook\`, `BuyerKiosk\Backstock\`, `BuyerKiosk\Core\` etc.
  - Rationale: Aligns with existing directory organization; groups related functionality
  - Trade-offs: Some files move directories; clearer organization long-term
  - User confirmed: ✅ Yes

- [x] **ADR-2: Deprecated Class Aliases**
  - Choice: Provide aliases with deprecation warnings, plan for removal
  - Rationale: Enables gradual migration; prevents breaking existing code
  - Trade-offs: Temporary complexity; requires eventual cleanup
  - User confirmed: ✅ Yes

- [x] **ADR-3: New src/ Directory**
  - Choice: Create `src/BuyerKiosk/` as PSR-4 root, migrate files there
  - Rationale: Clean separation from legacy structure; standard PHP convention
  - Trade-offs: File moves required; clear migration path
  - User confirmed: ✅ (implied by PSR-4 requirement)

- [x] **ADR-4: Store Migrates First**
  - Choice: Migrate Store class before any dependents
  - Rationale: 30+ classes extend Store; must be available for inheritance
  - Trade-offs: Careful ordering required; test after each phase
  - User confirmed: ✅ (technical requirement)

## Quality Requirements

- **Performance**: Autoloader resolution < 1ms per class (PSR-4 standard)
- **Reliability**: 100% test pass rate throughout migration
- **Maintainability**: All classes follow PSR-4 naming conventions
- **Compatibility**: Legacy code works via aliases during transition period

## Risks and Technical Debt

### Known Technical Issues

- **Circular dependency**: Customer ↔ Buy reference each other (handled via autoloader)
- **Duplicate includes**: FiveStars, EmailReportController loaded twice in current code (eliminated by autoloader)

### Technical Debt

- **Legacy aliases**: Must be removed in future release
- **Empty directories**: Old models/Class/ and controllers/ will be empty (remove after verification)

### Implementation Gotchas

- **Load order**: Autoloader handles this, but tests must verify
- **Global functions**: `dbConnectByName()` in BaseModel.php must remain as global function or move to utility class
- **Inheritance chains**: Must migrate parent before child classes

## Test Specifications

### Critical Test Scenarios

**Scenario 1: Autoloader Loads Classes**
```gherkin
Given: Composer autoloader is registered
When: Code instantiates "new \BuyerKiosk\Core\Store('ou00')"
Then: Store class is loaded from src/BuyerKiosk/Core/Store.php
And: Store connects to kiosk_ou00 database
```

**Scenario 2: Legacy Alias Works**
```gherkin
Given: Legacy aliases are registered
When: Code instantiates "new Store('ou00')"
Then: Deprecation warning is emitted
And: BuyerKiosk\Core\Store is loaded
And: Functionality works identically
```

**Scenario 3: Inheritance Chain Works**
```gherkin
Given: Store is migrated to BuyerKiosk\Core\Store
And: Buy extends Store
When: Code instantiates "new \BuyerKiosk\Core\Buy('ou00', 123)"
Then: Buy inherits from Store correctly
And: All Store methods available on Buy
```

**Scenario 4: Existing Tests Pass**
```gherkin
Given: All classes migrated to PSR-4
When: Running ./test.sh
Then: All 31 test files pass
And: No new failures introduced
```

### Test Coverage Requirements

- **Autoloading**: Verify each migrated class loads correctly
- **Aliases**: Verify legacy names resolve to new namespaces
- **Inheritance**: Verify all inheritance chains work
- **Integrations**: Verify external API calls still function
- **Database**: Verify multi-store connections work

---

## Glossary

### Domain Terms

| Term | Definition | Context |
|------|------------|---------|
| TypeNum | Store identifier pattern `[a-z][a-z]\d+` (e.g., `ou00`) | Used to route to store-specific database |
| Store | Multi-tenant store entity | Base class for most domain models |

### Technical Terms

| Term | Definition | Context |
|------|------------|---------|
| PSR-4 | PHP-FIG autoloading standard | Namespace-to-directory mapping convention |
| Class Alias | PHP mechanism to reference class by alternate name | Used for backward compatibility |
| Autoloader | Code that loads class files on demand | Composer provides PSR-4 autoloader |
