---
id: IP03
manual_id: IP03
series: Integrated Projects
title: 데이터 분석 대시보드 서비스 만들기
version: 0.1.0
content_version: 0.1.0
status: self-reviewed
audience: 입문 개발자·데이터 분석가·서비스 기획자·운영 책임자
estimated_time: 90분 실습 + 4시간 자율 학습
---

# 데이터 분석 대시보드 서비스 만들기

> **한 줄 목표:** 합성 원천 row를 지표·차트로 보여 주는 데서 멈추지 않고, data version·품질·분모·filter·접근 범위·insight·사람 결정·복구 evidence가 끝까지 연결된 로컬 서비스를 만듭니다.

## 1. 먼저 보는 한 장: 데이터에서 사람 결정까지

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/01-data-to-decision-journey.svg" alt="합성 원천 데이터에서 지표 정의, query, 차트, insight, 사람 결정으로 이어지는 흐름"><figcaption>그림 1. 대시보드의 완성 단위는 chart가 아니라 같은 ID와 계약으로 이어지는 결정 trace입니다.</figcaption></figure>

좋은 대시보드는 숫자를 많이 보여 주는 화면이 아닙니다. 어떤 source version을 읽었는지, 한 row가 무엇을 뜻하는지, 품질 검사를 통과했는지, 지표 분모가 무엇인지, 같은 filter가 chart와 table에 적용됐는지, 사람이 어떤 한계 아래 무엇을 결정했는지를 다시 따라갈 수 있어야 합니다.

| 단계 | 학습 질문 | IP03 evidence |
|---|---|---|
| SOURCE | 무엇을 언제 읽었나 | manifest·checksum·as-of |
| DEFINE | 어떤 grain·품질·지표인가 | schema·rules·metric version |
| QUERY | 어떤 범위로 계산했나 | filter·scope·query signature |
| EXPLAIN | 값과 한계를 어떻게 보였나 | chart·table·insight |
| DECIDE | 누가 무엇을 왜 했나 | decision history·review date |

## 2. 이 교재를 공부하는 순서

각 장은 **그림 보기 → 화면에서 찾기 → 직접 실행하기 → evidence 남기기 → 자기 말로 설명하기** 순서입니다. PDF를 먼저 훑고 앱을 열면, 화면의 각 ID와 경고가 장식이 아니라 어떤 계약의 증거인지 보이기 시작합니다.

| 순서 | 행동 | 완료 신호 |
|---|---|---|
| 1 · SEE | 도표의 화살표와 실패 경로를 본다 | 다음 단계 말하기 |
| 2 · FIND | 앱에서 같은 ID·값·경고를 찾는다 | DV·MET·QRY 연결 |
| 3 · DO | 정상·품질 gap·stale·scope 거부를 실행한다 | Expected 재현 |
| 4 · RECORD | 8개 evidence와 사람 판정을 남긴다 | 재검토 가능 |
| 5 · TEST | 30문제를 먼저 풀고 정답을 펼친다 | 틀린 도표로 회귀 |

> **PDF 학습 팁:** 표지를 넘긴 뒤 그림의 오른쪽 절반을 가리고 다음 단계를 먼저 말해 보세요. 눈으로 다시 읽는 것보다 흐름을 기억에서 복원하는 연습이 오래 남습니다.

## 3. 학습 Gate와 실제 운영 권한을 분리하기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/02-authority-and-data-safety-boundary.svg" alt="로컬 학습, pilot, production, assurance의 데이터 권한 경계"><figcaption>그림 2. 각 단계의 통과는 다음 단계의 보안·통계·경영 승인이 아닙니다.</figcaption></figure>

IP03은 합성 주간 집계로 데이터 서비스 계약을 학습합니다. 실제 사용자·고객·매출·개인정보·실제 성과·인과 효과를 다루지 않습니다. `data_service_review_ready`는 검토할 evidence가 연결됐다는 뜻이며 production approval이나 통계적 보증이 아닙니다.

| 포함 | 제외 | 다음 검증 권한 |
|---|---|---|
| 합성 48개 주간 row | 실제 고객·매출·PII | Data owner·privacy |
| 로컬 SQLite·stdlib | Cloud BI·warehouse | Architecture·security |
| 6개 합성 지표 | 실제 성과·목표 | Metric owner·finance |
| 12 합성 evaluation | 실제 분포·인과 | Analyst·statistician |
| 학습 Gate | 경영 의사결정 승인 | Decision owner |

## 4. 같은 사건을 UI·API·DB·Gate에서 추적하기

예를 들어 `DV-001`에서 `MET-04`를 전체 기간으로 조회하면 filter가 canonical JSON으로 정규화되고 `QRY-*` signature가 만들어집니다. 같은 signature가 KPI·chart·table·insight에 붙고, 결정 record는 insight와 actor·reason·review date를 참조합니다.

| 계층 | 핵심 record | 추적 기준 |
|---|---|---|
| UI | selected version·filters·metric | DV-001·MET-04 |
| API | dashboard query·problem response | request·QRY signature |
| DB | versions·rows·quality·insights·decisions | foreign key |
| Contract | schema·metric·quality version | owner·effective date |
| Evaluation | EV-01~12 | expected·actual·evidence |
| Gate | CTRL-01~12·SC-01~24 | risk·critical·coverage |

