# Time Safari Architecture — Examples and Testing

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

## Error Handling Patterns

### Global Error Handler

```typescript

// main.ts
app.config.errorHandler = (err, instance, info) => {
  const componentName = instance?.$options?.name || 'Unknown';
  logger.error(`[${componentName}] Vue error`, err, info);
};

window.addEventListener('unhandledrejection', (event) => {
  logger.error('[Global] Unhandled promise rejection', event.reason);
});

```

### Platform-Specific Error Wrapping

```typescript

// services/platforms/CapacitorPlatformService.ts
export class CapacitorPlatformService {
  async getFileContents(path: string): Promise<string> {
    try {
      const result = await Filesystem.readFile({
        path: path,
        encoding: 'utf8'
      });
      return result.data;
    } catch (error) {
      logger.error('[Capacitor API Error] Failed to read file', error, path);
      throw new Error(`Failed to read file: ${path}`);
    }
  }
}

```

## Testing Patterns

### Platform-Specific Test Skipping

```typescript

// tests/QRScanner.test.ts
describe('QRScanner Service', () => {
  test('should start scanning on web', async () => {
    test.skip(process.env.VITE_PLATFORM !== 'web', 'Web-only test');

    const scanner = new WebInlineQRScanner();
    await scanner.startScanning();
    // Assert scanning started
  });

  test('should start scanning on mobile', async () => {
    test.skip(process.env.VITE_PLATFORM !== 'capacitor', 'Mobile-only test');

    const scanner = new CapacitorQRScanner();
    await scanner.startScanning();
    // Assert scanning started
  });
});

```

### Mock Service Testing

```typescript

// tests/mocks/QRScannerMock.ts
export class QRScannerMock implements QRScannerService {
  private isScanning = false;
  private listeners: Map<string, Function[]> = new Map();

  async startScanning(): Promise<void> {
    this.isScanning = true;
    this.emit('scanningStarted');
  }

  async stopScanning(): Promise<void> {
    this.isScanning = false;
    this.emit('scanningStopped');
  }

  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);
      }
    }
  }

  private emit(event: string, ...args: any[]): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      callbacks.forEach(callback => callback(...args));
    }
  }

  getScanningState(): boolean {
    return this.isScanning;
  }
}

```

## Integration Examples

### Service Composition

```typescript

// services/QRScannerService.ts
export class QRScannerService {
  constructor(
    private platformService: PlatformService,
    private notificationService: NotificationService
  ) {}

  async startScanning(): Promise<void> {
    try {
      await this.platformService.startCamera();
      this.notificationService.show('Camera started');
    } catch (error) {
      this.notificationService.showError('Failed to start camera');
      throw error;
    }
  }
}

```

### Component Integration

```typescript

// components/QRScannerDialog.vue
export default class QRScannerDialog extends Vue {
  @Inject() private qrScannerService!: QRScannerService;

  async mounted() {
    try {
      await this.qrScannerService.startScanning();
    } catch (error) {
      this.$notify.error('Failed to start scanner');
    }
  }

  beforeDestroy() {
    this.qrScannerService.stopScanning();
  }
}

```

## Best Practices

### Service Design

- Keep services focused and single-purpose

- Use dependency injection for service composition

- Implement proper error handling and logging

- Provide clear interfaces and contracts

### Testing Strategy

- Test platform-specific behavior separately

- Use mocks for external dependencies

- Test error conditions and edge cases

- Validate service contracts and interfaces

### Error Handling

- Log errors with appropriate context

- Provide user-friendly error messages

- Implement graceful degradation

- Handle platform-specific error scenarios

---

**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_patterns.mdc` for core patterns

**Status**: Active examples and testing guide
**Priority**: Medium
**Estimated Effort**: Ongoing reference
**Dependencies**: architectural_patterns.mdc
**Stakeholders**: Development team, Testing team

## Model Implementation Checklist

### Before Architectural Examples

- [ ] **Pattern Selection**: Choose appropriate architectural pattern for the use
  case
- [ ] **Service Design**: Plan service structure and dependencies
- [ ] **Testing Strategy**: Plan testing approach for the example
- [ ] **Error Handling**: Plan error handling and logging strategy

### During Architectural Examples

- [ ] **Service Implementation**: Implement focused, single-purpose services
- [ ] **Dependency Injection**: Use proper dependency injection patterns
- [ ] **Error Handling**: Implement proper error handling and logging
- [ ] **Interface Design**: Provide clear interfaces and contracts

### After Architectural Examples

- [ ] **Testing Execution**: Test platform-specific behavior separately
- [ ] **Service Validation**: Validate service contracts and interfaces
- [ ] **Error Testing**: Test error conditions and edge cases
- [ ] **Documentation**: Update architectural examples documentation
