You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

56 KiB

아리(Ari) — AI Life OS · 개발 개요

일·삶을 한곳에서 관리하는 한국어 AI 개인비서 아리의 MVP 개발 진입 문서. 핵심 철학: "적을 때는 분류하지 않는다 — 분류·배치·자동화는 아리가." 사용자는 읽고 탭 한 번, 나머지는 아리가 합니다.

이 문서는 dev/ 문서 세트의 일부입니다 — 가장 먼저 이 overview.md를 읽으세요. 이후 phase 문서(phase-0-foundation.mdphase-1-design-system.mdphase-2-backend.mdphase-3-tasks.mdphase-4-inbox.mdphase-5-dashboard.mdphase-6-integration.md)를 빌드 순서대로 진행합니다. 각 phase 문서로의 정확한 연결은 §11 개발 Phase 로드맵§14 이 문서 세트 사용법에 있습니다.

MVP 이후(포스트-MVP): 나머지 10개 페이지와 연합·실연동·능동 에이전트·프로덕션은 별도 세트로 문서화되어 있습니다 — post-mvp-overview.md(포스트-MVP 진입 문서)부터 시작해 phase-7-approvals-automation.mdphase-8-calendar-meetings.mdphase-9-mail-notifications.mdphase-10-research-travel.mdphase-11-life-care.mdphase-12-daily-narrative.mdphase-13-integrations.mdphase-14-proactive-agent.mdphase-15-production.md 순으로 진행합니다. 이 세트는 위 MVP 규약(스택·토큰·데이터모델·API·테스트)을 그대로 상속합니다.

원본 디자인(픽셀 충실 재현 기준)은 다음 경로에 보관되어 있습니다. 이 문서의 모든 값(색 HEX, px, 클래스명, 한국어 문구, 데이터 필드)은 이 파일들에서 그대로 인용했습니다.

REF = /Users/kim1634/mycloud/personal/workspace/ari_assistant/workspace/design-reference
  REF/대시보드.html · REF/인박스.html · REF/작업.html      (MVP 3개 페이지 진입 HTML)
  REF/assets/dash.css                                     (디자인 토큰의 기준 :root)
  REF/assets/shell.jsx                                    (Topbar/SubRail/Icon, MAIN 13항목, P 아이콘 맵)
  REF/assets/data.js                                      (대시보드 시드: user/schedule/goals/...)
  REF/assets/tasks-data.js                                (작업 트리·people·columns·scaffold)
  REF/assets/tasks-risk.jsx                               (리스크 레이더 계산 규칙, TODAY=8)
  REF/assets/sinbox-data.js                               (인박스 캡처·분류 시드)
  REF/assets/approve-data.js                              (결재함 읽기전용 시드)
  REF/PROJECT-README.md · REF/HANDOFF-README.md           (제품 설명·핸드오프)

0. 목차

  1. 개요 & 목표
  2. 선행 조건 / 산출물
  3. 제품 비전 & 철학
  4. 데모 페르소나(지우)와 한 주의 시드 데이터
  5. MVP 범위 & 13페이지 비전 경계
  6. 시스템 아키텍처
  7. 기술 스택 결정과 근거
  8. 리포지토리 구조
  9. 데이터 모델 개요
  10. REST API 개요
  11. 디자인 시스템 요약
  12. 페이지 연합(federation) 흐름
  13. 개발 Phase 로드맵
  14. LLM(Ollama) 추상화 & 분류 계약
  15. 상태 처리 & 엣지 케이스 (전역 원칙)
  16. 테스팅 & 검증
  17. 완료 기준 (Definition of Done)
  18. 용어집
  19. 이 문서 세트 사용법

(위 §번호는 본 진입 문서 내부의 절 번호입니다. CONTRACT 아웃라인 항목과 1:1 대응하며 일부 절은 통합되어 있습니다.)


1. 개요 & 목표

이 문서는 아리 MVP의 진입 문서이자 단일 출처(single source of truth)입니다. 제품 비전, 데모 데이터, 아키텍처, 스택, 데이터 모델, REST API, 디자인 시스템, 페이지 연합 흐름, 개발 로드맵을 총괄합니다. 다른 phase 문서는 이 문서의 정의를 그대로 참조하며, 임의로 변경하지 않습니다.

이 phase(문서)가 끝나면 무엇이 동작하는가: 직접적으로 코드가 동작하지는 않습니다 — 이 문서는 지도입니다. 그러나 이 문서를 읽고 나면 개발자는 (1) 무엇을 만드는지, (2) 어떤 기술로, (3) 어떤 순서로, (4) 어떤 데이터/계약으로 만들어야 하는지를 완전히 이해하고 phase-0-foundation.md로 바로 진입할 수 있습니다.

MVP의 한 줄 정의: 한국어 사용자 지우가, 인박스에 자유롭게 적은 한 줄을 아리가 작업/일정/아이디어로 자동 분류하고, 작업 페이지에서 칸반으로 관리하며 리스크 레이더가 마감·쏠림·의존성을 경고하고, 대시보드에서 하루를 한눈에 집계해 보는 — 로컬 완결형 웹앱(빌드/배포 가능).


2. 선행 조건 / 산출물

선행 조건 (의존 phase)

  • 없음. 이 문서는 phase 0의 선행 문서이자 전 phase의 인덱스입니다.

산출물 (Deliverables)

산출물 내용
제품 정의 비전·철학·페르소나·MVP 경계 (§3~§5)
아키텍처 그림 브라우저↔FastAPI↔SQLite↔Ollama 데이터 흐름 (§6)
스택 결정표 선택 기술과 근거 (§7)
리포 트리 frontend/ + backend/ 모노레포 전체 구조 (§8)
데이터 모델 표 엔티티·필드·관계 (§9)
API 계약 표 메서드/경로/용도/요청·응답 예시 (§10)
디자인 토큰 요약 색/폰트/글래스/아이콘/라이트·다크 (§11)
연합 흐름도 캡처→분류→작업→리스크→대시보드 (§12)
로드맵 표 phase 0~6 목표·산출물·의존성·작업량 (§13)
LLM 계약 요약 Provider 추상화 + 분류 스키마 + 골든 케이스 (§14)
용어집 인박스/결재함/리스크 레이더/sphere/scaffold 등 (§18)

3. 제품 비전 & 철학

아리는 할 일 앱이 아니라 "Life OS" 를 지향합니다. 핵심 가치는 세 개의 문장으로 압축됩니다.

3.1 "적을 때는 분류하지 않는다 — 분류·배치·자동화는 아리가."

사용자의 인지 부담을 0에 가깝게 만드는 것이 1순위입니다. 사용자는 떠오른 것을 인박스에 한 줄 던지기만 하면 됩니다. 어느 프로젝트인지, 작업인지 일정인지, 언제 할지는 아리가 정합니다. (원본 sinbox-data.js 주석: "적을 때는 분류하지 않는다 — 분류·배치·자동화는 아리가.")

예) "다음 주에 한국 놀러가는 비행기 티켓 사기" 한 줄 → 아리가 작업 / 개인 영역 / 개인 여행 — 한국 프로젝트 / 가격 추적 알림까지 자동 처리. 사용자는 결과를 읽고 탭 한 번으로 확정.