## 5. 역할과 row scope를 서버에서 지키기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/03-roles-and-row-scope.svg" alt="Data steward, Analyst, Decision owner, Viewer의 command와 row scope"><figcaption>그림 3. Role은 command를, scope는 query가 반환할 row 범위를 제한합니다.</figcaption></figure>

| 역할 | 읽기 범위 | 허용 command | 거부되는 일 |
|---|---|---|---|
| DATA_STEWARD | ALL | quality·refresh | 사업 결정 |
| ANALYST | ALL | query·insight create | 최종 판정 |
| DECISION_OWNER | ALL aggregate | insight decide | source 수정 |
| VIEWER | SEOUL aggregate | read only | 타 지역·mutation |

Viewer가 주소창이나 개발 도구로 `BUSAN`을 요청해도 서버가 `region_scope_denied`로 거부합니다. 화면에서 filter를 감추는 것은 편의이고, 서버가 session의 actor scope와 요청 resource를 다시 비교하는 곳이 보안 경계입니다.

## 6. Data version 수명주기와 변경 이력

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/04-data-version-lifecycle.svg" alt="DRAFT에서 INGESTED, VALIDATED, PUBLISHED, DECIDED로 가는 data version 수명주기"><figcaption>그림 4. 정상 흐름과 작업 실패·품질 quarantine 경로를 분리합니다.</figcaption></figure>

| 상태 | 뜻 | 다음 확인 |
|---|---|---|
| DRAFT | source 계약 준비 | owner·window |
| INGESTED | row와 manifest 저장 | schema·count |
| VALIDATED | quality rule 완료 | critical 0 |
| PUBLISHED | 지표 조회 가능 | as-of·scope |
| DECIDED | 사람 판정 연결 | history·review date |
| QUARANTINED | critical issue 있음 | repair·rerun |
| FAILED | refresh·ingest 작업 실패 | incident·restore |

기존 version을 덮어쓰면 과거 결정이 어떤 숫자를 보았는지 설명할 수 없습니다. 변경은 새 data version과 transition event로 추가하고, actor·reason·time을 남깁니다.

## 7. Manifest·checksum·provenance

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/05-source-manifest-checksum-provenance.svg" alt="합성 원천과 manifest, query 재현 근거를 연결한 provenance"><figcaption>그림 5. 지표값에서 source version·checksum·as-of로 돌아갈 수 있어야 합니다.</figcaption></figure>

| Manifest field | 예 | 왜 필요한가 |
|---|---|---|
| source | YEONCORE Learning Lab synthetic weekly | 원천 정체 |
| owner | Learning Operations | 설명 책임 |
| as-of | 2026-05-25 | 최신성 |
| grain | week×region×channel | row 의미 |
| row count | 48 | 누락·중복 대조 |
| checksum | SHA-256 digest | 내용 변경 감지 |
| schema version | 1.0.0 | field 계약 |

## 8. Schema·grain·품질 rule·quarantine

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/06-schema-grain-quality-quarantine.svg" alt="Grain, 필수값, 범위, cross-field 검사 뒤 publish 또는 quarantine으로 나뉘는 흐름"><figcaption>그림 6. 품질 문제를 숨기지 않고 KPI 공개를 차단합니다.</figcaption></figure>

IP03의 row grain은 `week_start × region × channel`입니다. 주 8개, region 3개, channel 2개이므로 정상 version은 48개 row입니다. 검사 순서는 unique key → required → type·range → child-parent relation입니다.

| Rule | 검사 | 실패 예 | 처리 |
|---|---|---|---|
| DQ-UNI-01 | grain unique | 같은 주·지역·채널 중복 | CRITICAL |
| DQ-COM-01 | required | enrolled null | CRITICAL |
| DQ-VAL-03 | 0 이상 integer | service_cost -1 | CRITICAL |
| DQ-CON-01 | child ≤ parent | activated > enrolled | CRITICAL |
| DQ-CON-02 | SLA numerator ≤ denominator | within24h > closed | CRITICAL |

## 9. 세 data version으로 정상·품질 gap·stale 비교하기

| Version | Rows | Quality | Freshness | KPI |
|---|---|---|---|---|
| DV-001 | 48 | critical 0 | fresh | VALID |
| DV-002 | 49 | critical 4 | fresh | 모두 WITHHELD |
| DV-003 | 48 | critical 0 | stale | 값 + STALE 경고 |

DV-002의 목적은 오류를 고치는 척하는 것이 아닙니다. 중복·null·음수·cross-field issue를 각각 구조화해 보여 주고, 그럴듯한 숫자를 공개하지 않는 fail-closed 경로를 학습합니다. DV-003은 정확성과 최신성이 서로 다른 계약임을 보여 줍니다.

## 10. 지표 이름보다 분자·분모·maturity 먼저 읽기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/07-metric-contract-and-denominator.svg" alt="MET-04 완료율의 분자, 분모, maturity, null, rounding 계약"><figcaption>그림 7. 같은 이름의 지표도 분모와 관찰 기간이 다르면 서로 다른 지표입니다.</figcaption></figure>

