# backend/app/services/journey.py — 여정 집계 from sqlmodel import Session, select from ..models import Event, JourneyLink, Person, Task, TaskStatus from ..schemas import ( GaugeOut, JourneyCardsOut, JourneyHeaderOut, JourneyLinkOut, JourneyMetaOut, JourneyOut, JourneyPersonOut, JourneyRowOut, JourneyStageOut, JourneyTableOut, MeetCardOut, RoutineCardOut, TaskCardOut, TileCardOut, ) STAGES = [ ("s1", "아침 준비", "06:40 – 09:00", "blue", "2"), ("s2", "오전 집중", "09:00 – 13:00", "coral", "4"), ("s3", "오후 협업", "13:00 – 17:00", "violet", "4"), ("s4", "마무리 & 내일", "17:00 – 23:00", "ink", "4"), ] ROUTINE_CARDS = [ dict( node="m-sleep", icon="moon", title="수면 7시간 12분", meta="평소만큼 푹 잔 밤", tag="컨디션 좋음", tool="tick", toolTone="ok", ), dict( node="m-brief", icon="sun", title="아침 브리핑 확인", meta="맑음 24° · 출근 23분", tag="4분 빠름", tool="cal", toolTone="", ), ] TASK_NODES = [ ("t-report", "k1", "경영 전략 · 우선"), ("t-wire", "k2", "온보딩 · 우선"), ("t-interview", "k5", "온보딩 · 리서치"), ("t-welcome", "k3", "팀 운영"), ] MEET_NODES = [ ("k-stand", "e1", "minseo", False), ("k-design", "e2", "hyunwoo", False), ("k-strat", "e3", "jaeho", True), ("k-11", "e4", "minseo", False), ] TILE_CARDS = [ dict(node="w-focus", hi=True, icon="target", tt="지금 집중", ts="분기 리포트 마무리"), dict(node="w-retro", hi=False, icon="send", tt="회고 배포", ts="팀 채널 공유"), dict(node="w-health", hi=False, icon="heart", tt="운동 30분", ts="주 3/4회"), dict(node="w-next", hi=False, icon="cal", tt="내일 준비", ts="일정 4건"), ] PEOPLE_TASKCOUNT = {"jiwoo": 4, "hyunwoo": 2, "minseo": 2, "jaeho": 2, "sua": 3} PEOPLE_ROLE = { "jiwoo": "나 · PM", "hyunwoo": "디자인", "minseo": "팀 운영", "jaeho": "데이터", "sua": "리서치", } TABLE_ROWS = [ ("t-report", "k1", True, "09:00"), ("t-wire", "k2", False, "11:00"), ("t-interview", "k5", False, "13:30"), ("t-welcome", "k3", True, "08:30"), ("t-card", "k4", False, "18:00"), ] STATUS_CHIP = { "doing": ("prog", "진행중"), "review": ("review", "검토"), "done": ("done", "완료"), "todo": ("sched", "예정"), "waiting": ("prog", "진행중"), } def build_journey(s: Session) -> JourneyOut: people = s.exec(select(Person)).all() tasks = {t.id: t for t in s.exec(select(Task)).all()} events = {e.id: e for e in s.exec(select(Event)).all()} # 여정 협업 인물은 핵심 5인만(메일 발신자 제외) core = {"jiwoo", "hyunwoo", "minseo", "jaeho", "sua"} person_out = [ JourneyPersonOut( id=p.id, name=p.name, initial=p.initial, color=p.color, me=p.is_me, tasks=PEOPLE_TASKCOUNT.get(p.id, 0), role=PEOPLE_ROLE.get(p.id, ""), ) for p in people if p.id in core ] stages = [ JourneyStageOut(id=i, title=t, time=tm, tone=tone, n=n) for (i, t, tm, tone, n) in STAGES ] s1 = [RoutineCardOut(**c) for c in ROUTINE_CARDS] s2 = [] for node, tid, meta in TASK_NODES: t = tasks.get(tid) s2.append( TaskCardOut( node=node, title=t.title if t else node, meta=meta, who=t.assignee_id if t else "jiwoo", done=(t.status == TaskStatus.done) if t else False, ) ) s3 = [] for node, eid, who, soon in MEET_NODES: e = events.get(eid) meta = f"{e.tag} · {e.dur}" if e else "" s3.append( MeetCardOut( node=node, time=e.time if e else "", title=e.title if e else node, meta=meta, who=who, soon=soon, ) ) s4 = [TileCardOut(**c) for c in TILE_CARDS] links = [ JourneyLinkOut( from_node=link.from_node, to_node=link.to_node, tone=link.tone, dash=link.dash ) for link in s.exec(select(JourneyLink).order_by(JourneyLink.sort_order)).all() ] rows = [] for node, tid, star, start in TABLE_ROWS: t = tasks.get(tid) chip, label = STATUS_CHIP.get(t.status.value if t else "todo", ("sched", "예정")) rows.append( JourneyRowOut( node=node, title=(t.title if t else node), star=star, statusKey=chip, statusLabel=label, startTime=start, who=(t.assignee_id if t else "jiwoo"), ) ) counts = {"prog": 0, "review": 0, "done": 0, "sched": 0} for r in rows: counts[r.statusKey] = counts.get(r.statusKey, 0) + 1 subtitle = ( f"{len(rows)}건 · 진행중 {counts['prog']} · 검토 {counts['review']} " f"· 완료 {counts['done']} · 예정 {counts['sched']}" ) gauges = [ GaugeOut(pct=87, tone="blue", val="5.2", unit="시간", label="딥 워크", sub="목표 6시간"), GaugeOut(pct=72, tone="coral", val="72", unit="%", label="활동 링", sub="7.2천 걸음"), ] return JourneyOut( header=JourneyHeaderOut(dateLabel="6월 10일 화요일", weather="맑음 · 한낮 28°"), meta=JourneyMetaOut(stageCount=4, itemCount=12, collabCount=5, peopleMore="+3"), people=person_out, stages=stages, cards=JourneyCardsOut(s1=s1, s2=s2, s3=s3, s4=s4), links=links, rows=rows, table=JourneyTableOut(subtitle=subtitle), gauges=gauges, gaugeFoot="오후 3시예요 — 물 한 잔, 5분 스트레칭 어때요?", )