03

통합인생OS · 홈·대시보드

기능설계 ③ — 모든 시스템의 관문이 되는 단 하나의 홈 화면

항목내용
기능 IDFEAT-HOME
연결 시스템마스터 시스템① 통합인생OS — 12대 시스템을 한 화면에 집약
한 줄 정의어르신이 앱을 켜면 가장 먼저 보는 화면. 오늘 할 일·안부·아리·SOS를 큰 카드로 한눈에
관련 액터PWA실벗서버아리
설계 철학 — 어르신은 "여러 메뉴를 찾아다니지" 않습니다. 홈은 "오늘 무엇을 하면 되는지"를 큰 글씨·큰 버튼으로 말해주는 비서여야 합니다. 모든 위젯은 서버가 우선순위를 매겨 내려줍니다.

설계 7계층 체크리스트

계층이 문서의 섹션
① UI홈 화면 SCR-HOME-01 (인사·위젯 카드·하단 탭바)
② Flow앱 진입 → 위젯 우선순위 결정 → 렌더 플로우
③ Datahome_widgets / user_dashboard_state DDL
④ APIGET /home/dashboard · PUT /home/widgets/order
⑤ Seq홈 집계 시퀀스 (여러 시스템 데이터 병합)
⑥ Comp홈 위젯 컴포넌트·집계 서비스 구조
⑦ Test검수 체크리스트

① UI · 화면 명세

홈 화면 SCR-HOME-01

영역요소 / 동작
인사 헤더"순자님, 좋은 아침이에요 ☀️" (시간대별 인사) + 날씨·오늘 날짜
아리 카드 (최상단)아리 아바타 썸네일 + 먼저 건넨 말 1줄 → 탭 시 대화 화면(d01)
오늘 할 일 위젯복약·일정·안부 등을 큰 체크 카드로. 완료 시 ✓ 표시
가족 안부 위젯최근 가족 메시지/사진 1건 미리보기 → 탭 시 가족(d05)
SOS 고정 버튼화면 어디서나 접근 가능한 빨간 플로팅 버튼 → SOS(d02)
하단 탭바🏠 홈 · 💬 아리 · 👪 가족 · 🎮 놀이 · ☰ 더보기 (5탭, 큰 아이콘)

위젯 표시 규칙

상황표시
복용할 약이 있음복약 위젯을 최상단(아리 다음)으로 승격, 빨간 점
가족 새 메시지 있음가족 안부 위젯에 배지(N)
오늘 할 일 모두 완료"오늘 할 일을 다 하셨어요! 👏" 격려 카드
데이터 로딩 실패스켈레톤 → 캐시된 직전 홈 표시 + 새로고침 안내(빈 화면 금지)

② Flow · 진입·렌더 플로우

앱 실행 토큰 확인 캐시 홈 즉시 표시 /home/dashboard 호출 위젯 병합·정렬 홈 렌더 완료

핵심: 캐시 우선(Stale-While-Revalidate). 어르신은 흰 화면을 기다리지 않는다. 직전 홈을 즉시 보여주고, 서버 응답이 오면 부드럽게 갱신.

위젯 우선순위 결정 (서버)

순위조건위젯
0 (고정)항상아리 카드
130분 내 복약 시간복약 알림
2오늘 일정 있음일정
3가족 새 활동가족 안부
4~기본 순서놀이·일자리·건강 등

③ Data · DB 스키마

홈은 여러 시스템 데이터를 집계하는 화면이므로 자체 테이블은 가볍다. 위젯 정의 + 사용자별 정렬 상태만 저장.

