# Laurel Admin Dashboard Design この文書は Laurel のローカル Admin / dashboard 改善の設計メモです。 Ghost Admin と Ghost Editor は研究対象にするが、Laurel は file-first / Markdown-first / static publishing の道具として設計する。 Ghost の CMS 機能を移植する文書ではない。 ## North Star Laurel Admin は "refined editorial workbench" かつ "precise local publishing console" である。 - Markdown と Git 上のファイルを source of truth にする。 - Posts / Pages / Authors / Tags / Settings は実ファイルを中心に扱う。 - 変更検知、保存前 fingerprint、現在 fingerprint、ファイルパス、build freshness を 画面上の主要情報にする。 - deploy しないと公開されない前提を守る。 - Preview は active theme で保存済み最新ファイルがどう見えるかを示す。 未保存変更がある場合は、Preview が保存済み状態に基づくことを明示する。 - Email / newsletter / members / paid tiers は Admin 改善の対象外にする。 Ghost 由来 frontmatter が存在しても破壊せず保持するだけに留める。 Ghost に勝つ領域は local files、sync safety、static build visibility、 schema-backed editing、Git awareness。勝たなくてよい領域は hosted multi-user SaaS、 membership billing、real-time analytics、email sending。 ## Personas and Jobs | Persona | Main jobs | Admin priority | | --- | --- | --- | | Solo writer | write, organize, preview, publish | 集中編集、下書き一覧、保存済み Preview、publish readiness | | Developer-publisher | verify, build, fix, publish | file path、Git 状態、build/deploy 状態、diagnostics | | Migration reviewer | migrate, verify, fix | Ghost import 差分、未知 frontmatter 保持、route preview | | Theme builder | theme, preview, verify | active theme Preview、device/SEO/social preview、render diagnostics | | Docs maintainer | write, organize, link-check | metadata editing、content health、bulk review | 機能追加は上の job に紐づかない限り優先しない。 ## Information Architecture Top-level navigation (sidebar) は意図的に 3 項目に絞る。Authors / Tags は Settings 配下の Taxonomy サブビューとして再配置し、Sync は status rail で 常時可視化することで sidebar を圧迫させない。 | Section | Purpose | Subviews | | --- | --- | --- | | Posts | 記事の作業台 | All, Drafts, Scheduled, Published | | Pages | 固定ページの作業台 | All, Drafts, Published | | Settings | サイト、build、taxonomy の集約 | Site, Theme, Authors, Tags, Build, Sync, Advanced | Authors / Tags は `/authors`、`/tags` の URL を維持しつつ、sidebar 上では Settings 配下のサブナビ (`Settings > Site` / `Authors` / `Tags`) として現れる。 これにより既存リンクと bookmark を壊さず、IA は Ghost Admin の Site Settings に近い密度感を保てる。 Posts / Pages 一覧は作成日基準の pagination を持つ。検索、状態 filter、sort は API foundation の後に段階導入する。左 nav は Ghost の高密度構造を参考にしつつ、 Laurel では file-backed state rail を常時表示する。 ## Screen Contracts ### Dashboard Home 専用 Home は持たない。`/` は Posts にリダイレクトし、sync/build/preview は sidebar の status rail に常時表示する。各 view top には作業内容を直接示す per-view header (kicker + 20px section title + 1 行 meta) だけを置き、巨大な site title hero や 4 個並ぶ stats カードは作らない。これは Ghost Admin の list-first density と note 系の calm typography を踏襲する判断で、画面の主役 を当該リストや Settings panel に渡すための制約として運用する。 ### Lists Posts / Pages / Authors / Tags は「読む一覧」ではなく編集作業台にする。 - primary columns: title, status, updated/created, route, file path, sync state。 - row action は edit、preview、open file、duplicate、more menu に分ける。 - status badge は Draft / Scheduled / Published / Dirty / External change / Conflict / Build stale を同じ体系で扱う。 - 長い日本語、長い slug、長い file path は折り返しまたは middle truncation で処理し、 レイアウトを押し広げない。 ### Settings Settings は Ghost Admin X Settings の検索可能な構造を参考にする。ただし Laurel では Site / Content paths / Theme / Build / Sync / Advanced に分け、設定値の出所を `laurel.toml`、content directory、theme package、runtime state として明示する。 編集モードは inline edit、drawer、full-screen の 3 種を使い分ける。小さな値は inline、 複数 field と検証が必要な設定は drawer、content path や import/export など破壊的変更を 伴う操作は full-screen confirmation に寄せる。 ### Sync Laurel 固有価値は Ghost にはない双方向同期である。 - 保存前 fingerprint と現在 fingerprint を比較し、外部変更を上書きしない。 - conflict は toast だけに押し込まず、row badge、status rail、conflict panel に出す。 - Activity は file watcher、save、build、preview request、external edit を時系列で表示する。 - Git 状態は補助情報であり、Git 操作 UI の全面移植はしない。 ## Editor Direction Ghost Editor は Koenig / Lexical、title、excerpt、feature image、card insertion、 post settings、preview を統合した集中執筆画面として研究する。ただし Laurel は Koenig / Lexical の内部データモデルを移植しない。 Laurel の責務境界: | Area | Laurel contract | | --- | --- | | Body | Markdown text を保存する。将来の MDX / shortcode / card 補助も Markdown 上の明示構文にする。 | | Metadata | YAML frontmatter を構造化 panel で編集し、未知 key は保持する。 | | Preview | 保存済み最新ファイルを active theme で render する。未保存 live preview は公開状態の代替にしない。 | | Save | fingerprint 照合後に書き込む。衝突時は overwrite しない。 | | Build | static build freshness と diagnostics を editor から確認できるようにする。 | Editor recovery の境界: - Autosave でファイルへ書き込まない。未保存本文は `localStorage / sessionStorage` の draft として fingerprint と path 単位で保持し、保存成功時だけ削除する。 - 保存前 snapshot は browser local revisions として直近分だけ残す。rollback は editor へ復元するだけで、 明示的な Save と fingerprint 照合を通るまで disk へ書かない。 - 外部編集で現在 fingerprint が変わった場合、古い fingerprint の draft は警告付きの復元候補として扱い、 自動で現在ファイルを上書きしない。 - draft / revision は本文や frontmatter を含むため、機密情報をブラウザ storage に残すリスクがある。 共有端末では手動削除や保存成功後の削除を前提にし、server-side history へ拡張する場合も明示的な opt-in にする。 Ghost から取り込む体験: - title と本文に集中できる広い編集面。 - metadata / feature image / SEO / social preview を脇に置く post settings 感。 - card insertion の発見しやすさ。ただし Laurel では Markdown shortcode 補助として扱う。 - word count、reading time、publish readiness の軽量な feedback。 取り込まない機能: - Koenig / Lexical の persisted JSON model。 - Ghost Admin autosave 前提の公開 workflow。 - newsletter/email preview、members-only delivery、paid tiers、billing。 - hosted multi-user collaboration、role/permission、staff invite。 ## Visual and Brand Direction Laurel のブランド語彙は files、sync、source、draft、publish、build、theme。 Ghost 風の汎用 CMS 語彙に寄せすぎず、ファイル編集と静的公開の状態がラベルと badge で 伝わる UI にする。説明文を読ませる UI にはしない。 Dashboard の具体的な色、typography、spacing、component styling は [`admin-dashboard-design-system.md`](./admin-dashboard-design-system.md) を実装参照にする。 この design system は note.com の読書体験を参考にしつつ、Laurel の file-first dashboard へ 翻訳したものとして扱う。 Premium feel は主観ではなく、次の基準でレビューする。 - neutral foundation + sync green + conflict amber/red + file blue + editorial black。 - 1画面で主役になる色は neutral を除き 2 系統まで。 - 乱雑な gradient、単色テーマ、カード内カード、説明過多、低密度 hero、謎 icon を避ける。 - UI font は小さく締め、editor title と本文だけ余白を広く使う。 - viewport 幅連動の font-size は使わない。 - card radius は 8px 以下を基準にする。 - border と shadow は階層表現のためだけに使う。 - icon は既存 icon library を優先し、未知 icon には tooltip を付ける。 ## Frontend Architecture Policy Dashboard shell は `renderDashboardHtml()` を公開契約にし続ける。返す HTML は `
` と `/assets/dashboard.js` / `/assets/dashboard.css` への 参照だけを持つ最小シェルで、UI 本体は **Preact + JSX** で書かれたバンドルが クライアント側で `
` にマウントする。`renderDashboardHtml()` の 契約 (CSP、token meta、skip link、`#root`) は変えない。 実装単位は `src/cli/dashboard/web/` 配下で次のように分割する。 - `entry.tsx` — Preact `render(, root)` のマウント点 - `DashboardApp.tsx` — ルート、ルーティング、shell layout - `components/` — `Sidebar` / `PageHeader` / `Toolbar` / `SettingsSubnav` / `ContentTable` / `TaxonomyView` / `SettingsView` / `CreateView` / `EditorView` / `StatePanel` - `hooks/` — `useUiReducer` / `useEventStream` - `lib/` — `api` (fetch wrappers) / `routes` (path 解決) / `format` (date, fingerprint) / `storage` (draft/revision/theme localStorage) / `view-head` - `styles.css` — note 由来の design token と既存 component class を移植したもの UI 状態は `useReducer` で `reduceDashboardUiState` を回し、純粋関数本体は `src/cli/dashboard/ui-state.ts` (Preact 非依存) に置く。これにより DOM lib を 持たない CLI 側 tsconfig からも import でき、`bun test` で reducer を直接 ユニットテストできる。検索、status filter、posts/pages pagination、density、 theme、loading/error/conflict は同じ reducer の action として更新する。 Loading / Error / Conflict / Empty は `StatePanel` component を 1 系統だけ使う。 ビルドは `bun run build:dashboard-bundle` で `dist/dashboard-bundle/` に `dashboard.js` (Preact + entry) と `dashboard.css` (token + component CSS) を 出力する。`prepublishOnly` 経由で npm パッケージにも同梱され、CLI 配布時に ビルドステップを要求しない。dashboard サーバは `/assets/dashboard.{js,css}` を `Bun.file` でストリーム配信し、バンドルが未生成の場合は明示的に `Run \`bun run build:dashboard-bundle\` ...` のヒントを返す。 `tsc --noEmit` は 2 段で走る。`src/cli/dashboard/web/` は DOM lib が必要なので 専用 `tsconfig.json` を持ち、ルート tsconfig は web ディレクトリを exclude する。 biome の format/lint は両方をカバーする。 Dark mode は opt-in ではなく system preference を既定にする。手動 toggle は `localStorage` に `system` / `light` / `dark` を保存するだけで、Laurel config や content file は 変更しない。テーマ token は最小限に留め、静的サイトの active theme とは別概念として扱う。 Iconography は dashboard 内で一貫した nav/toolbar の小さな icon surface に限定する。 追加の icon bundle は持たず、外部ライブラリを導入する場合は別タスクで bundle strategy と アクセシビリティ label を同時に決める。 ## I18n, Feature Flags, Telemetry Admin UI copy は当面 English を fallback とする。サイト本文、frontmatter、`laurel.toml` の `locale` は保持するが、CMS 的な翻訳管理 UI は作らない。i18n を入れる場合は file-backed な Admin catalog を source of truth にし、実行時に外部 service から文言を取得しない。 Feature flag は local-only / file-first にする。必要になった場合は明示的な config または dashboard state の settings surface に出し、remote rollout や hosted flag service は使わない。 Telemetry は dashboard から収集しない。Admin は local process が local files を扱う道具であり、 利用状況、content title、file path、編集イベントを外部送信しない。将来 opt-in telemetry を検討する 場合も、既定 off、送信内容の明示、file-first な設定、テスト可能な no-network 契約を必須にする。 ## Ghost Reference Board Ghost 比較は好みではなく、画面単位の比較軸で扱う。 | Ghost screen | What to study | Laurel win condition | | --- | --- | --- | | Posts list | density, hierarchy, quick scanning | file path、sync state、route preview を追加しても密度を壊さない | | Editor | focus, title/body rhythm, settings side menu | Markdown-first のまま集中感と metadata 安全性を両立する | | Settings | searchable IA, grouped cards | config source と build/sync 影響を Ghost より明確にする | | Design/Navigation | visual editing affordance | active theme と static output の関係を見失わせない | Laurel 側 screenshot は同じ viewport で保存し、density、hierarchy、whitespace、 affordance、state visibility を記録してから実装判断する。 ## Executable Visual QA Dashboard visual QA は Browser plugin に依存しない。CI/local では Bun script が dashboard server を一時起動し、HTML/API smoke を通したうえで Chrome DevTools Protocol から screenshot と HTML snapshot を保存する。Browser plugin が使える場合は同じ URL を 開いて目視確認してよいが、必須の実行経路にはしない。 標準コマンド: - `bun scripts/dashboard-visual-qa.ts --project tests/fixtures/dashboard-visual-project` - `bun scripts/dashboard-visual-qa.ts --project tests/fixtures/dashboard-visual-project --smoke-only` - `bun scripts/dashboard-visual-qa.ts --project tests/fixtures/dashboard-visual-project --dry-run` 出力先は既定で `.laurel/dashboard-visual-qa`。この directory は git 管理外で、 `smoke.json`、`plan.json`、`-.png`、`-.html` を 保存する。fixture は出力先の `.work/project` にコピーしてから使うため、Conflict 画面の 外部変更再現で `tests/fixtures/dashboard-visual-project` は変更しない。server と Chrome は script の `finally` で停止する。 対象 viewport: | Viewport | Size | Purpose | | --- | --- | --- | | desktop | 1440x1100 | Ghost Admin desktop baseline と比較する | | laptop | 1280x900 | 一般的な作業 laptop で密度と折り返しを見る | | mobile | 390x844 | 狭幅 nav、toolbar、table scroll、editor drawer を見る | 対象画面は Posts / Pages / Settings / Editor / Conflict / Empty。Posts と Pages は一覧密度、 Settings は card grouping、Editor は Markdown-first の集中感、Conflict は fingerprint 保護の可視性、Empty は検索結果ゼロ時の余白と行動導線を見る。 Ghost comparison pass line: - Ghost の模倣ではなく、file path、sync state、build/source 情報が自然に読める。 - title/path/status/date が desktop/laptop/mobile で重ならず、長い日本語と slug が折り返す。 - Posts / Pages / Settings / Editor / Conflict / Empty の主要操作が viewport 変更で消えない。 - 色は neutral foundation を主役にし、sync green、conflict amber/red、file blue を状態表示に限定する。 - card 内 card、過剰な gradient、説明過多の hero、viewport 幅連動 font-size を使わない。 - Editor は Ghost の集中感を参考にするが、保存済み Preview と fingerprint safety を Laurel 固有価値として Ghost より明確にする。 Fallback 手順: 1. Browser plugin が使える場合は script の smoke URL または dashboard URL を開いて追加確認する。 2. Browser plugin がない場合は標準 script の Chrome DevTools Protocol capture を使う。 3. Chrome/Chromium が見つからない CI では `--smoke-only` で HTML/API smoke と docs/test を通し、 visual artifact は Chrome がある local runner で作る。 4. Chrome の場所が標準検出できない場合は `LAUREL_CHROME_PATH=/path/to/chrome` を指定する。 Screenshot regression は現時点では強制 pixel gate にしない。OS font、Chrome version、 antialiasing の差分で不安定になりやすいため、まず review artifact と checklist を gate にする。 pixel comparison を導入する場合は Docker image、font、viewport、threshold を固定してから 別 PR で CI 必須化する。 ## Rollout Plan 巨大 PR を避ける。PR #504 の次フェーズは次の順で小さく進める。 1. API/test foundation: filter、search、sort、sync metadata、fingerprint 契約。 2. State model: dirty、external change、conflict、build stale、preview freshness。 3. Design tokens: palette、type scale、spacing、badge、button、list row。 4. Posts/Pages list UX: status subviews、pagination polish、route/file visibility。 5. Settings IA: searchable grouped cards、source labels、safe edit modes。 6. Sync/conflict UX: status rail、activity timeline、conflict recovery。 7. Editor focus mode: Markdown body、metadata panel、saved-theme preview。 8. Visual QA: Ghost comparison board、responsive、a11y、long text checks。 各 PR は単独でレビュー可能にし、scope、tests、visual evidence、Ghost 研究からの 判断、Laurel 固有価値を PR body に書く。`main` merge 後に新 branch を切る運用を基本にし、 ローカルだけで巨大な積み上げを作らない。 ## Out of Scope Admin 改善では次を実装しない。 - Email campaign creation、newsletter sending、email preview。 - Members signup/login backend、member analytics、paid tiers、billing。 - Hosted multi-user SaaS 管理、staff roles、permission matrix。 - Ghost Admin API / integrations directory の移植。 既存 content に Ghost 由来の `email_*`、newsletter、members、paid visibility などの frontmatter がある場合は破壊せず保持する。UI は専用機能として扱わず、必要なら unknown/frontmatter preservation として表示する。