| ID | 지표 | 계산 | Maturity |
|---|---|---|---|
| MET-01 | 등록 학습자 | SUM(enrolled) | week closed |
| MET-02 | 7일 활성화율 | SUM(activated_7d) / SUM(enrolled) | 7 days |
| MET-03 | 7일 복귀율 | SUM(returned_7d) / SUM(activated_7d) | 7 days after activation |
| MET-04 | 28일 완료율 | SUM(completed_28d) / SUM(activated_7d) | only cohorts aged 28 days |
| MET-05 | Support 24h SLA | SUM(support_within_24h) / SUM(support_closed) | closed tickets only |
| MET-06 | 완료자당 비용 | SUM(service_cost_krw) / SUM(completed_28d) | 28-day mature cohorts |

DV-001 전체 범위의 결정적 결과는 등록 2,840명, 활성화율 62.0%, 7일 복귀율 64.8%, 28일 완료율 49.8%, Support 24h SLA 86.0%, 완료자당 비용 27,500원입니다. 이 값은 실제 사업 성과가 아니라 query·표시·평가 계약을 재현하는 합성 fixture입니다.

## 11. Filter를 canonical query signature로 고정하기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/08-filter-query-signature.svg" alt="Data version, region, channel, 기간, actor scope를 canonical JSON과 hash로 묶는 과정"><figcaption>그림 8. KPI·chart·table·insight가 같은 filter인지 signature로 확인합니다.</figcaption></figure>

화면의 보이는 선택값만 저장하면 기본값·scope·metric version이 빠질 수 있습니다. IP03은 key 순서를 고정한 canonical JSON에서 SHA-256 일부를 계산해 `QRY-*`를 만듭니다. 숫자가 같아도 signature가 다르면 같은 결과라고 간주하지 않습니다.

| 포함 field | 예 |
|---|---|
| version | DV-001 |
| region | BUSAN 또는 actor scope |
| channel | ALL |
| start·end | 2026-04-06~2026-05-25 |
| actorScope | ALL 또는 SEOUL |
| metricVersion | 1.0.0 |

## 12. 집계·subtotal·chart-table reconciliation

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/09-aggregation-reconciliation.svg" alt="48개 grain row를 region과 channel 두 경로로 집계해 grand total과 대조하는 과정"><figcaption>그림 9. 서로 다른 집계 경로와 시각 표현의 차이가 모두 0이어야 합니다.</figcaption></figure>

비율은 row별 퍼센트를 평균내지 않습니다. `SUM(numerator) ÷ SUM(denominator)`로 계산하고, region subtotal과 channel subtotal이 같은 grand total에 도달하는지 대조합니다. Chart mark의 값도 equivalent table cell과 일치해야 합니다.

| 대조 | Expected |
|---|---|
| Region subtotal ↔ grand total | delta 0 |
| Channel subtotal ↔ grand total | delta 0 |
| Chart mark ↔ HTML table | delta 0 |
| Viewer scope ↔ 반환 row | 비허용 region 0 |

## 13. Trusted Overview 화면에서 계약 읽기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/01-overview-trusted-desktop.png" alt="DV-001 trusted overview의 여섯 KPI, 주간 chart, equivalent table"><figcaption>실습 화면 1. 값보다 먼저 version·as-of·query signature·quality 상태를 확인합니다.</figcaption></figure>

상단에서 `DV-001 · TRUSTED`, as-of, 48 valid rows, query signature를 찾습니다. 여섯 KPI를 위의 지표 계약과 대조하고, 주간 chart의 점과 아래 표의 값을 비교합니다. 화면의 숫자만 캡처하지 말고 같은 query 근거를 함께 남깁니다.

## 14. Quality gap에서 KPI WITHHELD 읽기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/02-overview-quality-gap-desktop.png" alt="DV-002 quality gap overview에서 KPI가 WITHHELD되고 네 critical issue가 표시된 화면"><figcaption>실습 화면 2. 오류 데이터로 계산한 숫자 대신 공개 보류 이유를 보여 줍니다.</figcaption></figure>

DV-002로 바꾸면 여섯 KPI가 모두 `WITHHELD`가 됩니다. 빨간 경고의 issue count와 version 상태를 확인한 뒤 Explore에서 어떤 row·rule이 실패했는지 내려갑니다. 경고만 표시하고 숫자를 계속 보여 주는 구현은 이 실습의 통과 기준이 아닙니다.

## 15. Chart와 동등한 table을 함께 설계하기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/10-chart-encoding-accessible-alternative.svg" alt="직접 label과 모양 cue가 있는 chart와 같은 값을 가진 HTML table"><figcaption>그림 10. 색상만으로 말하지 않고 축·단위·label·표로 같은 정보를 제공합니다.</figcaption></figure>

Chart type은 질문과 data structure에 맞게 고릅니다. 시간 변화는 line, 범주 크기 비교는 bar가 기본입니다. 3D·과도한 장식·잘린 축은 피하고, 단위·data version·filter·source를 가까이 둡니다. 접근성은 자동 검사 한 번으로 끝나지 않으며 실제 keyboard·screen reader·확대 흐름을 추가로 시험해야 합니다.

