# BurningTimes 신규 범용 코어 — 아키텍처 설계안

> **작성일**: 2026-04-14
> **작성자**: 개발실장
> **상태**: PD님 결정(네임스페이스 `BurningTimes.*`, MVP=Tier1+2) 반영 v1.2
> **적용 대상**: 이전 프로젝트 **이후** 프로젝트 (현 프로젝트에는 미적용)

---

## 1. 프로젝트 정체성

| 항목 | 값 | 비고 |
|------|-----|------|
| **정식 명칭** | `BT.Framework` | PD님 확정 ✅ (2026-04-14) |
| **UPM 패키지 이름** | `com.nerdnavis.framework` | PD님 확정 ✅ (2026-04-14) |
| **루트 네임스페이스** | `BurningTimes` | PD님 확정 ✅ |
| **Unity 호환** | 6000.0.x (Unity 6 LTS) 이상 | 이전 프로젝트 환경 기준 |
| **API 호환성** | .NET Standard 2.1 | |
| **저장소** | PD님 NAS Git (세부 논의 대기) | ①②④ 완료 후 확정 예정 |
| **첫 적용 프로젝트** | 이전 프로젝트의 **다음** 프로젝트 | |

## 2. 네임스페이스 체계

```
BurningTimes                         루트 (공용 인터페이스, 공용 enum)
│
├── BurningTimes.Core                코어 시스템
│   ├── Patterns                  싱글톤·옵저버·오브젝트풀·팩토리
│   ├── Container                 ObservableList/Dictionary/Queue 등
│   ├── Coroutine                 코루틴 러너
│   ├── Event                     이벤트 버스 (타입 안전)
│   ├── Data                      마스터 테이블·CSV 로더
│   ├── Util                      Math/Validation/Formatter/KeyMaker/Rate/Style
│   ├── Attribute                 ReadOnly/ShowIf/ArrayTitle
│   └── Optimization              EnumString/ScopedValue 등
│
├── BurningTimes.UI                  UI 프레임워크
│   ├── UGUI                      UGUI 기반 (이전 프로젝트 경험 반영)
│   ├── UIToolkit                 UI Toolkit 기반 (기존 코어 계승)
│   ├── Components                SafeArea/FitLabel/Layout
│   └── Extensions
│
├── BurningTimes.Save                [Tier 2] 세이브/로드 시스템
├── BurningTimes.Localization        [Tier 2] 로컬라이제이션
├── BurningTimes.Audio               [Tier 2] 오디오 매니저
├── BurningTimes.Addressable         [Tier 2] Addressable 래퍼
├── BurningTimes.Economy             [Tier 2] 재화 모델 (Goods) — PD님 지시로 Tier 2 이관
│
├── BurningTimes.Network             [Tier 3] (서버팀 셋업 이후)
├── BurningTimes.Security            [Tier 3] (서버팀 셋업 이후)
│
└── BurningTimes.Editor              에디터 도구
    ├── Build                     빌드 자동화
    ├── Hierarchy                 계층창 개선
    ├── Data                      CSV/Excel 컨버터
    └── Symbols                   컴파일 심볼 관리
```

## 3. 네이밍 재작성 매핑표 (IP 회피 필수)

기존 코드 **구조·로직 재사용 허용**, **네이밍·식별자는 반드시 재작성**.

### 네임스페이스
| 기존 | 신규 |
|------|------|
| `DG.Core` | `BurningTimes.Core` |
| `DG.Util` | `BurningTimes.Core.Util` |
| `DG.Util.Container` | `BurningTimes.Core.Container` |
| `DG.UI` | `BurningTimes.UI` |
| `DG.Manager` | `BurningTimes.Core.Event` (→ EventBus로 재설계) |
| `DG.OutGame` | `BurningTimes.Core.Goods` (Goods만 분리) |
| `DG.Editor` | `BurningTimes.Editor` |
| `DG.Core.Tool` | `BurningTimes.Editor.Data` |