3.2 "할까요?"가 아니라 "이미 해뒀어요"

아리는 묻고 기다리지 않습니다. 미리 처리한 뒤 승인/되돌리기를 제공합니다(원본 approve-data.js 주석: "아리는 '할까요?'라고 묻지 않고 미리 해둔다.").

  • 위험도 낮음(low): 이미 처리. 되돌리기만 제공. 예) "치과 예약을 16:00로 옮겼어요"(undoLabel: "원래 시간으로").
  • 위험도 높음(high): 보내기/결제/타인 전달 등은 사용자 확인 후 실행. 예) "현우님께 회신 초안이 준비됐어요"(cta: "보내기", alt: "수정").

이 원칙은 인박스에서 분류를 먼저 실행하고 결과를 보여준 뒤 확인받는 방식(POST /api/inbox/capture가 동기 분류까지 수행)으로 MVP에 구현됩니다.

3.3 "개인 일은 숨기지 않는다 — 개인 = 프로젝트"

가장 중요한 모델 원칙입니다. "개인"은 별도 비밀 섹션이 아니라 그냥 하나의 폴더(영역) 이며, 업무/개인은 같은 트리에서 '필터'로만 구분됩니다(원본 tasks-data.js 트리: 최상위 work(업무)·life(개인) 두 폴더가 동급). 아리는 배치(언제 하면 좋을지)만 추천하지 강제로 숨기지 않습니다.

원본 분류 reason 문구가 이 철학을 그대로 말합니다(sinbox-data.js):

"작업 트리의 '개인' 아래에 '여행 — 한국' 프로젝트를 만들어 넣었어요 — 따로 섹션이 생기는 게 아니라 다른 작업과 똑같이 보여요."

배치 추천 예: 엄마 생신 선물 알아보기"주말 오전 블록", 엄마 생신 선물"6/20 전". 강제 숨김이 아니라 추천임에 유의.


4. 데모 페르소나(지우)와 한 주의 시드 데이터

4.1 사용자: 지우(PM)

필드 출처
이름 지우 data.js: user.name / tasks-data.js: people.jiwoo.name
이니셜 data.js: user.initial (상단바 아바타 .t-ava에 표시)
역할 PM PROJECT-README
식별 is_me = true, 색 --blue tasks-data.js: people.jiwoo = { ..., c: "var(--blue)", me: true }

4.2 팀원 5인 (person)

tasks-data.js: people 그대로 이식. color 값까지 고정.

