Files
Dansori_EQ/docs/ARCHITECTURE.md
T
eKeerar 117afeec05 Clean up repo: prune non-dev assets, redirect build output, add .gitignore
- Remove old/unneeded material: mockups/, docs/Image (ChatGPT imgs·GIFs),
  character art docs (IMAGE_GEN_*, *.md.old, BRAND_CHARACTERS, CHARACTER_PROFILES),
  asset backups (Characters_OriginalBackup, SourceCandidates),
  unused puppet variants (LeeSoriExtended/Regenerated/Upper/V2/V3), tools/ art scripts
- Keep active assets only: LeeSori + LeeSoriDance puppets, Live2DPreview, Live2DHost, mascot PNGs
- Fix dangling references in kept docs (README, CLAUDE, ARCHITECTURE, TYPOGRAPHY, CHARACTER_UI_INTEGRATION)
- Refresh HANDOFF.md to live state (LeeSoriDance puppet, D:\Project paths)
- Redirect all build output to Build/ via Directory.Build.props (bin+obj)
- Add .gitignore and untrack previously committed bin/obj artifacts

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:39:09 +09:00

173 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ARCHITECTURE
## 1. 기술 스택 (확정)
| 영역 | 선택 | 이유 |
|---|---|---|
| 런타임 | **.NET 8** | 최신 LTS, 네이티브 Windows |
| UI | **WPF + WPF-UI (lepoco)** | Fluent Design System / Mica·다크모드 / WinUI 감성. 텍스트 UI 아님 |
| 차트 | **LiveCharts2** | 애니메이션되는 아름다운 EQ 커브. (대안: ScottPlot=정적·경량) |
| MVVM | **CommunityToolkit.Mvvm** | 소스제너레이터 기반, 보일러플레이트 최소 |
| DB | **SQLite (Microsoft.Data.Sqlite)** | 로컬 프로파일 인덱스 |
| AI | **Anthropic REST (HttpClient)** 또는 `Anthropic.SDK` NuGet | 구조화 출력(tool use) |
| 패키징 | **MSIX 또는 velopack/single-file** | 배포. 라이선스 제외 옵션과 연동 |
> WPF-UI가 Mica 배경 + Fluent 컨트롤 + 다크테마를 제공해 다크·Fluent
> 룩앤필을 네이티브로 재현할 수 있다. 그래프는 LiveCharts2의 `CartesianChart`로 로그 X축(주파수)
> + 선형 Y축(dB), 영역 그라데이션 채우기.
## 2. 컴포넌트 구성
```
DansoriEQ.sln
├─ DansoriEQ.App (WPF, WPF-UI) ── Views/ViewModels, 그래프, 프롬프트 독
├─ DansoriEQ.Core (class lib)
│ ├─ Profiles/ ProfileRepository, AutoEqParser, DbUpdater
│ ├─ Eq/ EqState, Filter(model), ApoRenderer, PreampCalculator
│ ├─ Ai/ ClaudeClient, EqPromptBuilder, EqDeltaSchema
│ └─ Apo/ ApoLocator, ApoConfigInstaller(승격 1회), IncludeWriter
└─ DansoriEQ.Setup (elevated helper, 최초 1회 UAC — 아래 4장)
```
## 3. 데이터 흐름
```
프로파일 선택 → ProfileRepository.Load(id) → EqState(base)
→ ApoRenderer → IncludeWriter.Write(ai_eq.txt) → APO 라이브 리로드 → 그래프 갱신
프롬프트 입력 → EqPromptBuilder(현재 EqState + 헤드폰 메타 + 요청)
→ ClaudeClient(tool use, EqDeltaSchema) → EqDelta(JSON)
→ EqState.Apply(delta) → PreampCalculator → ApoRenderer → IncludeWriter → APO
→ AI 설명 텍스트를 응답 패널에 표시 / 히스토리 스택 push
```
## 4. APO 연동 & 저권한 전략 (중요)
문제: APO의 `config.txt``C:\Program Files\EqualizerAPO\config\` 아래라 쓰기에 승격 필요.
매번 승격은 "저권한" 원칙 위반.
**채택 방식 — "1회 승격 설정, 이후 무승격":**
1. **최초 실행 설정 마법사**(DansoriEQ.Setup, UAC 1회):
- APO 설치 경로 탐지: 레지스트리 `HKLM\SOFTWARE\EqualizerAPO``InstallPath`.
- 사용자 쓰기 가능한 EQ 파일 준비. **권장:** `config` 폴더 내 `ai_eq.txt`를 만들고
**그 파일(또는 폴더)에 현재 사용자 쓰기 ACL 부여**(icacls). 그리고 `config.txt`
`Include: ai_eq.txt` 한 줄 추가(중복 방지 검사).
- 완료 플래그 저장(`%LOCALAPPDATA%\DansoriEQ\setup.json`).
2. **이후 실행**: 앱은 `ai_eq.txt`만 갱신 → **승격 불필요**. APO가 저장 즉시 리로드.
> ⚠️ **M1에서 검증할 스파이크:** APO `Include:`가 절대경로를 허용하는지 확인.
> - 허용 O → `ai_eq.txt`를 `%APPDATA%\DansoriEQ\`에 두고 절대경로 Include(ACL 불필요, 가장 깔끔).
> - 허용 X(상대경로만) → 위 4-1의 config 폴더 내 파일 + ACL 부여 방식으로.
> 두 경로 모두 "1회 승격, 이후 무승격"을 만족. 스파이크 결과로 하나 확정.
APO 필터 문법(렌더 타깃):
```
Preamp: -6.0 dB
Filter 1: ON PK Fc 3000 Hz Gain 3.0 dB Q 1.20
Filter 2: ON LSC Fc 90 Hz Gain 4.0 dB Q 0.70
Filter 3: ON HSC Fc 10000 Hz Gain -1.5 dB Q 0.70
```
- 타입 매핑: PK=peaking, LSC=low-shelf, HSC=high-shelf, (LP/HP 확장 가능).
- **Preamp = -(양의 게인 총합) 또는 최소 -(최대 양의 게인) − 여유 1dB.** 클리핑 방지 필수.
## 5. 프로파일 DB & 라이선스 분리
### 폴더 레이아웃
```
data/
├─ profiles/
│ ├─ open/ ← 재배포 허용(퍼미시브) 소스. 배포 빌드에 포함
│ └─ restricted/ ← 재배포 불가 소스. 배포 빌드에서 제외
├─ manifest.json ← 소스별 {name, license, distributable, url, commit}
└─ dansorieq.db ← SQLite 인덱스(open+restricted 모두 인덱싱)
```
### 원칙
- **수집(개발 중 1회):** AutoEQ repo를 zip/clone로 확보 → 파싱 → 소스 라이선스에 따라
`open/` 또는 `restricted/`로 분류 저장 → SQLite에 upsert.
- **UI:** DB를 조회할 때 **라이선스 구분 없이 병합**해서 보여준다(IEM/헤드폰만 구분).
- **배포:** 패키징 시 `--exclude-restricted` 옵션 → `restricted/` 폴더와 해당 DB 행 제외.
(개인 사용 로컬 빌드는 전체 포함.)
- DB 스키마:
```sql
CREATE TABLE headphone(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
brand TEXT,
type TEXT CHECK(type IN ('iem','headphone')) NOT NULL,
source TEXT, -- 측정/소스명
license TEXT, -- 예: 'CC-BY', 'restricted'
distributable INTEGER, -- 0/1 (UI에선 필터하지 않음)
target TEXT, -- 예: 'Harman IE 2019'
preamp_db REAL,
filters_json TEXT, -- [{type,fc,gain,q}]
raw_text TEXT, -- 원본 ParametricEQ.txt
updated_at TEXT
);
CREATE INDEX ix_hp_type ON headphone(type);
CREATE INDEX ix_hp_name ON headphone(name);
```
### 앱 내 업데이트
- "DB 업데이트" → 최신 소스(zip) 재확보 → 파싱 → **upsert(변경분만)** → manifest commit/날짜 갱신.
- UI 하단에 `N profiles · 최신: YYYY-MM-DD` 표시.
## 6. AI 레이어 스키마 (구조화 출력)
`EqDelta` (Claude가 tool use로 반환):
```json
{
"preamp_db": -6.0,
"filters": [
{ "type": "PK", "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true },
{ "type": "LSC", "fc": 90, "gain": 4.0, "q": 0.7, "enabled": true }
],
"explanation": "보컬 존재감을 위해 3kHz +3dB…",
"replace": false // false=현재 상태에 병합, true=전체 교체
}
```
시스템 프롬프트 요지:
- 역할: 파라메트릭 EQ 전문가. APO 제약(타입 PK/LSC/HSC, Fc 2020000Hz, Gain ±12dB 권장,
Q 0.36) 안에서만 출력.
- 입력으로 **현재 EqState + 헤드폰 모델/타입 + 사용자 요청** 제공 → 요청을 delta로 반영.
- 오디오 상식 힌트(보컬≈2–5kHz, 저음 단단히≈4080Hz 무게+150250Hz 뭉침 컷, 치찰음≈68kHz).
- **Preamp 안전값 계산 규칙 명시.**
- 런타임 모델: 기본 **Claude Sonnet**(요청당 25k 토큰), 옵션으로 Opus.
## 7. 오픈 이슈 → DEV_PLAN 참조
- APO Include 절대경로 허용 여부(스파이크).
- AutoEQ repo 구조/소스 라이선스 최신 상태 확인(수집 스크립트에서).
- 다중 출력 장치별 APO config 타깃팅(고급 옵션, MVP 이후).
## 8. EQ 프리셋 공유 포맷 (.tweq)
사용자가 만든 EQ를 다른 사용자와 공유하기 위한 파일. **JSON**, 확장자 `.tweq`.
```json
{
"format": "dansorieq.eq",
"version": 1,
"app_version": "0.1.0",
"created_utc": "2026-07-01T12:00:00Z",
"author_note": "밝고 보컬 중심 튜닝",
"target": {
"name": "Truthear x Crinacle Zero",
"brand": "Truthear",
"type": "iem",
"source": "AutoEQ",
"target_curve": "Harman IE 2019"
},
"eq": {
"preamp_db": -6.0,
"filters": [
{ "type": "PK", "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true }
]
},
"history": [
{ "role": "user", "text": "보컬 가까이, 저음 단단히", "ts": "..." },
{ "role": "ai", "text": "3kHz +3dB, 180Hz -2.5dB…", "ts": "..." }
]
}
```
- **내보내기**: 현재 EqState + 대상 기기 메타 + 대화 히스토리(간략)를 직렬화해 저장.
- **가져오기**: 검증(format/version, 값 범위 클램프, 크기 상한) → **정보 패널(대상 기기 / 히스토리 / 작성자 노트) 표시** → EQ 적용.
- **라이선스 안전**: 파일엔 측정 데이터가 아니라 **기기 이름/메타만** 포함 → 재배포 문제 없음.
- **보안**: history 텍스트는 **표시 전용**(실행/링크 처리 안 함), 항목 수·길이 상한, API 키 미포함.
## 9. 설정 & Claude API 키 관리
- **별도 설정 화면**(WPF-UI NavigationView: Home/EQ ↔ Settings).
- 섹션: [AI · API 키] / [테마] / [APO] / [데이터베이스].
- **API 키**: 등록 / 삭제 / 교체, "연결 테스트", **DPAPI 암호화 저장**(`%LOCALAPPDATA%\DansoriEQ`).
- **모델 선택**: 기본 Claude Sonnet / 옵션 Opus.
- 키 미등록 시 프롬프트 독 비활성 + 등록 안내.