| 시각 계약 | 확인 |
|---|---|
| 축·단위 | 무엇을 얼마나 측정했는가 |
| 직접 label | 범례 왕복을 줄였는가 |
| 색상 독립 | 모양·텍스트 cue가 있는가 |
| 동등한 표 | 같은 값·순서·filter인가 |
| Keyboard focus | filter와 view 이동이 가능한가 |
| Reflow | 375px에서 가로 넘침이 없는가 |

## 16. Explore에서 품질 issue와 row를 연결하기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/03-explore-quality-issues-desktop.png" alt="Explore 화면의 DV-002 raw rows와 네 품질 issue"><figcaption>실습 화면 3. Issue ID·rule·severity·row key를 원천 row와 대조합니다.</figcaption></figure>

Issue 목록에서 `DQ-UNI-01`, `DQ-COM-01`, `DQ-VAL-03`, `DQ-CON-01`을 찾습니다. 같은 row key를 raw table에서 찾아 어떤 값이 계약을 어겼는지 설명합니다. 실제 서비스에서는 수정 actor·repair reason·새 version을 추가하되 기존 문제 version을 삭제하지 않습니다.

## 17. Metrics에서 여섯 지표 계약 비교하기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/04-metric-contracts-desktop.png" alt="Metrics 화면의 지표 registry와 numerator denominator maturity owner version"><figcaption>실습 화면 4. 이름보다 business question·분자·분모·maturity·null policy를 먼저 읽습니다.</figcaption></figure>

`MET-02`와 `MET-03`은 모두 7일 비율이지만 분모가 각각 enrolled와 activated입니다. `MET-04`와 `MET-06`은 28일 mature cohort만 사용합니다. Owner와 version이 없다면 지표 정의 변경의 승인과 비교 가능성을 설명하기 어렵습니다.

## 18. Evidence 화면에서 Gate signal 읽기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/05-evidence-gate-desktop.png" alt="Evidence 화면의 12 controls, 24 scenarios, 12 evaluation cases, readiness Gate"><figcaption>실습 화면 5. PASS 숫자뿐 아니라 control·risk·critical·evidence 연결을 확인합니다.</figcaption></figure>

`24/24`만 기록하지 마세요. Critical 12/12, controls 12/12, evaluation 12/12, orphan 0, unsupported 0, regression 0을 함께 읽고 open TBR 2건과 production gap도 공개합니다.

## 19. Observation을 causal claim으로 부풀리지 않기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/11-insight-observation-not-causality.svg" alt="지원되는 기간 관찰과 지원되지 않는 인과 주장을 나란히 비교"><figcaption>그림 11. 상관과 기간 차이는 원인·효과·예측을 증명하지 않습니다.</figcaption></figure>

지원되는 문장은 ‘최근 4주 완료율이 직전 4주보다 2.8%p 높게 관찰된다’처럼 source·comparison·limitation을 가집니다. ‘프로그램 변경 때문에 올랐다’는 문장은 실험 설계와 추가 evidence가 없으므로 validator가 거부합니다.

| Insight field | 질문 |
|---|---|
| observation | 데이터에서 직접 보이는가 |
| comparison | 무엇과 같은 정의로 비교했는가 |
| data version | 어느 snapshot인가 |
| query signature | 같은 filter를 재현할 수 있는가 |
| uncertainty | 얼마나 확정하기 어려운가 |
| limitation | 무엇을 말할 수 없는가 |

## 20. 사람 판정과 decision history

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/12-human-decision-log-escalation.svg" alt="Insight를 ACCEPT, REJECT, EDIT, ESCALATE로 판정하는 흐름"><figcaption>그림 12. 사람 검토는 단순 확인이 아니라 이유와 다음 행동이 있는 명시적 결정입니다.</figcaption></figure>

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/06-human-decision-desktop.png" alt="Decision owner 화면에서 insight를 판정하고 history를 확인하는 모습"><figcaption>실습 화면 6. Decision·reason·next action·review date·actor·time을 history로 추가합니다.</figcaption></figure>

결정은 기존 insight를 수정해 없애지 않습니다. `ACCEPTED`, `REJECTED`, `EDITED`, `ESCALATED` 중 하나를 선택하고 reason·next action·review date를 남깁니다. 상향은 실패가 아니라 현재 권한과 근거로 단정하지 않는 정상적인 안전 경로입니다.

## 21. Freshness·refresh·incident·restore

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/13-freshness-refresh-incident-restore.svg" alt="주기 갱신과 품질 검사, publish, freshness monitoring, 실패와 last known good 복구"><figcaption>그림 13. 최신성은 timestamp가 아니라 갱신·실패·복구 계약입니다.</figcaption></figure>

| 상황 | 화면 | 운영 evidence |
|---|---|---|
| 정상 refresh | 새 as-of·FRESH | job run·row count·checksum |
| Quality 실패 | WITHHELD·QUARANTINED | issue IDs·repair owner |
| Upstream 실패 | INCIDENT | error·retry·owner |
| SLA 초과 | STALE 경고 | freshness age |
| 복구 | last known good 또는 새 version | restore·integrity·decision |

