# Phase 1 설계 스펙: 인증 + 사용자 관리 + 프로젝트 CRUD + 활동 로그

**작성일**: 2026-03-14
**상태**: 승인됨
**범위**: TheRoad Scene Lab 메인 프로젝트 Phase 1

---

## 1. 개요

Phase 1은 시스템의 기반을 구축한다: 인증, 사용자 관리, 다중 creator 협업이 가능한 프로젝트 CRUD, 활동 로그, 프론트엔드 셸. 이 기반 위에 Phase 2(시나리오 분석, 엔티티 추출)와 Phase 3(이미지 생성 파이프라인)이 구축된다.

## 2. 아키텍처

### 2.1 모노레포 구조

```
theroad-i1/
├── backend/                    # FastAPI 애플리케이션
│   ├── app/
│   │   ├── main.py             # 앱 팩토리, 시작/종료 처리
│   │   ├── api/
│   │   │   ├── v1/
│   │   │   │   ├── auth.py     # 로그인, 로그아웃, 내 정보
│   │   │   │   ├── users.py    # 사용자 CRUD (admin 전용)
│   │   │   │   └── projects.py # 프로젝트 CRUD + 멤버 관리
│   │   │   └── deps.py         # 의존성 주입 (DB 세션, 현재 사용자 등)
│   │   ├── core/
│   │   │   ├── config.py       # .env 설정 로드
│   │   │   ├── security.py     # 비밀번호 해싱, 세션 관리
│   │   │   ├── database.py     # SQLite 엔진 팩토리 (카탈로그 + 프로젝트)
│   │   │   └── version_registry.py  # 코드 모듈 버전 + 프롬프트 의존성 추적
│   │   ├── models/
│   │   │   ├── catalog.py      # User, ProjectRegistry, ProjectMember (카탈로그 DB)
│   │   │   └── project.py      # 프로젝트 범위 모델 (Phase 2에서 추가)
│   │   ├── schemas/
│   │   │   ├── auth.py         # LoginRequest, UserResponse
│   │   │   ├── user.py         # UserCreate, UserUpdate
│   │   │   └── project.py      # ProjectCreate, ProjectUpdate, MemberAdd
│   │   ├── services/
│   │   │   ├── auth_service.py     # 로그인/세션 비즈니스 로직
│   │   │   ├── user_service.py     # 사용자 CRUD 비즈니스 로직
│   │   │   └── project_service.py  # 프로젝트 CRUD + 멤버 관리 로직
│   │   ├── logging/
│   │   │   ├── activity_logger.py  # 독립 로깅 모듈 (모든 변화 기록)
│   │   │   └── models.py          # ActivityLog 모델
│   │   └── i18n/
│   │       ├── ko.json         # 한국어 문자열 (기본)
│   │       └── en.json         # 영어 문자열 (향후)
│   ├── alembic/                # DB 마이그레이션
│   ├── requirements.txt
│   └── .env
├── frontend/                   # React + Vite + TypeScript
│   ├── src/
│   │   ├── main.tsx
│   │   ├── App.tsx             # 라우터 + AuthProvider
│   │   ├── api/
│   │   │   └── client.ts       # fetch 래퍼 (세션 쿠키 자동 포함)
│   │   ├── i18n/
│   │   │   ├── ko.json         # 한국어 UI 문자열 (기본)
│   │   │   ├── en.json
│   │   │   └── useI18n.ts      # 훅: t('key') → 번역된 문자열
│   │   ├── hooks/
│   │   │   ├── useAuth.ts      # 로그인 상태, login/logout
│   │   │   └── useApi.ts       # API 호출 + 에러 처리
│   │   ├── components/
│   │   │   ├── layout/         # Sidebar, Topbar, AppShell
│   │   │   ├── ui/             # Button, Input, Modal, Table, Badge
│   │   │   └── shared/         # ActivityFeed, MemberList
│   │   ├── pages/
│   │   │   ├── Login.tsx
│   │   │   ├── Dashboard.tsx       # 프로젝트 목록
│   │   │   ├── ProjectDetail.tsx   # 프로젝트 상세 + 멤버 + 로그
│   │   │   ├── admin/
│   │   │   │   ├── Users.tsx       # 사용자 관리
│   │   │   │   └── ActivityLog.tsx # 전체 활동 로그
│   │   │   └── NotFound.tsx
│   │   └── styles/
│   │       └── global.css      # CSS 변수 + 리셋
│   ├── vite.config.ts
│   └── package.json
├── prompts/                    # 외부 프롬프트 파일 (버전 관리)
│   ├── manifest.json
│   ├── _base/                  # 기본 프롬프트 (모든 프로젝트의 시작점)
│   └── projects/               # 프로젝트별 프롬프트 분기
├── projects/                   # 프로젝트별 SQLite DB + 에셋
├── docs/
│   └── dev-log.md              # 개발 로그 (날짜 + 커밋 해시 연결)
├── .gitignore
└── requirements.txt
```