id name initial color is_me
jiwoo 지우 var(--blue) (#4f72e0) true
hyunwoo 현우 var(--violet) (#8b6fd4) false
minseo 민서 var(--green) (#4e9b66) false
jaeho 재호 var(--coral) (#df7256) false
sua 수아 oklch(0.66 0.13 200) false

주의: 수아의 색은 토큰이 아닌 리터럴 oklch(0.66 0.13 200) 입니다. 시드 시 person.color에 문자열 그대로 저장.

4.3 배경: 6월 7~12일 가상의 한 주, 기준일 6월 8일

  • 대시보드 표시 날짜: today = "6월 7일 일요일"(data.js). 단, 리스크 계산 기준 TODAY = 8(6월 8일, tasks-risk.jsx 7번째 줄 const TODAY = 8;). 이 둘은 의도적으로 다릅니다 — 대시보드 날짜 라벨과 리스크 마감 비교 기준일을 혼동하지 마세요. 백엔드 services/risk.pyTODAY=8을 기준 상수로 이식합니다.
  • 작업 마감(due)은 MM-DD 문자열(예 "06-08", "06-14", "06-20"). 리스크 계산은 due.split("-")[1](일)만 정수로 비교(dueD). 표시는 6/{일}(dueTxt).

4.4 시드 데이터 한눈에 (출처별)

영역 시드 출처 핵심 시드 항목(예)
작업 트리 tasks-data.js: tree 업무(work)▸경영 전략/온보딩 리디자인/팀 운영, 개인(life)▸일상/여행 — 한국/가족
작업 tasks-data.js: tasks k1 분기 리포트 초안 마무리(doing, due 06-08, 높음), k20 한국행 비행기 티켓 구매(life-trip), k14 데이터 전처리 파이프라인(waiting, delegated) 등
인박스 sinbox-data.js: items s1~s4 (골든 분류 케이스가 곧 시드)
대시보드 일정 data.js: schedule 09:30 스탠드업, 11:00 디자인 리뷰, 14:00 분기 전략 미팅(soon:true), 16:30 1:1—민서님
목표 data.js: goals 분기 OKR—리텐션 68%, 주 4회 운동 75%, '딥 워크' 책 완독 40%
결재함(읽기전용) approve-data.js: items a1~a6, savedToday: "47분", autoCountNight: 7
아침 브리핑 data.js: weather/commute/sleep/briefingNote 24°·맑음, 출근 23분, 수면 7시간 12분, 브리핑 노트(HTML 포함)

날씨 값 주석: weather_temp = 24(현재 기온), weather_cond의 "한낮 28°" = 일 최고 기온 — 의도적으로 다른 값입니다(원본 data.js 근거). 두 값을 혼동하지 마세요.

briefingNote, 작업 notesHTML 문자열을 포함합니다(<b>, <h3>, <blockquote>). 렌더 시 신뢰된 시드로 취급하되 §15 새니타이즈 원칙을 참조.


5. MVP 범위 & 13페이지 비전 경계

5.1 전체 비전 — 13페이지

원본은 13개 화면(상단 내비 MAIN 배열, shell.jsx)을 가집니다.

대시보드 · 인박스 · 결재함(badge 3) · 자동화 · 여정 · 일정 · 작업(badge 4) · 메일 · 알림(badge 6) · 리서치 · 여행 · 라이프 · 하루 마감

5.2 MVP — 페이지 3개만 구현

# 라우트 라벨 MVP 담당 phase 문서
1 /tasks 작업 구현 phase-3-tasks.md
2 /inbox 인박스 구현 phase-4-inbox.md
3 /dashboard 대시보드 구현 phase-5-dashboard.md
4~13 결재함·자동화·여정·일정·메일·알림·리서치·여행·라이프·하루 마감 "준비 중" 플레이스홀더 phase-1-design-system.md (placeholder 라우팅)

5.3 경계 규칙 (반드시 지킬 것)

  1. 상단 내비는 13항목 전부 노출합니다(내비 일관성). shell.jsxMAIN 배열(13항목·badge·icon·라벨)을 그대로 frontend/components/Topbar.tsx로 이식합니다.
  2. MVP 외 10개 항목은 클릭 시 /(placeholder) 라우트의 "준비 중" 화면으로 이동(앱 셸·테마는 동일 유지).
  3. 대시보드의 결재함/일정 요약 카드는 시드 데이터 기반 읽기 전용으로 표시합니다(결재함 페이지 자체는 MVP 외이지만, 요약 카드는 approve-data.js/data.js 시드로 채움 → GET /api/dashboardapprovals_summary/schedule 제공).
  4. 배지 숫자도 고정 노출: 결재함 3, 작업 4, 알림 6(원본 MAINbadge 값). 단 작업/결재함 배지는 향후 동적화 가능하도록 GET /api/dashboardbadges:{appr,task,noti}로 공급.

6. 시스템 아키텍처

6.1 텍스트 아키텍처 다이어그램

┌──────────────────────────────────────────────────────────────────────────┐
│  브라우저                                                                    │
│  ┌────────────────────────────────────────────────────────────────────┐   │
│  │  Next.js (App Router, React, TypeScript)                            │   │
│  │  app/layout.tsx  =  ThemeProvider(next-themes) + <Topbar/>          │   │
│  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐                │   │
│  │  │ /tasks       │ │ /inbox       │ │ /dashboard   │  /(placeholder) │   │
│  │  │ 칸반/리스트   │ │ 캡처→분류     │ │ 브리핑·요약    │  "준비 중"      │   │
│  │  │ ·리스크       │ │ ·확인·실체화  │ │ ·집계         │  (MVP 외 10)   │   │
│  │  └──────────────┘ └──────────────┘ └──────────────┘                │   │
│  │         │  lib/api.ts (fetch wrapper) · lib/types.ts (1:1 schemas)  │   │
│  └─────────┼──────────────────────────────────────────────────────────┘   │
└────────────┼───────────────────────────────────────────────────────────────┘
             │  HTTP/JSON  (prefix /api)   ·   dev: Next rewrites → :8000
             ▼
┌──────────────────────────────────────────────────────────────────────────┐
│  FastAPI (Python)                                                          │
│  app/main.py  (CORS, /api router include)                                  │
│  ┌─────────────────────────── routers/ ──────────────────────────────┐    │
│  │ tree.py  tasks.py  inbox.py  dashboard.py  people.py  llm.py        │    │
│  └─────────┬──────────────────────────────────────────┬───────────────┘    │
│            │ services/                                  │ llm/               │
│            │  classification.py  risk.py  scaffold.py   │  provider.py(IF)   │
│            │                                            │  ollama.py         │
│            │  schemas.py (Pydantic I/O)                 │  heuristic.py      │
│            │  models.py (SQLModel)  db.py (engine)      │  prompts.py        │
│            ▼                                            ▼                    │
│  ┌──────────────────────┐                  ┌──────────────────────────┐     │
│  │  SQLite (ari.db)      │                  │  LLMProvider 추상화        │     │
│  │  SQLModel + Alembic   │                  │  health()/classify_      │     │
│  │  seed.py (시드 적재)   │                  │  capture()/generate_json │     │
│  └──────────────────────┘                  └────────────┬─────────────┘     │
└────────────────────────────────────────────────────────┼───────────────────┘
                                                          │ HTTP (format=json)
                                                          ▼
                                          ┌──────────────────────────────┐
                                          │  Ollama (로컬 LLM 런타임)        │
                                          │  OLLAMA_HOST=:11434            │
                                          │  OLLAMA_MODEL=<주입, 모델 비종속>│
                                          │  미가용 시 → HeuristicProvider │
                                          └──────────────────────────────┘

6.2 데이터 흐름 (대표 시나리오: 인박스 캡처)

[사용자 입력 "비행기 티켓 사기"]
   │ 1. POST /api/inbox/capture {kind:"text", raw:"..."}
   ▼
[FastAPI inbox.py]
   │ 2. inbox_item 생성 (status=new) → DB
   │ 3. services/classification.py 호출
   │      → LLMProvider.classify_capture(raw, context=트리/사람)
   │           ├─ Ollama 가용:  ollama.py (format=json 구조화 출력)
   │           └─ 미가용/테스트: heuristic.py (정규식 규칙 폴백)
   │ 4. inbox_classification 저장 (type/sphere/project_suggestion/reason/confidence)
   │ 5. item.status = classified
   ▼
[응답 {item, classification}]  → 프론트가 칩/이유/행선지 카드 렌더
   │ 6. (사용자가 확인) POST /api/inbox/{id}/confirm
   ▼
[type=task 이면 task 생성 → materialized_task_id 연결, status=confirmed]
   │ 7. 작업 페이지 GET /api/tasks 에 즉시 등장 (federation)
   │ 8. GET /api/risks 가 새 task 포함해 마감/쏠림/의존성 재계산
   │ 9. GET /api/dashboard 가 task_summary/inbox_recent 집계 갱신

7. 기술 스택 결정과 근거

확정 스택 — 절대 변경 금지. (CONTRACT) 아래 표는 근거만 보강합니다.

레이어 선택 근거
프론트엔드 Next.js (App Router) + React + TypeScript 파일 기반 라우팅이 MVP 3페이지 + placeholder 그룹과 자연스럽게 매핑(app/dashboard, app/inbox, app/tasks, app/(placeholder)). TS로 lib/types.ts ↔ 백엔드 schemas.py 1:1 타입 계약. dev rewrites로 /api 프록시.
디자인 토큰 CSS Variables (styles/tokens.css) 원본이 이미 :root CSS 변수 + [data-theme="dark"] 오버라이드 구조 → 무손실 이식. 프레임워크 종속 없음.
테마 토글 next-themes 원본은 document.documentElementdata-theme + localStorage. next-themes가 동일 메커니즘(SSR 깜빡임 방지 포함)을 제공.
백엔드 Python + FastAPI 타입 힌트 기반 자동 OpenAPI, Pydantic 검증으로 API 계약을 코드로 강제. LLM/분류 로직(파이썬 생태계)과 자연스럽게 결합.
DB SQLite 단일 파일·무설정, 로컬 완결형 MVP에 적합. 트리/중첩(parent_id) 인접 리스트 모델로 충분.
ORM SQLModel(SQLAlchemy) + Alembic SQLModel 모델 = Pydantic 스키마 기반이라 models.py/schemas.py 정합 용이. Alembic으로 스키마 진화 관리.
LLM 로컬 Ollama + Provider 추상화 프라이버시(로컬 처리)·비용 0. 모델 비종속: OLLAMA_MODEL 환경변수 주입, LLMProvider 인터페이스로 감싸 특정 모델 강제 금지. 미가용 시 HeuristicProvider 폴백으로 오프라인/테스트에서도 분류 동작.
백엔드 테스트 pytest + httpx TestClient 라우터/서비스/분류를 결정적으로 검증. HeuristicProvider로 LLM 없이 골든 케이스 테스트.
프론트 테스트 Vitest + React Testing Library(컴포넌트), Playwright(E2E), axe(접근성) 단위→통합→E2E→a11y 4단. 연합 흐름(캡처→확인→작업 등장)은 E2E로 검증.
패키지 매니저 프론트 pnpm(또는 npm), 백엔드 uv(또는 pip+venv) 빠른 설치·재현성.

8. 리포지토리 구조

repo root: /Users/kim1634/mycloud/personal/workspace/ari_assistant/workspace

workspace/
├─ frontend/                          Next.js (App Router, TypeScript)
│  ├─ app/
│  │  ├─ layout.tsx                   앱 셸: ThemeProvider(next-themes) + <Topbar/>
│  │  ├─ page.tsx                     / → /dashboard 리다이렉트
│  │  ├─ dashboard/page.tsx           ⑤ 대시보드
│  │  ├─ inbox/page.tsx               ④ 인박스
│  │  ├─ tasks/page.tsx               ③ 작업
│  │  └─ (placeholder)/               MVP 외 10페이지 "준비 중"
│  │     └─ [slug]/page.tsx
│  ├─ components/                     디자인 시스템
│  │  ├─ Icon.tsx                     중앙 paths 맵 기반 SVG (shell.jsx P 맵 이식)
│  │  ├─ Topbar.tsx                   13항목 mainnav + 검색/알림/테마/아바타
│  │  ├─ SubRail.tsx                  좌측 아이콘 레일(선택; 작업 페이지)
│  │  ├─ GlassCard.tsx  Badge.tsx  Chip.tsx  Button.tsx
│  │  ├─ SegmentToggle.tsx            칸반/리스트 전환 (캘린더는 post-MVP placeholder)
│  │  └─ Avatar.tsx
│  ├─ lib/
│  │  ├─ api.ts                       fetch 래퍼 (/api 호출)
│  │  ├─ types.ts                     schemas.py 와 1:1 대응 타입
│  │  └─ hooks/                       useTree, useTasks, useInbox, useDashboard ...
│  ├─ styles/
│  │  ├─ tokens.css                   디자인 토큰 (dash.css :root 이식)
│  │  └─ globals.css                  body 그라데이션·폰트·전역
│  ├─ tests/                          Vitest + RTL
│  ├─ playwright/                     E2E + axe
│  ├─ next.config.js                  /api rewrites
│  ├─ tsconfig.json
│  └─ package.json
├─ backend/                           FastAPI
│  ├─ app/
│  │  ├─ main.py                      앱 생성, CORS, /api 라우터 등록
│  │  ├─ db.py                        engine/session
│  │  ├─ models.py                    SQLModel 테이블 (§9)
│  │  ├─ schemas.py                   Pydantic I/O 스키마 (types.ts 와 1:1)
│  │  ├─ routers/
│  │  │  ├─ tree.py                   폴더/프로젝트 트리
│  │  │  ├─ tasks.py                  작업 CRUD·이동·코멘트·scaffold
│  │  │  ├─ inbox.py                  캡처·분류·확인·재분류·dismiss
│  │  │  ├─ dashboard.py              집계
│  │  │  ├─ people.py                 사람
│  │  │  └─ llm.py                    LLM health
│  │  ├─ services/
│  │  │  ├─ classification.py         분류 오케스트레이션(프롬프트+폴백)
│  │  │  ├─ risk.py                   리스크 레이더(TODAY=8, tasks-risk.jsx 이식)
│  │  │  └─ scaffold.py               하위작업 제안(pickScaffold 정규식 이식)
│  │  ├─ llm/
│  │  │  ├─ provider.py               LLMProvider 추상 인터페이스
│  │  │  ├─ ollama.py                 OllamaProvider (format=json)
│  │  │  ├─ heuristic.py              HeuristicProvider (정규식 폴백)
│  │  │  └─ prompts.py                분류 프롬프트
│  │  └─ seed.py                      REF/assets 시드 적재
│  ├─ migrations/                     alembic
│  ├─ tests/                          pytest
│  └─ pyproject.toml
├─ dev/                               (이 개발 문서들 — overview.md 외 7개 phase 문서)
├─ design-reference/                  (원본 프로토타입 — 픽셀 충실 재현 기준)
└─ README.md

9. 데이터 모델 개요

SQLite. 필드명은 CONTRACT 고정값 그대로. frontend/lib/types.tsbackend/app/schemas.py 필드 1:1.

9.1 엔티티 관계 (텍스트 ER)

person ──┐ (assignee)
         ▼
folder 1──* project (self ▸ parent_id 무한 중첩) 1──* task (self ▸ parent_id 무한 중첩) 1──* task_comment
                                                          │
inbox_item 1──1 inbox_classification (최신)               │
inbox_item.materialized_task_id ─────────────────────────┘ (confirm 시 연결)

대시보드 읽기전용 시드: event · approval · goal · briefing

9.2 핵심 엔티티·필드

엔티티 PK 핵심 필드 비고
person id(text, 예 jiwoo) name, initial, color, is_me(bool) 색은 토큰 또는 oklch 리터럴
folder id(text, 예 work/life) name(업무/개인), tone, icon, sort_order, is_system(bool) 최상위 영역(업무/개인)
project id(text) folder_id→folder, parent_id→project(nullable), name, tone, sort_order, pinned(bool) 무한 중첩, pinned=즐겨찾기
task id(text, 예 k1/kx3) project_id, parent_id(nullable), title, status, assignee_id, due(date,null), prio, notes(HTML), est, delegated(bool), sort_order, created_at, updated_at 무한 중첩 하위작업
task_comment id(text, 예 c1) task_id, person_id, text, created_at
inbox_item id(text, 예 s1) kind, raw, status, created_at, materialized_task_id(null)
inbox_classification id(text, 예 cls1) inbox_item_id(1:1 최신), type, sphere, project_id(null), proj_label, tone, due_text, when_text, extra, reason(한국어), confidence(float), model, created_at
event(읽기전용) id(text) time, title, tag, dur, tone, soon(bool) data.js: schedule
approval(읽기전용) id(text) icon, tone, risk(low|high), time, title, detail, cta(null), alt(null), undo_label(null) approve-data.js: items
goal(읽기전용) id(text) title, pct, sub, tone data.js: goals (tone=키 값 blue 등, var(--blue)로 저장 안 함)
briefing(읽기전용) 단일 row/settings today, weather, commute, sleep, note data.js (today="6월 7일 일요일"=히어로 날짜 라벨; 리스크 계산 TODAY=8(6/8)과 혼동 금지)

9.3 열거형(enum) — 고정값

enum
task.status (칸반 컬럼) todo(할 일) · doing(진행 중) · waiting(대기 중) · review(검토) · done(완료) — 라벨·순서 고정 (tasks-data.js: columns)
task.prio 높음 · 보통 · 낮음
inbox_item.kind text · voice · image
inbox_item.status new · classified · confirmed · dismissed
inbox_classification.type task · event · idea
inbox_classification.sphere work · life
tone (전역) blue · violet · coral · green · amber · ink · faint

칸반 컬럼 accent(columns): todo=--faint, doing=--blue, waiting=--violet, review=--coral, done=--green.


10. REST API 개요

FastAPI, prefix /api. (엔드포인트·동작 고정.) 상세 요청/응답 스키마는 phase-2-backend.md에서 전개.

메서드 경로 용도
GET /api/health 헬스체크 {status:"ok"}
GET /api/people person[]
GET /api/tree folder[] (각 folder.projects 중첩, project.task_count 포함)
POST /api/folders 폴더 생성 {name,tone?,icon?}
PATCH /api/folders/{id} 폴더 수정
DELETE /api/folders/{id} 폴더 삭제
POST /api/projects 프로젝트 생성 {folder_id,parent_id?,name,tone?}
PATCH /api/projects/{id} 프로젝트 수정
DELETE /api/projects/{id} 프로젝트 삭제
POST /api/projects/{id}/pin pinned 토글(즐겨찾기)
GET /api/tasks?area=work|life&project_id=&status=&assignee= 중첩 task 트리
GET /api/tasks/{id} 단건
POST /api/tasks 생성 {title,project_id,parent_id?,status?,assignee_id?,due?,prio?,notes?,est?}
PATCH /api/tasks/{id} 상태 이동·필드 수정
DELETE /api/tasks/{id} 삭제
POST /api/tasks/{id}/comments 코멘트 {person_id,text}
POST /api/tasks/{id}/scaffold 제목 기반 하위작업 제안. body {create?:bool=false, use_llm?:bool=false}{kind, icon, items:[{title,est}], created, created_task_ids[]}
GET /api/risks?area=work RiskRadar 결과(지연/쏠림/의존성), 최대 3건
GET /api/inbox inbox_item[] (+ 최신 classification)
POST /api/inbox/capture {kind, raw} → item 생성 + 동기 분류 → {item, classification}
POST /api/inbox/{id}/reclassify 재분류 {type?} (타입 강제 가능)
POST /api/inbox/{id}/confirm 분류 결과를 작업/일정/아이디어로 실체화(federation) → 생성 엔티티
POST /api/inbox/{id}/dismiss 무시
GET /api/dashboard {user:{name,initial}, briefing, saved_today, today_routed, schedule[], task_summary:{open_count,items[]}, goals[], approvals_summary[], inbox_recent[], badges:{appr,task,noti}}
GET /api/llm/health {reachable, model, ...}

10.1 대표 요청/응답 예시

POST /api/inbox/capture

// 요청
{ "kind": "text", "raw": "다음 주에 한국 놀러가는 비행기 티켓 사기" }
// 응답
{
  "item": { "id": "s1", "kind": "text", "raw": "다음 주에 한국 놀러가는 비행기 티켓 사기",
            "status": "classified", "materialized_task_id": null },
  "classification": {
    "type": "task", "sphere": "life",
    "project_suggestion": { "id": null, "label": "개인  여행 — 한국" },
    "tone": "coral", "due_text": "출발 전 · ~6/14", "when_text": "오늘 21:00 빈 시간 추천",
    "extra": "가격 추적 알림 켜둠",
    "reason": "구매라는 행동이 있으니 '작업' 맞아요. 작업 트리의 '개인' 아래에 '여행 — 한국' 프로젝트를 만들어 넣었어요 — 따로 섹션이 생기는 게 아니라 다른 작업과 똑같이 보여요.",
    "confidence": 0.92, "model": "<OLLAMA_MODEL 또는 heuristic>"
  }
}

GET /api/risks?area=work (TODAY=8 기준, 최대 3건. 강조어는 **굵게** 마크다운, 식별자 필드는 task_id)

[
  { "kind": "지연 위험", "icon": "clock", "tone": "coral", "task_id": "k1",
    "text": "**분기 리포트 초안 마무리** — 오늘(6/8) 마감인데 아직 진행 중이에요", "cta": "작업 열기" },
  { "kind": "업무 쏠림", "icon": "scale", "tone": "amber", "task_id": null,
    "text": "미완료 작업 N건이 내게 몰려 있어요 — 팀 평균의 X배. 벅찬 작업은 위임 & 추적으로 넘겨보세요", "cta": null },
  { "kind": "의존성", "icon": "link", "tone": "violet", "task_id": "...",
    "text": "**예산 섹션 작성**이(가) 늦어지면 **경영진 검토 요청 메일**까지 함께 밀려요", "cta": "후속 작업 보기" }
]

GET /api/dashboard (집계 응답 정본 — phase-2 소유 형태를 그대로 소비)

{
  "user": { "name": "지우", "initial": "지" },
  "briefing": {
    "today": "6월 7일 일요일",
    "weather": { "temp": 24, "cond": "맑음 · 한낮 28°", "icon": "sun" },
    "commute": "출근 23분",
    "sleep": "수면 7시간 12분",
    "note": "...<b>분기 리포트</b>..."
  },
  "saved_today": "47분",
  "today_routed": 7,
  "schedule": [
    { "time": "09:30", "title": "팀 데일리 스탠드업", "tag": "프로덕트", "dur": "15분", "tone": "blue", "soon": false }
  ],
  "task_summary": {
    "open_count": 4,
    "items": [ { "id": "k1", "title": "분기 리포트 초안 마무리", "prio": "높음", "project": "분기 리포트" } ]
  },
  "goals": [ { "id": "g1", "title": "분기 OKR — 사용자 리텐션", "pct": 68, "sub": "12개 중 8개 달성", "tone": "blue" } ],
  "approvals_summary": [ { "id": "a4", "icon": "mail", "tone": "violet", "title": "현우님께 회신 초안이 준비됐어요", "time": "보내기 대기" } ],
  "inbox_recent": [ { "id": "s1", "kind": "text", "raw": "...", "type": "task", "proj_label": "개인  여행 — 한국", "tone": "coral" } ],
  "badges": { "appr": 3, "task": 4, "noti": 6 }
}

approvals_summaryrisk=="high"만 최대 3건, 필드는 {id,icon,tone,title,time}(detail/cta/alt/undo_label 미포함). task_summary{open_count, items[]}(total/done/by_status 아님). goals[].tone·schedule[].tonetone은 백엔드에서 (blue 등)로 저장하고 프론트가 var(--tone)로 변환. weather.icon은 시드에 cloudSun으로 저장되며 응답·표시 시 sun으로 매핑(R11 참조). 사용자 인사("좋은 아침이에요, {name}님")는 response.user.name 사용(하드코딩 금지).


11. 디자인 시스템 요약

기준 파일: REF/assets/dash.css :root. → frontend/styles/tokens.css로 무손실 이식. body 전역은 globals.css.

11.1 토큰 카테고리 (HEX 그대로)

카테고리 토큰 = 값
배경 --bg-top #f6efe7 · --bg-mid #eef0f1 · --bg-bot #e9ebed (body: linear-gradient(178deg, top 0%, mid 20%, bot 100%), background-attachment: fixed)
카드 --card #ffffff · --card-2 #f4f5f6 · --card-3 #eef0f1
잉크 --ink #211f1c · --ink-2 #514d47 · --muted #8d8a85 · --faint #b6b3ad
라인 --line rgba(33,31,28,.07) · --line-2 rgba(33,31,28,.13)
채움(선택) --fill #29241f · --fill-soft #36302a · --on-fill #f4efe6
CTA 라임 --lime #c2f24a · --lime-hi #cdf85e · --lime-ink #233006
액센트 --blue #4f72e0 · --coral #df7256 · --green #4e9b66 · --violet #8b6fd4 · --amber #e0a23c
라운드 --radius 22px · --radius-sm 14px
그림자 --shadow 0 10px 30px -14px rgba(30,26,22,.22), 0 2px 6px -2px rgba(30,26,22,.06) · --shadow-sm 0 4px 14px -8px rgba(30,26,22,.18)
글래스 --glass rgba(255,255,255,.4) · --glass-2 rgba(255,255,255,.26) · --glass-brd rgba(255,255,255,.7) · --glass-ink rgba(26,22,18,.46) · --blur blur(26px) saturate(190%) · --glass-hi inset 0 1px 0 rgba(255,255,255,.75)

11.2 폰트

  • --font-disp: "Onest", "Pretendard", system-ui (디스플레이/제목)
  • --font-ui: "Pretendard", "Onest", system-ui (본문 기본)
  • --font-mono: "DM Mono", ui-monospace (숫자/영문, .mono { font-variant-numeric: tabular-nums })
  • 한국어 가독성: body { word-break: keep-all; letter-spacing: -0.011em; }
  • 로드: Onest+DM Mono(Google Fonts), Pretendard(jsDelivr CDN) — 작업.html <head> 참조.

11.3 라이트/다크

  • 메커니즘: documentElementdata-theme="light|dark" 속성 + localStorage 영속 → next-themes 사용.
  • 다크 오버라이드([data-theme="dark"]): --bg-top #201d1a · --card #2c2925 · --ink #f3eee6 · --fill #f4efe6(반전) 등. 전체 값은 dash.css 54~77행 그대로 이식.
  • 토글 UI: 상단바 달/해 아이콘 버튼(Icon name="moon"|"sun", shell.jsx Topbar).

11.4 글래스

반투명 카드 = background: var(--glass) + backdrop-filter: var(--blur) + border: 1px solid var(--glass-brd) + box-shadow: var(--glass-hi). 상단바는 backdrop-filter: blur(14px) saturate(150%), sticky, height 70px.

11.5 아이콘 패턴

  • 원본: 인라인 SVG path 딕셔너리 P + <Icon d="name"/>가 path 문자열을 "|"로 split해 다중 <path> 렌더(shell.jsx 42~49행).
  • 이식: frontend/components/Icon.tsx중앙 paths + <Icon name="..."/>. shell.jsxP전체(spark/grid/route/cal/check/tick/mail/target/heart/wallet/brain/zap/more/search/bell/back/send/sun/moon/swap/up/arrow/inbox/mic/image/pen/users/clock/play/plus/shield/pin)를 옮긴다. 리스크 전용 아이콘(tasks-risk.jsx RP: radar/clock/scale/link/chev)도 통합.
  • 공통 SVG 속성: viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.9} strokeLinecap/Linejoin="round", .ic { width:1em; height:1em }.
  • 누락 시 렌더 깨짐 주의(원본 개발 메모) — paths 맵은 단일 출처로 통합하고 누락 키 가드.

11.6 공유 컴포넌트

컴포넌트 역할 원본
Icon(name) 중앙 paths 맵 SVG shell.jsx Icon
Topbar(current) 좌 브랜드(아리/AI LIFE OS) · 중앙 13항목 mainnav · 우 검색/알림(dot)/테마/아바타. active=글래스 pill shell.jsx Topbar+MAIN, dash.css .topbar/.mainnav/.top-actions/.t-btn/.t-ava
SubRail(items,active,onPick) 좌측 아이콘 레일(아이콘+툴팁, dot 배지, sep). MVP 작업 페이지 선택적 사용 shell.jsx SubRail
GlassCard, Badge, Chip, Button(라임 CTA), SegmentToggle, Avatar 프리미티브. SegmentToggle=칸반/리스트(캘린더는 post-MVP placeholder)

12. 페이지 연합(federation) 흐름

아리의 핵심 가치는 화면 간 데이터를 주고받는 하나의 흐름입니다(PROJECT-README §5). MVP에서 구현하는 연합:

12.1 캡처 → 분류 → 작업 (메인 루프)

인박스: 한 줄 입력
   → POST /api/inbox/capture (동기 분류, classification.py)
   → 결과 칩(type/sphere)·이유(reason)·행선지 카드(proj_label) 표시
   → POST /api/inbox/{id}/confirm
       └ type=task → task 생성 + materialized_task_id 연결
   → 작업 페이지 GET /api/tasks 에 "다른 작업과 똑같이" 등장 (개인=프로젝트 원칙)

시드 예: s1(비행기 티켓) → 작업 k20 한국행 비행기 티켓 구매(life-trip)로 실체화된 모습이 이미 트리에 존재(k20.notes: "스마트 인박스에서 자동 생성된 작업이에요").

12.2 리스크 레이더 = 작업 데이터로 계산

GET /api/risks현재 작업 트리를 직접 계산(별도 저장 없음, risk.py, TODAY=8):

  • 지연 위험: status≠done && due 일자 ≤ 8 → 1건. 예) k1 분기 리포트(due 06-08, doing).
  • 업무 쏠림: 담당자별 미완료 수 집계 → 최다 담당자가 평균×1.5 이상 && 4건 이상이면 경고. me위임 & 추적 CTA, 타인이면 재배분 권유.
  • 의존성: 제목 기반 DEPS 매칭(예산 섹션 작성→경영진 검토 요청 메일, 데이터 전처리 파이프라인→사용자 인터뷰 5건 정리). 둘 다 미완료면 1건. 최대 3건 반환.

12.3 대시보드 = 집계 화면

GET /api/dashboard가 다른 데이터를 읽어 집계(그래서 마지막에 빌드):

  • task_summary ← tasks, inbox_recent ← inbox_item, schedule/approvals_summary ← 읽기전용 시드, briefing/goals ← 시드, badges ← 카운트.
  • 따라서 페이지 빌드 순서는 작업 → 인박스 → 대시보드(§13 빌드 순서와 일치).

13. 개발 Phase 로드맵

13.1 로드맵 표

Phase 문서 목표(끝나면 동작) 주요 산출물 의존성 예상 작업량
0 phase-0-foundation.md 모노레포 스캐폴딩·개발환경. Next dev + FastAPI /api/health + SQLite + Ollama 연결 확인 frontend/·backend/ 골격, next.config rewrites, db.py, /api/health, /api/llm/health overview S
1 phase-1-design-system.md 토큰·앱 셸. Topbar 13항목·테마 토글·Icon·라우팅·placeholder 화면 tokens.css, globals.css, Icon/Topbar/SubRail/GlassCard/..., (placeholder) 라우트 0 M
2 phase-2-backend.md 데이터모델·마이그레이션·시드·전 REST API·Ollama 추상화·분류/리스크/scaffold 서비스 models.py, alembic, seed.py, routers 6, services 3, llm 4, schemas.py 0 L
3 phase-3-tasks.md 작업 페이지: 폴더 트리 사이드바, 칸반/리스트(캘린더는 placeholder), 하위작업, 상세 드로어, 리스크 레이더 app/tasks/page.tsx, 트리/칸반/드로어 컴포넌트, useTasks/useTree/useRisks 1,2 L
4 phase-4-inbox.md 인박스: 캡처 컴포저, 실시간 분류, 결과 칩/이유, 확인·재분류, 행선지 카드, 작업 실체화 app/inbox/page.tsx, 컴포저/분류결과/행선지 컴포넌트, useInbox 1,2,3 M
5 phase-5-dashboard.md 대시보드: 아침 브리핑, 결재함/인박스 요약, 일정/작업/목표 요약, 자연어 명령 입력 app/dashboard/page.tsx, 브리핑/요약 카드, useDashboard 1,2,3,4 M
6 phase-6-integration.md 연합 흐름 통합·E2E·접근성·성능·실행법·MVP 수용 기준 Playwright E2E, axe, 실행 스크립트, 수용 체크리스트 0~5 M

작업량 표기: S(작음)/M(보통)/L(큼) — 상대 추정.

13.2 빌드 순서

0 → 1 → 2 → ( 3 → 4 → 5 ) → 6
                작업  인박스  대시보드

페이지는 작업 → 인박스 → 대시보드 순(대시보드가 작업·인박스 데이터를 집계하므로 마지막, §12.3).


14. LLM(Ollama) 추상화 & 분류 계약

14.1 Provider 추상화 (backend/app/llm/)

# provider.py — 추상 인터페이스 (특정 모델 비종속)
class LLMProvider(ABC):
    def health(self) -> dict: ...                       # {reachable, model, ...}
    def generate_json(self, prompt: str, schema: dict) -> dict: ...
    def classify_capture(self, raw: str, context: dict) -> Classification: ...
구현 파일 설명
OllamaProvider ollama.py Ollama HTTP API(/api/chat 또는 /api/generate)에 format=json 구조화 출력. 설정 OLLAMA_HOST(기본 http://localhost:11434), OLLAMA_MODEL(주입). 모델 비종속 — 문서·코드에서 특정 모델 강제 금지.
HeuristicProvider heuristic.py LLM 미가용/오프라인/테스트용 규칙 기반 폴백. 시간표현 정규식→event, 행동동사+기한→task, 막연→idea. tasks-data.js pickScaffold 정규식 패턴을 분류 보조에 참고.

선택 로직: OllamaProvider.health().reachable이 false면 자동으로 HeuristicProvider로 폴백 → 오프라인/CI에서도 분류가 동작.

14.2 분류 결과(Classification) 스키마 = inbox_classification 필드

type Classification = {
  type: "task" | "event" | "idea";
  sphere: "work" | "life";
  project_suggestion: { id?: string; label: string };  // 예 "개인  여행 — 한국"
  due_text?: string; when_text?: string; extra?: string;
  reason: string;          // 사람이 읽는 한국어 한두 문장
  confidence: number;      // 0~1
};

14.3 분류 규칙 (프롬프트 + 폴백 공통)

  1. 시간 명시 → event(일정). 행동(동사)+기한 → task(작업). 막연/미정 → idea(아이디어).
  2. sphere: 업무 키워드(미팅/리포트/온보딩/OKR/리뷰…) → work, 개인 키워드(가족/여행/선물/구독/병원…) → life.
  3. project_suggestion: 기존 프로젝트 트리 매칭, 없으면 적절한 folder 아래 새 프로젝트 제안(예: 비행기 티켓 → 개인 여행 — 한국).
  4. reason: 사람이 읽는 한국어 1~2문장. 개인=프로젝트 철학을 말로 설명(예: "따로 섹션이 생기는 게 아니라 다른 작업과 똑같이 보여요").

14.4 골든 분류 테스트 케이스 (반드시 테스트에 포함, = 인박스 시드 s1~s4)

입력(raw) type sphere project_suggestion 비고
다음 주에 한국 놀러가는 비행기 티켓 사기 task life 개인 여행 — 한국 extra 가격추적
수요일 11시 자전거 수리 맡기기 event life 개인 캘린더 when 수 11:00
엄마 생신 선물 미리 알아보기 task life 가족 주말 블록
온보딩 환영 화면에 짧은 애니메이션 넣으면 어떨까 idea work 온보딩 리디자인 · 아이디어 보드 보드 보관

15. 상태 처리 & 엣지 케이스 (전역 원칙)

각 페이지 phase 문서가 세부를 다루되, 전역 원칙은 다음과 같습니다.

상태 전역 처리
로딩 글래스 스켈레톤(카드 형태 유지). 데이터 hook(lib/hooks/)의 isLoading.
빈(empty) 인박스 빈: "적을 때는 분류하지 않아요 — 떠오른 걸 그냥 적어보세요" 류 안내. 작업 빈 컬럼: 컬럼 라벨 유지 + placeholder.
에러 lib/api.ts가 비2xx를 throw → 카드 단위 에러 + 재시도 버튼. 전체 앱 셸(Topbar/테마)은 유지.
오프라인/LLM 미가용 GET /api/llm/health.reachable=false → 분류는 HeuristicProvider로 계속 동작, classification.model="heuristic" 표기. UI는 "아리가 규칙 기반으로 분류했어요" 류 미세 힌트(선택).
HTML 시드(notes/briefingNote) 신뢰된 시드지만 사용자 입력 경로(task.notes)는 새니타이즈(예: DOMPurify) 후 렌더.
무한 중첩 project/task parent_id 깊이 무제한 — 렌더는 들여쓰기(depth), API는 중첩 트리 반환. 깊이 폭주 가드 권장.
삭제 연쇄 folder/project 삭제 시 하위 처리 정책은 phase-2-backend.md에서 확정(이 문서는 엔드포인트만 정의).

16. 테스팅 & 검증

본 문서 자체는 지도이므로 "검증" = 문서 정확성 + 각 phase로의 정합성을 점검하는 것입니다. 동시에, 전 phase가 공통으로 쓸 테스트 도구·실행 명령·통과 기준을 여기서 한 번에 정의합니다(각 phase 문서는 이를 재사용).

16.1 실행 명령 (전 phase 공통 레퍼런스)

# 백엔드 (backend/)
uv run pytest                          # 또는: pytest
uv run pytest -k "classify"            # 골든 분류 케이스만
uv run uvicorn app.main:app --reload   # 개발 서버 (:8000)
uv run alembic upgrade head            # 마이그레이션
uv run python -m app.seed              # 시드 적재

# 프론트엔드 (frontend/)
pnpm dev                               # Next dev (:3000, /api → :8000 rewrite)
pnpm test                              # Vitest + React Testing Library (컴포넌트)
pnpm playwright test                   # Playwright E2E
pnpm playwright test --grep @a11y      # axe 접근성 (태그 기반, 예시)
pnpm build && pnpm start               # 프로덕션 빌드 검증

16.2 이 문서(overview)의 검증 케이스

# 검증 항목 통과 기준
O-1 토큰 값 일치 §11 표의 모든 HEX/px가 REF/assets/dash.css :root와 100% 일치
O-2 people 일치 §4.2 5인의 id/name/initial/color/is_me가 tasks-data.js: people와 일치(수아 oklch 포함)
O-3 enum 일치 §9.3 모든 enum 값·라벨·순서가 CONTRACT/columns와 일치
O-4 API 표 완전성 §10 표가 CONTRACT의 24개 엔드포인트를 빠짐없이 포함
O-5 골든 케이스 = 시드 §14.4 4건이 sinbox-data.js: items s1~s4와 type/sphere/proj 일치
O-6 TODAY 구분 §4.3에 today="6월 7일 일요일" vs 리스크 TODAY=8 차이가 명시
O-7 빌드 순서 §13.2가 0→1→2→(3→4→5)→6, 페이지 작업→인박스→대시보드
O-8 상호 참조 모든 phase 문서가 정확한 파일명(phase-N-*.md)으로 링크됨
O-9 13항목 내비 §5.1/§11.6의 MAIN 항목·badge(결재함3/작업4/알림6)가 shell.jsx: MAIN과 일치

16.3 전 phase 공통 통과 기준(요약, 상세는 각 문서)

  • 백엔드: pytest 전건 통과, 골든 분류 4케이스 통과(LLM 없이 HeuristicProvider로도), GET /api/risks가 TODAY=8로 지연/쏠림/의존성 최대 3건 정확.
  • 프론트: pnpm test 컴포넌트 통과, pnpm playwright test 연합 E2E(캡처→확인→작업 등장) 통과, axe 위반 0(심각도 serious 이상).
  • 디자인 충실도: 라이트/다크 토큰 적용, 상단바 13항목·테마 토글 동작, 글래스/라운드/그림자가 토큰과 일치.

16.4 수동 QA 체크리스트 (MVP 전체)

  • / 진입 시 /dashboard로 리다이렉트.
  • 상단 내비 13항목 모두 표시, MVP 외 10항목 클릭 시 "준비 중" 화면(셸 유지).
  • 테마 토글(달/해) 동작 + 새로고침 후 유지(localStorage).
  • 인박스에 4개 골든 문장 입력 → 각각 task/event/idea·work/life·올바른 행선지·한국어 이유 표시.
  • 인박스 작업형 항목 확인 → 작업 페이지 트리에 등장.
  • 작업 페이지 칸반 5컬럼(할 일/진행 중/대기 중/검토/완료) 라벨·순서.
  • 리스크 레이더에 지연(분기 리포트)·쏠림·의존성 경고 표시.
  • 대시보드 아침 브리핑·일정 4건·목표 3개·결재함/인박스 요약 표시.
  • 한국어 줄바꿈 word-break: keep-all 적용(어절 단위 줄바꿈).

17. 완료 기준 (Definition of Done)

이 진입 문서의 DoD:

  • 제품 비전·3대 철학(적을 때 분류 안 함 / 이미 해뒀어요 / 개인=프로젝트) 서술.
  • 페르소나(지우)·팀원 5인·6/7~12 한 주·TODAY=8 명시.
  • MVP 범위(작업/인박스/대시보드)와 13페이지 경계·placeholder 규칙.
  • 텍스트 아키텍처 다이어그램(브라우저↔FastAPI↔SQLite↔Ollama)·데이터 흐름.
  • 스택 결정·근거표.
  • 모노레포 전체 트리.
  • 데이터 모델(ER·필드·enum) 표.
  • REST API 24엔드포인트 표 + 요청/응답 예시.
  • 디자인 토큰(HEX/px)·폰트·라이트/다크·글래스·아이콘 패턴.
  • 연합 흐름(캡처→분류→작업, 리스크=작업계산, 대시보드 집계).
  • phase 0~6 로드맵 표 + 빌드 순서.
  • LLM Provider 추상화 + 분류 스키마/규칙/골든 케이스.
  • 용어집·문서 세트 사용법.
  • 모든 phase 문서를 정확한 파일명으로 상호 참조.

18. 용어집

용어 정의
인박스(Inbox) "일단 적으세요"의 진입점. 텍스트/음성/이미지 캡처(inbox_item)를 받아 아리가 분류. MVP 핵심 페이지.
캡처(Capture) 인박스에 던진 한 줄/메모. POST /api/inbox/capture로 생성 + 동기 분류.
분류(Classification) 캡처를 task/event/idea + work/life + 행선지 프로젝트 + 한국어 reason으로 판정한 결과(inbox_classification).
실체화(Materialize / federation) 분류 결과를 실제 엔티티로 확정. confirm 시 task 생성 + materialized_task_id 연결 → 작업 페이지에 등장.
결재함(Approvals) 아리가 "이미 해둔" 자동 처리를 모아 승인/되돌리기(approval). MVP는 대시보드 요약 카드로만 읽기전용 노출. risk=low(되돌리기)/high(확인 후 실행).
리스크 레이더(Risk Radar) 작업 트리를 직접 계산해 지연 위험·업무 쏠림·의존성을 최대 3건 경고(GET /api/risks, TODAY=8).
sphere 영역 구분 work(업무) / life(개인). "개인=프로젝트" 원칙상 별도 섹션이 아니라 필터.
folder(영역) 트리 최상위(업무/개인). 사용자 생성 가능, is_system으로 시스템 폴더 구분.
project folder 아래 무한 중첩 가능한 프로젝트. pinned=즐겨찾기.
task / 하위작업 작업. parent_id로 무한 중첩(하위작업도 그 자체로 완전한 작업). status 5단(칸반).
scaffold(자동 쪼개기) 작업 제목 기반 하위작업 제안(POST /api/tasks/{id}/scaffold). pickScaffold 정규식으로 research/dev/doc/generic 템플릿 선택.
tone 색 토큰 집합 blue/violet/coral/green/amber/ink/faint. 카드 점·바·라벨 액센트.
prio(우선순위) 높음/보통/낮음.
브리핑(Briefing) 대시보드 아침 요약(날씨/출근/수면/노트). data.js.
글래스(Glass) 반투명 카드 스타일(--glass* + --blur). 클린 화이트 글래스 테마의 정체성.
Provider 추상화 LLM 교체 가능 인터페이스(LLMProvider). OllamaProvider(로컬) ↔ HeuristicProvider(폴백). 모델 비종속(OLLAMA_MODEL).
SubRail 좌측 아이콘 레일(아이콘+툴팁+dot+sep). MVP는 작업 페이지에서 선택적 사용.

19. 이 문서 세트 사용법

19.1 읽는 순서

  1. overview.md(이 문서) — 전체 그림·계약·로드맵. (현재)
  2. phase-0-foundation.md — 모노레포 스캐폴딩 & 개발환경(Next + FastAPI + SQLite + Ollama 연결 확인).
  3. phase-1-design-system.md — 디자인 토큰 이식 + 앱 셸(Topbar/테마/Icon/레이아웃/placeholder 라우팅).
  4. phase-2-backend.md — 데이터모델·마이그레이션·시드·REST API·Ollama 추상화·분류/리스크/scaffold 서비스.
  5. phase-3-tasks.md — 작업 페이지(트리 사이드바·칸반/리스트[캘린더는 placeholder]·하위작업·상세 드로어·리스크 레이더).
  6. phase-4-inbox.md — 인박스(캡처 컴포저·실시간 분류·칩/이유·확인/재분류·행선지·작업 실체화).
  7. phase-5-dashboard.md — 대시보드(아침 브리핑·결재함/인박스 요약·일정/작업/목표 요약·자연어 명령 입력).
  8. phase-6-integration.md — 연합 통합·E2E·접근성·성능·실행법·MVP 수용 기준.

19.2 작업 방식

  • 각 phase 문서는 개요/선행·산출물/상세구현/데이터·타입·API/디자인 충실도/상태·엣지/테스팅·검증/DoD/다음 단계 9개 섹션을 가집니다.
  • 항상 빌드 순서(§13.2) 를 지키세요: 0→1→2→(3→4→5)→6.
  • 값(색·필드·문구)은 항상 REF/assets의 원본을 단일 출처로 삼고, 의심되면 이 문서의 표와 대조하세요.
  • 계약(데이터 모델·API·토큰·스택·명명)은 변경 금지 — 변경이 필요하면 먼저 이 overview.md를 갱신하고 전 phase에 전파합니다.

끝. 다음 문서: phase-0-foundation.md