### 클래스
| 기존 | 신규 | 사유 |
|------|------|------|
| `UniList<T>` | `ObservableList<T>` | 표준 .NET 용어 |
| `UniDictionary<K,V>` | `ObservableDictionary<K,V>` | |
| `UniQueue<T>` | `ObservableQueue<T>` | |
| `UniEventList<T>` | (통합 제거) | `ObservableList`에 옵저버 기능 통합 |
| `UniObserverList<T>` | (통합 제거) | 동상 |
| `UniEventQueue<T>` | (통합 제거) | `ObservableQueue`로 통합 |
| `UniObserverQueue<T>` | (통합 제거) | 동상 |
| `UniDoubleArray<T>` | `Grid2D<T>` | 이름 직관화 |
| `UniPair<A,B>` | (제거) | .NET `ValueTuple` 사용 권장 |
| `UniRange` | `NumRange` | 직관성 |
| `UniEnumValue` | `EnumLookup` | |
| `UniGroup` | `Group<T>` | |
| `BoostController` | `BuffController` | 게임 업계 표준 용어 |
| `Boost`, `BoostElement` | `BuffEntry`, `BuffDefinition` | |
| `SchedulHandler` | `TaskScheduler` (네임 충돌 시 `GameScheduler`) | 오탈자 수정 |
| `ObserverManager` | `EventBus` | 현대 네이밍 + 타입 안전 재설계 |
| `MyHierarchyHeader` | `HierarchyHeader` | `My` 접두사 제거 |
| `MyHierarchyGroup` | `HierarchyGroup` | |
| `MyHierarchySettings` | `HierarchySettings` | |
| `Toolkit.*` | (분할 유지, 네임 변경) `MathEx`, `ValidationEx`, `FormatEx`, `KeyMaker`, `RateRoller`, `StyleEx` | 부분 클래스 의존 축소 |
| `CoroutineHandler` + `CoroutineRunner` | `CoroutineRunner` 단일화 | 2개 분리 이유 불명, 통합 |
| `Singleton<T>`, `AsyncSingleton<T>`, `InnerSingleton<T>`, `ReadySingleton<T>` | **통합 → `MonoSingleton<T>`** + 옵션 플래그 | 4종 분산의 유지보수 부담 해소 |
| `WaitCahe` | `WaitCache` | **오탈자 수정** |
| `MasterTableBase`, `MasterTableSO` | `DataTable`, `DataTableSO` | 네이밍 일관성 |
| `CustomParserBase` | `CustomParser` | `Base` 접미사 제거 (추상은 abstract 키워드로 충분) |
| `GachaGradeInfo`, `GachaTracker` | `GachaGrade`, `PityTracker` | `Info` 접미사 제거, 천장 기능 명확 |
| `RegistUIHelper`, `ShowHideRegistUI` | `UIRegistry`, `UIVisibilityToggle` | 오탈자(Regist→Register) + 역할 명시 |

## 4. 기존 코드 구조적 개선점 (PD님 지시: "더 효율적으로 변형" 반영)

### 4-1. 싱글톤 4종 통합 → `MonoSingleton<T>` + 옵션
**문제**: 기존에는 `Singleton`, `AsyncSingleton`, `InnerSingleton`, `ReadySingleton` 4개가 각기 존재해 사용자가 어느 것을 써야 하는지 혼란.

**개선안**:
```csharp
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    [SingletonOption(Persistent = true, AutoCreate = true, InitMode = InitMode.Sync)]
    public static T Instance { get; }
}
```
- `Persistent`: `DontDestroyOnLoad` 여부
- `AutoCreate`: 인스턴스 없을 때 자동 생성 여부
- `InitMode`: `Sync` / `Async` / `ManualReady`
- 쓰레드 안전은 내부 표준 제공, 사용자 선택 필요 없음

### 4-2. ObserverManager → EventBus (타입 안전 재설계)
**문제**:
- 문자열 키 기반 → 오타·컴파일 검증 불가
- `object data` 전달 → 박싱·언박싱 비용
- `GenerateItemTypeKey(ItemType, int)` 같은 **프로젝트 특화 키 생성기가 코어에 존재** → C11 오염