## 22. Row scope authorization과 audit

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/14-row-scope-authorization-audit.svg" alt="Session role과 scope를 query와 resource에 적용하고 allow 또는 deny audit를 남기는 흐름"><figcaption>그림 14. Client filter를 신뢰하지 않고 서버가 허용 row를 다시 계산합니다.</figcaption></figure>

Authorization은 로그인 여부만 보는 검사가 아닙니다. `actor + action + resource + row scope`를 매 요청마다 확인합니다. 허용된 요청과 거부된 요청 모두 secret·raw PII 없이 actor ID·action·outcome·request ID를 audit에 남깁니다.

| 공격/실수 | Expected |
|---|---|
| Viewer BUSAN query | 403 region_scope_denied |
| Viewer decision POST | 403 action denied |
| 잘못된 CSRF | 403, mutation 0 |
| 알 수 없는 region | 400 validation problem |
| SQL meta-character input | parameterized query·문자열 처리 |

## 23. 모바일 Overview에서 정보 우선순위 확인하기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/07-overview-mobile.png" alt="375×812 모바일 Overview의 version, KPI, chart, 하단 navigation"><figcaption>실습 화면 7. 축소판이 아니라 한 열의 읽기 순서로 재배치됩니다.</figcaption></figure>

모바일에서는 version·quality·freshness를 먼저 읽고 KPI와 chart로 내려갑니다. 하단 navigation은 고정하고 main만 scroll하며, card·chart·table이 viewport보다 넓어지지 않아야 합니다. 375×812에서 document와 body의 가로 overflow가 0인지 확인했습니다.

## 24. 모바일 Explore에서 넓은 data를 안전하게 읽기

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/08-explore-quality-mobile.png" alt="375×812 모바일 Explore의 quality issue와 raw data 읽기 흐름"><figcaption>실습 화면 8. Issue를 먼저 보고 필요한 표 영역을 명시적으로 탐색합니다.</figcaption></figure>

넓은 raw table을 억지로 축소하면 글자가 읽히지 않습니다. 화면의 핵심 issue summary는 한 열로 유지하고, 표는 header·단위·row key를 잃지 않는 내부 탐색 영역으로 다룹니다. 오류 상태를 색만으로 구분하지 않습니다.

## 25. Data Service Gate로 전체 흐름 판정하기

<figure class="visual diagram"><img src="../../07_Assets/IP03/diagrams/15-data-service-gate.svg" alt="Source, quality, metric, query, visual, insight, decision, operation 여덟 signal을 합친 Gate"><figcaption>그림 15. 24/24 통과 뒤에도 실제 데이터·사용자·조직 승인 gap이 남습니다.</figcaption></figure>

<figure class="visual screenshot"><img src="../../07_Assets/IP03/lab/09-evidence-mobile.png" alt="375×812 모바일 Evidence 화면의 Gate와 control scenario evaluation"><figcaption>실습 화면 9. 작은 화면에서도 Gate 결과와 근거 목록의 읽기 순서를 유지합니다.</figcaption></figure>

| Gate signal | Threshold | IP03 actual |
|---|---|---|
| Scenario | 24/24 | 24/24 |
| Critical | 12/12 | 12/12 |
| Controls | 12/12 | 12/12 |
| Evaluation | 12/12 | 12/12 |
| Aggregation delta | 0 | 0 |
| Orphan | 0 | 0 |
| Unsupported | 0 | 0 |
| Decision | 명시 | data_service_review_ready |

## 26. 12 controls·24 scenarios·세 readiness version

| Version | Pass | Critical | Evidence | Orphan | Unsupported | TBR | Decision |
|---|---|---|---|---|---|---|---|
| chart-demo-v1 | 7 | 4/12 | 4 | 13 | 7 | 8 | blocked_source_contract |
| defined-dashboard-v2 | 16 | 9/12 | 15 | 3 | 2 | 4 | blocked_metric_integrity |
| governed-decision-v3 | 24 | 12/12 | 24 | 0 | 0 | 2 | data_service_review_ready |

**12 Controls**

| ID | Control | Minimum evidence |
|---|---|---|
| CTRL-01 | Source manifest·checksum·owner | source-manifest |
| CTRL-02 | Schema·grain·time contract | schema-grain |
| CTRL-03 | Quality rules·quarantine·repair | quality-report |
| CTRL-04 | Metric definition·denominator·version | metric-contract |
| CTRL-05 | Filter·time·scope·query signature | filter-signature |
| CTRL-06 | Aggregation·subtotal·reconciliation | reconciliation |
| CTRL-07 | Chart encoding·axis·label integrity | chart-integrity |
| CTRL-08 | Accessible table·contrast·keyboard | accessible-alternative |
| CTRL-09 | Insight provenance·uncertainty·limitation | insight-record |
| CTRL-10 | Human decision·reason·escalation | decision-history |
| CTRL-11 | Freshness·refresh·incident·restore | operation-evidence |
| CTRL-12 | Row scope·authorization·audit·Gate | data-gate-package |

**24 Scenarios**