### 2.2 핵심 원칙

- `api/` → HTTP 레이어만 담당 (요청 파싱, 응답 포매팅)
- `services/` → 비즈니스 로직 (프레임워크 독립적, 테스트 가능)
- `logging/` → 독립 모듈, 모든 service에서 주입받아 사용
- `i18n/` → 모든 문자열 외부화; 한국어가 기본 언어
- `models/` → 카탈로그 DB 모델과 프로젝트 DB 모델 분리
- 모든 프롬프트는 외부 파일, 코드에 하드코딩 금지
- 코드 모듈 버전은 `version_registry.py`에서 프롬프트 의존성과 함께 추적

## 3. 인증

### 3.1 메커니즘

세션 기반 쿠키 인증.

- 로그인: `POST /api/v1/auth/login` → username + password → 세션 쿠키 설정
- 세션은 카탈로그 SQLite의 session 테이블에 저장
- 쿠키: `HttpOnly`, `SameSite=Lax`
- 세션 TTL: 24시간. 만료된 세션은 접근 시 지연 삭제
- 비밀번호 해싱: bcrypt
- 비밀번호 변경 강제 없음 (내부 프로토타입)
- 로그인 속도 제한 없음 (내부 프로토타입)
- 개발 환경: Vite 프록시가 `/api/*`를 FastAPI로 전달하므로 동일 출처 — CORS 이슈 없음

### 3.2 기본 계정

최초 기동 시 자동 생성:

| 사용자명 | 비밀번호 | 역할 |
|----------|----------|------|
| `admin` | `admin123` | admin |
| `creator` | `creator123` | creator |

## 4. 데이터 모델

### 4.1 카탈로그 DB (`service.sqlite`) — 전역

```sql
user_account (
    id            TEXT PRIMARY KEY,     -- UUID
    username      TEXT UNIQUE NOT NULL,
    display_name  TEXT NOT NULL,
    password_hash TEXT NOT NULL,
    role          TEXT NOT NULL CHECK (role IN ('admin', 'creator')),
    is_active     INTEGER DEFAULT 1,
    created_at    TEXT NOT NULL,
    updated_at    TEXT NOT NULL
)

session (
    id            TEXT PRIMARY KEY,     -- 세션 토큰
    user_id       TEXT NOT NULL REFERENCES user_account(id),
    created_at    TEXT NOT NULL,
    expires_at    TEXT NOT NULL
)

project_registry (
    id            TEXT PRIMARY KEY,     -- UUID
    name          TEXT NOT NULL,
    description   TEXT DEFAULT '',
    status        TEXT DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deleted')),
    db_path       TEXT NOT NULL,        -- projects/{id}/project.sqlite 경로
    created_by    TEXT NOT NULL REFERENCES user_account(id),
    created_at    TEXT NOT NULL,
    updated_at    TEXT NOT NULL
)

project_member (
    id            TEXT PRIMARY KEY,
    project_id    TEXT NOT NULL REFERENCES project_registry(id),
    user_id       TEXT NOT NULL REFERENCES user_account(id),
    role          TEXT NOT NULL CHECK (role IN ('owner', 'member')),
    added_by      TEXT REFERENCES user_account(id),
    created_at    TEXT NOT NULL,
    UNIQUE(project_id, user_id)
)

activity_log (
    id            TEXT PRIMARY KEY,
    actor_id      TEXT NOT NULL REFERENCES user_account(id),
    action        TEXT NOT NULL,        -- 'user.create', 'project.create' 등
    resource_type TEXT NOT NULL,        -- 'user', 'project', 'member'
    resource_id   TEXT,
    project_id    TEXT,
    detail_json   TEXT DEFAULT '{}',    -- 변경 전후 값
    ip_address    TEXT,
    created_at    TEXT NOT NULL
)
```

