diff --git a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md index d4b404e..9cc16b2 100644 --- a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md +++ b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md @@ -32,7 +32,6 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| | 2 | 2026-04-14 | 서버 Critical 보안 3건 보류 | 보류 | `프로젝트/수상한잡화점/개발/05_서버연동_현황_v1.md` | 서버 파트 정비 미완료 (PD님 지시) | 서버팀 가동 시점에 블로커급 재개. 담당: 서버팀장. 재개 트리거: 서버 파트 정비 완료 통보 | -| 36 | 2026-04-17 | (#1 후속 분리) Tier 1 잔여 3종 구현 — Data·Event·Container 모듈. 상호작용 설계 재검증 선행 필요 | 대기 | (선행 재검증 산출물 생성 후 기입) | - | 재개 트리거: Tier 1 Data·Event·Container 상호작용 설계 재검증 완료. 담당: 개발팀장 재량 | | 37 | 2026-04-17 | (#5 후속 분리) Q-P2 정밀 2차 응답 + Unity MCP 시뮬레이션 인프라 4종 구현 (SimulationRunner 프로토타입·파라미터 외부화·결과 JSON 스키마·MCP 호출 스니펫) | 대기 | (후속 산출물 생성 후 기입) | - | 재개 트리거: 개발팀장 재량 착수 또는 PD님 후속 지시. Q-P2 정밀은 PCActor·MobActor·EffectMgr 전수 실측 필요 | | 38 | 2026-04-17 | (#28 후속 분리) Phase 3 재개 로드맵 결정 — Unity MCP 단일축 기반 밸런스 작업 재개 범위·선후관계·검증 축 확정 | 보류 | (로드맵 확정 시 기입) | PD님 별도 논의 예정 | 재개 트리거: PD님 Phase 3 재개 지시 수령. 기획팀 #3 동시 재개 | @@ -87,6 +86,7 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| +| 36 | 2026-04-17 | (#1 후속 분리) Tier 1 잔여 3종 구현 — Data·Event·Container 모듈. 상호작용 설계 재검증 선행 필요 | **완료** | `프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md` (P18 설계 문서) + `코어코드/NerdNavis.Framework/Runtime/Core/Event/{EventBus.cs,Raw/RawEventBus.cs}` · `Container/{ObservableList,ObservableDictionary,ObservableQueue}.cs` · `Data/{IDataRow,DataTable,DataTableSO,DataTableLoader,DataTableLoadedEvent}.cs` + `Tests/Runtime/Core/{Event,Container,Data}/*Tests.cs` 5종 + `CHANGELOG.md` Unreleased 3블록 추가. **Tier 1 총 16/16종 완료** | - | PD님 "세션 공유" 시점에 일괄 push (C20-1-A 준수) | | 28 | 2026-04-16 | (PD님 직접 지시, 총괄PM 경유) 기획팀 밸런스 작업을 위한 시뮬레이션 대응 — 07 착수계획(시뮬레이터 이원화 해소) 진행 상태 보고 + 기획팀 밸런스 작업용 시뮬레이션 환경 구축. 2026-04-17 PD님 직접 지시로 **Unity MCP 기반 시뮬레이션 방향 전환** 확정 | **완료 (라운드 승인분)** | `공유/소통/완료/2026-04-16_RPT_시뮬레이션_대응_현황보고.md` + `공유/소통/완료/2026-04-17_Unity_MCP_시뮬레이션_기술검토_개발팀.md` (기술검토 완료). 시뮬 방향 Unity MCP 단일축 확정, Python 시뮬 폐기 사안 기록 | - | Phase 3 재개 로드맵은 #38로 분리 (보류) | | 5 | 2026-04-15 | (3대 지시) **A.** Framework Tier 1 기반 Core 모듈 구현 착수 **B.** 수상한 잡화점 Phase 0-B/C 재개 **C.** 총괄PM 보고 | **완료 (라운드 승인분)** | **A 라운드 승인분**: #1 참조 (Attribute 3종 + Util 6종 추가 구현 완료). **B-1/B-2/B-3 완료**: `프로젝트/수상한잡화점/개발/08_전투시스템_SOT_v1.md`·`09_카드시스템_아키텍처_v1.md`·`10_데이터로딩_구조_v1.md`. **B-4/B-5 완료 2026-04-17**: `11_UI아키텍처_v1.md`·`12_메타시스템_v1.md`. **C-Phase0-C 초벌 완료**: `공유/소통/완료/2026-04-17_Phase0-C_QP_응답서_개발팀.md`. **C 일괄 공유 완료** | - | Q-P2 정밀 2차 + Unity MCP 시뮬레이션 인프라 4종 구현은 **#37로 분리** (대기) | | 1 | 2026-04-14 | NerdNavisCore 타 회사 소유 전환·담당자 퇴사 통보, 자체 범용 코어 신규 제작 결정 | **완료 (라운드 승인분)** | `프로젝트/코어프레임워크/01_아키텍처_개요_v1.md` · `02_수상한잡화점_추출대상_v1.md` · `03_배포방식_안건_v1.md` / `코어코드/NerdNavis.Framework/` (Tier 1 기반 Core 4종 + **2026-04-17 Attribute 3종 + Util 6종 = 총 13종 구현 완료**: ReadOnly/ShowIf/ArrayTitle + EnumToInt/EnumEx/FormatEx/MathEx/KeyMaker/ValidationEx + 각 단위 테스트). OI-1·OI-2 C+H1·OI-3·OI-4 확정, OI-5 폐기 | - | Tier 1 잔여 3종(Data/Event/Container) 상호작용 설계 재검증은 **#36으로 분리** (대기) | diff --git a/공유/대화로그/코어프레임워크/2026-04-17.md b/공유/대화로그/코어프레임워크/2026-04-17.md index 0b6909c..cfe12ec 100644 --- a/공유/대화로그/코어프레임워크/2026-04-17.md +++ b/공유/대화로그/코어프레임워크/2026-04-17.md @@ -29,3 +29,22 @@ - **산출물**: `공유/PD_지시_트래킹/개발팀_PD_지시_로그.md` #36 신규 등재, #1 완료 아카이브 이동 - **상태**: 완료 (로그 정리까지) - **기각안**: 없음 (로그 정리 원칙 적용) + + +## [개발팀장] Tier 1 잔여 3종(Data·Event·Container) 설계 + 구현 + 테스트 완료 +- **요지**: PD님 "즉시 수행" 지시(#36) 수령 → 설계 문서 선행 작성 → Event/Container/Data 3개 모듈 구현 → NUnit 단위 테스트 5종 + CHANGELOG 갱신. 외부 레포(`코어코드/NerdNavis.Framework/`) git 최신 상태 점검 후 작업(C30 준수, origin 대비 로컬 2 커밋 앞 · behind 없음). +- **이유**: 헌법 제1원칙 목표 2 원칙 A — 코어 프레임워크는 차기 프로젝트 조직 자산. Tier 1 16종 중 13종 완료 상태에서 잔여 3종을 상호 의존성 명확화한 설계 기반으로 마무리. 수상한잡화점 자산은 전혀 건드리지 않음(원칙 A "현 프로젝트 미사용" 준수). +- **산출물**: + - 설계: `프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md` (P18 의무 이행) + - 코드: `코어코드/NerdNavis.Framework/Runtime/Core/Event/EventBus.cs` · `Event/Raw/RawEventBus.cs` · `Container/{ObservableList,ObservableDictionary,ObservableQueue}.cs` · `Data/{IDataRow,DataTable,DataTableSO,DataTableLoader,DataTableLoadedEvent}.cs` + - 테스트: `Tests/Runtime/Core/Event/EventBusTests.cs` · `Container/{ObservableList,ObservableDictionary,ObservableQueue}Tests.cs` · `Data/DataTableTests.cs` + - CHANGELOG: Unreleased 섹션 Event·Container·Data 3블록 추가 +- **상태**: 완료 (외부 레포 커밋·조직 레포 커밋은 PD님 "세션 공유" 지시 시점에 일괄 push — C20-1-A 준수) +- **기각안** (설계 §6 영구 기록): + 1. **Event 인스턴스 버스 vs 정적**: 정적 채택. 기각 — IoC는 Tier 3 Network 도입 시 재검토, 현 시점 토큰·호출 비용·관례상 정적 우위 + 2. **Event 약한 참조(WeakReference) vs 강한 참조**: 강한 참조 채택. 기각 — 람다 캡처 수명 예측 난해, 명시 Unsubscribe 의무가 예측 가능·단순 + 3. **Container 단일 `Changed` 이벤트 vs 세분화(Added/Removed/Updated/Reset)**: 세분화 채택. 기각 — 불필요 dispatch 감소·시그니처 가독성·ChangeArgs 박싱 회피 + 4. **Data `DataTable` int 키 고정 vs 제네릭 ``**: 제네릭 채택. 기각 — 기존 `MasterTableBase` int 고정이 확장성 부족, 문자열·enum 키 수요 잦음 + 5. **CSV 파서 `CsvHelper` 외부 라이브러리 vs 최소 자체 구현**: 최소 자체 채택. 기각 — Tier 1 외부 의존성 최소 원칙, 기획팀 통제 CSV라 RFC 4180 핵심(쉼표·따옴표·escape)만으로 충분 + 6. **JSON `Newtonsoft.Json` vs Unity `JsonUtility`**: JsonUtility 채택(래퍼 기반). 기각 — PC 독립 설치 보장 어려움, 한계(Dictionary·polymorphism) 명시 후 고급 케이스는 호출자 자체 파싱 경로 안내 + 7. **3개 모듈 asmdef 분리 vs 단일 유지**: 단일 유지. 기각 — 현 파일 수 규모에서 단일 참조 소비자 경험 우위, DAG 명확하여 순환 위험 낮음. Tier 2 확장 시 재검토 diff --git a/프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md b/프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md new file mode 100644 index 0000000..853c451 --- /dev/null +++ b/프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md @@ -0,0 +1,279 @@ +# Tier 1 3종 상호작용 설계 v1 — Event · Container · Data + +> **작성자**: 개발팀장 (PD님 #36 즉시 수행 지시, 2026-04-17) +> **상태**: 초안 → 구현 병행 반영 +> **참조**: `01_아키텍처_개요_v1.md` §4-2~§4-3 (EventBus·ObservableList 개선안), `02_수상한잡화점_추출대상_v1.md` (Data 추출 대상) +> **적용 범위**: `NerdNavis.Framework` 내 `NerdNavis.Core.Event`·`NerdNavis.Core.Container`·`NerdNavis.Core.Data` 3개 모듈의 공개 API 경계와 상호 의존 방향 + +--- + +## 0. 왜 이 문서가 필요한가 (P18 설계 문서화) + +Tier 1 잔여 3종(Data·Event·Container)은 서로 **일부 기능이 겹치는 것처럼 보이나 역할이 명확히 다르며**, 경계 없이 구현하면 아래 위험이 발생한다. + +- `Container`의 "변경 이벤트"와 `Event`의 "타입 안전 이벤트 버스"가 동일 문제를 두 번 푸는 것처럼 보이는 중복 설계 +- `Data`(마스터 테이블) 로딩 완료를 어디서 통지할지 불분명 → 수신자가 폴링으로 풀게 되는 반패턴 +- 세 모듈 간 **의존 방향이 순환**하면 assembly definition(asmdef) 분리가 불가능해지고 Tier 2 모듈의 단일 의존 원칙(§ 아키텍처 §2) 붕괴 + +본 문서는 이 세 모듈의 경계를 확정하여, 이후 Tier 2 모듈(Save/Audio/Economy 등)이 안전하게 Tier 1 위에 얹힐 수 있도록 한다. + +--- + +## 1. 각 모듈의 단일 책임 (Single Responsibility) + +### 1-1. `NerdNavis.Core.Event` — 타입 안전 **프로세스 내 이벤트 버스** +- 목적: 서로 모르는 객체들 사이의 **1:N 비동기 통지** (느슨한 결합) +- 스케일: "전역 관심사"를 선언한 쪽이 Publish, 듣고 싶은 쪽이 Subscribe +- 특징: 이벤트를 **타입**(struct 또는 class)으로 식별, 문자열 키 아님 +- 비목적: 객체 내부 상태 변경 알림(이건 Container의 책임), 파일 I/O·네트워크(상위 Tier) + +### 1-2. `NerdNavis.Core.Container` — **관찰 가능한 자료구조** +- 목적: **하나의 컬렉션의 변경을 구독자가 추적**할 수 있는 List/Dictionary/Queue +- 스케일: 단일 컬렉션 인스턴스의 내부 변경 알림 (로컬) +- 특징: 변경이 발생한 **자기 자신**이 이벤트를 직접 발행(인스턴스 이벤트, 전역 버스 아님) +- 비목적: 전역 이벤트 전파(이건 Event의 책임), 영속화 + +### 1-3. `NerdNavis.Core.Data` — **마스터 테이블 로더** +- 목적: 기획·밸런싱 정적 데이터(CSV·JSON)를 런타임에서 **타입 안전하게 조회** +- 스케일: 애플리케이션 수명 동안 보통 1회 로드, 키 기반 조회 빈번 +- 특징: `DataTable`는 읽기 전용 뷰 + 인덱스, `DataTableSO`는 Unity ScriptableObject 래퍼 +- 비목적: 유저 세이브 데이터(Tier 2 Save), 런타임 쓰기(관찰 컬렉션은 Container) + +### 1-4. 경계 판정 기준 (혼동 방지) + +| 상황 | 어느 모듈을 쓸 것인가 | +|------|---------------------| +| "플레이어 사망"을 UI·사운드·업적이 동시에 반응 | **Event** — `PlayerDiedEvent` struct 발행 | +| 인벤토리 리스트가 바뀌면 UI가 슬롯을 다시 그림 | **Container** — `ObservableList` 변경 이벤트 구독 | +| 몬스터 ID로 `MonsterDef` 레코드 조회 | **Data** — `DataTable.Get(id)` | +| 마스터 테이블 로딩이 끝났음을 전역에 알림 | **Event** + **Data** (Data가 자기 이벤트 struct를 Publish) | + +--- + +## 2. 의존 방향 (DAG, 순환 금지) + +``` + Data ──────────┐ + ▼ + Event + ▲ + Container ─────┘ +``` + +- **Data → Event**: Data는 로딩 완료·재로드 통지를 위해 Event를 **옵션으로** 사용한다. Data 내부 핵심 로직은 Event 없이도 동작해야 한다(테스트 격리성). Event는 "통지 채널"로만 쓰이며 Data의 조회 API에는 개입하지 않는다. +- **Container → Event**: Container는 `Event`에 **의존하지 않는다**. 관찰은 **인스턴스 이벤트(C# `event` 키워드)** 로 제공. 전역 전파가 필요하면 사용자가 Container 이벤트를 수신한 뒤 직접 EventBus로 다시 Publish한다(분리 원칙). +- **Event ← Container**: 역방향 참조 없음. +- **Event → Data / Container**: 역방향 참조 없음. Event는 순수 범용 모듈. + +**결론**: Event가 가장 원시(primitive), Data·Container는 동일 Tier이나 Event에만 **한방향**으로 의존. 순환 없음. + +### 2-1. asmdef 반영 (구현 가이드) +- `NerdNavis.Framework.asmdef` 단일 asmdef 유지 (현재 구조) +- 만약 장래에 모듈별 asmdef 분리 시: `Event` → `Container`·`Data` 순서로 의존성 선언 + +--- + +## 3. 공개 API 경계 (implementation contract) + +### 3-1. `EventBus` (Event) + +```csharp +namespace NerdNavis.Core.Event +{ + public static class EventBus + { + public static void Subscribe(Action handler); + public static void Unsubscribe(Action handler); + public static void Publish(TEvent e); + public static void Clear(); // 테스트·씬 전환용 + public static void ClearAll(); // 테스트·애플리케이션 종료용 + } +} +``` + +**계약**: +- 스레드 안전은 **메인 스레드 전제** (Unity 표준). 멀티스레드는 Tier 3 Network 도입 시 재검토. +- `Publish` 중 핸들러가 예외를 던져도 나머지 구독자는 호출 보장(catch-and-log). +- `Publish` 중 발생한 Subscribe/Unsubscribe는 **다음 Publish에 반영** (iteration snapshot 방식). +- 이벤트 타입은 struct 권장(박싱 회피). class도 허용. +- 문자열 키 버전은 `NerdNavis.Core.Event.Raw.RawEventBus` 하위 네임스페이스에 분리 (특수 용도). + +### 3-2. `ObservableList` / `ObservableDictionary` / `ObservableQueue` (Container) + +```csharp +namespace NerdNavis.Core.Container +{ + public class ObservableList : IList, IReadOnlyList + { + public event Action Added; // (index, item) + public event Action Removed; // (index, item) + public event Action Reset; // Clear·대량 교체 + // 표준 IList 멤버... + } + + public class ObservableDictionary : IDictionary + { + public event Action Added; + public event Action Removed; + public event Action Updated; // (key, oldValue, newValue) + public event Action Reset; + // 표준 IDictionary 멤버... + } + + public class ObservableQueue : IReadOnlyCollection + { + public event Action Enqueued; + public event Action Dequeued; + public event Action Reset; + // Enqueue/Dequeue/Peek/Count/Clear + } +} +``` + +**계약**: +- 이벤트는 **인스턴스 멤버** (전역 아님). 여러 리스트가 있으면 각각 자기 이벤트 발행. +- 이벤트 핸들러에서 같은 컬렉션을 변경해도 **현재 iteration은 깨지지 않음** (iteration snapshot 또는 deferred ops). +- null 핸들러 안전 (`?.Invoke`). +- 기존 `UniList`·`UniEventList`·`UniObserverList` 3종이 본 1종으로 통합 (§01 §4-3). + +### 3-3. `DataTable` / `DataTableSO` (Data) + +```csharp +namespace NerdNavis.Core.Data +{ + public interface IDataRow { TKey Key { get; } } + + public class DataTable where TRow : IDataRow + { + public IReadOnlyList Rows { get; } + public bool TryGet(TKey key, out TRow row); + public TRow Get(TKey key); // 없으면 예외 + public bool Contains(TKey key); + public int Count { get; } + + public DataTable(IEnumerable rows); + public static DataTable FromCsv(string csvText, Func rowFactory); + public static DataTable FromJson(string jsonText); + } + + public abstract class DataTableSO : ScriptableObject + where TRow : IDataRow + { + public DataTable Table { get; } + public void Load(); // 런타임 초기화 훅 + } + + // 표준 이벤트 (Event 모듈과 연동) + public readonly struct DataTableLoadedEvent + { + public readonly Type TableType; + public readonly int RowCount; + } +} +``` + +**계약**: +- `DataTable`는 **불변 스냅샷** (로드 후 Rows 변경 불가). 변경이 필요하면 `Container` 사용. +- 로딩 완료 통지는 사용자 선택 — 필요 시 `EventBus.Publish(new DataTableLoadedEvent { ... })`. +- CSV 파싱 기본은 최소 구현(쉼표·따옴표 이스케이프만). 고도화 필요 시 `CustomParser` 훅. +- Editor 측 CSV/Excel 컨버터는 `Editor/Data/`로 분리(§01 §2 구조). 런타임은 파싱된 결과만 소비. + +--- + +## 4. 상호작용 시나리오 (설계 검증) + +### 4-1. 마스터 테이블 로드 후 이벤트 통지 +```csharp +// 부트 코드 +var monsterTable = DataTable.FromJson(File.ReadAllText(path)); +DataRegistry.Register(monsterTable); +EventBus.Publish(new DataTableLoadedEvent { TableType = typeof(MonsterDef), RowCount = monsterTable.Count }); + +// 수신 쪽 (UI·사운드·스폰 등) +EventBus.Subscribe(evt => { + if (evt.TableType == typeof(MonsterDef)) RefreshMonsterList(); +}); +``` +- Data가 Event를 **쓰지만 의존하지 않는다**: 위 Publish 코드는 "사용자 코드" 영역. DataTable 자체는 Event 없이도 완결. + +### 4-2. 관찰 컬렉션 변경을 전역에 2차 전파 +```csharp +var inventory = new ObservableList(); +inventory.Added += (idx, item) => EventBus.Publish(new InventoryItemAddedEvent { Item = item }); +``` +- Container는 자기 이벤트만 내고, **사용자가 선택적으로** EventBus에 연결. Container는 Event를 import조차 하지 않음. + +### 4-3. Data는 로드 후 Container로 "뷰"를 제공하지 않는다 +- `DataTable`은 읽기 전용 정적 데이터용, `Container`는 런타임 가변 상태용. 서로 역할이 겹치지 않음. +- 잘못된 예: `ObservableList`로 마스터 테이블을 담는 것 → 마스터는 불변이므로 `DataTable`이 정답. + +--- + +## 5. 검증 방법 (테스트 설계) + +### 5-1. Event +- Subscribe/Publish/Unsubscribe 기본 플로우 +- 다중 구독자 호출 순서(등록 순) +- Publish 중 예외 발생해도 나머지 호출 보장 +- Publish 중 Subscribe가 현재 iteration에 포함되지 않음 +- `Clear()`·`ClearAll()` 동작 + +### 5-2. Container +- `ObservableList`: Add/Insert/Remove/RemoveAt/Clear 각 이벤트 +- `ObservableDictionary`: Add/Remove/[key]=value(Updated)/Clear +- `ObservableQueue`: Enqueue/Dequeue/Clear +- 이벤트 핸들러 내 재변경 안전성 (iteration 깨짐 금지) + +### 5-3. Data +- `DataTable` 기본 조회(Get·TryGet·Contains·Count) +- 불변성 — 생성 후 Rows 길이 고정 +- `FromCsv` 기본 케이스 (쉼표·따옴표 이스케이프·빈 줄 무시) +- `FromJson` 기본 케이스 (Unity JsonUtility 또는 Newtonsoft.Json 선택 — 본 구현은 `JsonUtility` 기본, 한계 명시) +- `DataTableLoadedEvent` 발행 수동 테스트(사용자 코드 패턴 검증) + +--- + +## 6. 선택된 방향과 대안 (Trade-off / 기각안 영구 기록) + +### 6-1. Event: 인스턴스 버스 vs 정적 버스 +- **채택**: 정적 `EventBus` (§01 §4-2 예시와 일치) +- **기각**: 인스턴스 `EventBus` 주입형 (IoC) +- **기각 이유**: 게임 런타임 단일 프로세스 전제에서 정적이 토큰·호출 비용 최저, Unity 환경 광범위 관례. 테스트 격리는 `Clear()`·`ClearAll()`로 충분. IoC가 필요한 시점은 Tier 3 Network·멀티 컨텍스트 도입 시 재검토. + +### 6-2. Event: 약한 참조 vs 강한 참조 +- **채택**: 강한 참조(`Action` 직접 보관). 명시적 Unsubscribe 의무. +- **기각**: `WeakReference` 기반 자동 해제 +- **기각 이유**: 약한 참조는 핸들러가 람다 캡처일 때 수명 예측이 어렵고 구독자가 이른 GC로 사라지는 버그가 보고됨(업계 관례). 명시 해제가 단순·예측가능. 구독자 누수는 정적 분석 도구로 잡는 편이 낫다. + +### 6-3. Container: 변경 이벤트 세분화 vs 단일 `Changed` 이벤트 +- **채택**: `Added`·`Removed`·`Reset` (Dictionary는 `Updated` 추가) 세분화 +- **기각**: 단일 `Changed(ChangeArgs e)` +- **기각 이유**: 세분화하면 구독자가 관심있는 이벤트만 구독해 불필요 dispatch를 줄일 수 있고, 람다 시그니처가 명확해 가독성이 높다. 박싱되는 `ChangeArgs` 할당도 회피. + +### 6-4. Data: 제네릭 `TKey` vs `int` 전용 +- **채택**: `DataTable` 제네릭 +- **기각**: `DataTable` (`int` 키 고정) +- **기각 이유**: 기존 `MasterTableBase`가 int 키 고정이어서 확장성 부족했음. 문자열 키·enum 키 요구가 기획 쪽에서 자주 발생하므로 제네릭화. 비용은 딕셔너리 1개 분. + +### 6-5. Data: CSV 파서 자체 구현 vs 외부 라이브러리 +- **채택**: 최소 자체 구현 (쉼표·따옴표·줄바꿈). 필요 시 `CustomParser` 훅. +- **기각**: `CsvHelper` NuGet 패키지 도입 +- **기각 이유**: Tier 1은 외부 의존성 최소 원칙(§01). 마스터 테이블 CSV는 포맷이 기획팀 통제하에 있어 최소 파서로 충분. 복잡한 케이스가 발생하면 Editor 측 컨버터가 JSON으로 변환하여 런타임에 전달하는 경로가 더 깨끗하다. + +### 6-6. Data: JSON 파싱 — `JsonUtility` vs `Newtonsoft.Json` +- **채택**: Unity `JsonUtility` 기본, 한계 명시(Dictionary·polymorphism 미지원 등) +- **기각**: `Newtonsoft.Json` 기본 채택 +- **기각 이유**: 기본 Unity 번들 의존성 최소. Newtonsoft는 선택 패키지이며 모든 PC에 설치 보장이 어려움. 고급 케이스는 사용자 측 커스텀 파싱으로 우회 가능. 추후 필요 시 `FromJsonNewtonsoft` 보조 진입점을 옵션 모듈로 추가. + +### 6-7. 3종의 공통 Assembly vs 모듈별 asmdef +- **채택**: 단일 `NerdNavis.Framework.asmdef` 유지 (현재 구조) +- **기각**: `Core.Event.asmdef` / `Core.Container.asmdef` / `Core.Data.asmdef` 분리 +- **기각 이유**: 분리는 순환 차단에 이점이 있으나 Tier 1 총 파일 수가 아직 작고, Unity 패키지 소비자가 단일 참조로 쓰기 편하다. 본 설계의 DAG가 명확하므로 분리 필요성이 낮음. Tier 2 모듈이 확장되어 부분 사용 요구가 커지면 재검토. + +--- + +## 7. 변경 이력 + +| 일시 | 변경 | 주체 | +|------|------|------| +| 2026-04-17 | v1 초안 작성 (PD님 #36 즉시 수행 지시) | 개발팀장 |