**개선안**:
```csharp
public static class EventBus
{
    public static void Subscribe<TEvent>(Action<TEvent> handler);
    public static void Unsubscribe<TEvent>(Action<TEvent> handler);
    public static void Publish<TEvent>(TEvent e);
}
// 사용 예
EventBus.Subscribe<PlayerDiedEvent>(OnPlayerDied);
EventBus.Publish(new PlayerDiedEvent { PlayerId = 42 });
```
- 이벤트를 **타입으로 식별** → 컴파일 타임 안전
- `GenerateItemTypeKey` 등 프로젝트 특화 키는 **전부 제거** (프로젝트 쪽에서 이벤트 struct로 정의)
- 문자열 키 버전은 `EventBus.Raw` 하위 네임스페이스로 분리 (특수 용도만)

### 4-3. 컨테이너 2종 체계 단순화
**문제**: `UniList` / `UniEventList` / `UniObserverList` 3종이 나뉘어 "언제 어느 것?" 혼란.

**개선안**:
- `ObservableList<T>` 하나로 통합
- 이벤트(`OnAdd`, `OnRemove`, `OnChange`, `OnClear`)는 기본 제공
- 옵저버가 필요 없을 때는 표준 `List<T>` 사용하면 됨 (원래 그랬어야 함)
- Dictionary/Queue도 동일 단순화

### 4-4. CoroutineHandler + CoroutineRunner 통합
**문제**: 2개가 분리된 이유가 README·코드 주석에도 없음.

**개선안**:
- `CoroutineRunner` 하나로 통합
- 일시정지·재시작·중복방지·키 기반 식별 전부 단일 API로
- 향후 UniTask 지원 여부는 별도 결정(외부 의존성)

### 4-5. `DG.OutGame/Goods.cs`, `RegistUIHelper`, `ShowHideRegistUI` 위치 재검토
**문제**: `OutGame` 네임스페이스가 코어에 있는데 내용은 사실상 UI 레지스트리 + 재화 모델. 게임 특화인지 범용인지 애매.

**결정 (PD님 확정 ✅ 2026-04-14)**:
- `Goods`는 **Tier 2로 이관** → `BurningTimes.Economy.Goods`
- `RegistUIHelper` → `UIRegistry` 로 `BurningTimes.UI` 하위 이동 (Tier 1 유지)
- `ShowHideRegistUI` → `UIVisibilityToggle` 로 `BurningTimes.UI` 하위 이동 (Tier 1 유지)

### 4-6. Boost 시스템 재설계 (Buff 표준화)
**문제**: "Boost"는 모바일 광고/강화 뉘앙스 → 범용 게임 프레임워크로서 부적절.

**개선안**:
- `BuffSystem` 으로 재명명 + 재설계
- 시간·스택·중첩 정책·가산/승산/치환 정책 명시적 enum화
- `IModifier<T>` 인터페이스 기반 → 게임 스탯 시스템과 쉽게 결합

### 4-7. Toolkit.* 부분 클래스 해체
**문제**: 기존 `Toolkit.Math.cs`, `Toolkit.Rate.cs`, `Toolkit.Formatter.cs` 등은 전부 `partial class Toolkit`. 단일 진입점은 편하지만, **IDE 자동완성이 수백 개 메서드 노출** → 탐색 저하.

**개선안**:
- 부분 클래스 해체: `MathEx`, `RateRoller`, `FormatEx`, `KeyMaker`, `ValidationEx`, `StyleEx` 각각 독립 static 클래스
- using static 가능, 카테고리별 명확한 진입점

### 4-8. WaitCahe 오탈자 수정
**문제**: 파일명·클래스명 모두 `WaitCahe` (Cache 오탈자). 기존 사용처 그대로 따라감.

**개선안**: `WaitCache` 로 수정. (재작성이므로 기회 활용)

### 4-9. ServiceLocator 신설 (v1.2 추가, PD님 지시 2026-04-14)
**배경**: PD님께서 Tier 1 구현 지시 시 Logger·ServiceLocator·CoroutineRunner 3종을 기반 Core로 명시. 기존 설계에는 ServiceLocator 개념이 없었고 "MonoSingleton + EventBus" 2축으로만 서비스 접근을 해결하려 했음.