### 4.2 프로젝트 DB (`projects/{id}/project.sqlite`) — 프로젝트별

Phase 1에서는 최소 스키마로 DB를 생성:

```sql
project_meta (
    key           TEXT PRIMARY KEY,
    value         TEXT NOT NULL
)
```

Phase 1에서 `project_meta`에 `name`, `created_at`, `schema_version`을 저장. Phase 2에서 `episode`, `entity_canon`, `entity_variant`, `scene` 등 추가 예정.

### 4.3 프로젝트 디렉토리 구조

```
projects/{project-id}/
├── project.sqlite
└── assets/
    ├── screenplays/    # 업로드된 시나리오 PDF
    ├── references/     # 엔티티 참조 이미지
    ├── generated/      # 생성된 이미지
    └── exports/        # PDF/EPUB 출력물
```

### 4.4 마이그레이션 전략

- 카탈로그 DB: 표준 Alembic 단일 DB 마이그레이션
- 프로젝트 DB: `ProjectMigrator` 유틸리티가 개별 프로젝트 SQLite에 스키마 마이그레이션 적용. 프로젝트 열기 시 `project_meta.schema_version`을 확인하고 대기 중인 마이그레이션을 순방향으로만 실행

## 5. API 설계 (OpenAPI / OAS)

### 5.1 인증

| 메서드 | 경로 | 설명 | 인증 |
|--------|------|------|------|
| POST | `/api/v1/auth/login` | 로그인 → 세션 쿠키 설정 | 공개 |
| POST | `/api/v1/auth/logout` | 로그아웃 → 세션 삭제 | 인증 필요 |
| GET | `/api/v1/auth/me` | 현재 로그인 사용자 정보 | 인증 필요 |

### 5.2 사용자 (admin 전용)

| 메서드 | 경로 | 설명 |
|--------|------|------|
| GET | `/api/v1/users` | 사용자 목록 조회 |
| POST | `/api/v1/users` | 사용자 생성 |
| GET | `/api/v1/users/{id}` | 사용자 상세 조회 |
| PATCH | `/api/v1/users/{id}` | 사용자 수정 |
| DELETE | `/api/v1/users/{id}` | 사용자 비활성화 (소프트 삭제) |

### 5.3 프로젝트

| 메서드 | 경로 | 설명 | 접근 권한 |
|--------|------|------|-----------|
| GET | `/api/v1/projects` | 내 프로젝트 목록 (admin은 전체) | 인증 필요 |
| POST | `/api/v1/projects` | 프로젝트 생성 (생성자가 자동 owner) | admin, creator |
| GET | `/api/v1/projects/{id}` | 프로젝트 상세 | 멤버 또는 admin |
| PATCH | `/api/v1/projects/{id}` | 프로젝트 수정 | owner 또는 admin |
| DELETE | `/api/v1/projects/{id}` | 프로젝트 삭제 | owner 또는 admin |

### 5.4 프로젝트 멤버

| 메서드 | 경로 | 설명 | 접근 권한 |
|--------|------|------|-----------|
| GET | `/api/v1/projects/{id}/members` | 멤버 목록 | 멤버 또는 admin |
| POST | `/api/v1/projects/{id}/members` | 멤버 추가 | owner 또는 admin |
| PATCH | `/api/v1/projects/{id}/members/{uid}` | 멤버 역할 변경 | owner 또는 admin |
| DELETE | `/api/v1/projects/{id}/members/{uid}` | 멤버 제거 | owner 또는 admin |

### 5.5 활동 로그

| 메서드 | 경로 | 설명 | 접근 권한 |
|--------|------|------|-----------|
| GET | `/api/v1/activities` | 전체 활동 로그 | admin 전용 |
| GET | `/api/v1/projects/{id}/activities` | 프로젝트별 활동 로그 | 멤버 또는 admin |

