You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							214 lines
						
					
					
						
							5.5 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							214 lines
						
					
					
						
							5.5 KiB
						
					
					
				
								# 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
							 | 
						|
								
							 |