# Tuner App - Architecture Documentation
## Clean Architecture Diagram
```mermaid
graph TB
subgraph "Presentation Layer"
UI[TunerInterface Component]
Hooks[Custom Hooks
useTuner, useAudioCapture, etc.]
Components[Dumb Components
Button, NoteDisplay, etc.]
end
subgraph "Domain Layer - Pure Business Logic"
Types[types.ts
Core Type Definitions]
NoteConverter[note-converter.ts
Frequency ↔ Note]
TuningCalc[tuning-calculator.ts
Sharp/Flat/InTune Logic]
Instruments[instruments.ts
Instrument Configs]
end
subgraph "Infrastructure Layer - External Services"
AudioCapture[AudioCaptureService
Web Audio API Wrapper]
PitchDetector[PitchDetector
Autocorrelation Algorithm]
Errors[Custom Error Types]
end
subgraph "External APIs"
WebAudio[Web Audio API]
Microphone[Device Microphone]
end
UI --> Hooks
Hooks --> Components
Hooks --> TuningCalc
Hooks --> NoteConverter
Hooks --> Instruments
Hooks --> AudioCapture
Hooks --> PitchDetector
AudioCapture --> WebAudio
WebAudio --> Microphone
TuningCalc --> NoteConverter
TuningCalc --> Types
NoteConverter --> Types
Instruments --> Types
PitchDetector --> Errors
AudioCapture --> Errors
style UI fill:#00bfff,stroke:#0080ff,stroke-width:2px
style Hooks fill:#87ceeb,stroke:#4682b4,stroke-width:2px
style Components fill:#b0e0e6,stroke:#4682b4,stroke-width:2px
style Types fill:#98fb98,stroke:#228b22,stroke-width:2px
style NoteConverter fill:#98fb98,stroke:#228b22,stroke-width:2px
style TuningCalc fill:#98fb98,stroke:#228b22,stroke-width:2px
style Instruments fill:#98fb98,stroke:#228b22,stroke-width:2px
style AudioCapture fill:#ffd700,stroke:#ff8c00,stroke-width:2px
style PitchDetector fill:#ffd700,stroke:#ff8c00,stroke-width:2px
style Errors fill:#ffd700,stroke:#ff8c00,stroke-width:2px
```
## Dependency Flow
The architecture strictly enforces the dependency rule:
```
Presentation → Domain ← Infrastructure
↓ ↓
→ Infrastructure → External APIs
```
### Key Rules
1. **Domain has zero dependencies** - Pure TypeScript, no React, no external libraries
2. **Infrastructure depends on external APIs** - Web Audio API, browser APIs
3. **Presentation depends on both** - Uses hooks to orchestrate domain + infrastructure
4. **Components are pure** - Only receive props, no business logic
## Data Flow Example
User clicks "Start Tuning":
```mermaid
sequenceDiagram
participant User
participant TunerInterface
participant useTuner
participant AudioCapture
participant PitchDetector
participant NoteConverter
participant TuningCalc
User->>TunerInterface: Click "Start"
TunerInterface->>useTuner: start()
useTuner->>AudioCapture: start()
AudioCapture->>Browser: Request mic permission
Browser-->>User: Permission dialog
User-->>Browser: Grant permission
Browser-->>AudioCapture: MediaStream
loop Real-time processing
AudioCapture->>useTuner: Audio samples
useTuner->>PitchDetector: detectPitch(samples)
PitchDetector-->>useTuner: frequency (Hz)
useTuner->>NoteConverter: frequencyToNote(Hz)
NoteConverter-->>useTuner: note {name, octave}
useTuner->>TuningCalc: calculateTuningState()
TuningCalc-->>useTuner: {status, cents, accuracy}
useTuner-->>TunerInterface: Update state
TunerInterface-->>User: Display note & meter
end
```
## Component Composition
The UI is built through composition of small, focused components:
```mermaid
graph TD
TunerInterface[TunerInterface]
TunerInterface --> InstrumentSelector
TunerInterface --> ErrorMessage
TunerInterface --> DisplayPanel[Display Panel]
TunerInterface --> Button
TunerInterface --> StatusIndicator
DisplayPanel --> NoteDisplay
DisplayPanel --> FrequencyDisplay
DisplayPanel --> TuningMeter
style TunerInterface fill:#00bfff,stroke:#0080ff,stroke-width:3px
style InstrumentSelector fill:#87ceeb,stroke:#4682b4
style ErrorMessage fill:#87ceeb,stroke:#4682b4
style DisplayPanel fill:#87ceeb,stroke:#4682b4
style Button fill:#87ceeb,stroke:#4682b4
style StatusIndicator fill:#87ceeb,stroke:#4682b4
style NoteDisplay fill:#b0e0e6,stroke:#4682b4
style FrequencyDisplay fill:#b0e0e6,stroke:#4682b4
style TuningMeter fill:#b0e0e6,stroke:#4682b4
```
## File Organization
```
src/
├── domain/ # 🟢 Pure Logic (Green)
│ ├── types.ts # Type definitions
│ ├── note-converter.ts # Mathematical conversions
│ ├── tuning-calculator.ts # Tuning logic
│ └── instruments.ts # Configuration data
│
├── infrastructure/ # 🟡 External Services (Gold)
│ ├── audio-capture.ts # Microphone access
│ ├── pitch-detector.ts # Signal processing
│ └── audio-errors.ts # Error handling
│
├── presentation/ # 🔵 UI Layer (Blue)
│ ├── hooks/ # Smart - contain logic
│ │ ├── useAudioCapture.ts
│ │ ├── usePitchDetection.ts
│ │ ├── useInstrument.ts
│ │ └── useTuner.ts
│ │
│ └── components/ # Dumb - only presentation
│ ├── Button.tsx
│ ├── FrequencyDisplay.tsx
│ ├── NoteDisplay.tsx
│ ├── TuningMeter.tsx
│ ├── InstrumentSelector.tsx
│ ├── StatusIndicator.tsx
│ ├── ErrorMessage.tsx
│ └── TunerInterface.tsx
│
├── styles/ # Design system
│ └── components.css
│
├── index.css # Frutiger Aero design tokens
├── App.tsx # Root component
└── main.tsx # Entry point
```
## Benefits of This Architecture
### Testability
- Domain logic can be unit tested without React
- Infrastructure can be mocked for testing
- Components can be tested in isolation
### Maintainability
- Clear separation makes changes easier
- Each layer has a single responsibility
- Dependencies flow in one direction
### Scalability
- Easy to add new instruments (just update domain)
- Can swap pitch detection algorithms (infrastructure)
- Can redesign UI without touching logic (presentation)
### Reusability
- Domain logic could be used in a mobile app
- Components can be used in other projects
- Hooks encapsulate reusable behavior