MariaDB · UTF8MB4 · InnoDB
CREATE TABLE home_widgets ( id INT PRIMARY KEY AUTO_INCREMENT, widget_key VARCHAR(40) UNIQUE, -- 'medication','family','play'... title VARCHAR(60), icon VARCHAR(20), default_ord TINYINT DEFAULT 99, is_active TINYINT DEFAULT 1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE user_dashboard_state ( user_id BIGINT PRIMARY KEY, widget_order JSON, -- ["medication","family",...] 개인 정렬 hidden_keys JSON, -- 숨긴 위젯 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
설계 포인트 — 홈 데이터는 medications·calendar_events·notifications 등 기존 p25 테이블에서 읽어서 집계만 한다. 중복 저장하지 않는다.

④ API · 엔드포인트 명세

M경로설명
GET/home/dashboard홈에 표시할 위젯 + 데이터 일괄 조회(집계)
PUT/home/widgets/order사용자 위젯 정렬·숨김 저장
GET /api/v1/home/dashboard · 200
{ "success": true, "data": { "greeting": "순자님, 좋은 아침이에요 ☀️", "ari": { "message": "어제 손주 본다 하셨죠? 오늘 만나세요?" }, "widgets": [ { "key":"medication", "ord":1, "badge":"혈압약 1개", "urgent":true }, { "key":"family", "ord":3, "badge":2 } ] }, "meta": { "cached_at":"2026-06-18T08:00:00+09:00" } }

⑤ Seq · 홈 집계 시퀀스

PWA
앱 실행 → 캐시된 홈 즉시 표시 → GET /home/dashboard 호출
실벗서버
병렬 조회: 복약(medications)·일정(calendar_events)·가족(notifications)·아리(proactive)
실벗
위젯 우선순위 규칙 적용 + user_dashboard_state 개인정렬 병합
아리
먼저 건넬 말 1줄 생성(ari_memory 기반) — 실패 시 기본 인사로 폴백
실벗
집계 JSON 반환 (+ cached_at)
PWA
위젯 부드럽게 갱신(diff 렌더) + 캐시 업데이트
장애 폴백 — 일부 시스템 조회 실패 시 해당 위젯만 제외하고 나머지 렌더. 홈 전체가 깨지지 않는다.

⑥ Comp · 컴포넌트 / 모듈 구조

프론트엔드 (PWA)

features/home/ ├─ HomeView.js # 홈 화면 컨테이너 ├─ widgets/ │ ├─ AriCard.js # 아리 먼저 말걸기 카드 │ ├─ MedicationWidget.js # 복약 위젯 │ ├─ FamilyWidget.js # 가족 안부 위젯 │ └─ WidgetRenderer.js # ord순 동적 렌더 ├─ TabBar.js # 하단 5탭 └─ homeCache.js # SWR 캐시(localStorage)

백엔드 (PHP)

app/ ├─ Controllers/HomeController.php # /home/* └─ Services/ └─ DashboardAggregator.php # 다중 시스템 병합·우선순위
모듈책임
DashboardAggregator홈의 두뇌. 여러 시스템을 병렬 조회하고 우선순위 규칙으로 위젯 순서 결정. 부분 실패 허용.
WidgetRenderer서버가 준 ord 순서대로 위젯을 동적 렌더. 알 수 없는 key는 무시(전방호환).

⑦ Test · 검수 체크리스트

ID시나리오기대 결과
T-01아침에 앱 실행"좋은 아침" 인사 + 아리 카드 최상단 표시
T-02복약 시간 30분 전 진입복약 위젯이 1순위로 승격, 빨간 점 표시
T-03오프라인 상태로 앱 실행캐시된 직전 홈 즉시 표시 + "연결 확인 중" 안내(빈 화면 금지)
T-04가족 위젯 일부 조회 실패가족 위젯만 제외, 나머지 홈 정상 렌더
T-05아리 먼저말걸기 생성 실패기본 인사로 폴백, 홈 정상
T-06위젯 순서 변경 후 재접속user_dashboard_state 반영된 개인 정렬로 표시
완료 판정 — T-01~T-06 통과 시 FEAT-HOME 완료. 특히 T-03·T-04(캐시·부분실패)는 "홈은 절대 안 깨진다" 원칙의 핵심.
기능설계 ③ 완성 — 홈은 12대 시스템의 관문. 이 7계층 설계로 "켜자마자 오늘 할 일이 보이는" 비서형 홈을 구현합니다.