| ID | Scenario | Lane | Control | Risk | Critical |
|---|---|---|---|---|---|
| SC-01 | source manifest and checksum | data-source | CTRL-01 | source | YES |
| SC-02 | grain unique key | data-source | CTRL-02 | schema | YES |
| SC-03 | required value completeness | data-source | CTRL-03 | quality |  |
| SC-04 | cross-field validity quarantine | data-source | CTRL-04 | denominator | YES |
| SC-05 | fresh dataset publish | data-source | CTRL-05 | filter | YES |
| SC-06 | quality repair and rerun | data-source | CTRL-06 | visual |  |
| SC-07 | metric version and owner | metric-query | CTRL-07 | decision |  |
| SC-08 | zero denominator returns N/A | metric-query | CTRL-08 | access | YES |
| SC-09 | mature cohort exclusion | metric-query | CTRL-09 | source | YES |
| SC-10 | filter canonical signature | metric-query | CTRL-10 | schema | YES |
| SC-11 | region subtotal reconciliation | metric-query | CTRL-11 | quality | YES |
| SC-12 | chart table value equality | metric-query | CTRL-12 | denominator | YES |
| SC-13 | zero baseline and honest scale | visual-experience | CTRL-01 | filter |  |
| SC-14 | direct labels and unit | visual-experience | CTRL-02 | visual |  |
| SC-15 | non-colour status cue | visual-experience | CTRL-03 | decision |  |
| SC-16 | keyboard filter workflow | visual-experience | CTRL-04 | access |  |
| SC-17 | responsive chart and table | visual-experience | CTRL-05 | source |  |
| SC-18 | quality gap value withheld | visual-experience | CTRL-06 | schema | YES |
| SC-19 | insight source and limitation | governance-operation | CTRL-07 | quality |  |
| SC-20 | unsupported causality rejected | governance-operation | CTRL-08 | denominator | YES |
| SC-21 | viewer cross-region denied | governance-operation | CTRL-09 | filter | YES |
| SC-22 | decision reason and history | governance-operation | CTRL-10 | visual |  |
| SC-23 | stale refresh incident restore | governance-operation | CTRL-11 | decision |  |
| SC-24 | value risk authority handoff | governance-operation | CTRL-12 | access |  |

첫 후보는 chart 데모 7/24, 두 번째는 정의된 대시보드 16/24, 세 번째는 거버넌스와 결정·복구가 연결된 24/24입니다. 기능 수가 아니라 빠진 위험 경로와 evidence를 비교합니다.

## 27. 90분 실습 워크북

| 시간 | 행동 | 남길 evidence | 통과 질문 |
|---|---|---|---|
| 0~10분 | 목적·권한·source | boundary·manifest | 실제 승인과 분리됐나 |
| 10~20분 | grain·schema·quality | DV-001/002 비교 | 4 issue를 찾나 |
| 20~30분 | metric contract | 6 metric 정의 | 분모·maturity를 말하나 |
| 30~40분 | filter·signature | QRY trace | 같은 query를 재현하나 |
| 40~50분 | 집계·chart·table | delta 0 | 세 대조가 맞나 |
| 50~60분 | insight | 관찰·한계 | 인과를 단정하지 않나 |
| 60~70분 | role·scope·decision | deny·history | 서버가 거부하나 |
| 70~80분 | freshness·restore | incident·integrity | stale를 숨기지 않나 |
| 80~90분 | Gate·handoff | 24/24·TBR·gap | 다른 사람이 재현하나 |

별도 워크북 `02_Labs/Integrated_Projects/IP03_build-data-analysis-dashboard-service.md`와 증거 패키지 `03_Templates/TIP03_data-dashboard-evidence-package.md`를 함께 사용합니다. 실습 생성기는 새 폴더에서 test·audit·snapshot·restore·variant·boundary evidence 8개를 다시 만듭니다.

## 28. 공식 자료와 적용 경계

> 아래 1차 자료는 원리와 최신 세부사항을 다시 확인하기 위한 출처입니다. 링크 사용은 IP03의 표준 적합성·접근성 인증·통계 검증·보안 승인을 뜻하지 않습니다. 확인 기준일은 2026-07-17입니다.