### 5.6 권한 규칙

- admin은 모든 것에 접근 가능
- creator는 자신이 멤버인 프로젝트에만 접근 가능
- 프로젝트 설정 변경, 멤버 관리, 삭제는 owner 또는 admin만 가능
- 모든 상태 변경은 ActivityLogger 모듈을 통해 기록

### 5.7 엣지 케이스 규칙

- **사용자 비활성화**: 소프트 삭제만 수행 (`is_active = 0`). 비활성화된 사용자의 세션은 즉시 무효화. 소유한 프로젝트는 유지됨 — 소유권을 먼저 이전하거나 다른 owner가 존재해야 함. 마지막 admin은 비활성화 불가.
- **프로젝트 삭제**: 소프트 삭제 (`status = 'deleted'`). 프로젝트 디렉토리와 SQLite 파일은 보존. admin이 복구 가능.
- **프로젝트 보관**: `PATCH /api/v1/projects/{id}`에서 `status: 'archived'`로 변경. owner 또는 admin이 보관/해제 가능.
- **owner 제거**: 프로젝트 owner는 멤버에서 제거 불가. 소유권 변경은 `PATCH /api/v1/projects/{id}/members/{uid}`에서 `role: 'owner'`로 이전. 프로젝트에는 항상 최소 1명의 owner가 존재해야 함.
- **프로젝트 이름 중복**: 허용. 프로젝트는 UUID로 식별.
- **페이지네이션**: 모든 목록 엔드포인트는 `?page=1&per_page=20` 지원 (기본값). 활동 로그는 추가로 `?action=`, `?actor_id=`, `?from=`, `?to=` 필터 지원.

### 5.8 표준 에러 응답

```json
{
  "error": {
    "code": "user.duplicate_username",
    "message": "이미 존재하는 사용자명입니다"
  }
}
```

`code`는 i18n 키, `message`는 해당 키로 조회한 번역된 문자열.

### 5.9 프로젝트 목록 응답 형태

```json
{
  "items": [
    {
      "id": "uuid",
      "name": "Soul Ride S1",
      "description": "...",
      "status": "active",
      "member_count": 3,
      "my_role": "owner",
      "created_by": "admin",
      "created_at": "2026-03-14T19:30:00"
    }
  ],
  "total": 12,
  "page": 1,
  "per_page": 20
}
```

## 6. 활동 로그 모듈

### 6.1 설계

독립 모듈로, 서비스 레이어에 주입되어 사용 (API 레이어가 아님).

```python
class ActivityLogger:
    def log(self, *, actor_id, action, resource_type, resource_id=None,
            project_id=None, detail=None, ip_address=None) -> None
```

### 6.2 액션 형식

`도메인.동작` 패턴:

- `auth.login`, `auth.logout`
- `user.create`, `user.update`, `user.deactivate`
- `project.create`, `project.update`, `project.delete`, `project.archive`
- `member.add`, `member.remove`, `member.role_change`

### 6.3 상세 JSON

변경 시 이전/이후 값 기록:

```json
{"before": {"name": "기존 이름"}, "after": {"name": "새 이름"}}
```

### 6.4 실패 격리

로그 기록 실패가 메인 동작을 막지 않도록 try/except 처리.

## 7. 국제화 (i18n)

### 7.1 백엔드

모든 에러 메시지와 상태 문자열을 `backend/app/i18n/ko.json`에 저장. 시작 시 로드. 헬퍼 함수 `t(key, **kwargs)`로 변수 치환 포함 문자열 조회.

### 7.2 프론트엔드

모든 UI 문자열을 `frontend/src/i18n/ko.json`에 저장. 커스텀 `useI18n()` 훅이 `t(key)` 함수 제공. 한국어가 기본이자 주 언어.

### 7.3 하드코딩 금지

모든 사용자 대면 문자열은 반드시 i18n 파일에서 가져와야 함. 적용 대상:
- 에러 메시지
- 버튼 라벨
- 페이지 제목
- 상태 텍스트
- 플레이스홀더 텍스트
- 토스트 알림

