# Time Safari Architecture — Patterns and Examples

> **Agent role**: Reference this file for architectural patterns and
> examples when working with TimeSafari architecture design.

## Architectural Patterns

### Factory Pattern Implementation

```typescript
// PlatformServiceFactory.ts
export class PlatformServiceFactory {
  private static instance: PlatformServiceFactory;

  static getInstance(): PlatformServiceFactory {
    if (!PlatformServiceFactory.instance) {
      PlatformServiceFactory.instance = new PlatformServiceFactory();
    }
    return PlatformServiceFactory.instance;
  }

  getQRScannerService(): QRScannerService {
    const platform = process.env.VITE_PLATFORM;

    switch (platform) {
      case 'web':
        return new WebInlineQRScanner();
      case 'capacitor':
        return new CapacitorQRScanner();
      case 'electron':
        return new ElectronQRScanner();
      default:
        throw new Error(`Unsupported platform: ${platform}`);
    }
  }
}
```

### Service Interface Definition

```typescript
// interfaces/QRScannerService.ts
export interface QRScannerService {
  startScanning(): Promise<void>;
  stopScanning(): Promise<void>;
  addListener(event: string, callback: Function): void;
  removeListener(event: string, callback: Function): void;
}
```

### Platform-Specific Implementation

```typescript
// services/QRScanner/WebInlineQRScanner.ts
export class WebInlineQRScanner implements QRScannerService {
  private listeners: Map<string, Function[]> = new Map();

  async startScanning(): Promise<void> {
    // Web-specific implementation
    const stream = await navigator.mediaDevices.getUserMedia({ video: true });
    // Process video stream for QR codes
  }

  async stopScanning(): Promise<void> {
    // Stop video stream
  }

  addListener(event: string, callback: Function): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(callback);
  }

  removeListener(event: string, callback: Function): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index > -1) {
        callbacks.splice(index, 1);
      }
    }
  }
}
```

## Deep Linking Implementation

### URL Format

```
timesafari://<route>[/<param>][?query=value]
```

### Web Implementation

```typescript
// router/index.ts
router.beforeEach((to, from, next) => {
  // Parse deep link parameters
  if (to.query.deepLink) {
    const deepLink = to.query.deepLink as string;
    // Process deep link
    handleDeepLink(deepLink);
  }
  next();
});

function handleDeepLink(deepLink: string) {
  // Parse and route deep link
  const url = new URL(deepLink);
  const route = url.pathname;
  const params = url.searchParams;

  // Navigate to appropriate route
  router.push({ name: route, query: Object.fromEntries(params) });
}
```

### Capacitor Implementation

```typescript
// main.capacitor.ts
import { App } from '@capacitor/app';

App.addListener('appUrlOpen', (data) => {
  const url = data.url;
  // Parse deep link and navigate
  handleDeepLink(url);
});
```

## Platform Detection

### Feature Detection vs Platform Detection

```typescript
// ✅ Good: Feature detection
function hasCameraAccess(): boolean {
  return 'mediaDevices' in navigator &&
         'getUserMedia' in navigator.mediaDevices;
}

// ❌ Bad: Platform detection
function isWeb(): boolean {
  return process.env.VITE_PLATFORM === 'web';
}
```

### Conditional Imports

```typescript
// services/platforms/index.ts
export async function getPlatformService() {
  const platform = process.env.VITE_PLATFORM;

  switch (platform) {
    case 'capacitor':
      const { CapacitorPlatformService } =
        await import('./CapacitorPlatformService');
      return new CapacitorPlatformService();
    case 'electron':
      const { ElectronPlatformService } =
        await import('./ElectronPlatformService');
      return new ElectronPlatformService();
    default:
      const { WebPlatformService } =
        await import('./WebPlatformService');
      return new WebPlatformService();
  }
}
```

---

**See also**:

- `.cursor/rules/app/architectural_decision_record.mdc` for core
  architecture principles
- `.cursor/rules/app/architectural_implementation.mdc` for
  implementation details
- `.cursor/rules/app/architectural_examples.mdc` for examples and
  testing patterns

**Status**: Active patterns and examples
**Priority**: Medium
**Estimated Effort**: Ongoing reference
**Dependencies**: architectural_decision_record.mdc,
  architectural_implementation.mdc
**Stakeholders**: Development team, Architecture team

## Model Implementation Checklist

### Before Architectural Patterns

- [ ] **Pattern Selection**: Choose appropriate architectural pattern for the use
  case
- [ ] **Platform Analysis**: Identify platform-specific requirements
- [ ] **Service Planning**: Plan service structure and dependencies
- [ ] **Testing Strategy**: Plan testing approach for the pattern

### During Architectural Patterns

- [ ] **Pattern Implementation**: Implement chosen architectural pattern
- [ ] **Platform Abstraction**: Use platform abstraction layers appropriately
- [ ] **Service Composition**: Compose services using dependency injection
- [ ] **Interface Design**: Provide clear interfaces and contracts

### After Architectural Patterns

- [ ] **Pattern Validation**: Verify pattern is implemented correctly
- [ ] **Platform Testing**: Test across all target platforms
- [ ] **Service Testing**: Test service composition and dependencies
- [ ] **Documentation**: Update architectural patterns documentation
