| 항목 | 내용 |
| 기능 ID | FEAT-HOME |
| 연결 시스템 | 마스터 시스템① 통합인생OS — 12대 시스템을 한 화면에 집약 |
| 한 줄 정의 | 어르신이 앱을 켜면 가장 먼저 보는 화면. 오늘 할 일·안부·아리·SOS를 큰 카드로 한눈에 |
| 관련 액터 | PWA실벗서버아리 |
설계 철학 — 어르신은 "여러 메뉴를 찾아다니지" 않습니다. 홈은 "오늘 무엇을 하면 되는지"를
큰 글씨·큰 버튼으로 말해주는 비서여야 합니다. 모든 위젯은 서버가 우선순위를 매겨 내려줍니다.
▍설계 7계층 체크리스트
| 계층 | 이 문서의 섹션 |
| ① UI | 홈 화면 SCR-HOME-01 (인사·위젯 카드·하단 탭바) |
| ② Flow | 앱 진입 → 위젯 우선순위 결정 → 렌더 플로우 |
| ③ Data | home_widgets / user_dashboard_state DDL |
| ④ API | GET /home/dashboard · PUT /home/widgets/order |
| ⑤ Seq | 홈 집계 시퀀스 (여러 시스템 데이터 병합) |
| ⑥ Comp | 홈 위젯 컴포넌트·집계 서비스 구조 |
| ⑦ Test | 검수 체크리스트 |
② Flow · 진입·렌더 플로우
앱 실행→
토큰 확인→
캐시 홈 즉시 표시→
/home/dashboard 호출→
위젯 병합·정렬→
홈 렌더 완료
핵심: 캐시 우선(Stale-While-Revalidate). 어르신은 흰 화면을 기다리지 않는다. 직전 홈을 즉시 보여주고, 서버 응답이 오면 부드럽게 갱신.
▍위젯 우선순위 결정 (서버)
| 순위 | 조건 | 위젯 |
| 0 (고정) | 항상 | 아리 카드 |
| 1 | 30분 내 복약 시간 | 복약 알림 |
| 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계층 설계로 "켜자마자 오늘 할 일이 보이는" 비서형 홈을 구현합니다.