docs(playground): plan file workspace

This commit is contained in:
hand-dot
2026-05-14 16:16:38 +09:00
parent ca6b6dc8f3
commit b2ece0f0ee

137
PLAYGROUND-PLAN.md Normal file
View File

@@ -0,0 +1,137 @@
# Playground File Workspace Plan
最終更新: 2026-05-14
## 目的
- `playground/public/template-assets` と同じような template collection directory を、ブラウザ内
localStorage ではなく、ユーザーが選んだローカルディレクトリ上の実ファイル群として扱う。
- Designer / FormViewer と、同じディレクトリを編集する AI / editor / CLI が
`<template-name>/template.json` を介して協調できるようにする。
- Playground は「編集 UI」でありつつ、保存先は mounted collection 内で選択した template の
`template.json` にする。
## 既存構造メモ
- `playground/public/template-assets` は root 直下に `<template-name>/template.json` が並ぶ collection。
- 既存 gallery は `playground/src/routes/Templates.tsx` で sample templates と local projects を表示する。
- Local project workspace の正体は `playground/src/lib/playgroundProjects.ts``PlaygroundProject[]`
`localStorage``playground:projects:v1` に保存される。
- 現在の import は `Import Template JSON` のみ。1 つの `Template` を local project として保存する。
- 現在の export は `Template JSON` download のみ。inputs、source、title、kind は export されない。
## Browser API 前提
- `showDirectoryPicker({ mode: "readwrite" })` で template collection root directory を選ぶ。
- root 直下の child directories から `<template-name>/template.json` を探し、`checkTemplate` に通るものを
mounted templates として扱う。
- File System Access API は secure context と user gesture が必要。`localhost`
`https://playground.pdfme.com` は前提にできる。
- 非対応ブラウザでは従来の import/download fallback のままにする。
- `FileSystemFileHandle.createWritable()` で selected template JSON file を上書き保存できる。
- File / directory handle は IndexedDB に保存できる。次回アクセス時の復元候補に使う。
- `FileSystemObserver` は experimental / non-standard。使える場合だけ使い、MVP は polling fallback を標準経路にする。
- 現在の TypeScript DOM lib には `showDirectoryPicker``FileSystemObserver` の型がないため、
playground 側に小さな ambient type を追加する。
参考:
- https://developer.chrome.com/docs/capabilities/web-apis/file-system-access
- https://wicg.github.io/file-system-access/
- https://developer.mozilla.org/en-US/docs/Web/API/FileSystemObserver/observe
## 確定要件
- 対象は `playground/public/template-assets/<template-name>/template.json` と同じ directory collection 形式。
- root 直下の child directories を走査し、各 `<template-name>/template.json``checkTemplate` などで
validation して pdfme `Template` として認識できたものを mounted templates にする。
- valid template directory が 1 つもない場合は、blank template を
`untitled-template/template.json`, `untitled-template-2/template.json` のように採番して新規作成する。
- 保存時は `JSON.stringify(template, null, 2)` の pretty JSON で、現在開いている
`<template-name>/template.json` に上書き保存する。
- 保存時に browser 側で thumbnail を再生成し、対応する `<template-name>/thumbnail.png` へ上書きする。
- Designer に未保存変更がある状態で外部変更を検知した場合は conflict dialog を出し、ユーザーに選択させる。
- FormViewer で template が変わった時は、同名 field の入力値を保持する。
- workspace file は template JSON だけを同期対象にする。`inputs.json` は同期しない。
- JSX / md2pdf の `source.tsx` / `source.md` は初期実装では対象外。
- `base.pdf` や画像などの相対 path asset は読まない。現状どおり data URL / URL / base64 保存前提。
- 前回開いた workspace は IndexedDB に handle を保存し、次回アクセス時に復元候補として出す。
## MVP 方針
- `Open Folder` / `Open Directory` を My Workspace 付近に追加する。
- Directory workspace は「collection root directory handle + template entries」と定義する。
- Template entry は `<template-name>/template.json` file handle と `<template-name>/thumbnail.png` file handle から作る。
- Open 時は root 直下の child directories を scan し、`template.json` の JSON parse と `checkTemplate`
を通った directories を collection entries にする。
- valid template directory がない場合は `getBlankTemplate()` を新規 directory に pretty JSON で作成し、その entry を開く。
- Open 成功時は mounted collection を Templates 画面の workspace section に表示し、選択した template を
Designer または FormViewer に読み込む。
- `metadata.json` は初期実装では考慮しない。将来、root `metadata.json` と per-template `metadata.json`
読み取り、title / description / tags / order に反映する余地を残す。
- `index.json`, `manifest.json`, `manifests/<version>.json` は mounted collection では read-only/generated-ish
metadata として扱い、初期実装では更新しない。
- Designer の save は file workspace active 時に prompt なしで selected template JSON file へ上書き保存する。
localStorage project 保存は fallback / 別 mode として残す。
- FormViewer は selected template JSON file の変更を検知して `updateTemplate()` する。
inputs は `getInputFromTemplate(template)` で補完しつつ、既存入力を schema name ベースで保持する。
- Collection root の directory changes も polling / observer で検知し、template directory の追加・削除・rename
を Templates 画面に反映する。
## 同期・競合
- clean state で外部変更を検知した場合は自動 reload する。
- Designer に未保存変更がある状態で外部変更を検知した場合は、`Reload from disk` / `Keep editing` /
`Save over disk` を選べる conflict dialog を出す。
- 保存時に disk version が最後に読んだ version から進んでいた場合も同じ conflict として扱う。
- selected template JSON file が invalid JSON / invalid Template になった場合、現在の UI は維持しつつ
error toast を出す。AI が書きかけの瞬間を polling で拾う可能性があるため、次の valid change で
自動復帰できるようにする。
- Form 入力中に selected template JSON file が変わった場合、同名 field の入力値は保持し、新規 field は
`getInputFromTemplate` の default を入れ、消えた field は捨てる。
## 実装候補
- `playground/src/lib/fileWorkspace.ts`
- `isFileWorkspaceSupported()`
- `openTemplateCollectionDirectory()`
- `scanTemplateCollection()`
- `readTemplateEntry(entry)`
- `writeTemplateEntry(entry, template)`
- `writeTemplateThumbnail(entry, template, inputs?)`
- `createBlankTemplateEntry(collection, title?)`
- `subscribeTemplateCollectionChanges(listener)`
- IndexedDB に active collection root handle と selected template id/path を保存・復元する helper
- `playground/src/lib/templateInputs.ts`
- template reload 時に既存 inputs を schema name ベースで reconcile する helper。
- `playground/src/vite-env.d.ts` または `playground/src/lib/fileSystemAccess.d.ts`
- `Window.showDirectoryPicker`
- `FileSystemHandle.queryPermission/requestPermission`
- `FileSystemObserver` の最小 ambient type。
- `playground/src/routes/Templates.tsx`
- My Workspace toolbar に `Open Folder` を追加する。
- Open 成功後に mounted collection templates を project card と同じ gallery UI で表示する。
- mounted collection の card は Designer / FormViewer を開くときに selected template entry を active にする。
- `playground/src/routes/Designer.tsx`
- load request に active mounted template entry を追加する。
- `onSaveTemplate` で file workspace active 時は selected template JSON file と thumbnail へ write。
- 外部変更購読で `designer.current.updateTemplate(template)`
- dirty tracking と conflict UI。
- `playground/src/routes/FormAndViewer.tsx`
- active mounted template entry を読み込み対象に追加する。
- 外部変更購読で `ui.current.updateTemplate(template)` と inputs reconcile。
- Tests
- file workspace helper は fake file handles で unit test する。
- UI E2E は native picker を mock し、open, save overwrite, thumbnail write, external change polling,
invalid JSON recovery, conflict branch を確認する。
## 未確定要件
- 保存時の thumbnail 再生成で使う inputs。Designer は `getInputFromTemplate(template)` でよいか、
直近 FormViewer inputs があれば使うか。
- Designer の `Save Project` 文言は file workspace active 時に `Save JSON` / `Save <filename>` に変えるか。
- `Save As` は localStorage project 複製のまま残すか、別 directory entry 作成にするか。
- FormViewer での `Save` は inputs 保存のままか、file workspace mode では非表示にするか。
- polling interval。AI との並走なら 1-2 秒が体感よさそう。
- IndexedDB に保存した workspace handle の復元 UX。起動時に自動復元を試すか、`Reopen last folder` を出すか。
- 対応ブラウザを Chromium 系に寄せるか。Safari / Firefox では fallback のままでよいか。