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

# 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