**설계 판단**:
- **MonoSingleton** = 씬 생명주기와 동기화되는 `MonoBehaviour` 단일 인스턴스 (Update/OnDestroy 훅 필요한 서비스)
- **ServiceLocator** = 순수 C# 서비스 레지스트리 (MonoBehaviour 아님, 인터페이스 바인딩·테스트 대체 용이)
- **EventBus** = 타입 안전 이벤트 분기 (Pub/Sub)

세 축은 역할이 분리되어 공존한다. ServiceLocator는 "안티패턴" 비판이 있으나 경량 DI 컨테이너 대체로서 **(1) 테스트 시 Mock 주입 가능 (2) 인터페이스 기반 느슨한 결합 (3) 기동 순서 제어 용이** 이점이 있다.

**개선안**:
```csharp
public static class ServiceLocator
{
    public static void Register<T>(T service) where T : class;
    public static void Register<T>(Func<T> factory) where T : class; // Lazy
    public static T Resolve<T>() where T : class;
    public static bool TryResolve<T>(out T service) where T : class;
    public static void Unregister<T>() where T : class;
    public static void Clear(); // 테스트용
}
// 사용 예
ServiceLocator.Register<ISaveProvider>(new JsonSaveProvider());
var save = ServiceLocator.Resolve<ISaveProvider>();
```

**주의 규칙**:
1. 인터페이스 타입으로만 등록·조회 권장 (구체 타입 바인딩은 결합도 상승)
2. 씬 전환 시 scope 고려 — 글로벌 서비스만 등록, 씬 서비스는 `MonoSingleton` 사용
3. `Resolve` 실패 시 `ServiceNotRegisteredException` 발생 (silent null 금지)
4. 코어 자체는 ServiceLocator에 의존하지 않음 (순환 의존 방지)

## 5. Tier 1 모듈 목록 (MVP 필수)

| 영역 | 네임스페이스 | 기존 코드 기반 여부 | 비고 |
|------|-------------|-------------------|------|
| 싱글톤 | `BurningTimes.Core.Patterns` | ✅ 4종 통합 (4-1) | `MonoSingleton<T>` + 옵션 |
| **서비스 로케이터** | `BurningTimes.Core.Patterns` | 🔴 신규 (4-9) | `ServiceLocator` — PD님 지시 v1.2 추가 |
| 이벤트 버스 | `BurningTimes.Core.Event` | 🟡 재설계 (4-2) | 타입 안전 |
| 옵저버 컨테이너 | `BurningTimes.Core.Container` | 🟡 단순화 (4-3) | |
| 코루틴 | `BurningTimes.Core.Coroutine` | 🟡 통합 (4-4) | |
| 오브젝트풀 | `BurningTimes.Core.Patterns` | ✅ 거의 그대로 | `ObjectPool<T>` |
| 팩토리 | `BurningTimes.Core.Patterns` | ✅ 거의 그대로 | |
| 로깅 | `BurningTimes.Core.Util` | 🟡 카테고리·필터 확장 | `Log` |
| 데이터 테이블 | `BurningTimes.Core.Data` | ✅ 구조 계승 | `DataTable`, `DataTableSO` |
| CSV 로더 | `BurningTimes.Core.Data` | ✅ 거의 그대로 | |
| Toolkit | `BurningTimes.Core.Util` | 🟡 부분 클래스 해체 (4-7) | |
| 속성(Attribute) | `BurningTimes.Core.Attribute` | ✅ 거의 그대로 | ReadOnly/ShowIf |
| UI 프레임워크 (UGUI) **주력** | `BurningTimes.UI.UGUI` | 🔴 신규 (이전 프로젝트 경험 반영) | `UIView` UGUI 버전. PD님 지시: 주력 ✅ |
| UI 프레임워크 (UIToolkit) **보조** | `BurningTimes.UI.UIToolkit` | ✅ 기존 `UIView` 계승 | 최소 수준 유지, 확장 우선순위 낮음 |
| SafeArea | `BurningTimes.UI.Components` | ✅ 계승 | |
| 에디터 도구 | `BurningTimes.Editor.*` | ✅ 계승 (네이밍만 변경) | |

## 6. Tier 2 모듈 목록 (신규 설계)

기존 코어에 없었던 누락 모듈. 완전 신규 설계.