## 8. 버전 관리

### 8.1 코드 모듈 버전 레지스트리

`backend/app/core/version_registry.py`에서 각 모듈을 다음 정보로 추적:
- `version`: semver
- `updated_at`: ISO 날짜시간
- `prompt_dependency`: 이 코드가 사용하는 프롬프트 버전
- `description`: 모듈 설명

코드 변경 시마다 업데이트. 코드-프롬프트 추적성을 보장.

### 8.2 프롬프트 버전 구조

```
prompts/
├── manifest.json           # 전역 레지스트리
├── _base/                  # 기본 프롬프트 (모든 프로젝트의 시작점)
│   ├── entity_extraction/v5/
│   ├── scene_stills/v2/
│   └── prototype_prompts/v5/
└── projects/{project-id}/  # 프로젝트별 분기 (오버라이드)
    ├── manifest.json       # branched_from, reason 포함 오버라이드 매핑
    └── entity_extraction/v5.1/
```

프로젝트별 manifest에 기록: `base_ref`, `overrides` (각각 `branched_from`, `branched_at`, `reason` 포함), `fallback_policy: "use_base"`.

### 8.3 결과물 계보 (lineage)

모든 생성 결과물에 포함되는 메타데이터:

```json
{
  "lineage": {
    "module": "entity_extractor",
    "module_version": "1.1.0",
    "prompt_source": "projects/{id}/entity_extraction/v5.1",
    "prompt_hash": "sha256:...",
    "executed_at": "2026-03-15T14:25:00",
    "executed_by": "creator01"
  }
}
```

### 8.4 개발 로그

`docs/dev-log.md`에 모든 커밋을 다음 항목으로 기록:
- 날짜
- 커밋 해시
- 영향받은 모듈 + 버전 변경
- 프롬프트 의존성 변경 (있는 경우)
- 변경 내용 설명

## 9. 프론트엔드 화면

### 9.1 로그인 페이지
- 사용자명 + 비밀번호 폼
- 다크 테마, 중앙 카드
- i18n에서 가져온 에러 메시지

### 9.2 대시보드
- 프로젝트 카드 그리드
- 각 카드: 이름, 에피소드 수, 멤버 수, 상태 뱃지, 역할 뱃지
- "새 프로젝트" 버튼 및 빈 카드
- admin은 전체 프로젝트, creator는 자기 프로젝트만 표시

### 9.3 프로젝트 상세
- 탭: 개요 / 멤버 / 활동
- 개요: 상태, 멤버 수, 에피소드 수 (Phase 2), 최근 활동 피드
- 멤버: 역할 뱃지가 있는 멤버 테이블, 추가/제거 (owner/admin만)
- 활동: 이 프로젝트의 필터링 가능한 활동 로그
- 사이드바에 Phase 2 메뉴 자리 표시 (에피소드, 엔티티) — 비활성 상태

### 9.4 관리: 사용자 관리
- 사용자 테이블: 사용자명, 표시 이름, 역할, 상태
- 사용자 생성 모달
- 사용자 수정 모달
- admin만 접근 가능

### 9.5 관리: 활동 로그
- 전체 시스템 활동 로그
- 액션 종류, 사용자, 프로젝트, 날짜 범위로 필터링 가능

## 10. 기술 스택 요약

| 레이어 | 기술 |
|--------|------|
| 백엔드 | Python 3.12+, FastAPI |
| DB | SQLite (카탈로그 + 프로젝트별) |
| ORM | SQLAlchemy |
| 마이그레이션 | Alembic |
| 프론트엔드 | React 18+, Vite, TypeScript |
| 스타일링 | CSS 변수 (다크 테마, 컴포넌트 기반) |
| 인증 | 세션 쿠키 (HttpOnly) |
| API 문서 | OpenAPI / Swagger (FastAPI 자동 생성) |

## 11. 범위 외 (Phase 2 이후)

- 시나리오 업로드 및 파싱
- 엔티티 추출 / 씬 스틸 추출
- 이미지 생성 파이프라인
- LLM 모듈 통합
- 리뷰 워크플로
- PDF/EPUB 출력
- LoRA 관리
- Opik/LiteLLM 연동