| 공식 자료 | 확인할 원리 | 적용 경계 |
|---|---|---|
| [W3C WCAG 2.2](https://www.w3.org/TR/WCAG22/) | Keyboard·focus·reflow·name·contrast 요구 | 자동 검사만으로 전체 적합 보장 아님 |
| [W3C Non-text Contrast](https://www.w3.org/WAI/WCAG22/understanding/non-text-contrast.html) | Chart·control·focus의 시각 구분 | 실제 색·상태·사용자 검증 필요 |
| [W3C Use of Color](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color) | 색만으로 정보를 전달하지 않는 원리 | Label·shape·table을 함께 시험 |
| [ONS Data Visualisation](https://service-manual.ons.gov.uk/data-visualisation) | 공공 데이터 시각화 설계 질문 | IP03 업무 맥락에 맞춘 재검토 필요 |
| [ONS Chart Elements](https://service-manual.ons.gov.uk/data-visualisation/build-specifications/chart-elements) | 제목·축·source·note 등 chart 구성 | 모든 chart type의 정답을 보장하지 않음 |
| [ONS Colours in Charts](https://service-manual.ons.gov.uk/data-visualisation/colours/using-colours-in-charts) | 제한된 색과 강조 사용 | 실제 brand·contrast test 추가 |
| [Government Data Quality Framework](https://www.gov.uk/government/publications/the-government-data-quality-framework/the-government-data-quality-framework) | 품질을 lifecycle과 책임으로 다루는 관점 | 영국 정부 framework 참고이며 조직 적용 필요 |
| [Data Quality Framework Guidance](https://www.gov.uk/government/publications/the-government-data-quality-framework/the-government-data-quality-framework-guidance) | 품질 활동을 실행하는 질문 | IP03 4개 rule만으로 실제 품질 보장 아님 |
| [SQLite Aggregate Functions](https://www.sqlite.org/lang_aggfunc.html) | SUM·COUNT 등 집계 함수 의미 | 업무 분모와 grain 계약은 별도 |
| [SQLite WITH Clause](https://www.sqlite.org/lang_with.html) | CTE로 query 단계를 나누는 방법 | Query 성능·warehouse 확장은 별도 |
| [JSON Schema 2020-12](https://json-schema.org/draft/2020-12) | 구조화 data type·required·constraint | 업무 의미·권한·품질 책임은 별도 |
| [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) | Deny by default·매 요청 authorization | 침투시험·조직 access review를 대신하지 않음 |

## 29. 셀프 테스트 30

### 1. IP03에서 대시보드의 완성 단위는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 차트가 아니라 원천 row·지표 계약·filter·시각화·insight·사람 결정·재검토가 연결된 trace입니다.</p>
</details>

### 2. data_service_review_ready는 production 승인을 뜻하나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 아닙니다. 합성 데이터와 로컬 환경에서 evidence가 학습 검토 가능한 상태라는 뜻이며 실제 데이터·보안·통계·경영 승인과 분리됩니다.</p>
</details>

### 3. Viewer에게 BUSAN filter를 숨기면 row scope 보안이 끝나나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 아닙니다. 직접 API 요청을 보내도 서버가 Viewer의 SEOUL scope를 적용하거나 요청을 거부해야 합니다.</p>
</details>

### 4. Data version을 파일명 하나로 관리하면 부족한 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Source checksum·row count·schema·as-of·quality state·actor·transition을 함께 추적할 수 없기 때문입니다.</p>
</details>

### 5. Manifest에 최소 무엇을 남기나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Source name·owner·as-of·extraction window·row count·schema version·checksum·data version을 남깁니다.</p>
</details>

### 6. IP03 한 row의 grain은 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> week_start × region × channel입니다.</p>
</details>

### 7. DV-002의 네 critical issue는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 중복 key·필수값 null·음수 measure·child가 parent보다 큰 cross-field 위반입니다.</p>
</details>

### 8. Quality gap에서 KPI 값을 숨기지 않고 0으로 보여 주면 왜 위험한가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 0이 실제 업무 값처럼 해석될 수 있어 그럴듯한 오답이 되므로 WITHHELD와 issue reason을 보여 줘야 합니다.</p>
</details>

### 9. 같은 '완료율'이라도 서로 다른 지표일 수 있는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 분자·분모·maturity·제외·기간·rounding이 다르면 이름이 같아도 계산과 의미가 달라지기 때문입니다.</p>
</details>

### 10. 분모가 0일 때 IP03의 기본 처리 원칙은 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 0%로 만들지 않고 N/A로 표시해 관측 불가와 실제 0을 구분합니다.</p>
</details>

### 11. Query signature는 어떤 요소를 묶나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Data version·region·channel·start·end·actor scope·metric version을 canonical JSON으로 만든 뒤 hash합니다.</p>
</details>

### 12. 두 KPI의 숫자가 같아도 바로 같은 결과라고 할 수 없는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Query signature와 data version이 다르면 서로 다른 범위·시점·정의에서 우연히 같은 값일 수 있기 때문입니다.</p>
</details>

### 13. Reconciliation에서 확인하는 세 가지 0 차이는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Region subtotal 대 grand total, channel subtotal 대 grand total, chart mark 대 table cell의 차이입니다.</p>
</details>

### 14. Rate를 row별 평균으로 계산하면 왜 틀릴 수 있나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Row마다 분모가 다르므로 비율 평균 대신 분자 합계 ÷ 분모 합계를 계산해야 하기 때문입니다.</p>
</details>

### 15. Bar chart의 수치축을 0에서 시작하는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Bar 길이가 값의 크기를 나타내므로 잘린 축이 차이를 과장하지 않게 하기 위해서입니다.</p>
</details>

### 16. 차트와 같은 값의 HTML 표를 제공하는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Screen reader·keyboard·저시력·정확한 값 확인 등 다른 사용 방식에서도 동등한 정보를 얻도록 하기 위해서입니다.</p>
</details>

### 17. 색상 외에 label과 모양 cue가 필요한 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 색을 구분하기 어렵거나 인쇄·저대비 환경에서도 상태와 범주를 식별할 수 있게 하기 위해서입니다.</p>
</details>

### 18. '프로그램 변경 때문에 완료율이 올랐다'가 거부되는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 관찰 대시보드의 상관과 기간 비교만으로 원인·효과를 증명할 수 없기 때문입니다.</p>
</details>

### 19. 좋은 insight record에 필요한 여섯 요소는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Observation·comparison·source data version·query signature·uncertainty·limitation입니다.</p>
</details>

### 20. 사람 결정 네 가지는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> ACCEPTED·REJECTED·EDITED·ESCALATED입니다.</p>
</details>

### 21. Decision history를 덮어쓰지 않는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 누가 어떤 근거와 상황에서 판정을 바꿨는지 시간순으로 추적하고 재검토하기 위해서입니다.</p>
</details>

### 22. Freshness와 data quality는 같은 개념인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 아닙니다. 규칙을 통과한 데이터도 너무 오래되면 현재 결정에 부적합할 수 있습니다.</p>
</details>

### 23. Refresh 실패 때 last known good를 보여 줄 조건은 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> STALE 경고·as-of·incident 상태·복구 계획과 함께 이전 검증 version임을 명확히 표시해야 합니다.</p>
</details>

### 24. UI에서 menu를 숨기는 것과 server authorization의 차이는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Menu 숨김은 사용성이고, server authorization은 모든 요청에서 role·scope·resource·action을 검사하는 보안 경계입니다.</p>
</details>

### 25. 24/24 scenario만으로 실제 사업 가치를 증명할 수 있나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 아닙니다. 계약과 workflow의 합성 검증이며 실제 사용자 결정 시간·품질·행동 결과는 pilot에서 검증해야 합니다.</p>
</details>

### 26. Orphan evidence가 0이어야 하는 이유는 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 모든 증거가 어떤 control·scenario·평가·결정을 지지하는지 설명할 수 있어야 하기 때문입니다.</p>
</details>

### 27. 세 readiness variant를 비교하는 목적은 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 차트 데모 7/24, 정의된 대시보드 16/24, 거버넌스 결정 24/24의 차이를 통해 빠진 계약이 Gate를 왜 막는지 배우기 위해서입니다.</p>
</details>

### 28. Restore rehearsal에서 row count만 같으면 충분한가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 아닙니다. Database integrity·foreign key·version·evaluation·decision history와 핵심 query를 다시 확인해야 합니다.</p>
</details>

### 29. 실제 데이터 pilot 전에 가장 먼저 추가할 검증은 무엇인가요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> Data owner 승인·개인정보와 계약 검토·실제 source profiling·metric owner 확인·사용자 task test·접근권한 검토입니다.</p>
</details>

### 30. 좋은 IP03 handoff는 어떤 질문에 답해야 하나요?

<details class="answer">
<summary>정답 보기</summary>
<p><strong>정답:</strong> 어떤 원천과 정의로 숫자를 만들고, 누가 어떤 범위를 보고, 어떤 한계에서 누가 결정하며, 실패 뒤 어떻게 복구하고, 무엇이 아직 미검증인지 답해야 합니다.</p>
</details>

## 30. 용어집 300과 전체 로드맵 완주

`04_Glossary/GLOSSARY_data_analysis_dashboard_service.md`에는 source·schema·quality·time·SQL·metric·analysis·chart·accessibility·insight·decision·security·operation·evaluation·handoff의 15묶음, 정확히 300개 고유 용어가 있습니다.

| 묶음 | 핵심 질문 |
|---|---|
| 01~03 | 무엇을 읽었고 한 row는 무엇이며 믿어도 되는가 |
| 04~06 | 언제의 data이고 어떻게 계산했으며 분모는 무엇인가 |
| 07~09 | 어떻게 비교·시각화하고 누구나 같은 정보를 얻는가 |
| 10~12 | 무엇을 주장하고 누가 결정하며 어떤 범위만 보는가 |
| 13~15 | 실패 뒤 복구하고 Gate와 handoff를 어떻게 재현하는가 |

IP01은 사용자의 실제 업무를 API·DB·운영 흐름으로 연결했고, IP02는 AI 문서 검토의 provenance·evaluation·human decision을 연결했습니다. IP03은 dataset → metric → visualization → insight → decision을 완성해 통합 프로젝트 3종을 닫습니다.

```text
IP01 · 업무형 웹 서비스
   +  IP02 · 근거 있는 AI 검토 서비스
   +  IP03 · 결정 가능한 데이터 대시보드
   ↓
47개 기초 매뉴얼 + 3개 통합 프로젝트 → 학습자 pilot → yeoncore.ai 게시
```

> **완주 확인:** 좋은 대시보드는 숫자를 대신 결정하는 화면이 아닙니다. 어떤 데이터와 정의로 만들었는지 보여 주고, 품질과 최신성 문제에서는 멈추며, 허용된 범위만 공개하고, 사람이 근거·한계·이유·다음 행동을 남기며, 다른 사람이 같은 evidence로 다시 확인할 수 있는 서비스입니다.

---

## 배포본 안내

- 매뉴얼 ID: `IP03`
- 콘텐츠 버전: `v0.1.0`
- [인쇄용 PDF](../IP03/IP03_build-data-analysis-dashboard-service_v0.1.0.pdf)
- 그림·실습·템플릿·용어집 링크는 이 프로젝트 폴더 구조를 기준으로 합니다.