### 6-0. `BurningTimes.Economy` — 재화 모델 (PD님 지시로 Tier 2 이관)
- `Goods` 범용 재화 모델 (타입·수량·최대치·오버플로 정책)
- 기존 `DG.OutGame/Goods.cs` 구조 계승, 네이밍만 변경
- 인벤토리·획득 이벤트 훅 (`EventBus` 연동)

### 6-1. `BurningTimes.Save` — 세이브/로드
- `ISaveProvider` 인터페이스 (PlayerPrefs / JSON 파일 / 암호화 JSON / 클라우드 교체 가능)
- JSON 직렬화 + 버전 마이그레이션 훅(`IMigration`)
- AES 암호화는 선택 레이어 (`EncryptedJsonProvider`)
- 키 관리는 Tier 3 `BurningTimes.Security.ICryptoProvider` 합류 전까지는 디바이스ID 유도 임시 방식

### 6-2. `BurningTimes.Localization` — 로컬라이제이션
- Unity Localization 패키지 래퍼
- 키 기반 조회 + 폴백 체인(현재 언어 → 영어 → 키 원본)
- 런타임 언어 변경 이벤트 (`LocaleChangedEvent` via EventBus)
- 폰트 자동 스왑 지원

### 6-3. `BurningTimes.Audio` — 오디오 매니저
- BGM 채널 1 + SFX 채널 풀링(8~16)
- AudioMixer 연동, 볼륨 저장(Save 연동)
- iOS 사일런트 모드 대응, Unity AudioFocus 처리
- 3D 오디오는 초기 미포함 (필요 시 Tier 2 후속)

### 6-4. `BurningTimes.Addressable` — Addressable 래퍼
- 참조 카운팅 기반 `AddressableHandle<T>`
- Preload/Unload 정책(`Scene` / `Manual` / `TTL`)
- 로드 실패 폴백 훅
- 이전 프로젝트 `AddrHandleBase` 를 범용화한 형태

## 7. Tier 3 목록 (서버팀 셋업 시점 합류)

| 영역 | 네임스페이스 | 합류 조건 |
|------|-------------|-----------|
| 네트워크 추상화 | `BurningTimes.Network` | 서버팀 구성 + 백엔드 스택 결정 후 |
| IAP 영수증 검증 | `BurningTimes.Network.Purchase` | 〃 |
| 서버 전투 아비터 인터페이스 | `BurningTimes.Core.Battle` | 〃 |
| 암호화·서명 | `BurningTimes.Security` | 〃 |

**→ `project_shop_security_pending.md` 메모에 연동된 Critical 3건 재기동과 동시 추진**

## 8. 폴더 구조 (패키지 스켈레톤)

```
com.nerdnavis.framework/
├── package.json
├── README.md
├── CHANGELOG.md
├── LICENSE.md (내부용 고지)
│
├── Runtime/
│   ├── BT.Framework.Runtime.asmdef
│   ├── Core/
│   │   ├── Patterns/
│   │   ├── Container/
│   │   ├── Coroutine/
│   │   ├── Event/
│   │   ├── Data/
│   │   ├── Util/
│   │   ├── Attribute/
│   │   └── Optimization/
│   ├── UI/
│   │   ├── UGUI/          (주력)
│   │   ├── UIToolkit/     (보조, 최소)
│   │   ├── Components/
│   │   └── Extensions/
│   ├── Save/              [Tier 2]
│   ├── Localization/      [Tier 2]
│   ├── Audio/             [Tier 2]
│   ├── Addressable/       [Tier 2]
│   └── Economy/           [Tier 2] (Goods)
│
├── Editor/
│   ├── BT.Framework.Editor.asmdef
│   ├── Build/
│   ├── Hierarchy/
│   ├── Data/
│   └── Symbols/
│
└── Tests/
    ├── Runtime/
    │   └── BT.Framework.Tests.asmdef
    └── Editor/
        └── BT.Framework.EditorTests.asmdef
```

## 9. 이전 프로젝트 코드 활용 (범용 패턴 추출 대상)

이전 프로젝트 Unity 프로젝트 (`D:/BurningTimes/FilGoodBandits/DeckBuilding/Assets/Script/`) 에서 **범용화 가치가 있는 패턴**. 상세는 별도 문서 `02_이전 프로젝트_추출대상_v1.md` 로 분리 예정.

