init: company-haness 설계
This commit is contained in:
+175
@@ -0,0 +1,175 @@
|
||||
artifact-kind: design-direction-concept
|
||||
artifact-version: 1
|
||||
|
||||
identity:
|
||||
direction-id: ledger-studio
|
||||
representative-screen-id: dual-entry-shared-lab
|
||||
producer-run-id: hyeonworks-vnext-v1-direction-divergence-ledger-20260718T1135Z
|
||||
context-package-sha256: 52ef4f1c5e433157bc23eb801d3fb122923d7f50d667af41019be3b4b1489c83
|
||||
|
||||
visual-thesis: >-
|
||||
Lost Update를 홍보용 카드 모음이나 장애 콘솔이 아니라, 독자가 가설과 관찰값을 직접 대조하는
|
||||
편집형 기술 저널의 한 페이지로 보인다. 서로 다른 두 entry는 대칭인 orientation 칼럼으로만
|
||||
분리되고, 굵은 merge rule 아래에서 동일한 tx-lost-update-01 causal ledger로 합류한다.
|
||||
깊이는 콘텐츠 수가 아니라 100을 함께 읽은 두 세션이 150과 70을 차례로 쓰며 기대값 120을
|
||||
잃는 한 사례의 인과를 감사 가능하게 드러내는 데서 나온다.
|
||||
|
||||
reference-clusters:
|
||||
- id: scientific-lab-notebook
|
||||
role: "학습을 수동 독서가 아닌 검증 기록으로 보이게 하는 구조"
|
||||
signals:
|
||||
- "가설, 관찰, 결과가 규칙선과 여백 주석으로 이어진다."
|
||||
- "관찰 사실과 해석을 서로 다른 라벨로 분리한다."
|
||||
translation:
|
||||
- "Predict → Observe → Compare → Explain → Transfer를 순서가 있는 기록 행으로 사용한다."
|
||||
- "coral은 Observed 값과 증상 단서처럼 증거가 있는 지점에만 쓴다."
|
||||
guardrail: "낡은 종이 질감, 손글씨 장식, 과학실 소품을 문자 그대로 모사하지 않는다."
|
||||
|
||||
- id: long-form-technical-journal
|
||||
role: "활성 주제 하나의 깊이를 카탈로그 규모보다 먼저 전달하는 편집 위계"
|
||||
signals:
|
||||
- "큰 serif 논제, 짧은 dek, 넓은 여백이 읽기 시작점을 만든다."
|
||||
- "masthead와 folio 표기가 한 호의 기술 논문처럼 현재 범위를 명시한다."
|
||||
translation:
|
||||
- "왼쪽 hero는 질문을, 오른쪽 folio는 검증할 값과 실행 순서를 맡는다."
|
||||
- "Atlas는 Concurrency → Transaction Isolation → Lost Update 한 줄만 보여준다."
|
||||
guardrail: "완성되지 않은 주제를 거대한 지도나 콘텐츠 카탈로그로 부풀리지 않는다."
|
||||
|
||||
- id: double-entry-ledger
|
||||
role: "초기값, 기대값, 관찰값과 두 세션의 쓰기를 같은 기준선에서 감사"
|
||||
signals:
|
||||
- "숫자가 고정 폭 열과 수평 rule 위에 정렬된다."
|
||||
- "Initial / Expected / Observed 명칭이 값의 의미를 색과 무관하게 설명한다."
|
||||
translation:
|
||||
- "100 / 120 / 70을 한 ledger folio에 놓고 70만 evidence-coral로 강조한다."
|
||||
- "A reads 100, B reads 100, A writes 150, B writes 70을 번호 행으로 기록한다."
|
||||
guardrail: "금융 대시보드, KPI 카드, 장식용 표처럼 보이게 만들지 않는다."
|
||||
|
||||
- id: scholarly-margin-annotation
|
||||
role: "본문 흐름을 방해하지 않고 범위와 증거 상태를 명시하는 주석 체계"
|
||||
signals:
|
||||
- "작은 mono label과 folio 번호가 본문 serif와 분명히 구별된다."
|
||||
- "guided scenario 한계가 결과 근처에 붙어 과잉 해석을 막는다."
|
||||
translation:
|
||||
- "tx-lost-update-01, Shared scenario, Guided scenario를 evidence annotation으로 둔다."
|
||||
- "실제 로그나 운영 DB를 분석하지 않고 원인을 확정하지 않는다는 경계를 평문으로 쓴다."
|
||||
guardrail: "사건 파일, 경고 테이프, 확정 진단 어휘를 사용하지 않는다."
|
||||
|
||||
- id: causal-process-plate
|
||||
role: "두 세션의 시간 순서를 장식적 다이어그램 없이 읽히게 하는 인쇄 도식"
|
||||
signals:
|
||||
- "번호, 동사, 값, 짧은 rule로 사건의 선후 관계를 고정한다."
|
||||
- "DOM 읽기 순서와 시각 순서가 같아 선형으로도 이해된다."
|
||||
translation:
|
||||
- "read / write를 네 개의 trace row로 표시하고 세션 이름을 텍스트로 유지한다."
|
||||
- "모바일에서도 같은 행 순서를 바꾸지 않고 열만 압축한다."
|
||||
guardrail: "node canvas, 드래그 타임라인, neon terminal 창으로 바꾸지 않는다."
|
||||
|
||||
layout-grammar:
|
||||
desktop:
|
||||
viewport: "1280px 기준, 최대 1440px editorial spread"
|
||||
rules:
|
||||
- "상단은 짧은 Atlas breadcrumb, 그 아래 hero를 약 1.05:0.95 비대칭 2열로 구성한다."
|
||||
- "왼쪽은 thesis/dek/promise, 오른쪽은 tx-lost-update-01 ledger folio를 배치한다."
|
||||
- "orientation 영역만 동일 폭 2열 entry로 나누고 이후 학습 구조는 단일 열로 합친다."
|
||||
- "merge-rule은 두 entry 바로 아래에서 Same Lost Update Lab을 한 번만 선언한다."
|
||||
- "공통 학습 루프는 다섯 열, guided-scenario 경계는 그 아래 한 개의 주석 띠로 둔다."
|
||||
compact:
|
||||
viewport: "360–780px"
|
||||
rules:
|
||||
- "hero, entry, loop, boundary를 DOM 순서 그대로 한 열로 적층한다."
|
||||
- "420px 이하에서 masthead를 두 줄로 쌓고 ledger value를 세 행으로 바꿔 가로 넘침을 막는다."
|
||||
- "merge label, trace row, footer는 줄바꿈을 허용하되 의미 순서는 유지한다."
|
||||
spacing:
|
||||
base: "8px 계열의 여백을 쓰되 hero와 section 사이에는 32–80px의 editorial pause를 둔다."
|
||||
density: "증거 folio 내부는 조밀하게, orientation 설명 주변은 넓게 두어 읽기 속도를 분리한다."
|
||||
|
||||
interaction-grammar:
|
||||
entry-selection:
|
||||
- "개념을 알고 있어요와 증상만 알고 있어요는 native anchor이며 둘 다 #shared-lab으로 이동한다."
|
||||
- "두 선택은 orientation 카피만 다르고 tx-lost-update-01, 진행 상태, 학습 콘텐츠를 분기하지 않는다."
|
||||
- "hover와 focus-visible에서 동일한 mint 바탕을 주고 3px focus outline을 별도로 유지한다."
|
||||
reading-flow:
|
||||
- "skip link는 키보드 사용자를 entry heading으로 바로 보낸다."
|
||||
- "이후 순서는 Predict → Observe → Compare → Explain → Transfer로 고정한다."
|
||||
- "실험 실행 화면으로 확장할 때 상태 변화는 aria-live로 알리되 focus를 강제로 이동하지 않는다."
|
||||
motion:
|
||||
default: "합류선을 그리거나 evidence row를 강조한다면 짧은 1회 전환만 허용한다."
|
||||
reduced: "prefers-reduced-motion에서는 smooth scroll과 모든 전환을 제거하고 최종 상태를 즉시 표시한다."
|
||||
input:
|
||||
- "필수 동작은 Tab, Enter, Space로 가능해야 하며 drag-only 조작을 두지 않는다."
|
||||
- "색은 보조 신호이고 상태명, 숫자, 순번, 동사를 항상 함께 제공한다."
|
||||
|
||||
type-grammar:
|
||||
display:
|
||||
family: "Georgia 계열 humanist serif"
|
||||
use: "논제, entry 질문, scenario 제목, 단계 설명"
|
||||
behavior: "큰 크기와 촘촘한 자간으로 편집적 긴장을 만들되 장문 본문에는 쓰지 않는다."
|
||||
body:
|
||||
family: "Inter 또는 system neutral grotesk"
|
||||
use: "dek, 안내, 경계 설명, 링크 동작"
|
||||
behavior: "한국어 본문은 최소 16px에 가까운 크기와 1.5 line-height를 유지한다."
|
||||
evidence:
|
||||
family: "ui-monospace 또는 system monospace"
|
||||
use: "scenario id, 값, 순번, atlas path, evidence label"
|
||||
behavior: "영문 uppercase label은 짧게 쓰고 한국어 핵심 설명을 mono로 대체하지 않는다."
|
||||
hierarchy-rule: "serif는 논제와 설명, mono는 id·값·증거 주석이라는 역할 경계를 넘지 않는다."
|
||||
|
||||
primitive-grammar:
|
||||
dominant:
|
||||
- name: entry-column
|
||||
anatomy: "entry tag + serif question + orientation copy + text arrow"
|
||||
rule: "두 개만 나란히 두며 선택 이후에는 반복하지 않는다."
|
||||
- name: causal-ledger
|
||||
anatomy: "Initial / Expected / Observed values + ordered read/write rows"
|
||||
rule: "값과 순서를 같은 folio 안에서 비교해 덮어쓰기를 감사 가능하게 한다."
|
||||
- name: evidence-margin
|
||||
anatomy: "mono label + 범위 설명"
|
||||
rule: "Guided scenario와 증거 상태를 본문 가까이에 둔다."
|
||||
exclusive:
|
||||
- name: merge-rule
|
||||
rule: "두 수평선이 하나의 Same Lost Update Lab seal로 합류한다."
|
||||
- name: ledger-folio
|
||||
rule: "흰 종이 면, 검은 상단 rule, 한 방향의 offset shadow만 사용한다."
|
||||
- name: annotated-value
|
||||
rule: "label과 숫자를 함께 표시하며 관찰값만 coral로 제한한다."
|
||||
prohibited:
|
||||
- "node canvas 또는 거대한 Atlas map"
|
||||
- "terminal window 또는 neon hacker styling"
|
||||
- "glass card grid 또는 보라 SaaS gradient"
|
||||
- "incident 확정 진단을 암시하는 경고 primitive"
|
||||
|
||||
color-and-rule-grammar:
|
||||
paper: {value: "#f5f1e8", role: "집중 읽기용 페이지 바탕"}
|
||||
ink: {value: "#17201f", role: "본문과 인과 경계"}
|
||||
evidence-coral: {value: "#bb4d3b", role: "관찰 결과와 증상 단서에만 사용"}
|
||||
orientation-violet: {value: "#4b4f96", role: "비진단 entry와 step index의 작은 보조 신호"}
|
||||
focus: {value: "#075d58", role: "명시적 keyboard focus outline"}
|
||||
ledger-rule: {value: "1px solid #17201f", role: "합류와 비교 경계, 카드 테두리 남용 금지"}
|
||||
|
||||
content-contract:
|
||||
shared-scenario-id: tx-lost-update-01
|
||||
entry-labels: ["개념을 알고 있어요", "증상만 알고 있어요"]
|
||||
atlas-path: [Concurrency, Transaction Isolation, Lost Update]
|
||||
values: {initial: 100, expected: 120, observed: 70, session-a-write: 150, session-b-write: 70}
|
||||
learning-loop: [Predict, Observe, Compare, Explain, Transfer]
|
||||
trust-boundary: >-
|
||||
교육용 고정 guided scenario이며 실제 로그나 운영 데이터베이스를 분석하지 않고 장애 원인을
|
||||
확정하지 않는다. 증상 entry는 검증할 후보 메커니즘만 좁힌다.
|
||||
roadmap-honesty: "현재 활성 depth는 Transaction Isolation / Lost Update 하나이며 다음 주제는 비활성으로 표시한다."
|
||||
|
||||
accessibility-contract:
|
||||
- "360/768/1280px에서 가로 스크롤 없이 읽기 순서와 합류 의미를 보존한다."
|
||||
- "native anchor, skip link, 명시적 focus-visible을 사용한다."
|
||||
- "세션, 단계, 값, 경계는 텍스트와 숫자로 명명해 색에만 의존하지 않는다."
|
||||
- "reduced-motion에서 smooth scroll과 전환을 제거한다."
|
||||
- "확장되는 실험 상태는 aria-live로 알리고 예측 가능한 focus 순서를 유지한다."
|
||||
|
||||
coded-slice-evidence:
|
||||
file: index.html
|
||||
verified-structure:
|
||||
- "두 한국어 entry가 동일 #shared-lab anchor를 참조한다."
|
||||
- "tx-lost-update-01 folio에 100 / 120 / 70과 네 개의 read/write 행이 있다."
|
||||
- "공통 Predict / Observe / Compare / Explain / Transfer 루프가 있다."
|
||||
- "Guided scenario 한계 문구가 있다."
|
||||
- "max-width 780px와 420px 재배치, focus-visible, prefers-reduced-motion 대안이 있다."
|
||||
@@ -0,0 +1,52 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Hyeonworks — Ledger Studio direction</title>
|
||||
<style>
|
||||
:root{--paper:#f5f1e8;--ink:#17201f;--muted:#5c6561;--line:#b8b5a9;--violet:#4b4f96;--coral:#bb4d3b;--mint:#dce9df;--white:#fffdfa;--focus:#075d58}
|
||||
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,sans-serif;line-height:1.5}
|
||||
a{color:inherit}.skip{position:absolute;left:1rem;top:-5rem;background:var(--ink);color:white;padding:.7rem 1rem;z-index:20}.skip:focus{top:1rem}
|
||||
:focus-visible{outline:3px solid var(--focus);outline-offset:4px}
|
||||
header{display:flex;justify-content:space-between;align-items:center;padding:1.1rem clamp(1rem,4vw,4.5rem);border-bottom:1px solid var(--line);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase}
|
||||
.brand{font-weight:800}.edition{color:var(--muted)}
|
||||
main{max-width:1440px;margin:auto;padding:clamp(2rem,6vw,6rem) clamp(1rem,5vw,5rem)}
|
||||
.atlas{display:flex;gap:.7rem;align-items:center;color:var(--muted);font:600 .73rem/1.2 ui-monospace,monospace;text-transform:uppercase;letter-spacing:.06em}.atlas b{color:var(--ink)}.atlas span{color:var(--coral)}
|
||||
.hero{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(360px,.95fr);gap:clamp(2rem,7vw,8rem);padding:clamp(2rem,5vw,5rem) 0 4rem;border-bottom:1px solid var(--ink)}
|
||||
h1{font-family:Georgia,serif;font-weight:500;font-size:clamp(3.1rem,7vw,7.4rem);line-height:.91;letter-spacing:-.055em;margin:1.2rem 0 1.5rem;max-width:11ch}.dek{max-width:56ch;font-size:clamp(1rem,1.4vw,1.2rem);color:#36403d}
|
||||
.promise{display:flex;gap:1rem;align-items:center;margin-top:2rem;font-size:.86rem;font-weight:700}.promise:before{content:"";width:3.6rem;border-top:2px solid var(--coral)}
|
||||
.folio{align-self:end;border-top:6px solid var(--ink);background:var(--white);padding:1.2rem 1.3rem 1.4rem;box-shadow:10px 10px 0 #d7d1c4}
|
||||
.folio-head{display:flex;justify-content:space-between;font:700 .72rem ui-monospace,monospace;text-transform:uppercase;letter-spacing:.07em;border-bottom:1px solid var(--line);padding-bottom:.8rem}.scenario{font-family:Georgia,serif;font-size:1.65rem;margin:1.2rem 0 .25rem}.values{display:grid;grid-template-columns:repeat(3,1fr);margin:1rem 0;border-block:1px solid var(--line)}.value{padding:.9rem .5rem}.value+.value{border-left:1px solid var(--line)}.value small{display:block;color:var(--muted);font-size:.68rem;text-transform:uppercase}.value b{font:700 1.7rem ui-monospace,monospace}.value:last-child b{color:var(--coral)}
|
||||
.trace{display:grid;gap:.48rem;font:.77rem ui-monospace,monospace}.trace-row{display:grid;grid-template-columns:1.8rem 5rem 1fr;gap:.6rem;align-items:center}.trace-row i{height:1px;background:var(--line)}
|
||||
.entry-title{display:flex;align-items:end;justify-content:space-between;gap:2rem;margin:3.6rem 0 1.25rem}.entry-title h2{font:500 clamp(2rem,4vw,4rem)/1 Georgia,serif;margin:0;max-width:13ch}.entry-title p{max-width:38ch;color:var(--muted);margin:0}
|
||||
.entries{display:grid;grid-template-columns:1fr 1fr;border:1px solid var(--ink);background:var(--white)}
|
||||
.entry{padding:clamp(1.4rem,3vw,2.6rem);min-height:300px;display:flex;flex-direction:column;text-decoration:none;position:relative}.entry+.entry{border-left:1px solid var(--ink)}.entry:hover,.entry:focus-visible{background:var(--mint)}.entry-tag{font:700 .7rem ui-monospace,monospace;text-transform:uppercase;letter-spacing:.08em;color:var(--violet)}.entry h3{font:500 clamp(1.7rem,3vw,2.8rem)/1.05 Georgia,serif;margin:1rem 0}.entry p{max-width:38ch;color:#424b48}.entry .arrow{margin-top:auto;font-weight:800}.entry .arrow:after{content:" →"}.entry.symptom .entry-tag{color:var(--coral)}
|
||||
.merge{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:1rem;margin:1.2rem 0 0;font:700 .72rem ui-monospace,monospace;text-transform:uppercase;letter-spacing:.08em}.merge:before,.merge:after{content:"";border-top:1px solid var(--ink)}.merge strong{padding:.55rem .8rem;background:var(--ink);color:var(--paper)}
|
||||
.loop{display:grid;grid-template-columns:repeat(5,1fr);margin-top:4.5rem;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.step{padding:1.2rem .8rem;min-height:110px}.step+.step{border-left:1px solid var(--line)}.step b{display:block;font:700 .72rem ui-monospace,monospace;color:var(--violet);margin-bottom:.45rem}.step span{font-family:Georgia,serif;font-size:1.05rem}
|
||||
.boundary{margin-top:2rem;display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:start;background:#ebe4d7;padding:1rem 1.2rem}.boundary b{font:.7rem ui-monospace,monospace;text-transform:uppercase;color:var(--coral)}.boundary p{margin:0;font-size:.88rem}
|
||||
footer{display:flex;justify-content:space-between;padding:2rem clamp(1rem,5vw,5rem);border-top:1px solid var(--line);color:var(--muted);font-size:.75rem}
|
||||
@media(max-width:780px){.hero{grid-template-columns:1fr}.folio{max-width:560px}.entry-title{align-items:start;flex-direction:column}.entries{grid-template-columns:1fr}.entry+.entry{border-left:0;border-top:1px solid var(--ink)}.entry{min-height:235px}.loop{grid-template-columns:1fr}.step{min-height:auto;display:grid;grid-template-columns:5rem 1fr}.step+.step{border-left:0;border-top:1px solid var(--line)}.boundary{grid-template-columns:1fr}footer{display:block}}
|
||||
@media(max-width:420px){header{align-items:flex-start;flex-direction:column;gap:.35rem}.edition{text-transform:none;letter-spacing:.04em}.atlas{align-items:flex-start;flex-wrap:wrap;line-height:1.6}.folio{box-shadow:6px 6px 0 #d7d1c4}.values{grid-template-columns:1fr}.value{display:grid;grid-template-columns:1fr auto;align-items:end}.value+.value{border-left:0;border-top:1px solid var(--line)}.trace-row{grid-template-columns:1.5rem minmax(0,7.5rem) 1fr}.merge{gap:.55rem}.merge strong{text-align:center}footer span{display:block}footer span+span{margin-top:.35rem}}
|
||||
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition:none!important}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip" href="#entries">출발점으로 건너뛰기</a>
|
||||
<header><div class="brand">Hyeonworks / Technology Atlas</div><div class="edition">Field note 001 · Transaction Isolation</div></header>
|
||||
<main>
|
||||
<div class="atlas"><span>Concurrency</span> / Transaction Isolation / <b>Lost Update</b></div>
|
||||
<section class="hero" aria-labelledby="title">
|
||||
<div><h1 id="title">결과보다 먼저, 원인을 예측합니다.</h1><p class="dek">기술 개념을 알고 있어도, 이상한 결과만 알고 있어도 괜찮습니다. 서로 다른 단서에서 출발해 같은 Lost Update 실험에서 상태 변화를 검증합니다.</p><div class="promise">두 입구, 하나의 학습 Lab</div></div>
|
||||
<aside class="folio" aria-label="Lost Update 실험 미리보기"><div class="folio-head"><span>Shared scenario</span><span>tx-lost-update-01</span></div><div class="scenario">두 요청은 성공했는데, 왜 70일까요?</div><div class="values"><div class="value"><small>Initial</small><b>100</b></div><div class="value"><small>Expected</small><b>120</b></div><div class="value"><small>Observed</small><b>70</b></div></div><div class="trace" aria-label="실행 순서"><div class="trace-row"><b>01</b><span>A reads 100</span><i></i></div><div class="trace-row"><b>02</b><span>B reads 100</span><i></i></div><div class="trace-row"><b>03</b><span>A writes 150</span><i></i></div><div class="trace-row"><b>04</b><span>B writes 70</span><i></i></div></div></aside>
|
||||
</section>
|
||||
<section id="entries" aria-labelledby="entry-heading"><div class="entry-title"><h2 id="entry-heading">어떤 단서를 가지고 있나요?</h2><p>두 경로는 짧은 준비 방식만 다릅니다. 실험과 설명, 진행 상태는 완전히 같습니다.</p></div>
|
||||
<div class="entries"><a class="entry" href="#shared-lab"><span class="entry-tag">Start 01 · concept</span><h3>개념을 알고 있어요</h3><p>Transaction Isolation에서 Lost Update가 어디에 위치하고 어떤 충돌이 필요한지 관계부터 정리합니다.</p><span class="arrow">개념에서 시작</span></a><a class="entry symptom" href="#shared-lab"><span class="entry-tag">Start 02 · symptom</span><h3>증상만 알고 있어요</h3><p>기대값 120, 실제값 70이라는 단서를 좁혀 검증할 후보 메커니즘을 찾습니다.</p><span class="arrow">증상에서 시작</span></a></div>
|
||||
<div class="merge" id="shared-lab"><strong>Same Lost Update Lab</strong></div>
|
||||
</section>
|
||||
<section class="loop" aria-label="공통 학습 루프"><div class="step"><b>01 · Predict</b><span>결과를 먼저 고릅니다</span></div><div class="step"><b>02 · Observe</b><span>두 세션을 실행합니다</span></div><div class="step"><b>03 · Compare</b><span>120과 70을 비교합니다</span></div><div class="step"><b>04 · Explain</b><span>덮어쓰기 인과를 씁니다</span></div><div class="step"><b>05 · Transfer</b><span>새 재고 사례에 적용합니다</span></div></section>
|
||||
<aside class="boundary"><b>Guided scenario</b><p>이 화면은 교육용 고정 시나리오입니다. 실제 로그나 운영 데이터베이스를 분석하지 않으며, 장애 원인을 확정하지 않습니다.</p></aside>
|
||||
</main>
|
||||
<footer><span>Active depth: Transaction Isolation / Lost Update</span><span>Next topics stay inactive until complete.</span></footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user