**1차 후보**
- `My/MyCoroutine.cs` → 코루틴 베이스 → `CoroutineRunner` 참고 자료
- `Template/MonoBehaviourSingletonTemplate.cs` → 싱글톤 패턴 → `MonoSingleton` 참고 자료
- `My/MyEnum.cs`, `MyValue.cs` 중 범용 enum/상수 선별
- `My/DSUtil.cs` → 데이터 구조 유틸 → `MathEx`/`ValidationEx` 흡수 후보
- `My/CryptoUtil.cs` → 구조는 참고, **하드코딩 키 제거** 후 `BurningTimes.Security` 초안 → **Tier 3으로 이관**
- `Addressable/AddrHandleBase.cs` → `BurningTimes.Addressable`
- `Manager/ErrorLogHookManager.cs` → 범용 로그 훅 패턴
- `UGUI/Common/GameUI.cs` → UGUI UIView 추상화 출발점
- `UGUI/Manager/UIAtlasMgr.cs` → UI 아틀라스 매니저
- `UGUI/Util/SafeArea.cs` → 이미 `FilGoodBandits` 네임스페이스 → `BurningTimes.UI.Components` 로 재작성
- `UGUI/Manager/uScrollViewMgr.cs`, `uScrollViewArrMgr.cs` → 무한 스크롤 패턴 범용화

## 10. 다음 작업 순서

| # | 작업 | 산출물 |
|---|------|--------|
| 1 | 본 설계안 PD님 검토 → 승인 | v1.1 고정 |
| 2 | 이전 프로젝트 추출 대상 상세 문서화 | `02_이전 프로젝트_추출대상_v1.md` |
| 3 | PD님과 NAS Git 저장소 위치·접근 방식 협의 | 저장소 URL 확정 |
| 4 | 패키지 스켈레톤 생성 (빈 폴더 + package.json + asmdef) | 공란 패키지 |
| 5 | Tier 1 모듈 순차 구현 | 각 모듈별 PR/커밋 |
| 6 | Tier 2 모듈 순차 구현 | |
| 7 | 이전 프로젝트 개발 준비(Phase 0-B/C) 재개 | |
| 8 | 서버팀 셋업 시점 Tier 3 합류 + 보안 Critical 3건 재기동 | `project_shop_security_pending.md` 참조 |

## 11. PD님 확정 사항 (2026-04-14)

| # | 항목 | 확정값 |
|---|------|--------|
| 1 | 정식 명칭 | `BT.Framework` ✅ |
| 2 | UPM 패키지 이름 | `com.nerdnavis.framework` ✅ |
| 3 | `Goods` (재화 모델) | **Tier 2로 이관** (`BurningTimes.Economy`) ✅ |
| 4 | UI 우선순위 | **UGUI 주력**, UI Toolkit은 보조(최소 유지) ✅ |
| 5 | 저장소 위치 | PD님 NAS Git, 위 4항 확정 후 별도 협의 (진행 중) |

## 12. 잔여 의사결정 (진행 중)

- **저장소 위치 / 접근 방식** — PD님 NAS Git. 위치·접근법 확정 필요 (스켈레톤 초기화 전 논의 필요)

---

## 부록 A. 변경 이력

- **v1 (2026-04-14)**: 초안. 기존 BurningTimesCore 85개 cs 파일 조사 + 이전 프로젝트 범용 패턴 1차 식별 기반.
- **v1.1 (2026-04-14)**: PD님 결정 4건 반영 — 정식 명칭·UPM 이름 확정, Goods는 Tier 2로 이관(`BurningTimes.Economy` 신설), UGUI 주력·UI Toolkit 보조 원칙.
- **v1.2 (2026-04-14)**: PD님 Tier 1 착수 지시(Logger·ServiceLocator·CoroutineRunner) 반영 — 섹션 4-9 ServiceLocator 설계 신설, Tier 1 모듈 목록에 ServiceLocator 추가. 기존 MonoSingleton·EventBus 설계는 유지되며 3축 역할 분리 원칙 명시.
