diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0d9d14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +local-data +node_modules/ +coverage/ +*.log + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..34eb66f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,63 @@ +# Code of Conduct + +## Purpose + +`mikuproject` aims to be a respectful and practical collaboration space for bug reports, feature requests, design discussion, documentation work, and code contributions. + +The goal is not to avoid disagreement. The goal is to keep discussion specific, constructive, and safe for participants. + +## Expected Behavior + +- Be respectful. +- Be specific. +- Prefer concrete repro steps, fixtures, examples, and tests over vague claims. +- Critique ideas, code, assumptions, and designs without attacking people. +- Keep technical disagreement focused on behavior, tradeoffs, and evidence. +- Accept that maintainers may ask to narrow scope, add tests, or clarify intent before accepting a change. + +## Unacceptable Behavior + +- Harassment, intimidation, or personal attacks +- Discriminatory, hateful, or abusive language +- Repeated hostile or bad-faith argument +- Dismissing or insulting contributors instead of addressing the technical point +- Publishing private or sensitive information without permission +- Spam, trolling, or deliberately disruptive behavior + +## Scope + +This code of conduct applies to project spaces such as: + +- Issues +- Pull requests +- Discussions and review comments +- Documentation contributions +- Other project-related public collaboration spaces managed for `mikuproject` + +## Maintainer Responsibility + +Project maintainers may moderate discussions and contributions to keep the project usable and collaborative. + +This may include: + +- Asking for clarification or tone adjustments +- Hiding, editing, locking, or closing discussions when appropriate +- Rejecting contributions that are technically unsuitable or behaviorally disruptive +- Limiting further participation in project spaces if necessary + +## Reporting + +If you experience or observe behavior that should be addressed, contact the project maintainer through a project channel that is appropriate for the situation. + +If a public thread would make the issue worse, prefer a private contact path instead of escalating in public. + +## Project Style + +For `mikuproject`, the preferred collaboration style is: + +- specific +- respectful +- test-oriented +- focused on reproducible behavior + +Technical rigor is welcome. Personal hostility is not. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2e0130d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,145 @@ +# Contributing to mikuproject + +Thank you for contributing to `mikuproject`. + +This project accepts bug reports, feature requests, documentation fixes, tests, and pull requests. + +## Before You Open an Issue or Pull Request + +- Check whether the topic is already covered by an existing issue or pull request. +- For behavior changes, describe the expected behavior and the current behavior clearly. +- For code changes, include or update tests when practical. +- Keep changes focused. Small, reviewable pull requests are preferred. + +## Development Notes + +- `index.html` and `mikuproject.html` are generated files. +- Edit `index-src.html`, `mikuproject-src.html`, and files under `src/` instead of editing generated output directly unless regeneration is intentionally part of the change. +- Application logic should normally be edited in `src/ts/`. +- `src/js/` is generated from `src/ts/`, but is currently committed to Git. If you change `src/ts/`, regenerate `src/js/` as part of the same change. +- When a behavior change affects project structure, input/output rules, or AI integration, update the relevant documentation as well. + +Documentation roles: + +- `README.md`: repository entry point and quick start +- `docs/architecture.md`: overall structure, build flow, generated files, and operational rules +- `docs/spec.md`: format and behavior specifications +- `docs/TODO.md`: incomplete work only + +## Recommended Checks + +Run relevant commands before submitting a pull request when possible. + +```bash +npm run build:js +npm run build:html +npm test +``` + +If your change touches sample workbook generation, also run: + +```bash +npm run build:xlsx-sample +``` + +## Pull Request Guidelines + +- Explain what changed and why. +- Mention any user-visible behavior change. +- Mention any specification or documentation updates if they are part of the change. +- If a change is incomplete or intentionally deferred, say so explicitly. + +## Contribution License + +By submitting an issue, pull request, comment, documentation change, code change, or other material that is intentionally submitted for inclusion in this project, you agree that: + +- Your contribution is provided under the Apache License 2.0 used by this repository. +- The project maintainer may use, modify, rewrite, adapt, edit, and redistribute your contribution as part of this project, as permitted by the project license structure. +- You have the right to submit the contribution. +- Unless you explicitly state otherwise, your contribution is treated as a "Contribution" under Section 5 of the Apache License 2.0. + +If you do not want a submission to be treated as a contribution for inclusion in the project, mark that clearly and do not open it as a pull request intended to be merged. + +## Attribution + +Contributors may be acknowledged in project history, release notes, or other project documents at the maintainer's discretion. + +## Code of Collaboration + +- Be specific. +- Be respectful. +- Prefer concrete repro steps, fixtures, and tests over vague reports. + +--- + +# mikuproject へのコントリビュート + +`mikuproject` へのコントリビュートありがとうございます。 + +このプロジェクトでは、バグ報告、機能提案、ドキュメント修正、テスト追加、Pull Request を受け付けます。 + +## Issue / Pull Request の前に + +- 既存の issue / pull request と重複していないか確認してください。 +- 挙動変更を伴う場合は、期待する挙動と現在の挙動を明確に書いてください。 +- コード変更では、可能なら対応するテストも追加または更新してください。 +- 変更は小さく、レビューしやすい単位が望ましいです。 + +## 開発メモ + +- `index.html` と `mikuproject.html` は生成物です。 +- 生成物を直接編集するのではなく、通常は `index-src.html`、`mikuproject-src.html`、`src/` 配下を編集してください。 +- アプリロジックの変更は、通常 `src/ts/` で行ってください。 +- `src/js/` は `src/ts/` から生成されますが、現状では Git 管理しています。`src/ts/` を変更した場合は、同じ変更で `src/js/` も更新してください。 +- project 構造、入出力ルール、生成AI 連携の挙動を変える場合は、関連ドキュメントも更新してください。 + +ドキュメントの役割: + +- `README.md`: リポジトリの入口と quick start +- `docs/architecture.md`: 全体構成、ビルド、生成物、運用ルール +- `docs/spec.md`: 形式仕様と挙動仕様 +- `docs/TODO.md`: 未完了作業のみ + +## 推奨チェック + +可能であれば、Pull Request 前に関連コマンドを実行してください。 + +```bash +npm run build:js +npm run build:html +npm test +``` + +sample workbook 生成に関わる変更では、あわせて次も実行してください。 + +```bash +npm run build:xlsx-sample +``` + +## Pull Request のガイド + +- 何を変えたか、なぜ変えたかを書いてください。 +- ユーザーに見える挙動変更があれば明記してください。 +- 仕様書やドキュメント更新を含む場合は、その旨も書いてください。 +- 未完了部分や意図的に後回しにした点があれば、明示してください。 + +## コントリビューションのライセンス + +このプロジェクトへ取り込みを意図して issue、pull request、コメント、ドキュメント変更、コード変更、その他の素材を提出した場合、次に同意したものとして扱います。 + +- あなたのコントリビューションは、このリポジトリで採用している Apache License 2.0 の下で提供されます。 +- プロジェクト管理者は、そのコントリビューションを本プロジェクトの一部として、プロジェクトのライセンス構造で許容される範囲で、利用、修正、書き換え、調整、編集、再配布できます。 +- あなたは、そのコントリビューションを提出する権利を持っています。 +- あなたが明示的に別扱いを示さない限り、その提出物は Apache License 2.0 第5条の "Contribution" として扱われます。 + +取り込みを意図しない連絡については、その旨を明確に示してください。マージを前提としない相談は、その前提が分かるように記述してください。 + +## 謝辞 + +コントリビューター名は、必要に応じて git 履歴、リリースノート、その他の文書で言及されることがあります。 + +## コラボレーション方針 + +- 具体的に書く +- 相手を尊重する +- 曖昧な説明より、再現手順、fixture、テストを優先する diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..115de9d --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +# Contributors + +This project includes contributions, feedback, and improvement suggestions from the following people. Thank you for helping improve `mikuproject`. + +- Toshiki Iga + - Original author and initial maintainer. diff --git a/README.md b/README.md new file mode 100644 index 0000000..99d6868 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +# mikuproject + +`mikuproject` は、`MS Project XML` を基軸に、変換・可視化・限定編集を行うローカル HTML ツールです。 + +`mikuproject` の強みは、同じプロジェクト情報を 1 つの意味体系のまま、用途に応じて複数の形式へ出し分けられることです。`MS Project XML` を基軸に、`XLSX`、`Markdown`、`JSON`、`Mermaid`、生成AI向け表現、そして必要に応じて `MS Project` へも橋渡しできるため、資料共有・レビュー・変換・再利用のそれぞれの場面に合わせて、無理なく形を変えて届けられます。 + +特に、次の 3 つを重視して設計しています。 + +- `MS Project XML` を基軸にした変換・可視化・限定編集 +- 生成AI 連携を意識した projection / 再取込 +- 人が読むための `WBS Excel ブック (.xlsx)` 帳票出力 + +配布物は `mikuproject.html` ひとつの single-file web app で、Web ブラウザさえあればインストール不要・ネットワーク不要で利用できます。 + +`MS Project XML` を意味の基軸として扱い、`.xlsx` と workbook JSON は確認・可視化・限定編集のための周辺表現として扱います。生成AI 連携の編集用 JSON は、workbook JSON と区別するため当面 `.editjson` 拡張子を推奨します。 + +## 代表的なユースケース + +- その1: 管理用の Excel ブックに必要な情報を入力し、`mikuproject` を用いて `WBS Excel ブック (.xlsx)` 形式へ変換する +- その2: 生成AI に専用プロンプトをセットして会話し、WBS 草案を作成する。生成された JSON を `mikuproject` へ入力し、`WBS Excel ブック (.xlsx)` 形式へ変換する +- その3: `MS Project` のデータを `MS Project XML` 形式でエクスポートし、それを入力として `WBS Excel ブック (.xlsx)` 形式へ変換する + +## スクリーンショット + +### Input + +`Load from file`、`サンプル`、`生成AI連携` から入力を受け付ける。 + +![Input](docs/screenshots/screen01.png) + +### Overview + +内部モデルの確認、validation、native SVG preview をここで行う。 + +![Overview](docs/screenshots/screen02.png) + +### Output + +`MS Project XML`、`XLSX`、workbook JSON、`WBS XLSX`、Mermaid、生成AI向け `.editjson` をここから保存する。 + +![Output](docs/screenshots/screen03.png) + +### WBS Excel ブック (.xlsx) + +人が読むための帳票として出力される `WBS Excel ブック (.xlsx)` の例。 + +![WBS Excel ブック](docs/screenshots/excel01.png) + +## できること + +- `MS Project XML` の読込 +- `ProjectModel` への変換と内容確認 +- `MS Project XML` の再生成 +- Mermaid gantt テキスト生成 +- `CSV + ParentID` のファイル読込とダウンロード +- 構造忠実な `Project / Tasks / Resources / Assignments / Calendars` workbook の `XLSX Export / Import` +- 構造忠実な `Project / Tasks / Resources / Assignments / Calendars` workbook の `JSON Export / Import` +- 表示専用の `WBS XLSX Export` +- 生成AI向け `project_overview_view` / `phase_detail_view` / `full bundle` の出力 +- 生成AIが返した `project_draft_view` の取込 + +## 使い始め方 + +もっとも簡単なのは、生成済みの [mikuproject.html](mikuproject.html) をブラウザで開く方法です。 + +画面上では主に次を行えます。 + +- `Load from file` からの `MS Project XML / XLSX / workbook JSON (.json) / 生成AI向け編集用 JSON (.editjson) / CSV + ParentID` の読込 +- `project_draft_view` ベースで生成したサンプル XML の読込 +- 生成AIが返した `project_draft_view` の JSON 貼り付け取込 +- 内部モデル、validation、native SVG preview、各 preview の確認 +- `MS Project XML / XLSX / WBS XLSX / workbook JSON / CSV + ParentID / Mermaid / 生成AI向け .editjson` の保存 + +## 開発 + +```bash +npm install +npm run build:js +npm run build:html +npm run build:xlsx-sample +npm test +npm run build +``` + +`local-data/` は確認用の再生成可能な生成物置き場として扱う。ここに出す sample や検証用出力は、Git 管理下の永続成果物ではなく、必要時に再生成できればよい前提とする。 + +## 関連ドキュメント + +- [docs/architecture.md](docs/architecture.md) +- [docs/spec.md](docs/spec.md) +- [docs/gap-notes.md](docs/gap-notes.md) +- [docs/mikuproject-ai-json-spec.md](docs/mikuproject-ai-json-spec.md) +- [docs/msprojectxml-ai-integration.md](docs/msprojectxml-ai-integration.md) +- [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md) +- [docs/TODO.md](docs/TODO.md) +- [CONTRIBUTING.md](CONTRIBUTING.md) +- [CONTRIBUTORS.md](CONTRIBUTORS.md) +- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) +- [LICENSE](LICENSE) diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md new file mode 100644 index 0000000..22bf3b5 --- /dev/null +++ b/THIRD-PARTY-NOTICES.md @@ -0,0 +1,41 @@ +# Third-Party Notices + +This document lists third-party software and reference materials used or referred to by `mikuproject`. + +## Third-party software + +## Reference materials + +### `open-msp-viewer` + +- Usage: Referred to as a temporary source of sample data for verification +- License: Apache License 2.0 +- Source: https://github.com/rpbouman/open-msp-viewer/ + +### MicrosoftDocs Project XML Data Interchange reference + +- Usage: Referred to when design decisions for `MS Project XML` handling are unclear. This reference is used together with the Microsoft-hosted Project 2007 schema endpoints such as `https://schemas.microsoft.com/project/2007/` and `mspdi_pj12.xsd`. +- License: CC-BY-4.0 for documentation and MIT for code +- Source: https://github.com/MicrosoftDocs/office-developer-msproject-xml-docs/tree/main/project-xml-data-interchange + +--- + +# 第三者告知 + +この文書は、`mikuproject` が利用または参照している第三者ソフトウェアおよび参考資料を記載したものです。 + +## 第三者ソフトウェア + +## 参考資料 + +### `open-msp-viewer` + +- 用途: 検証用サンプルデータの一時的な参照元 +- ライセンス: Apache License 2.0 +- Source: https://github.com/rpbouman/open-msp-viewer/ + +### MicrosoftDocs Project XML Data Interchange reference + +- 用途: `MS Project XML` の扱いで設計判断に迷った場合の補助資料。`https://schemas.microsoft.com/project/2007/` や `mspdi_pj12.xsd` などの Microsoft 側 schema 実体とあわせて参照する。 +- ライセンス: 文書は CC-BY-4.0、コードは MIT +- Source: https://github.com/MicrosoftDocs/office-developer-msproject-xml-docs/tree/main/project-xml-data-interchange diff --git a/docs/TODO.md b/docs/TODO.md new file mode 100644 index 0000000..6c68d01 --- /dev/null +++ b/docs/TODO.md @@ -0,0 +1,71 @@ +# TODO + +この文書には、未完了の作業だけを書く。概要説明や仕様判断は `README.md` と `docs/spec.md` に寄せる。 + +## mikuproject + +- 最優先: サンプルデータを更新し、利用者の好みに合う題材・構造・見た目へ見直す +- `excel-io` の workbook スタイルにフォントサイズ指定を追加し、XLSX 出力で大きい見出し文字を使えるようにする +- WBS workbook と `mikuproject-sample.xlsx` のタイトル行で、フォントサイズ指定をどこまで使うか整理する +- `Mermaid` 出力は Markdown / 設計資料向けに残しつつ、見た目を制御しやすい native SVG 描画を別系統で追加するか検討する +- native `SVG` について、今の既定である `近接ラベル` 表示だけを残し、左側にテキストを描画する `一覧ラベル` モードは将来的に廃止したい +- `mikuproject` の主要入出力を CLI からも扱えるようにするか検討する +- 作成するテキストファイルについて、BOM 付き / なしを切り替えるスイッチを追加する +- `local-data/` 配下のファイルを、参照用・検証用・生成物で整理する +- `local-data/` に置くべきでない生成物や一時ファイルがないか見直す +- `npm test` を `scripts/run-tests.mjs` ベースへ切り替えるか検討する +- `main.test.js` に残っている `xlsx import` の file input wiring を、UI 配線確認と import 結果確認へさらに分離する +- `XLSX Import` の実地回帰観点を明文化し、少なくとも次を継続確認する + - export した `.xlsx` をそのまま import できる + - Excel で 1 セル変更した `.xlsx` を import できる + - 同じファイル名で保存し直した `.xlsx` を連続 import できる + - 空 editable セルを埋めた変更を import できる + - `Name / Start / Finish / PercentComplete / PercentWorkComplete / Notes` など主要 editable 列が戻る + - `Milestone / Summary / Critical` など表示専用列は戻らない +- `main.ts` の summary / validation / preview 描画を別モジュール化し、DOM テストをさらに軽くする +- `phase_detail_view scoped` の `phase UID / root UID / max depth` 指定を、より選びやすい UI に改善する +- `task_edit_view` の projection を実装する +- `.editjson` の import で現状 `project_draft_view` だけを受けている制約を見直し、将来の `task_edit_view` / Patch JSON など他の `view_type` も扱えるようにする +- 既存 project 向け Patch JSON の schema を具体化する +- Patch JSON を内部モデルへ適用する処理を実装する +- Patch JSON import 後の validation と差分要約 UI を実装する +- import 前後で、どの `task / calendar / assignment` がどう変わったかを見やすく確認できる差分可視化を追加する +- 差分適用を前提として、生成AI や外部編集結果を全件置換ではなく部分適用できる運用を強化する +- `project_draft_request` を UI から生成しやすくするか整理する +- UI の微調整として、`Input / Overview / Output` の各カードの余白・見出し・ボタン階層を見直し、`miku` 系テーマの統一感をさらに整える +- `Overview` タブの summary / validation / preview の情報密度を見直し、どこを見る画面なのかをより直感的に伝わる構成へ調整する +- `Output` タブの生成AI連携と各種 export ボタンの優先度表現を見直し、主操作と補助操作の区別をより明確にする +- calendar 未設定時に自動補完する既定 calendar の祝日 `Exceptions` を、project 期間内だけに限定する +- WBS 上で土日と祝日を別色表示する場合も、`MS Project XML` 正本へ独自の非稼働日種別を追加せず、`WeekDays / Exceptions` の由来で描き分ける +- `build:xlsx-sample` の所要時間を個別計測し、sample workbook 生成処理の支配要因を確認する +- `main.test.js` の初期化 DOM をケース別に最小化できるか見直す +- CI 向けに `test:fast` と `test:full` のような実行導線を分けるか検討する +- `docs/spec.md` に残っている実装済み前提との差分を定期的に解消する +- 正本 / 表示用 / import 対象 / export 専用 の扱いを、UI または docs で分かりやすく可視化する +- `.xlsx import` の次段として、どのシート・列を今後 import 対象に広げるか整理する +- タスク実績について、`ActualStart / ActualFinish / ActualWork / RemainingWork / ActualCost / RemainingCost` などを今後どう扱うか整理し、将来的に対応する +- 将来検討: Earned Value (`PV / EV / AC / SPI / CPI` など) をどこまで扱うか整理し、必要なら対応する +- 実績・Earned Value 系は、いきなり広く対応せず、まず最小整理と小さな仕様を作って MVP から段階的に進める +- WBS 用の `ステータス` は `Task.ExtendedAttribute` で扱う前提で、`FieldID / FieldName / 値候補` を設計する +- `TaskStatus` 用 `ExtendedAttribute` を `mikuproject-sample.xlsx` と `WBS workbook` のどちらまで見せるか決める +- `TaskStatus` 用 `ExtendedAttribute` の値候補と、`PercentComplete` / `Active` との関係を整理する +- 画面検索ではなく、条件指定にもとづく task の部分 export / scoped export を強化できるか整理する +- `phase_detail_view scoped` の延長として、phase 単位の入出力をうまく取り回す方法を整理し、使い勝手のよい導線を検討する +- 画面では `Calendars / Exceptions` を read-only 確認に留める前提で、`XLSX Import` 側の `WeekDays / Exceptions / WorkWeeks` 編集導線をどこまで整えるか整理する +- `Calendar / Baseline / TimephasedData / ExtendedAttributes` をどの順で扱うか優先順位を決める +- validation について、warning の重要度分け、修正候補のヒント、入力由来別の注意をどこまで出すか整理する +- `mikuproject-sample.xlsx` の `Project` シートで、構造忠実方針を崩さない範囲の見た目調整を続ける +- `mikuproject-sample.xlsx` の `Resources / Assignments / NonWorkingDays` で、強調色が過剰にならない最終バランスを調整する +- `WBS` の `プロジェクト情報` / `凡例` などと、`Project` シートの `Basic Info` に入っているドット編みかけ表現を除去する +- WBS workbook の表示改善を継続する +- WBS workbook の見た目改善と、構造忠実 workbook との責務分離を保つ +- WBS について、完了タスクの表示 / 非表示を切り替えるオプションを追加する +- 将来検討: WBS workbook について、表示専用列と Excel 再利用向けの機械利用列(hidden 列)の分離が必要か整理する +- WBS Markdown の `プロジェクト情報` / `サマリ` / `WBS ツリー` / `WBS テーブル` をどう出すか sample ベースで固める +- `project summary markdown` のような、WBS 以外の Markdown 出力拡張を検討する +- `phase summary markdown` のような scoped Markdown 出力を追加するか検討する +- 高優先: `WBS記述書 Markdown` の最小版に着手したいが、現時点では実施できないため保留にする +- `WBS記述書 Markdown` 出力を追加し、task ごとの説明を別 Markdown として保存できるようにする +- `WBS記述書` 用 `Task.ExtendedAttribute` の最小項目として `TaskPurpose / TaskDeliverable / TaskOutOfScope / TaskDoneDefinition / TaskOwner` を扱う +- `WBS記述書 Markdown` では、長文補足を `Task.Notes` から出す +- `WBS記述書 Markdown` の sample 出力を作成し、1 task 1 節構成で読みやすいか確認する diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..3738438 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,184 @@ +# Architecture + +## 概要 + +`mikuproject` は、`MS Project XML` を意味の基軸として扱い、内部モデル `ProjectModel` を経由して複数の表現へ出し分ける構成を採る。 + +重視しているのは次の 3 点である。 + +- `MS Project XML` を基軸にした変換・可視化・限定編集 +- 生成AI 連携を意識した projection / 再取込 +- 人が読むための `WBS Excel ブック (.xlsx)` 帳票出力 + +## 全体構成 + +- 正本は `MS Project XML` +- 内部の中立表現は `ProjectModel` +- `.xlsx` と workbook JSON は補助的な入出力 +- まずは意味的ラウンドトリップを優先 + +主な流れは次のとおり。 + +- `MS Project XML -> ProjectModel -> MS Project XML` +- `MS Project XML -> ProjectModel -> XLSX` +- `MS Project XML -> ProjectModel -> mikuproject_workbook_json` +- `MS Project XML -> ProjectModel -> Mermaid` +- `MS Project XML -> ProjectModel -> 生成AI向け JSON projection` + +また、新規生成向けには次の流れを持つ。 + +- `project_draft_view -> ProjectModel -> MS Project XML / WBS Excel ブック (.xlsx)` + +`XLSX Import` と workbook JSON import は、自由編集をそのまま受け入れるのではなく、限定列の部分更新として扱う。 + +`mikuproject-sample.xlsx` は `MS Project XML` との対応関係を確認するための構造忠実 workbook として扱う。列やシートの対応関係は崩さず、見た目改善は可読性補助に留める。これに対して `mikuproject-wbs-sample.xlsx` は人が読むための表示重視 workbook として扱う。 + +## Single-file Web App + +配布物は `mikuproject.html` ひとつの single-file web app である。Web ブラウザさえあればインストール不要・ネットワーク不要で利用できる。 + +開発用 source は分割して管理するが、配布物としては single-file web app を維持する。 + +- HTML source: `mikuproject-src.html` +- TypeScript source: `src/ts/` +- generated JavaScript: `src/js/` +- CSS: `src/css/` + +`mikuproject.html` は `mikuproject-src.html` をもとに、ローカル CSS / JS を単一 HTML へインライン展開して生成する。 + +## リポジトリ構成 + +- `mikuproject.html`: 生成済みの単一 HTML アプリ +- `mikuproject-src.html`: HTML ソース +- `package.json`: Node.js ベースの開発設定 +- `src/ts/`: TypeScript ソース +- `src/js/`: `src/ts/` から生成し、Git 管理も行うブラウザ実行用 JavaScript +- `src/css/`: アプリ用 CSS +- `tests/`: Vitest ベースのテスト +- `testdata/`: XML テストデータ +- `scripts/`: ビルド補助スクリプト +- `docs/spec.md`: 現行仕様メモ +- `docs/gap-notes.md`: 保持項目や互換性のギャップメモ + +## 画面構成 + +### Input + +- `Load from file` からの `MS Project XML / XLSX / workbook JSON (.json) / 生成AI向け編集用 JSON (.editjson) / CSV + ParentID` の読込 +- `project_draft_view` ベースで生成したサンプル XML の読込 +- 生成AIが返した `project_draft_view` の JSON 貼り付け取込 + +### Overview + +- 内部モデルの要約確認 +- validation メッセージの確認 +- native `SVG` プレビューの確認 +- `Project / Tasks / Resources / Assignments / Calendars` の preview 確認 + +### Output + +- `MS Project XML` の保存 +- `XLSX` の保存 +- `WBS XLSX` の保存 +- `XLSX` 相当 workbook JSON の保存 +- `CSV + ParentID` の保存 +- Mermaid fenced code block を含む `.md` の保存 +- native `SVG` の保存 +- 生成AI向け `project_overview_view` / `phase_detail_view` / `full bundle` の `.editjson` 保存 + +## 生成AI連携 + +`mikuproject` は、生成AIとの直接連携に `MS Project XML` ではなく `JSON` を使う。 + +- 既存 project 向けには `project_overview_view` と `phase_detail_view` を出力する +- 既存 project 向けには `full bundle` も出力できる +- 新規生成向けには、生成AIが返した `project_draft_view` を取り込める +- `mikuproject_workbook_json` は `.json`、生成AI 向け編集用 JSON は `.editjson` を推奨拡張子とする +- 現時点で UI から実装済みなのは `project_overview_view` / `phase_detail_view` / `full bundle` の出力と `project_draft_view` の取込である +- `task_edit_view` と Patch JSON 適用は設計メモ段階で、まだ実装していない + +詳細な考え方は `docs/mikuproject-ai-json-spec.md` と `docs/msprojectxml-ai-integration.md` に置く。 + +## 開発 + +依存関係の導入: + +```bash +npm install +``` + +TypeScript 由来のブラウザ実行 JavaScript を再生成: + +```bash +npm run build:js +``` + +単一 HTML を再生成: + +```bash +npm run build:html +``` + +サンプル XLSX を再生成: + +```bash +npm run build:xlsx-sample +``` + +テスト実行: + +```bash +npm test +``` + +ビルドとテストをまとめて実行: + +```bash +npm run build +``` + +`npm run build` は `build:app` と `test` を順に実行する。 + +スクリプトの役割は次のとおり。 + +- `npm run build:js`: `src/ts/` から `src/js/` を生成する +- `npm run build:html`: `index-src.html` と `mikuproject-src.html` から `index.html` と `mikuproject.html` を生成する +- `npm run build:xlsx-sample`: `local-data/` 配下へサンプル XLSX / Markdown を生成する +- `npm run build:app`: `build:js`、`build:html`、`build:xlsx-sample` を順に実行する + +`scripts/build-project.mjs` は `--js-only` と `--html-only` を受け取り、JavaScript 生成と HTML 生成を切り替える。 + +## ソースと生成物の扱い + +`src/ts/` を正本として扱い、`src/js/` はそこから生成する中間生成物として扱う。ただし、現状では `src/js/` も Git 管理する。ブラウザ実行、テスト、`build:xlsx-sample` は `src/js/` を参照する。 + +運用ルール: + +- アプリロジックの修正は原則 `src/ts/` で行う +- `src/js/` は手編集の正本としては扱わない +- `src/ts/` を更新した場合は `npm run build:js` を実行し、`src/js/` の差分もあわせて扱う + +## 現在の状態 + +- `package.json` と `package-lock.json` を持つ単独の Node.js プロジェクトとして扱える +- ソース配置は `src/ts/`, `src/js/`, `src/css/` +- `npm run build:js`、`npm run build:html`、`npm test` は通る +- `local-data/` と `node_modules/` は Git 管理対象外 +- `local-data/` は確認用の再生成可能な生成物置き場として扱う +- `local-data/` 配下の sample や検証用出力は、消えてもよく、必要時に再生成できればよい前提とする + +## 制約 + +- `MS Project` 実機は未保有 +- 目標は XML の完全一致ではなく、意味的に往復できること +- `XLSX Import` の反映対象は限定列のみ +- workbook JSON import の反映対象も同じ限定列のみ +- `CSV + ParentID` は現在ファイルベースの補助入出力として扱う +- `Calendars` の `WeekDays / Exceptions / WorkWeeks` などは現時点では反映対象外 + +## ドキュメントの役割 + +- `README.md`: このリポジトリの入口 +- `docs/architecture.md`: 全体構成、配布形態、ビルド、運用ルール +- `docs/spec.md`: 仕様と設計判断の置き場 +- `docs/TODO.md`: 未完了作業の管理 diff --git a/docs/gap-notes.md b/docs/gap-notes.md new file mode 100644 index 0000000..e567705 --- /dev/null +++ b/docs/gap-notes.md @@ -0,0 +1,298 @@ +# mikuproject gap notes + +`mikuproject` の次段を考えるための、実例 XML ベースの棚卸しメモ。 + +前提: + +- 参照元は `local-data/` に一時配置した実例 XML +- Git 管理対象の testdata ではない +- ここでは `Project / Task / Resource / Assignment / Calendar` ごとに、実例で見えた主なタグを整理する +- 目的は「現在の内部モデルで保持しているもの」と「今後候補になるもの」の差分を把握すること + +## 対象実例 + +- `3PointPlan-example.xml` +- `01145024.xml` +- `Project_Grouping_and_Conditional_Formatting_Example.xml` +- `link types.xml` + +## 現在の STEP 1 で保持済み + +### Project + +- `Name` +- `Title` +- `Author` +- `Company` +- `CreationDate` +- `LastSaved` +- `SaveVersion` +- `CurrentDate` +- `StartDate` +- `FinishDate` +- `ScheduleFromStart` +- `DefaultStartTime` +- `DefaultFinishTime` +- `MinutesPerDay` +- `MinutesPerWeek` +- `DaysPerMonth` +- `StatusDate` +- `WeekStartDay` +- `WorkFormat` +- `DurationFormat` +- `CalendarUID` + +### Task + +- `UID` +- `ID` +- `Name` +- `OutlineLevel` +- `OutlineNumber` +- `WBS` +- `Type` +- `CalendarUID` +- `Priority` +- `Start` +- `Finish` +- `Duration` +- `ActualStart` +- `ActualFinish` +- `Deadline` +- `StartVariance` +- `FinishVariance` +- `Work` +- `WorkVariance` +- `TotalSlack` +- `FreeSlack` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `RemainingWork` +- `ActualWork` +- `Milestone` +- `Summary` +- `Critical` +- `PercentComplete` +- `PercentWorkComplete` +- `Notes` +- `ConstraintType` +- `ConstraintDate` +- `PredecessorLink` + +### Resource + +- `UID` +- `ID` +- `Name` +- `Type` +- `Initials` +- `Group` +- `WorkGroup` +- `MaxUnits` +- `CalendarUID` +- `StandardRate` +- `StandardRateFormat` +- `OvertimeRate` +- `OvertimeRateFormat` +- `CostPerUse` +- `Work` +- `ActualWork` +- `RemainingWork` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `PercentWorkComplete` + +### Assignment + +- `UID` +- `TaskUID` +- `ResourceUID` +- `Start` +- `Finish` +- `StartVariance` +- `FinishVariance` +- `Delay` +- `Milestone` +- `WorkContour` +- `Units` +- `Work` +- `ActualWork` +- `RemainingWork` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `PercentWorkComplete` +- `OvertimeWork` +- `ActualOvertimeWork` + +### Calendar + +- `UID` +- `Name` +- `IsBaseCalendar` +- `IsBaselineCalendar` +- `BaseCalendarUID` +- `WeekDays` +- `Exceptions` +- `WorkWeeks` + +## 実例で見えた主な未保持タグ + +### Project 候補 + +優先度が高そう: + +- 直近の高優先候補は消化済み + +メモ: + +- `Project CalendarUID` と calendar 実体の整合 validation は追加済み +- preview で `OutlineCodes / WBSMasks / ExtendedAttributes` の代表値を追えるようにした +- `ProjectModel -> Mermaid gantt` の片方向補助出力に着手済み + +後回し候補: + +- `ExtendedAttributes` の完全対応 +- `ExtendedAttributes` + +### Task 候補 + +優先度が高そう: + +- `Task CalendarUID` に紐づくカレンダー差分の可視化は前進済み + +メモ: + +- `Task CalendarUID` の存在 validation は追加済み +- preview で task ごとの calendar 名を表示するようにした +- predecessor の validation は task 名つきで追えるようにした + +実例で頻出だが重い: + +- `Baseline` +- `TimephasedData` + +特記事項: + +- `UID=0` +- 空 `Name` +- `OutlineLevel=0` + +は実例で普通に出るため、validation では placeholder 扱いを考慮済み + +### Resource 候補 + +優先度が高そう: + +- 直近の高優先候補は消化済み + +メモ: + +- preview で resource ごとの calendar 名を表示するようにした +- validation 文言は resource 名つきで追いやすくした + +実例で頻出だが重い: + +- `Baseline` +- `TimephasedData` + +### Assignment 候補 + +優先度が高そう: + +- 直近の高優先候補は消化済み + +メモ: + +- preview で assignment から task/resource 名を追えるようにした +- validation 文言は assignment UID と既知の task/resource 名を併記するようにした + +実例で頻出だが重い: + +- `Baseline` +- `TimephasedData` +- `ActualCost` +- `RemainingCost` +- `OvertimeWork` +- `ActualOvertimeWork` + +特記事項: + +- `ResourceUID=-65535` + +は実例で未割当を示す特別値として扱う前提 + +### Calendar 候補 + +優先度が高そう: + +- 直近の高優先候補は消化済み + +メモ: + +- calendarPreview を追加済み +- `Project / Task / Resource / BaseCalendar` からの参照数を preview で見えるようにした +- `BaseCalendarUID` の自己参照 warning を追加済み + +後回し候補: + +- 直近の軽量候補は消化済み + +## 次に拾う候補 + +現時点での優先順: + +1. 実例 XML ベースの `Calendar` 差分整理 + - task/resource ごとの calendar 差分が実例でどう使われるかを棚卸しする +2. `ExtendedAttributes` の次段整理 + - project 以外の `ExtendedAttributes` をどこまで保持・表示するかを決める +3. preview / validation の最終整形 + - 現状でかなり揃ったので、残る文言や導線を必要最小限で整える +4. 重い構造の着手判断 + - `Baseline` / `TimephasedData` を STEP 2 に含めるか別段に切るかを決める +5. 補助交換形式の次段整理 + - `Mermaid gantt` の dependency 表現をどこまで育てるかを決める + - `CSV + ParentID` を別軸の交換形式として整理する + +補足メモ: + +- `CSV + ParentID` は、`ID / ParentID / Name` を最小列とする「まず押さえるべき、よくある交換形式」の第1候補として整理開始した +- `Mermaid gantt` は可視化・共有向けの片方向補助出力、`CSV + ParentID` は編集・交換向けの候補として切り分けて考える +- `CSV + ParentID` は最小出力と最小逆変換を実装済みで、現時点の出力列は `ID / ParentID / WBS / Name / Start / Finish / PredecessorID / Resource / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / Type / Priority / Work / CalendarUID / ConstraintType / ConstraintDate / Deadline / Notes` +- UI には `CSV` のダウンロード導線と、CSV ファイル読込導線を追加済み +- 逆変換では `ParentID` から task 階層を再構築し、`PredecessorID` と `Resource` から最小の dependency / resource / assignment を復元する +- `PredecessorID / Resource` は `|` に加えて `,` `;` `、` の複数区切りを受け、trim と重複除去をかける +- 構造エラーとして `ID` 重複、空 `Name`、自己参照 / 欠落 / 循環 `ParentID` を import 時点で弾くようにした +- `single CSV` の次段比較候補として `tasks.csv / resources.csv / assignments.csv` をメモ化した +- 判断軸は「人が 1 枚で編集しやすいか」と「resource / assignment を正規化して安全に往復できるか」のトレードオフになる +- 複数 CSV に進む場合の最小草案として、`tasks.csv(ID / ParentID / Name)`, `resources.csv(ResourceID / Name)`, `assignments.csv(AssignmentID / TaskID / ResourceID)` を置く想定にした +- 分割時の実装順は `tasks.csv -> resources.csv -> assignments.csv` が自然で、calendar はさらに次段と考える +- `tasks.csv` については、`ParentID` 正本、`WBS` 補助、`ID / ParentID / Name` 必須、自己参照 / 欠落 / 循環 `ParentID` は import error、という最小仕様草案まで具体化した +- `tasks.csv` の第1段では `Baseline / TimephasedData / ExtendedAttributes / cost 詳細` は含めず、task 単体属性に集中する +- `resources.csv` については、`ResourceID` 正本、`Name` は必須だが重複非推奨、task との紐付けは持たず `assignments.csv` へ分離する、という最小仕様草案まで具体化した +- `resources.csv` の第1段では `Baseline / TimephasedData / ExtendedAttributes / cost 実績詳細` は含めない +- `assignments.csv` については、`AssignmentID / TaskID / ResourceID` 必須、`TaskID / ResourceID` は既存表を参照、assignment 固有の `Start / Finish / Units / Work / PercentWorkComplete` を持てる、という最小仕様草案まで具体化した +- `assignments.csv` の第1段では `Baseline / TimephasedData / ExtendedAttributes / cost 詳細 / contour 系` は含めない + +## 後回しでよいもの + +- `Baseline` 系 +- `TimephasedData` +- コスト系の完全保持 +- 表示設定 +- Project Server 連携系 +- `ExtendedAttributes` の完全対応 + +## 判断メモ + +- STEP 2 は、まず「実例で頻出し、意味が分かりやすく、XML 往復しやすい項目」から拾うのがよい +- `Baseline` や `TimephasedData` は重要だが、構造が重いため別段階が自然 +- 実例 XML を読む限り、parser 自体よりも「どこまでを内部モデルで保持するか」の整理が次の主題 +- preview / validation の detail 表示強化は一段進んだので、次は実例 XML を見ながら保持方針を詰める段階 +- 補助交換形式については、現時点では `single CSV` を主系統に維持し、複数 CSV は仕様草案止まりにするのが妥当 +- 複数 CSV へ切り替える条件は、同名 resource 衝突、多重 assignment の lossless 保持、`ResourceID` 正本連携の要求が具体化したとき +- `Mermaid gantt` は、単一 predecessor かつ `FS` かつ lag なし かつ変換しやすい duration の task だけ `after ...` を使う部分ネイティブ化まで進めた +- 複雑な predecessor は、`type` や `lag` を付けたコメントへ逃がす方針にした +- `lag` は `PT...` をそのまま見せるのではなく、`2h` のような短い表現へ寄せるところまで進めた diff --git a/docs/mikuproject-ai-json-spec.md b/docs/mikuproject-ai-json-spec.md new file mode 100644 index 0000000..a0c946b --- /dev/null +++ b/docs/mikuproject-ai-json-spec.md @@ -0,0 +1,397 @@ +# mikuproject AI JSON Prompt / Spec + +私たちは、これから取り組むプロジェクトの内容を理解し、WBS の観点から必要なマイルストーン / フェーズ / タスクを整理し、`mikuproject` に設定するための入力へ落とし込んでいきます。 + +`mikuproject` は、`MS Project XML` を基軸に、変換・可視化・限定編集を行う single-file web app です。 + +特に、次の 3 つを重視して設計しています。 + +- `MS Project XML` を基軸にした変換・可視化・限定編集 +- 生成AI 連携を意識した projection / 再取込 +- 人が読むための `WBS Excel ブック (.xlsx)` 帳票出力 + +`mikuproject` と私たち(生成AIを含む)の間のやり取りは、XML ではなく JSON ベースで行います。 + +このプロンプトを読んだ直後は、内容を受け取ったことを示すために `OK` とだけ回答してください。 + +## 現時点の実装状況 + +- 実装済み: `project_overview_view` の export +- 実装済み: `phase_detail_view` の export +- 実装済み: `project_draft_view` の import +- 未実装: `task_edit_view` +- 未実装: Patch JSON の import / 適用 +- `project_draft_request` は補助的な構想・helper であり、現行 UI の主機能ではありません + +## 前提 + +- AI へ渡される入力は用途別 projection JSON です +- AI は説明文を返してよいです +- 既存編集向けの Patch JSON は将来案として設計中です +- `MS Project XML` は保存と互換のための外部形式ですが、AI は直接扱いません +- workbook JSON と AI 向け編集用 JSON を混同しないため、当面 `project_draft_view` などの編集用 JSON には `.editjson` 拡張子を推奨します + +## 重要方針 + +- 全体 JSON の再出力は禁止です +- 不明な値を推測して補完してはいけません +- 未指定項目は変更しない前提です +- 与えられた projection と rules の範囲を超えて変更してはいけません +- 業務意味が不明な場合、断定的な再設計は避けてください +- 業務意味が不明な変更は候補案として扱ってください + +## Projection JSON の代表例 + +- `project_overview_view`: プロジェクト全体の構造、粒度、主要節目を把握するための要約ビュー +- `phase_detail_view`: 特定フェーズの task 群、主要 milestone、依存の要点を把握するための詳細ビュー +- `task_edit_view`: 個別 task を安全に編集するための作業ビュー。現時点では未実装です +- `project_draft_request`: 全く新規の project 草案を AI に生成させるための入力。現時点では設計メモ寄りです +- `project_draft_view`: 新規 project 草案の全量出力。現時点では import 済みです + +## ファイル拡張子の運用 + +- `mikuproject_workbook_json` は `.json` を推奨します +- `project_draft_view` は `.editjson` を推奨します +- `.editjson` は、将来 `task_edit_view` や Patch JSON などの AI 向け編集用 JSON 群にも拡張できる広めの拡張子として扱います +- 拡張子は判別補助であり、必要に応じて中身の `view_type` / `format` でも判定します + +## 補足 + +`phase_detail_view` は、安全な変更候補の抽出や、次に必要な `task_edit_view` の特定にも使えます。 +`phase_detail_view` には、phase 全体をそのまま渡す `full` モードと、対象を絞る `scoped` モードの両方がありえます。 +必要に応じて、`root_uid` と `max_depth` で対象範囲を絞って渡してよいです。 + +新規生成モードでは、既存 project の編集は行わず、全く新しい project の草案だけを返します。 + +### `project_overview_view` の例 + +```json +{ + "project": { + "name": "新基幹システム導入", + "planned_start": "2026-04-01", + "planned_finish": "2026-12-31" + }, + "summary": { + "task_count": 128, + "milestone_count": 12, + "max_outline_level": 4 + }, + "phases": [ + { + "uid": "100", + "name": "要件定義", + "wbs": "1", + "task_count": 18, + "milestone_count": 2, + "planned_start": "2026-04-01", + "planned_finish": "2026-05-15" + } + ] +} +``` + +### `phase_detail_view` の例 + +```json +{ + "project": { + "name": "新基幹システム導入" + }, + "phase": { + "uid": "100", + "name": "要件定義", + "wbs": "1", + "planned_start": "2026-04-01", + "planned_finish": "2026-05-15" + }, + "scope": { + "mode": "full", + "root_uid": null, + "max_depth": null + }, + "tasks": [ + { + "uid": "110", + "name": "現状業務整理", + "parent_uid": "100", + "position": 0, + "planned_duration": "PT40H", + "planned_duration_hours": 40, + "planned_start": "2026-04-01", + "planned_finish": "2026-04-05" + } + ], + "milestones": [ + { + "uid": "190", + "name": "要件定義完了", + "date": "2026-05-15" + } + ] +} +``` + +### `phase_detail_view` の範囲指定 + +- `mode = "full"` の場合は、phase 全体を対象にします +- `mode = "scoped"` の場合は、`root_uid` と `max_depth` で対象範囲を絞れます +- `root_uid` を指定すると、その task を起点にした subtree を対象にできます +- `max_depth` を指定すると、`root_uid` から何階層下まで含めるかを制御できます +- `mode = "full"` では `root_uid = null` かつ `max_depth = null` です + +### `task_edit_view` の例 + +これは将来の安全編集用 projection 案であり、現時点では `mikuproject` 本体に未実装です。 + +```json +{ + "project": { + "name": "新基幹システム導入" + }, + "phase": { + "uid": "100", + "name": "要件定義" + }, + "target_task": { + "uid": "120", + "name": "要件ヒアリング", + "parent_uid": "100", + "position": 1, + "planned_duration": "PT80H", + "planned_duration_hours": 80, + "planned_start": "2026-04-06", + "planned_finish": "2026-04-15" + }, + "predecessors": [ + { + "task_uid": "110", + "name": "現状業務整理", + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ], + "successors": [ + { + "task_uid": "130", + "name": "要件確定", + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ], + "rules": { + "allow_patch_ops": ["update_task", "move_task", "link_tasks", "unlink_tasks"], + "allowed_edit_fields": ["name", "planned_start", "planned_finish", "planned_duration", "planned_duration_hours"], + "forbid_completed_task_changes": true + } +} +``` + +### `project_draft_request` の例 + +これは新規生成プロンプト組み立て用の入力案です。現時点では主に設計用で、UI の主導線にはまだ載せていません。 + +```json +{ + "view_type": "project_draft_request", + "project": { + "name": "新規基幹刷新", + "planned_start": "2026-04-01" + }, + "requirements": { + "goal": "社内基幹システム刷新", + "team_count": 2, + "must_have_phases": ["要件定義", "設計", "実装", "テスト", "移行"], + "must_have_milestones": ["要件確定", "本番移行"] + } +} +``` + +### `project_draft_view` の例 + +```json +{ + "view_type": "project_draft_view", + "project": { + "name": "新規基幹刷新", + "planned_start": "2026-04-01" + }, + "tasks": [ + { + "uid": "draft-1", + "name": "要件定義", + "parent_uid": null, + "position": 0, + "is_summary": true + } + ] +} +``` + +### phase の定義 + +- 当面、phase は top-level summary task を指します +- ルート直下の summary task を phase とみなします +- ここでいう summary task は `is_summary = true` 相当の task です +- `UID=0` の project summary task は phase に含めません + +### UID + +- `uid` は常に string です +- `parent_uid`, `from_uid`, `to_uid`, `task_uid` も常に string です + +### 日付・期間 + +- 当面、WBS 理解用 projection は計画ベースです +- 曖昧な `start` / `finish` は使わず、意味名を分けます +- 例: + - `planned_start` + - `planned_finish` + - `planned_duration` + - `planned_duration_hours` + - `actual_start` + - `actual_finish` +- duration は元表現と補助数値を併記することがあります +- 例: + - `planned_duration: "PT40H"` + - `planned_duration_hours: 40` +- 両方がある場合、理解や比較には `*_hours` を補助的に使ってよいです + +### 依存関係 + +- dependency は単なる前後順ではなく意味的な関係です +- 少なくとも次を見ます + - 相手 task の `uid` + - 相手 task の `name` + - `type` + - `lag` + - `lag_hours` +- `type` は少なくとも次を扱います + - `FS` + - `SS` + - `FF` + - `SF` +- `predecessors` だけでなく `successors` も見てください +- `lag` は負値を取りうることがあります + +### rules + +- 各 projection には `rules` が含まれることがあります +- `rules` は参考情報ではなく、AI が返してよい Patch の契約です +- `allow_patch_ops` にない操作は返してはいけません +- `allowed_edit_fields` にない field は更新してはいけません +- `forbid_*` が true の条件は必ず守ってください + +### `rules` の例 + +```json +{ + "allow_patch_ops": ["update_task", "move_task", "link_tasks", "unlink_tasks"], + "allowed_edit_fields": [ + "name", + "planned_start", + "planned_finish", + "planned_duration", + "planned_duration_hours" + ], + "forbid_completed_task_changes": true, + "forbid_summary_task_direct_edit": true, + "forbid_delete_task": true +} +``` + +### Patch JSON の原則 + +- Patch JSON は `operations` 配列を持つオブジェクトです +- task の field 更新は `update_task` を使います +- 親子や順序の変更は `move_task` を使います +- 依存関係の追加や解除は `link_tasks` / `unlink_tasks` を使います + +### 新規生成モードの原則 + +- `project_draft_request` に対する返答は `project_draft_view` です +- このとき `Patch JSON` は返しません +- draft は正本ではなく草案です +- draft 内の `uid` は `"draft-1"` のような仮 UID でよいです +- `percent_complete` を含めてよいです +- task が通常 task で、`planned_start` / `planned_finish` が日付だけの場合、`mikuproject` 側では勤務時間帯を補完して扱うことがあります +- 同日 task の date-only 指定は、通常 task なら `09:00:00` 開始 / `18:00:00` 終了へ補完されることがあります +- 複数日 task の date-only 指定でも、通常 task なら開始日は `09:00:00`、終了日は `18:00:00` を補完して扱うことがあります +- `planned_finish` だけが与えられた通常 task は、まず同日の `planned_start` を補完したうえで、上記の勤務時間帯補完を適用することがあります +- `is_milestone: true` の task には、この勤務時間帯補完を適用しません + +### Patch の例 + +```json +{ + "operations": [ + { + "op": "update_task", + "uid": "101", + "fields": { + "name": "修正タスク" + } + } + ] +} +``` + +### 順序変更の例 + +```json +{ + "operations": [ + { + "op": "move_task", + "uid": "120", + "new_parent_uid": "100", + "new_index": 2 + } + ] +} +``` + +### 依存追加の例 + +```json +{ + "operations": [ + { + "op": "link_tasks", + "from_uid": "110", + "to_uid": "120", + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ] +} +``` + +### 変更不要の例 + +```json +{ + "operations": [] +} +``` + +## 出力ルール + +- 対話インタフェースでは、説明文を返してよいです +- 変更理由や不確実性を簡潔に説明してよいです +- ただし、最終的な機械処理対象 JSON は必ず最後に 1 個の `json` コードフェンスで囲って返してください +- 既存編集モードでは、その最後の `json` コードフェンス内は `Patch JSON` です +- 新規生成モードでは、その最後の `json` コードフェンス内は `project_draft_view` です +- `mikuproject` が処理対象にするのは、その最後の `json` コードフェンス内の JSON のみです +- 不明な場合は変更を最小にしてください +- 変更不要なら最後の `json` コードフェンスで空の `operations` を返してください +- 与えられていない task や field を勝手に推測しないでください + +## 改善候補 + +- 将来的には `suggest_only` のような提案専用モードを追加する余地があります +- 現時点の spec は task / phase / dependency を優先しており、resource や工数配分の扱いは今後の検討対象です +- phase 定義は当面 `top-level summary task` 固定ですが、将来的にはより柔軟な定義へ拡張する余地があります diff --git a/docs/msprojectxml-ai-integration.md b/docs/msprojectxml-ai-integration.md new file mode 100644 index 0000000..f7eb0fa --- /dev/null +++ b/docs/msprojectxml-ai-integration.md @@ -0,0 +1,1315 @@ +# MS Project XML x 生成AI 連携設計メモ + +この文書は、`mikuproject` における `MS Project XML` と生成AIの連携方針を整理するための設計メモである。 + +現時点では実装仕様の確定版ではなく、アーキテクチャ判断と今後の仕様化ポイントを明確にすることを目的とする。 + +現時点の実装範囲は次のとおり。 + +- 実装済み: `project_overview_view` export +- 実装済み: `phase_detail_view` export +- 実装済み: `project_draft_view` import +- 未実装: `task_edit_view` +- 未実装: Patch JSON の受信・適用 + +この設計では、生成AIとの会話は `JSON` ベースで行う方針とする。 + +- AI へ渡す入力は用途別 projection JSON +- AI から受け取る出力は、現状実装では `project_draft_view`、将来案としては Patch JSON を想定する +- workbook JSON と AI 向け編集用 JSON を区別するため、当面 `project_draft_view` などの編集用 JSON には `.editjson` 拡張子を推奨する + +`MS Project XML` は保存と互換のための外部形式として保持し、AI との直接入出力には使わない。 + +## 目的 + +`mikuproject` は `MS Project XML` を忠実に扱う編集ソフトとして設計する。 + +すでに `.xlsx` の import/export は実装済みであり、次の課題として生成AIとの安全な連携を検討する。 + +- `WBS` やプロジェクト構造を、AIが扱いやすい形で渡す +- AIの編集結果を、安全かつ検証可能な形で受け取る +- `MS Project XML` との互換性を維持する + +なお、現時点の UI で扱える生成AI連携は、既存 project に対する `project_overview_view` / `phase_detail_view` の保存と、新規草案として返ってきた `project_draft_view` の取込までである。 + +## 最重要方針 + +結論として、生成AIとの会話は `JSON` ベースで行い、`MS Project XML` をそのまま AI に渡さない。 + +代わりに次のレイヤで分離する。 + +- 外部形式: `MS Project XML` +- 内部形式: 正規化された canonical model +- AI 入出力形式: 用途別 projection JSON と、将来案としての Patch JSON + +要点は次のとおり。 + +- XML は保存と互換のための正本として扱う +- 内部では意味ベースの正規化モデルを扱う +- AI とは JSON ベースでやり取りする +- AI からの返却は、現状では `project_draft_view` の取込、将来は差分 Patch の受取を想定する + +一言でまとめると、`XML は保存、JSON は思考、Patch は将来の操作` である。 + +## レイヤ構造 + +想定するデータ構造のレイヤは次のとおり。 + +### 1. 外部形式 + +- `MS Project XML` +- 正本 +- 互換維持のための保存形式 + +### 2. 内部モデル + +- 正規化された `Project / Task / Resource / Assignment / Calendar` モデル +- `mikuproject` 内部で意味を保って扱う canonical representation + +### 3. AI 入出力形式 + +- AI入力: 用途別に投影した JSON +- AI出力: Patch JSON + +この分離により、AI側の都合と `MS Project XML` 側の都合を疎結合にできる。 + +## なぜ XML をそのまま AI に渡さないか + +`MS Project XML` は互換形式としては有用だが、AIとの直接連携には不向きである。 + +理由は次のとおり。 + +- XML の階層と要素数が多くノイズが多い +- AI にとって意味単位が読み取りづらい +- XML 全量を書き換えさせると破損リスクが高い +- 差分検証や部分適用が難しい + +したがって、AI 連携では XML の完全再構成を求めるのではなく、意味ベースの JSON と差分操作に変換して扱う。 + +## AI 向け JSON 設計方針 + +AI 向け JSON は、XML をそのまま JSON 化したものではなく、意味ベースで正規化した構造をもとに、目的別に投影した projection とする。 + +### NG + +- XML を機械的に JSON 化する +- 互換性都合の細かいフィールドをそのまま露出する +- AI に全フィールドの再出力を求める +- AI 用 JSON を 1 種類だけで済ませようとする + +### OK + +- タスクや依存関係など、意味のある単位に正規化する +- 今回の判断に必要な情報だけを出す +- 型と命名を一貫させる +- AI に理解しやすい構造を優先する +- 用途ごとに projection を切り替える + +例: + +```json +{ + "tasks": [ + { + "uid": 100, + "name": "要件定義", + "parent_uid": null, + "duration": "PT40H", + "duration_hours": 40, + "predecessors": [] + } + ] +} +``` + +AI は `PT40H` のような `ISO 8601 duration` をある程度理解できるが、比較や推論をより安定させるため、AI projection では元の表現に加えて補助の数値表現も併記する方針とする。 + +例: + +```json +{ + "duration": "PT40H", + "duration_hours": 40 +} +``` + +この場合、元の意味を保つ正規表現として `duration` を残しつつ、AI が扱いやすい補助値として `duration_hours` を与える。 + +## JSON は独自仕様でよいか + +AI 向け JSON は、業界標準に完全準拠している必要はない。 + +この用途では、次の条件を満たす独自 JSON で十分に成立する。 + +- フィールド名が自然で意味を推測しやすい +- 同じ意味に対して同じ名前を使う +- 型が安定している +- 暗黙ルールが少ない + +そのため、`OpenProject` など既存製品の JSON を参考にしつつ、`mikuproject` に必要な範囲で自作する方針が現実的である。 + +## 標準との距離感 + +完全にそのまま使える標準 JSON は現時点では見当たらない。 + +参考になるものはあるが、いずれもそのまま採用するには不足がある。 + +| 種類 | 位置づけ | +| --- | --- | +| `MS Project XML` | 標準だが XML であり、AI 入出力には不向き | +| `OpenProject JSON` | 実務的だが製品固有 | +| `schema.org Project` | 抽象的で WBS 編集には不足 | + +したがって方針としては、`OpenProject` 風のタスク中心 JSON を参考にしながら、`MS Project XML` へマッピングしやすい自前 schema を定義する。 + +## AI 入力は「最小」ではなく「十分」 + +AI 連携で重要なのは、単に情報量を減らすことではない。 + +`全部の真実` を渡すのではなく、`今回の判断に必要な真実` を渡すことが重要である。 + +AI に対して情報を過剰に渡すと、ノイズが増え、判断の焦点がぼやける。一方で、重要な制約や背景を削りすぎると、もっともらしいが不正確な提案を返しやすくなる。 + +したがって、設計原則は `minimal` ではなく `sufficient` である。 + +- 少なければよいわけではない +- 多ければ正確になるわけでもない +- 目的に対して十分な文脈を渡すことが重要 + +## AI 入力 JSON の考え方 + +AI に渡す JSON は、canonical model の単純縮小版ではなく、目的ごとに編集された `context-rich projection` として設計する。 + +この projection には、少なくとも次の 3 層を含める。 + +### 1. 編集対象 + +AI が直接読み取り、提案や変更の対象にするデータ。 + +例: + +- task の `uid` +- `name` +- `parent_uid` +- 並び順 +- predecessor +- duration +- start / finish + +### 2. 制約コンテキスト + +AI が守るべきルールや変更可能範囲。 + +例: + +- 変更禁止項目 +- 完了済み task は変更禁止 +- summary task の直接編集禁止 +- predecessor の循環禁止 +- 削除操作禁止 + +### 3. 判断補助コンテキスト + +AI が正しい解釈に到達するための背景情報。 + +例: + +- project 名 +- フェーズ概要 +- 親 task 名 +- 近傍 task +- 主要 milestone +- 対象プロジェクトの規模や種別 + +## 全体像が必要なケース + +AI の判断は、局所編集だけで完結しない場合がある。 + +たとえば次のような依頼では、全体像を渡す必要がある。 + +- WBS の抜け漏れを見たい +- 工程構成が妥当か見たい +- フェーズ配分の偏りを見たい +- 類似プロジェクトの WBS と比較したい +- 同種案件のたたき台を作りたい + +このようなケースでは、個別 task の列挙だけでは不十分であり、フェーズ構成、主要 milestone、依存のまとまり、件数集計、代表 task 群など、プロジェクト全体を理解するための情報を渡す必要がある。 + +## AI Projection は 1 種類ではない + +AI 入力は 1 種類の簡約 JSON で統一するより、用途別 projection を複数持つ方がよい。 + +候補は次のとおり。 + +- `project_overview_view` +- `phase_detail_view` +- `task_edit_view` +- `dependency_edit_view` +- `schedule_review_view` +- `similar_project_view` +- `comparison_view` +- `project_draft_request` +- `project_draft_view` + +必要に応じて、複数の projection を同時に AI へ渡してよい。 + +たとえば `task_edit_view` を主データとしつつ、`project_overview_view` を補助コンテキストとして併用する、という使い方が考えられる。 + +また、`project_overview_view` で全体像を把握した後、特定フェーズを深掘りするための中間ビューとして `phase_detail_view` を置く構成が考えられる。 + +このとき、`phase_detail_view` は `full` と `scoped` の 2 モードを持てるようにしておく方が実務的である。`full` は phase 全量を渡し、`scoped` は必要に応じて `root_uid` と `max_depth` で subtree 単位に絞る。 + +現行 UI では、既存 project 向けの生成AI連携は `Output` タブから扱う。 + +- `full bundle` +- `project_overview_view` +- `phase_detail_view full` +- `phase_detail_view scoped` + +を `.editjson` として保存できる構成とし、`scoped` の場合は `phase UID`、`root UID`、`max depth` 相当の入力を伴う。 + +一方で、既存 project の安全編集とは別に、全く新規の project 草案を AI に生成させるための `project_draft_request` / `project_draft_view` 系を分離して持つことも有効である。 + +## 新規生成モード + +既存計画の編集と、新規計画の生成は、同じ AI 連携でも別モードとして扱う方が安全である。 + +- 既存編集モード: 既存 project を前提にし、出力は `Patch JSON` +- 新規生成モード: 粗い要件から project 草案を生成し、出力は `project_draft_view` + +この新規生成モードでは、AI は既存 project を変更しない。許されるのは、新しい project の全量草案を返すことだけである。 + +現行 UI では、この新規生成モードは `Input` タブ内の `生成AI連携` から扱う。生成AIとの会話自体は外部で行い、`mikuproject` 側では `project_draft_view` を + +- `Load from file` から `.editjson` として開く +- JSON テキストを貼り付けて取り込む + +のいずれかで受け付ける。 + +### 新規生成モードの原則 + +- 既存 project の編集には使わない +- 出力は `Patch` ではなく全量の draft JSON とする +- draft は正本ではなく草案として扱う +- `mikuproject` 側で validation を通してから内部モデルへ取り込む +- 既存 UID と混同しないよう、仮 UID を使ってよい + +### `project_draft_request` の例 + +```json +{ + "view_type": "project_draft_request", + "project": { + "name": "新規基幹刷新", + "planned_start": "2026-04-01" + }, + "requirements": { + "goal": "社内基幹システム刷新", + "team_count": 2, + "must_have_phases": ["要件定義", "設計", "実装", "テスト", "移行"], + "must_have_milestones": ["要件確定", "本番移行"] + } +} +``` + +### `project_draft_view` の例 + +```json +{ + "view_type": "project_draft_view", + "project": { + "name": "新規基幹刷新", + "planned_start": "2026-04-01" + }, + "tasks": [ + { + "uid": "draft-1", + "name": "要件定義", + "parent_uid": null, + "position": 0, + "is_summary": true + } + ] +} +``` + +## `project_overview_view` の役割 + +`project_overview_view` は、個別 task を厳密に編集するためのビューではなく、プロジェクト全体の構造と粒度を AI に把握させるための要約 projection である。 + +主な用途は次のとおり。 + +- WBS 全体レビュー +- 抜け漏れ検出 +- フェーズ構成の妥当性確認 +- フェーズ配分の偏り確認 +- 類似プロジェクト比較の入力 +- 個別編集前の全体コンテキスト付与 + +逆に、次の用途には向かない。 + +- 個別 task の厳密編集 +- 全依存関係の詳細編集 +- resource / assignment の詳細編集 +- XML 互換維持のための保持項目確認 + +## `project_overview_view` に含めるべき情報 + +`project_overview_view` では、全 task の全属性を渡すのではなく、全体理解に効く情報を圧縮して渡す。 + +中核になるのは次の情報である。 + +- project の基本情報 +- task 全体件数などの集計 +- フェーズ一覧 +- 主要 milestone +- top level の依存関係 +- 判断ルールや制約 + +特に重要なのは `phases` であり、AI がまず全体像を把握するための中心データとなる。 + +## `project_overview_view` に含めすぎない方がよい情報 + +次のような情報は、原則として `project_overview_view` には入れない方がよい。 + +- 全 task の全属性 +- assignment の詳細 +- calendar の細粒度定義 +- XML 互換維持用の細かな保持項目 +- `TimephasedData` のような重い詳細 + +これらは別 projection で扱うべきであり、overview に混ぜると AI の注意が散りやすい。 + +## `project_overview_view` の最小構造案 + +```json +{ + "project": { + "name": "新基幹システム導入", + "domain": "enterprise-it", + "planning_mode": "forward", + "planned_start": "2026-04-01", + "planned_finish": "2026-12-31", + "status_date": "2026-06-01" + }, + "summary": { + "task_count": 128, + "summary_task_count": 18, + "milestone_count": 12, + "max_outline_level": 4 + }, + "phases": [ + { + "uid": 100, + "name": "要件定義", + "wbs": "1", + "task_count": 18, + "milestone_count": 2, + "planned_start": "2026-04-01", + "planned_finish": "2026-05-15" + } + ], + "milestones": [ + { + "uid": 190, + "name": "要件定義完了", + "parent_uid": 100, + "date": "2026-05-15" + } + ], + "top_level_dependencies": [ + { + "from_uid": 100, + "to_uid": 200, + "type": "FS" + } + ], + "rules": { + "completed_tasks_exist": true, + "allow_patch_ops": ["add_task", "update_task", "move_task"] + } +} +``` + +## `project_overview_view` の必須候補 + +最低限、次の項目は候補になる。 + +- `project.name` +- `project.planned_start` +- `project.planned_finish` +- `summary.task_count` +- `summary.max_outline_level` +- `phases` +- `milestones` +- `top_level_dependencies` +- `rules` + +## `phases` の重要性 + +`project_overview_view` の中心は `phases` である。 + +AI は全 task 一覧よりも、まずフェーズの塊を見た方が、全体構造、工程順序、粒度感を把握しやすい。 + +`phases` に持たせる候補は次のとおり。 + +- `uid` +- `name` +- `wbs` +- `task_count` +- `summary_task_count` +- `milestone_count` +- `planned_start` +- `planned_finish` +- `duration` +- `duration_hours` +- `percent_complete` + +## `phase` の定義 + +`project_overview_view` や `phase_detail_view` で使う `phase` は、曖昧な概念のままにせず、抽出ルールを固定した方がよい。 + +当面の基本方針としては、`phase` を `top-level summary task` ベースで定義するのがもっとも実務的である。 + +つまり、原則として次を `phase` とみなす。 + +- `Summary = true` +- ルート直下にある task +- `UID=0` の placeholder task は除外 + +この定義にすると、MS Project XML の task 階層と自然に対応しやすく、`project_overview_view` と `phase_detail_view` を一貫した基準で構成しやすい。 + +## `phase` 定義の利点 + +この定義には次の利点がある。 + +- XML 由来の task 階層と対応づけやすい +- project 全体を自然な大区分に分けやすい +- `phase_detail_view` の対象を `uid` で直接指せる +- Patch 適用後の再集計も行いやすい + +要するに、独自のフェーズ抽出ロジックを複雑に持つより、まずは `top-level summary task` を `phase` とみなす方が壊れにくい。 + +## `phase` とみなさないもの + +次のものは、原則として `phase` には含めない。 + +- `UID=0` の project summary task +- leaf task +- ルート直下であっても summary ではない task + +この場合、ルート直下の leaf task は、どこかの phase に属する task ではなく、phase 外の top-level task として別扱いする。 + +## 例外と fallback + +実際の WBS では、必ずしも top-level summary task がきれいにフェーズを表していない場合がある。 + +そのため、将来的には次の fallback を持つ余地がある。 + +1. `top-level summary task` を優先する +2. それが不十分な場合は、明示設定された phase marker を使う +3. さらに必要なら、特定 `OutlineLevel` を phase とみなす補助ルールを使う + +ただし、初期段階では fallback を増やしすぎると `phase` の意味がぶれるため、まずは `top-level summary task` に固定する方がよい。 + +## `phase_detail_view` との関係 + +`phase_detail_view` は、この定義で抽出された 1 つの `phase` を対象にする。 + +つまり `phase_detail_view.phase.uid` は、`project_overview_view.phases[].uid` のいずれかと一致する前提で扱う。 + +これにより、overview で見た phase を、そのまま detail へドリルダウンする導線が明確になる。 + +## 代表 task を含めるか + +`project_overview_view` は単なる集計だけでなく、必要に応じて代表 task を少数含めた方がよい。 + +要約だけでは、AI がフェーズの具体的な作業内容や粒度感を誤解することがあるためである。 + +そのため、phase ごとに `sample_tasks` を数件だけ含める設計は有効である。 + +例: + +```json +{ + "uid": 100, + "name": "要件定義", + "task_count": 18, + "sample_tasks": [ + { "uid": 110, "name": "現状業務整理" }, + { "uid": 120, "name": "要件ヒアリング" }, + { "uid": 130, "name": "要件確定" } + ] +} +``` + +## `project_overview_view` の位置づけ + +要するに、`project_overview_view` は、プロジェクト全体の構造、粒度、主要節目を AI に理解させるための要約 projection であり、個別 task 編集のための完全データではない。 + +## `phase_detail_view` の位置づけ + +`phase_detail_view` は、`project_overview_view` で把握した全体像のうち、特定フェーズだけを一段詳しく見るための projection である。 + +これは単なる task 一覧ではなく、フェーズの task 群、主要 milestone、依存の要点、必要に応じた要約情報をまとめて持てる詳細ビューとして位置づける。 + +そのため、`phase_task_list_view` のような限定的な一覧ビューよりも、将来の拡張に耐えやすい。 + +役割のイメージは次のとおり。 + +- `project_overview_view`: プロジェクト全体の把握 +- `phase_detail_view`: 特定フェーズの深掘り +- `task_edit_view`: 個別 task の厳密編集 + +また、`phase_detail_view` は phase 全体を返すだけでなく、特定 summary task 配下へ対象範囲を絞る中間ビューとしても使えるようにしておくとよい。 + +### 範囲指定の考え方 + +`phase_detail_view` には、少なくとも次の 2 モードがあるとよい。 + +- `full`: phase 全体をそのまま返す +- `scoped`: 対象 subtree に絞って返す + +`scoped` の場合は、次のような scope 指定を持たせる。 + +- `root_uid`: 対象 subtree の根 task UID +- `max_depth`: `root_uid` から何階層下まで含めるか + +この形にしておくと、overview と task_edit の間にある「少し詳しいがまだ広い」ビューを、用途に応じて段階的に絞り込める。 + +## `phase_detail_view` の具体例 + +```json +{ + "project": { + "name": "新基幹システム導入", + "planned_start": "2026-04-01", + "planned_finish": "2026-12-31" + }, + "phase": { + "uid": 100, + "name": "要件定義", + "wbs": "1", + "planned_start": "2026-04-01", + "planned_finish": "2026-05-15", + "task_count": 18, + "milestone_count": 2, + "percent_complete": 20 + }, + "tasks": [ + { + "uid": 110, + "name": "現状業務整理", + "parent_uid": 100, + "position": 0, + "is_summary": false, + "is_milestone": false, + "duration": "PT40H", + "duration_hours": 40, + "planned_start": "2026-04-01", + "planned_finish": "2026-04-05", + "percent_complete": 100, + "predecessor_uids": [] + }, + { + "uid": 120, + "name": "要件ヒアリング", + "parent_uid": 100, + "position": 1, + "is_summary": false, + "is_milestone": false, + "duration": "PT80H", + "duration_hours": 80, + "planned_start": "2026-04-06", + "planned_finish": "2026-04-15", + "percent_complete": 50, + "predecessor_uids": [110] + } + ], + "milestones": [ + { + "uid": 190, + "name": "要件定義完了", + "date": "2026-05-15" + } + ], + "dependency_summary": [ + { + "from_uid": 110, + "to_uid": 120, + "type": "FS" + } + ], + "rules": { + "allow_patch_ops": ["add_task", "update_task", "move_task"], + "forbid_completed_task_changes": true + } +} +``` + +この例では、`tasks` が中心データでありつつ、`phase` の要約、主要 `milestones`、依存の要点、`rules` を同時に持たせている。 + +これにより、AI は特定フェーズの中身を task 単位で追いながら、そのフェーズ全体の意味も見失いにくくなる。 + +## `task_edit_view` の位置づけ + +`task_edit_view` は、生成AIに個別 task の編集をさせるための projection である。 + +`project_overview_view` や `phase_detail_view` が理解と検討のためのビューであるのに対し、`task_edit_view` は実際の変更提案を安全に返させるための作業ビューと位置づける。 + +主な用途は次のとおり。 + +- task 名の修正 +- task の親子変更 +- task の順序変更 +- task の期間変更 +- 依存関係の追加や解除 +- 個別 task 周辺の整合見直し + +## `task_edit_view` に必要な情報 + +`task_edit_view` では、対象 task だけを孤立して渡すのではなく、編集判断に必要な局所文脈をあわせて渡す。 + +少なくとも次の情報が候補になる。 + +- 対象 task 本体 +- 親 task の情報 +- 近傍の sibling task +- 同フェーズ内の関連 task +- predecessor / successor +- 編集ルール + +特に、task 単体の属性だけでは sibling order や依存文脈を誤解しやすいため、近傍文脈は重要である。 + +## `task_edit_view` の具体例 + +```json +{ + "project": { + "name": "新基幹システム導入" + }, + "phase": { + "uid": 100, + "name": "要件定義" + }, + "target_task": { + "uid": 120, + "name": "要件ヒアリング", + "parent_uid": 100, + "position": 1, + "is_summary": false, + "is_milestone": false, + "planned_duration": "PT80H", + "planned_duration_hours": 80, + "planned_start": "2026-04-06", + "planned_finish": "2026-04-15", + "percent_complete": 50 + }, + "parent_task": { + "uid": 100, + "name": "要件定義" + }, + "sibling_tasks": [ + { + "uid": 110, + "name": "現状業務整理", + "position": 0 + }, + { + "uid": 130, + "name": "要件確定", + "position": 2 + } + ], + "predecessors": [ + { + "task_uid": 110, + "name": "現状業務整理", + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ], + "successors": [ + { + "task_uid": 130, + "name": "要件確定", + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ], + "rules": { + "allow_patch_ops": ["update_task", "move_task", "link_tasks", "unlink_tasks"], + "forbid_completed_task_changes": true, + "forbid_summary_task_direct_edit": true + } +} +``` + +この例では、`target_task` が中心だが、親、近傍 task、依存関係、ルールも同時に持たせている。 + +これにより、AI は対象 task を局所的に読みつつ、周辺文脈を踏まえた Patch を返しやすくなる。 + +## `task_edit_view` と Patch の接続 + +`task_edit_view` の目的は、AI に task を理解させることそのものではなく、妥当な Patch を返させることである。 + +そのため、`task_edit_view` では次を意識する。 + +- Patch で参照する識別子をそのまま見せる +- 移動や依存変更に必要な相手 task を見せる +- 編集禁止条件を `rules` として明示する +- 未指定項目は変更しない前提で、対象外項目を無理に並べない + +つまり `task_edit_view` は、`Patch JSON` を安全に生成させるための最小作業面として設計する。 + +## 日付・期間・進捗の意味論 + +AI が WBS を安定して理解するためには、日付や期間の意味を曖昧にしない方がよい。 + +特に次の点は、名前で区別して表現する。 + +- それが計画値か実績値か +- duration が計画上の期間か実績上の期間か +- 進捗値が計画補助なのか実績反映なのか + +当面の基本方針は、WBS 理解用 projection を `計画ベース` とすることである。 + +そのため、overview 系や phase 系の projection では、原則として計画値を主に渡す。 + +推奨: + +- `planned_start` +- `planned_finish` +- `planned_duration` +- `planned_duration_hours` +- `actual_start` +- `actual_finish` + +`start` や `finish` のような曖昧な名前は、計画と実績が混在し始めると意味衝突を起こしやすい。 + +生成AIは文脈から推測できることも多いが、推測に依存した schema は弱い。 + +そのため、値そのものを増やすことよりも、意味名を分けることを優先する。 + +実績情報は、初期段階では overview に全面展開せず、必要な用途でのみ別 projection または別レイヤとして重ねる方が扱いやすい。 + +例: + +```json +{ + "uid": 120, + "name": "要件ヒアリング", + "planned_start": "2026-04-06", + "planned_finish": "2026-04-15", + "planned_duration": "PT80H", + "planned_duration_hours": 80, + "actual_start": "2026-04-07", + "actual_finish": null, + "percent_complete": 50 +} +``` + +この方針により、AI にはまず計画構造を理解させ、その後に必要な場面だけ実績を重ねて見せられる。 + +## 依存関係の意味論 + +AI が WBS を理解するうえでは、依存関係を単なる前後順としてではなく、`type` と `lag` を持つ意味的な関係として見せた方がよい。 + +少なくとも次の情報を持たせる。 + +- 相手 task の `uid` +- 相手 task の `name` +- 依存種別 `type` +- ラグ `lag` +- ラグの補助値 `lag_hours` + +依存種別 `type` は、少なくとも次の 4 種を扱えるようにする。 + +- `FS`: Finish-to-Start +- `SS`: Start-to-Start +- `FF`: Finish-to-Finish +- `SF`: Start-to-Finish + +AI は `FS` を暗黙の既定として理解しがちだが、実際には `SS` や `FF` が工程設計上重要になる場合がある。 + +そのため、依存関係を扱う projection では、`type` を省略せず明示する方がよい。 + +## `lag` の扱い + +`lag` も duration と同様に、元表現と補助数値を併記する方が実務的である。 + +推奨: + +```json +{ + "type": "FS", + "lag": "PT8H", + "lag_hours": 8 +} +``` + +これにより、MS Project に寄せた元表現を保ちながら、AI が比較や計算をしやすくなる。 + +負のラグを許す場合も、同じ考え方で表せる。 + +```json +{ + "type": "SS", + "lag": "-PT8H", + "lag_hours": -8 +} +``` + +## predecessor と successor + +AI に対象 task の編集をさせる場合は、`predecessors` だけでなく `successors` も見せた方が安全である。 + +理由は次のとおり。 + +- predecessor だけでは、変更が後続 task に与える影響を見落としやすい +- successor だけでも、先行条件を見落としやすい +- 双方向を見せることで、局所編集の破壊範囲を判断しやすくなる + +そのため、`task_edit_view` では `predecessors` と `successors` を併記する方針が妥当である。 + +## 依存関係の Patch との接続 + +依存関係を変更する場合は、汎用の field 更新よりも、専用の Patch 操作として表した方が安全である。 + +候補: + +- `link_tasks` +- `unlink_tasks` + +たとえば追加は次のように表せる。 + +```json +{ + "operations": [ + { + "op": "link_tasks", + "from_uid": 110, + "to_uid": 120, + "type": "FS", + "lag": "PT0H", + "lag_hours": 0 + } + ] +} +``` + +これにより、依存の追加・解除・変更を task 本体の field 更新と混同しにくくなる。 + +## 依存関係で追加検討が必要な点 + +今後さらに詰める必要がある点は次のとおり。 + +- `lag` の単位を常に時間換算で持つか +- `type` の既定値を許すか、常に明示するか +- 同一 pair に複数 link を許すか +- summary task への link を許すか +- 循環依存をどう validation するか + +## `rules` の具体化 + +AI に渡す `rules` は、単なる参考情報ではなく、AI が返してよい Patch の範囲を制御するための明示的な制約セットとして扱う。 + +`rules` の目的は次のとおり。 + +- AI に許可された操作範囲を明示する +- 編集禁止条件を明示する +- Patch 生成時の推測を減らす +- validation 失敗を減らす + +つまり `rules` は、projection に付随する説明文ではなく、AI との編集契約として扱う。 + +## `rules` に入れる情報の種類 + +少なくとも次の 3 系統に分けて持たせるとよい。 + +### 1. 許可操作 + +AI が返してよい Patch 操作の一覧。 + +例: + +- `allow_patch_ops` + +候補値: + +- `add_task` +- `delete_task` +- `move_task` +- `update_task` +- `link_tasks` +- `unlink_tasks` + +### 2. 禁止条件 + +特定条件下での編集禁止ルール。 + +例: + +- `forbid_completed_task_changes` +- `forbid_summary_task_direct_edit` +- `forbid_delete_task` +- `forbid_dependency_changes` + +### 3. 制約パラメータ + +単純な可否だけでなく、編集範囲や閾値を表すルール。 + +例: + +- `max_new_tasks_per_request` +- `allowed_edit_fields` +- `allowed_target_scope` +- `allowed_dependency_types` + +## `rules` の具体例 + +```json +{ + "allow_patch_ops": ["update_task", "move_task", "link_tasks", "unlink_tasks"], + "allowed_edit_fields": [ + "name", + "planned_start", + "planned_finish", + "planned_duration", + "planned_duration_hours" + ], + "allowed_target_scope": "current_phase", + "allowed_dependency_types": ["FS", "SS", "FF", "SF"], + "forbid_completed_task_changes": true, + "forbid_summary_task_direct_edit": true, + "forbid_delete_task": true, + "max_new_tasks_per_request": 0 +} +``` + +この例では、 + +- 許可 op を限定し +- 更新可能 field を限定し +- 対象範囲を現在フェーズに限定し +- 完了済み task や削除操作を禁止している + +## `rules` の解釈方針 + +AI に対しては、`rules` に書かれていない操作を暗黙に許可しない方がよい。 + +したがって、基本は次の解釈を採る。 + +- `allow_patch_ops` にない op は返してはいけない +- `allowed_edit_fields` にない field は更新してはいけない +- `forbid_*` が `true` の条件は必ず守る +- 迷った場合は変更せず、Patch を小さく保つ + +この方針により、AI が「たぶん許されるだろう」と推測して広く変更するのを防ぎやすくなる。 + +## `rules` をどのビューに持たせるか + +`rules` は用途に応じて、各 projection に持たせてよい。 + +たとえば: + +- `project_overview_view` では大域的な編集方針 +- `phase_detail_view` では当該フェーズの編集範囲 +- `task_edit_view` では対象 task 周辺の具体的な編集制約 + +同じ key 名でも、ビューごとにスコープが違ってよい。ただし意味自体は変えない方がよい。 + +## `rules` と validation の関係 + +`rules` は AI への指示であると同時に、Patch 検証側でも使える方がよい。 + +つまり、返却された Patch は次の順で確認できる。 + +1. schema に合っているか +2. `rules` に違反していないか +3. 参照整合性に問題がないか +4. 業務ルールに違反していないか + +この順に見ることで、単なる型不正と、許可範囲逸脱と、業務不整合を分けて扱いやすくなる。 + +## `rules` で今後詰める点 + +今後さらに明確化したい点は次のとおり。 + +- `allow_patch_ops` を必須にするか +- `allowed_edit_fields` を常に持たせるか +- `forbid_*` を列挙型に寄せるか、boolean key で持つか +- スコープを `project / phase / task` のどこまで細かく切るか +- AI が `rules` 違反を検出したときに空 Patch を返すか、理由つき拒否を返すか + +## AI とのやり取り + +### AI へ渡すもの + +- WBS またはプロジェクトの用途別 projection JSON +- その projection JSON の schema +- 正しい例 +- 制約ルール + +### AI から受け取るもの + +- Patch JSON のみ + +AI に対しては、全体 JSON の再出力ではなく、差分だけを返すよう明示する。 + +## Projection 設計の実務方針 + +projection 設計では、次の考え方を採る。 + +- canonical model 全量をそのまま AI に見せない +- AI の用途ごとに projection を作る +- projection には編集対象だけでなく制約と背景も入れる +- XML 互換維持用の細かい保持項目は原則として見せない +- 今回の判断に不要な `Resource / Assignment / Calendar` 全量は渡さない +- ただし、判断に必要なら全体像や類似案件情報も渡す + +要するに、AI に必要なのは `縮小データ` ではなく、`目的に応じて編集された文脈付きデータ` である。 + +## Patch 形式 + +AI の返却は差分ベースの Patch 形式にする。 + +例: + +```json +{ + "operations": [ + { + "op": "update_task", + "uid": 101, + "fields": { + "name": "修正タスク" + } + } + ] +} +``` + +この方式の利点は次のとおり。 + +- 変更範囲が明確 +- 検証しやすい +- 適用前レビューがしやすい +- 不要な書き換えを抑制できる +- XML 全体破壊のリスクを減らせる + +## 識別子設計 + +識別子は次の考え方で整理する。 + +| 項目 | 扱い | +| --- | --- | +| `UID` | 正本。内部・Patch・参照で使う不変キー | +| `ID` | 表示用 | +| `WBS` | 派生値 | + +AI が参照・更新に使う主キーは `UID` に寄せる。 + +## JSON Schema の位置づけ + +`JSON Schema` は正式な標準仕様として採用できる。 + +主に `draft-2020-12` を前提候補とする。 + +### Schema でできること + +- 型制約 +- 必須項目の定義 +- `enum` 制約 +- 配列やオブジェクトの基本構造制約 + +### Schema だけではできないこと + +- 参照整合性の保証 +- 循環依存の検出 +- 業務ルール検証 +- 意味的妥当性の保証 + +そのため、`JSON Schema` は入口の構文検証として使い、その後に独自の validation を重ねる必要がある。 + +## Schema と例と制約 + +AI 制御では schema だけでは足りない。 + +精度はおおむね次の順で高くなる。 + +| 条件 | 期待精度 | +| --- | --- | +| Schema なし | 低い | +| Schema のみ | 中 | +| Schema + 例 | 高い | +| Schema + 例 + 制約 | 非常に高い | + +そのため、AI 入出力仕様として最低限必要なのは次の 3 点である。 + +1. `JSON Schema` +2. 正しい例 +3. 制約ルール + +## AI への指示方針 + +AI に対しては次を明示する。 + +- JSON のみ返す +- 出力形式を固定する +- 不明値は推測しない +- 全体返却は禁止し、Patch のみ返す + +抽象的な説明よりも、具体例を添えた方が精度は高い。 + +## 想定アーキテクチャ + +```text +MS Project XML + ↓ +正規化モデル(内部) + ↓ +AI 用 JSON + ↓ +AI(編集) + ↓ +Patch JSON + ↓ +検証 + ↓ +内部モデル更新 + ↓ +XML 再生成 +``` + +## 今後詰めるべき仕様論点 + +現時点の方向性は妥当だが、実装仕様としては次を詰める必要がある。 + +### 1. Patch 操作の粒度 + +`update_task` だけでは不足する。最低でも次の操作は候補になる。 + +- `add_task` +- `delete_task` +- `move_task` +- `reorder_task` +- `update_task` +- `link_tasks` +- `unlink_tasks` + +### 2. 階層と順序の扱い + +`parent_uid` だけでは sibling order を表現できない。 + +人間向けには次の表現が候補になる。 + +- `parent_uid + position` +- `before_uid` +- `after_uid` + +ただし、生成AIとの Patch では `before_uid / after_uid` は整合性を崩しやすく、扱いがやや不安定である。 + +そのため、AI とのやり取りでは、順序変更を汎用 field 更新として表すよりも、専用操作として表した方がよい。 + +推奨: + +- `move_task` +- `new_parent_uid` +- `new_index` + +例: + +```json +{ + "operations": [ + { + "op": "move_task", + "uid": 120, + "new_parent_uid": 100, + "new_index": 2 + } + ] +} +``` + +`new_index` は `0-based` と明記し、適用時に sibling 範囲チェックを行う。 + +さらに AI に許す操作を絞る場合は、`move_up / move_down / indent_task / outdent_task` のような意味的な操作へ寄せる余地もある。 + +### 3. 部分更新の意味論 + +Patch の `fields` に含まれない項目をどう扱うかを固定する必要がある。 + +- 未指定は変更なし +- `null` は原則として通常の更新値としては使わない +- 値の削除や解除が必要な場合は、専用操作または専用フィールド意味論で表す + +生成AIとのやり取りでは、`未指定は変更なし` を基本ルールにした方が安全である。 + +AI は全項目を安定して再出力するとは限らないため、未指定を削除扱いにすると意図しない消失が起きやすい。 + +この意味論が曖昧だと安全な適用ができない。 + +### 4. 業務ルール検証 + +Schema の後段で、少なくとも次を検証する必要がある。 + +- 参照先 `UID` が存在するか +- predecessor に循環がないか +- 日付や duration の整合性が取れているか +- summary task に対する制約を満たすか +- 削除や移動で不整合が起きないか + +### 5. 用途別 JSON 投影 + +AI に見せる JSON は単一万能形式ではなく、用途別に投影を分ける余地がある。 + +例: + +- 編集用ビュー +- 要約用ビュー +- 提案生成用ビュー + +### 6. 競合検出 + +古いスナップショットを前提に AI が Patch を返す可能性がある。 + +そのため Patch には次のような競合検出情報を持たせる余地がある。 + +- `base_revision` +- `snapshot_hash` + +### 7. 権限制御 + +AI に許す操作範囲をセッション単位で制限できるようにする。 + +例: + +- タスク名変更のみ許可 +- 依存関係変更は禁止 +- 削除操作は禁止 + +### 8. エラー分類 + +Patch 適用失敗時は、単なる失敗ではなく理由を分類して返せるようにする。 + +例: + +- schema error +- reference error +- business rule violation +- conflict + +## 現時点の暫定結論 + +`mikuproject` における生成AI連携の基本方針は次のとおりとする。 + +- 外部互換と保存は `MS Project XML` +- 内部処理と AI 連携は正規化 JSON +- AI の返却は Patch JSON +- 妥当性確認は schema と独自 validation を組み合わせる + +この方針により、XML 互換性を保ったまま、AI 編集に必要な安全性と実装容易性を両立しやすくなる。 diff --git a/docs/native-svg-spec.md b/docs/native-svg-spec.md new file mode 100644 index 0000000..904695d --- /dev/null +++ b/docs/native-svg-spec.md @@ -0,0 +1,93 @@ +# native SVG spec + +この文書は、`mikuproject` における自前 `SVG` 描画の最小仕様メモである。 + +## 位置づけ + +- 自前 `SVG` 描画は、`Mermaid` の置き換えを目的としない +- `Mermaid` 出力は、`Markdown` / 設計資料向けの軽量テキスト表現として残す +- 自前 `SVG` 描画は、見た目を制御しやすい preview / download 向けの別系統出力として扱う + +## 目的 + +- `WBS` を、`Mermaid` よりも見た目を制御しやすい `SVG` として描画する +- 同じ描画結果を、画面内 preview と `SVG` download の両方で使う +- `mikuproject` 内の他出力と表示解釈がぶれないようにする + +## 入力 + +- 入力は `ProjectModel` とする +- 表示期間、`holiday`、`business day`、進捗帯計算の基準は、`WBS XLSX` と同じロジックを使う +- `WBS XLSX` 側の `holidayDates`、表示期間、営業日判定と意味が一致することを優先する + +## MVP の描画要素 + +MVP では、少なくとも次を描画対象とする。 + +- phase 行 +- task bar +- milestone +- today line +- task label +- 日付軸 + +補足: + +- `WBS XLSX` で進捗を `■` や `□` で表している表現は、native `SVG` では持ち込まない + +## MVP のレイアウト方針 + +- 横軸は日単位とする +- 縦軸は task 1 行固定とする +- 折り返しは行わない +- ラベル衝突は初期段階では扱わない +- まずは素直に描けることを優先し、凝った自動レイアウトは後回しにする + +## ラベル配置モード + +- native `SVG` のラベル配置には 2 つのモードを持てるようにする +- 新デフォルトは `近接ラベル` とする +- 旧来方式は `一覧ラベル` とする + +### 近接ラベル + +- phase / task / milestone の名称を、対応する図形の右または左に近接して配置する +- 目の移動を減らし、ガント図としての読みやすさを優先する +- native `SVG` の既定表示は、この `近接ラベル` を前提とする + +### 一覧ラベル + +- 名称を左側の一覧領域にまとめて表示する +- 長い名称に強く、旧来の一覧 + 図形の見え方を維持したい場合に使う +- 旧来方式として残すが、既定にはしない + +## 出力方針 + +- 自前 `SVG` は preview 用と download 用を兼ねる単一の描画結果として生成する +- 生成した `SVG` 文字列を、そのまま preview に埋め込み、そのまま保存できる形を基本とする +- 線幅や寸法は `px` 前提ではなく、`viewBox` に基づく `SVG` の user unit で扱う + +## 役割分担 + +- `Mermaid` + - `Markdown` / 設計資料向け + - 軽量テキスト表現 +- native `SVG` + - 見た目重視の preview / download 向け + - 形状、色、配置を `mikuproject` 側で制御するための描画 + +## 非目標 + +MVP では、次は優先しない。 + +- `Mermaid` の完全互換 +- 折り返しやラベル衝突回避 +- 高度な自動レイアウト +- 過剰な装飾やアニメーション +- `MS Project` 代替のような重い描画編集機能 + +## 実装上の含意 + +- できるだけ `WBS XLSX` の表示ロジックを再利用し、判断に迷ったときは `WBS XLSX` に寄せる +- `Mermaid` と native `SVG` は別出力として併存させる +- 表示品質を上げたい要求は、まず native `SVG` 側で受ける前提とする diff --git a/docs/screenshots/excel01.png b/docs/screenshots/excel01.png new file mode 100644 index 0000000..bbb9b20 Binary files /dev/null and b/docs/screenshots/excel01.png differ diff --git a/docs/screenshots/screen01.png b/docs/screenshots/screen01.png new file mode 100644 index 0000000..1fa5af5 Binary files /dev/null and b/docs/screenshots/screen01.png differ diff --git a/docs/screenshots/screen02.png b/docs/screenshots/screen02.png new file mode 100644 index 0000000..51c5770 Binary files /dev/null and b/docs/screenshots/screen02.png differ diff --git a/docs/screenshots/screen03.png b/docs/screenshots/screen03.png new file mode 100644 index 0000000..c658956 Binary files /dev/null and b/docs/screenshots/screen03.png differ diff --git a/docs/spec.md b/docs/spec.md new file mode 100644 index 0000000..de6dd4f --- /dev/null +++ b/docs/spec.md @@ -0,0 +1,1093 @@ +# mikuproject + +`mikuproject` は、MS Project XML 形式の入出力を扱うプロジェクト管理アプリとして設計する。 + +この文書は `mikuproject` の仕様メモであり、README の代わりではない。利用方法やビルド手順は `README.md` に置き、未完了タスクは `docs/TODO.md` に置く。 + +配置先: + +- `docs/spec.md` + +アプリ名: + +- `mikuproject` + +前提: + +- このリポジトリ流儀の single-file web app とする +- ローカルで動作する HTML ツールとして構築する +- まずは UI よりも、MS Project XML の入出力と内部モデル化を優先する +- `MS Project XML` を意味の基軸として扱う +- 内部では `ProjectModel` を中立表現として扱う +- `.xlsx` は確認・可視化・限定編集のための周辺表現として扱う +- 仕様判断に迷った場合は、独自都合よりも `MS Project 仕様` に立ち返って判断する +- `MS Project` 実機は未保有である + +立ち位置: + +- `mikuproject` は `MS Project` 代替製品を目指すものではない +- 中核は、`MS Project XML` をハブにして `XLSX / Markdown / JSON / Mermaid / 生成AI / MS Project` をつなぐ変換・可視化・橋渡しツールである +- したがって、重要機能の優先順位も「橋渡しを強くするか」で判断する +- 具体的には、差分可視化、Patch 適用、phase 単位の scoped export/import、import/export の扱い可視化は優先しやすい +- 一方で、重い管理機能や UI 内完結の大規模操作は優先度を上げすぎない + +## STEP 1 の目的 + +STEP 1 の目的は、`MS Project XML` を意味的に往復できる状態を作ること。 + +ここでいう「往復できる」とは、次を意味する。 + +- `MS Project XML` を読める +- 必要な情報を内部モデルへ落とせる +- 内部モデルから `MS Project XML` を再生成できる +- 再生成した XML を、少なくとも `mikuproject` 自身で再読込できる +- 主要フィールドが壊れず往復できる + +注意: + +- 目標は「元の XML と完全一致」ではない +- 目標は「意味的に往復できる」ことである + +## `.xlsx` の位置づけ + +`mikuproject` における `.xlsx` は、`MS Project XML` の代替正本ではない。 + +- `MS Project XML` は意味の基軸 +- `ProjectModel` は内部の中立表現 +- `.xlsx` は確認・可視化・限定編集のための周辺表現 + +したがって、`.xlsx` 対応は `MS Project XML` の仕様を置き換えるためではなく、`ProjectModel` を介した補助入出力として追加する。 + +同様に、構造忠実 workbook の JSON 版も、`MS Project XML` の代替正本ではなく、`.xlsx` の写し身として扱う。 + +一方で、生成AI 連携の編集用 JSON はこれと別系統のものとし、当面は workbook JSON と混同しないよう `.editjson` 拡張子を推奨する。 + +現時点で想定する経路は次のとおり。 + +- `MS Project XML -> ProjectModel -> .xlsx` +- `.xlsx -> ProjectModel -> MS Project XML` +- `MS Project XML -> ProjectModel -> workbook JSON` +- `workbook JSON -> ProjectModel -> MS Project XML` + +ただし、`.xlsx -> ProjectModel` は自由編集をそのまま受け入れるのではなく、編集可能な列を限定した部分更新として扱う。 + +`workbook JSON -> ProjectModel` も同様に、自由編集をそのまま受け入れるのではなく、`.xlsx import` と同じ編集可能列の部分更新として扱う。 + +現時点の `.xlsx` / workbook JSON 周りは、実装済みの限定 import/export として次のように整理できる。 + +### 現状実装 + +- 構造忠実な汎用 workbook export/import + - `Project / Tasks / Resources / Assignments / Calendars` を `ProjectModel` 構造に沿って扱う +- 構造忠実 workbook の JSON export/import + - `mikuproject_workbook_json` として、`XLSX` workbook の論理構造を JSON へ写して扱う + - `format = "mikuproject_workbook_json"`、`version = 1` を持つ + - `Project / Tasks / Resources / Assignments / Calendars / NonWorkingDays` を `sheets` 配下に持つ + - import 時の反映対象列・キー・部分更新ルールは `XLSX Import` と同じにする +- 表示専用の `WBS` workbook export + - `Tasks` 中心の別 workbook として `.xlsx` 出力できる + - 現時点では export 専用であり、import は扱わない + - `WBS XLSX Export` では、`ProjectModel` から補完した既定祝日と、UI で指定した追加祝日を合成して扱う + - 指定した祝日は WBS 日付帯で祝日色として表示する + - sample 生成では、`Calendar.Exceptions` のうち非稼働日例外を祝日候補として WBS workbook へ反映する + - 現行レイアウトでは、先頭に `プロジェクト情報`、続いて `凡例` と `サマリ` を置き、その下に日付帯と task 一覧を並べる + - `プロジェクト情報` ブロックは先頭に置き、`プロジェクト名 / カレンダ / 開始日 / 終了日 / 現在日 / 祝日` を持つ + - `凡例` ブロックでは、進捗済み / 予定帯 / 当日 / 週頭 / 週末 / 祝日 / フェーズ / 進捗済みタスク / 予定タスク / マイルストーン / サマリ / クリティカル / 未設定 を見分けられるようにする + - `サマリ` ブロックには `表示日 / 表示週 / 営業日 / 前日数 / 後日数 / 表示 / 進捗 / 基準日 / タスク / リソース / 割当 / カレンダ` を持つ + - `サマリ` の値側は、長い日付がはみ出しにくいように結合セルで表示する + - 日付帯では、日付行と曜日行を分けて表示し、週ラベル専用行は持たない + - 曜日帯では `Sat` と `Sun` を強めの週末色で表示し、祝日は別色で表示する + - `タスク詳細` は `Task.Notes` を表示し、空の場合は `-` とする + - `J2` には `出力日時 YYYY-MM-DD HH:mm` を出す +- 表示専用の `WBS Markdown` export + - `WBS XLSX` と同じく、人が読むための帳票として扱う + - 当面は export 専用であり、import は扱わない + - `WBS XLSX` と同じ `ProjectModel` を入力にし、表示内容もできるだけ揃える + - 少なくとも `プロジェクト情報`、`WBS 本体`、`サマリ` を持つ + - `プロジェクト情報` では、見出し上の主名として `Project.Name` を使う + - `Project.Title` は、Markdown 出力の主表示には使わない + - 1 つの Markdown に、`WBS ツリー` と `WBS テーブル` の両方を含める + - 出力順は、`プロジェクト情報`、`WBS ツリー`、区切り線、`WBS テーブル`、区切り線、`サマリ` を基本とする + - 前半の主表示は `WBS ツリー` とし、`WBS テーブル` は確認用の詳細表、その後ろに `サマリ` を置く + - table 形式では、`プロジェクト情報` と `サマリ` を小さな Markdown table に分ける + - `WBS テーブル` は、可読性を優先して 1 個の大 table とする + - 結合セル、塗り色、罫線、列幅は Markdown へは持ち込まない + - `WBS ツリー` では、task 階層をインデントと記号で表す + - `WBS ツリー` では、子 task を `┗ ` で表し、階層が深い場合は `全角空白 + ┗ ` を段数ぶん積む形とする + - `WBS ツリー` は Markdown の list 記法に無理に寄せず、等幅で読める `WBS の文字` として出す + - `WBS ツリー` の task 行には、少なくとも `WBS / 名称 / 開始 / 終了 / 進捗` を含められるようにする + - `タスク詳細` は、`WBS テーブル` では列として保持し、`WBS ツリー` では task 本文の次行または後置表現で保持する + - 日付帯や進捗帯のような色依存の表現は、そのまま再現しない + - 色依存の表現は、日付文字列・数値へ落として表す + - `WBS Markdown` は、`WBS XLSX` と競合するものではなく、軽量なテキスト共有用の派生表現として扱う + - `WBS ツリー` と `WBS テーブル` の task 集合は一致させ、片方だけに存在する task を作らない + - 当面の仕様検討では、まずこの両方入り構成で sample 出力を作り、前半と後半の情報差を確認する +- 表示専用の `WBS記述書 Markdown` export + - `WBS` の階層表現そのものとは別物として扱う + - 目的は、各 task の意味・成果物・完了条件などを文章で確認しやすくすること + - 当面は export 専用であり、import は扱わない + - 最小設計では、保持元を `Task.ExtendedAttribute` 主体とし、長文補足のみ `Task.Notes` を使う + - 最小設計で扱う項目は、少なくとも次の 5 つとする + - `TaskPurpose` + - `TaskDeliverable` + - `TaskOutOfScope` + - `TaskDoneDefinition` + - `TaskOwner` + - 上記 5 項目は `Task.ExtendedAttribute` の `FieldName` で識別する前提とする + - 補足本文や自由記述は `Task.Notes` を使う + - Markdown 出力では、task ごとに 1 節を持つ構成を基本とする + - 各節では、少なくとも `WBS / 名称 / 目的 / 成果物 / スコープ外 / 完了条件 / 担当 / 補足` を必要に応じて出す + - 未設定の項目は空欄のまま出さず、省略する + - `WBS記述書 Markdown` は、`WBS Markdown` の代替ではなく、task 説明を補う別出力として扱う + - 当面は新規入力 UI を先に増やさず、既存の `ExtendedAttribute` / `Notes` からの export を優先する + +### workbook JSON の位置づけ + +`mikuproject` は、構造忠実 workbook のテキスト版として `mikuproject_workbook_json` を持てるようにする。 + +これは生成AI向け projection JSON とは別物であり、`XLSX` の写し身として扱う。 + +- 目的は、構造忠実 workbook をテキストで扱いやすくすること +- `XLSX` と意味を揃えた補助入出力として扱う +- 新しい編集モデルや新しい意味体系は持ち込まない +- styling、列幅、merge、塗り色などの表示情報は持たない + +`mikuproject_workbook_json` の最小外形は次のとおり。 + +```json +{ + "format": "mikuproject_workbook_json", + "version": 1, + "sheets": { + "Project": [], + "Tasks": [], + "Resources": [], + "Assignments": [], + "Calendars": [], + "NonWorkingDays": [] + } +} +``` + +sheet 名は、構造忠実 workbook の `XLSX` と同じく次で固定する。 + +- `Project` +- `Tasks` +- `Resources` +- `Assignments` +- `Calendars` +- `NonWorkingDays` + +各 sheet の列名は、対応する `XLSX` workbook の header と完全一致で固定する。 + +つまり、`mikuproject_workbook_json` は `XLSX` workbook の論理構造を JSON へ写したものであり、列追加や別名導入は行わない。 + +import 時の扱いも `XLSX Import` と完全に揃える。 + +- 反映対象列は `XLSX Import` と完全一致とする +- 反映単位は部分更新とする +- `Tasks / Resources / Assignments / Calendars` は `UID` をキーに扱う +- `NonWorkingDays` は `CalendarUID + Index` をキーに扱う +- 未対応列や未知の列は反映対象にしない +- `workbook JSON` だからといって自由編集を全量反映しない + +拡張子運用: + +- `mikuproject_workbook_json` は、構造忠実 workbook の JSON として `.json` を推奨する +- 生成AI 連携の編集用 JSON は、workbook JSON と区別するため `.editjson` を推奨する +- `project_draft_view` は当面この編集用 JSON 群に含め、`.editjson` で受け渡す前提とする + +### 新規作成時の既定非稼働日 + +`mikuproject` は `MS Project XML` を意味の基軸として扱うため、新規 project 作成時の既定非稼働日も、できる限り `MS Project XML` の calendar 表現にそのまま載る形で扱う。 + +新規 project を作成する場合、明示的な calendar 指定がなければ、既定 calendar を 1 つ作り、その中に次を合成して持たせる前提とする。 + +- 土日を非稼働日とする週次ルールを `WeekDays` へ設定する +- 日本の祝日を非稼働日例外として `Exceptions` へ設定する + +これらは独自の「非稼働日種別」や別 calendar 概念を正本側へ追加するのではなく、最初から `MS Project XML` として自然な 1 つの calendar にまとめて扱う。 + +この既定 calendar の表示名は、当面 `Standard` を既定値として扱う。新規 project に calendar が存在せず、project 側にも明示的な `CalendarUID` 指定がない場合に限り、この `Standard` calendar を自動補完する。 + +補完時は少なくとも次を行う。 + +- `Calendars` に既定 calendar を 1 件追加する +- `Project.CalendarUID` をその calendar の `UID` に設定する +- task / resource に個別 calendar 指定がない場合は、project 既定 calendar を継承する前提で扱う + +この既定 calendar に含める祝日例外は、無制限に生成するのではなく、原則として project の `StartDate` から `FinishDate` までの期間内に入るものへ限定する。 + +この制限は、calendar が存在しない project に対して `mikuproject` が既定 calendar を自動補完する場合にだけ適用する。 + +すでに calendar が存在する場合や、ユーザーが明示的に指定した calendar / `Exceptions` については、`mikuproject` 側で自動的に再構成・再トリミングしない前提とする。 + +意図: + +- 暗黙の「土日休み」を仕様化して、生成AI による新規計画作成でも前提を揃えやすくする +- 日本の業務予定として自然な初期状態を作る +- project 期間外の祝日を `MS Project XML` へ過剰に書き出さず、正本の見通しと差分の素直さを保つ +- 既存 calendar やユーザー指定内容を、`mikuproject` の都合で自動変更しない +- `MS Project XML` の `WeekDays / Exceptions` 表現をそのまま使い、独自概念への依存を増やさない +- 将来の実装では、明示的な calendar がある場合にこの既定値を上書きまたは置換できる余地を残す + +### WBS workbook の非稼働日反映方針 + +`WBS XLSX Export` では、単に祝日色を塗るだけでなく、表示上の期間計算にも非稼働日を反映する方向で扱う。 + +- 期間帯の表示では、非稼働日を作業期間から除外する +- 進捗帯の表示でも、同じ非稼働日基準を使う +- 祝日色の表示と、営業日ベースの期間/進捗表示とで基準が食い違わないようにする + +ここでいう非稼働日には、少なくとも次を含める。 + +- `Calendar.WeekDays` による週次の非稼働日 +- `Calendar.Exceptions` による祝日その他の非稼働日例外 + +土日と祝日は、WBS 上では表示都合で別色にしてよいが、そのために `MS Project XML` 正本へ別概念を追加しない。色分けは `mikuproject` 側の表示ルールで扱う。 + +現時点で `XLSX Import` の反映対象としている列は次のとおり。 + +- `Project`: `Name / Title / Author / Company / StartDate / FinishDate / CurrentDate / StatusDate / CalendarUID / MinutesPerDay / MinutesPerWeek / DaysPerMonth / ScheduleFromStart` +- `Tasks`: `Name / Start / Finish / PercentComplete / PercentWorkComplete / Notes` +- `Resources`: `Name / Group / MaxUnits` +- `Assignments`: `Units / Work / PercentWorkComplete` +- `Calendars`: `Name / IsBaseCalendar / BaseCalendarUID` +- `NonWorkingDays`: `Name / Date / FromDate / ToDate / DayWorking` + +一覧で見ると次のとおり。 + +| Sheet | Editable Columns | Notes | +| --- | --- | --- | +| `Project` | `Name / Title / Author / Company / StartDate / FinishDate / CurrentDate / StatusDate / CalendarUID / MinutesPerDay / MinutesPerWeek / DaysPerMonth / ScheduleFromStart` | project 単位の部分更新として扱う | +| `Tasks` | `Name / Start / Finish / PercentComplete / PercentWorkComplete / Notes` | `UID` をキーに部分更新する | +| `Resources` | `Name / Group / MaxUnits` | `UID` をキーに部分更新する | +| `Assignments` | `Units / Work / PercentWorkComplete` | `UID` をキーに部分更新する | +| `Calendars` | `Name / IsBaseCalendar / BaseCalendarUID` | `UID` をキーに部分更新する | +| `NonWorkingDays` | `Name / Date / FromDate / ToDate / DayWorking` | `CalendarUID + Index` をキーに部分更新する | + +`mikuproject_workbook_json` の import も、この表と同じ反映対象列・キー・部分更新ルールを使う。 + +`Tasks` シートの header ごとの扱いは次のとおり。 + +| Tasks Header | 扱い | +| --- | --- | +| `UID` | 表示のみ | +| `ID` | 表示のみ | +| `Name` | import 可 | +| `OutlineLevel` | 表示のみ | +| `OutlineNumber` | 表示のみ | +| `WBS` | 表示のみ | +| `Start` | import 可 | +| `Finish` | import 可 | +| `Duration` | 表示のみ | +| `PercentComplete` | import 可 | +| `PercentWorkComplete` | import 可 | +| `Milestone` | 表示のみ | +| `Summary` | 表示のみ | +| `Critical` | 表示のみ | +| `CalendarUID` | 表示のみ | +| `Predecessors` | 表示のみ | +| `Notes` | import 可 | + +`Resources` と `Assignments` が 0 件の workbook では、どの列が import 対象か分かるように、editable 列だけ着色されたダミー行を 1 行出してよい。これは表示補助であり、`UID` 等のキーが空なので import 時には無視される。 + +### Calendar 編集方針 + +`Calendars / Exceptions` は、業務上は重要だが壊しやすい領域でもあるため、当面は `mikuproject` の画面上で直接編集しない方針とする。 + +- 画面上では、calendar の存在、件数、参照状況、既定祝日の補完結果などの read-only 確認を主とする +- `Calendars / Exceptions / WeekDays / WorkWeeks` の実編集は、`MS Project XML` または `XLSX Import` 経由で行う +- 画面側に独自の calendar editor を持ち込まず、`MS Project XML` を意味の基軸とする設計を優先する + +### 現時点で反映対象外のもの + +これ以外の列や、未対応シートの編集は、現在の `XLSX Import` では反映対象としない。特に `Calendars` では、`WeekDays / WorkWeeks` はまだ反映対象外とする。`Exceptions` は `NonWorkingDays` シートとして限定的に扱う。 + +## WBS ステータスの扱い方針 + +`WBS` 用の業務ステータスは、`PercentComplete` の派生値としてではなく、`Task.ExtendedAttribute` に保持する前提で扱う。 + +- `Complete` と `Cancelled` を区別できるようにする +- `PercentComplete=100` とは別軸の状態として保持する +- `MS Project XML` の round-trip で保持しやすい形を優先する + +`MS Project` 互換の観点では、`Active=false` は「スケジュール対象外」として使いうるが、`WBS` 上での業務ステータス表示とは役割が異なる。そのため、`mikuproject` では `Cancelled` などの業務値を `ExtendedAttribute` に置く方針を採る。 + +具体的な `FieldID / FieldName / 値候補` は今後の設計項目とする。 + +### UI 上の確認手段 + +`XLSX Import` 後の validation では、`Calendars.BaseCalendarUID` が既存 Calendar を指していない場合や、自身を指している場合の warning も、差分要約と並べて確認できるようにする。 + +## STEP 1 の完了条件 + +STEP 1 の完了条件は次のとおり。 + +- `MS Project XML` を入力として読み込める +- XML から必要な情報を抽出し、内部モデルを生成できる +- 内部モデルから `MS Project XML` を出力できる +- 出力した XML を再読込しても例外にならない +- `xml -> model -> xml -> model` の往復後に、主要フィールドが保持されている + +## 現時点の実装メモ + +現時点では、STEP 1 の確認をしやすくするために、次の補助表示を持つ。 + +- `Project / Tasks / Resources / Assignments / Calendars` の件数サマリ +- 内部モデルの JSON 表示 +- `Project / Tasks / Resources / Assignments / Calendars` の preview 表示 +- validation メッセージ表示 + +preview / validation の現状メモ: + +- project は `OutlineCodes / WBSMasks / ExtendedAttributes` の代表値を preview で追えるようにする +- task / resource / assignment は参照先の名前つきで追えるようにする +- calendar は `Project / Task / Resource / BaseCalendar` からの参照関係を追えるようにする +- validation は `UID` だけでなく、可能な範囲で名前つきで追えるようにする + +注意: + +- これらは STEP 1 の主目的そのものではなく、意味的ラウンドトリップを確認しやすくするための補助機能である +- `.xlsx` 表示や `.xlsx import/export` も、同様に確認と限定編集のための補助機能として扱う +- `XLSX Import` の反映結果は、`Tasks / Resources / Assignments` ごとの件数と `UID` 単位の差分要約で確認できるようにする +- `XLSX Import` 後も validation を走らせ、反映結果と検証メッセージを同時に確認できるようにする +- validation では、`PercentComplete` の範囲外や `Start > Finish` のような編集結果も UI 上で追えるようにする +- validation が残っていても、`XML Export` はその時点の XML をそのまま保存できるようにする + +### 現在の UI 上の整理 + +現行 UI は、概ね次の 3 画面構成で整理している。 + +- `Input` + - `Load from file` から `MS Project XML`、`XLSX`、workbook JSON (`.json`)、生成AI向け編集用 JSON (`.editjson`)、`CSV + ParentID` を読込 + - サンプル XML の読込 + - 生成AIが返した `project_draft_view` の貼り付け取込 +- `Overview` + - 内部モデルの要約確認 + - validation の確認 + - native `SVG` preview の確認 + - preview 表示 +- `Output` + - `MS Project XML`、`XLSX`、`WBS XLSX`、workbook JSON、`CSV + ParentID` の保存 + - Mermaid fenced code block を含む `.md` と native `SVG` の保存 + - 生成AI向け `project_overview_view` / `phase_detail_view` / `full bundle` の `.editjson` 出力 + +生成AI連携の現状実装範囲: + +- 既存 project 向けには `project_overview_view` / `phase_detail_view` / `full bundle` の export を持つ +- 新規生成向けには `project_draft_view` の import を持つ +- `task_edit_view` の export と Patch JSON の import / 適用は、現時点では未実装とする + +ここでいう `Overview` は、内部実装上の `transform` 相当タブを、ユーザー向けに読み替えた呼称である。 + +## STEP 1 の入力データ前提 + +`MS Project` 実機を保有していないため、STEP 1 の入力データ前提は次のとおりとする。 + +- Microsoft 公開の `MS Project XML schema` を基準にする +- 当面の基準スキーマは `Microsoft Office Project 2007 XML Data Interchange Schema` とする +- 具体的には `https://schemas.microsoft.com/project/2007/` および `mspdi_pj12.xsd` を基準とする +- STEP 1 で扱うファイル形式は、`.mpp` ではなく `.xml` の `MS Project XML 形式` とする +- `.mpp` は MS Project のネイティブ本体形式、`.xml` は外部連携や交換のための XML 表現と捉える +- STEP 1 の検証用 XML は、自作の最小サンプル XML を用いる +- まずは `mikuproject` 自身で意味的に往復できることを優先する +- 実際の `MS Project` 本体が出力した XML との互換確認は、将来課題として扱う + +検証用データの参照元メモ: + +- 一時的な検証用データの参照元として `https://github.com/rpbouman/open-msp-viewer/` を利用する +- ただし、Git 管理下へそのまま格納するかどうかは別途判断する +- `open-msp-viewer` プロジェクトのサンプルには大いに助けられた。感謝する +- 実例 XML から見えた保持項目ギャップは `docs/gap-notes.md` に整理する +- 仕様判断で迷った場合は、MicrosoftDocs の Project XML Data Interchange リファレンスも補助資料として参照する + - `https://github.com/MicrosoftDocs/office-developer-msproject-xml-docs/tree/main/project-xml-data-interchange` + +## STEP 1 で扱う対象 + +STEP 1 では、MS Project XML のうち、次の情報を優先して扱う。 + +- `Project` 基本情報 +- `Tasks` +- `Resources` +- `Assignments` +- 必要最小限の `Calendars` +- `PredecessorLink` などの依存関係 + +## STEP 1 で優先する主要フィールド + +### Project + +- `Name` +- `Title` +- `Author` +- `Company` +- `CreationDate` +- `LastSaved` +- `SaveVersion` +- `CurrentDate` +- `StartDate` +- `FinishDate` +- `ScheduleFromStart` +- `DefaultStartTime` +- `DefaultFinishTime` +- `MinutesPerDay` +- `MinutesPerWeek` +- `DaysPerMonth` +- `StatusDate` +- `WeekStartDay` +- `WorkFormat` +- `DurationFormat` +- `CurrencyCode` +- `CurrencyDigits` +- `CurrencySymbol` +- `CurrencySymbolPosition` +- `FYStartDate` +- `FiscalYearStart` +- `CriticalSlackLimit` +- `DefaultTaskType` +- `DefaultFixedCostAccrual` +- `DefaultStandardRate` +- `DefaultOvertimeRate` +- `DefaultTaskEVMethod` +- `NewTaskStartDate` +- `NewTasksAreManual` +- `NewTasksEffortDriven` +- `NewTasksEstimated` +- `ActualsInSync` +- `EditableActualCosts` +- `HonorConstraints` +- `InsertedProjectsLikeSummary` +- `MultipleCriticalPaths` +- `TaskUpdatesResource` +- `UpdateManuallyScheduledTasksWhenEditingLinks` +- `CalendarUID` +- `OutlineCodes` +- `WBSMasks` +- `ExtendedAttributes` + +### Tasks + +- `UID` +- `ID` +- `Name` +- `OutlineLevel` +- `OutlineNumber` +- `WBS` +- `Type` +- `CalendarUID` +- `Priority` +- `Start` +- `Finish` +- `Duration` +- `ActualStart` +- `ActualFinish` +- `Deadline` +- `StartVariance` +- `FinishVariance` +- `Work` +- `WorkVariance` +- `TotalSlack` +- `FreeSlack` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `RemainingWork` +- `ActualWork` +- `Milestone` +- `Summary` +- `Critical` +- `PercentComplete` +- `PercentWorkComplete` +- `Notes` +- `ConstraintType` +- `ConstraintDate` +- `ExtendedAttribute` +- `Baseline` +- `TimephasedData` +- `TimephasedData` +- `PredecessorLink` + +### Resources + +- `UID` +- `ID` +- `Name` +- `Type` +- `Initials` +- `Group` +- `WorkGroup` +- `MaxUnits` +- `CalendarUID` +- `StandardRate` +- `StandardRateFormat` +- `OvertimeRate` +- `OvertimeRateFormat` +- `CostPerUse` +- `Work` +- `ActualWork` +- `RemainingWork` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `PercentWorkComplete` +- `ExtendedAttribute` +- `Baseline` +- `TimephasedData` + +### Assignments + +- `UID` +- `TaskUID` +- `ResourceUID` +- `Start` +- `Finish` +- `StartVariance` +- `FinishVariance` +- `Delay` +- `Milestone` +- `WorkContour` +- `Units` +- `Work` +- `Cost` +- `ActualCost` +- `RemainingCost` +- `PercentWorkComplete` +- `OvertimeWork` +- `ActualOvertimeWork` +- `ActualWork` +- `RemainingWork` +- `ExtendedAttribute` +- `Baseline` + +### Calendars + +- `UID` +- `Name` +- `IsBaseCalendar` +- `BaseCalendarUID` +- `WeekDays` +- `Exceptions` +- `WorkWeeks` + +## STEP 1 で後回しにするもの + +STEP 1 では、次のようなものは後回し候補とする。 + +- `.xlsx import` における自由編集の全面対応 +- `Calendars / Baseline / TimephasedData / ExtendedAttributes` の `.xlsx` 編集反映 + +- 表示設定 +- UI レイアウト情報 +- 独自拡張要素 +- 完全互換のために必要だが、主要データの意味保持に直結しない補助ノード群 + +## 内部モデル方針 + +内部モデルは、MS Project XML をそのまま保持するのではなく、意味的に扱いやすい正規化済みのモデルとする。 + +最小モデル案: + +```ts +type ProjectModel = { + project: { + name: string; + currentDate?: string; + startDate: string; + finishDate: string; + scheduleFromStart: boolean; + defaultStartTime?: string; + defaultFinishTime?: string; + minutesPerDay?: number; + minutesPerWeek?: number; + daysPerMonth?: number; + statusDate?: string; + weekStartDay?: number; + workFormat?: number; + durationFormat?: number; + currencyCode?: string; + currencyDigits?: number; + currencySymbol?: string; + currencySymbolPosition?: number; + fyStartDate?: string; + fiscalYearStart?: boolean; + criticalSlackLimit?: number; + defaultTaskType?: number; + defaultFixedCostAccrual?: number; + defaultStandardRate?: string; + defaultOvertimeRate?: string; + defaultTaskEVMethod?: number; + newTaskStartDate?: number; + newTasksAreManual?: boolean; + newTasksEffortDriven?: boolean; + newTasksEstimated?: boolean; + actualsInSync?: boolean; + editableActualCosts?: boolean; + honorConstraints?: boolean; + insertedProjectsLikeSummary?: boolean; + multipleCriticalPaths?: boolean; + taskUpdatesResource?: boolean; + updateManuallyScheduledTasksWhenEditingLinks?: boolean; + calendarUID?: string; + outlineCodes: OutlineCodeModel[]; + wbsMasks: WBSMaskModel[]; + extendedAttributes: ProjectExtendedAttributeModel[]; + }; + calendars: CalendarModel[]; + tasks: TaskModel[]; + resources: ResourceModel[]; + assignments: AssignmentModel[]; +}; + +type TaskModel = { + uid: string; + id: string; + name: string; + outlineLevel: number; + outlineNumber: string; + wbs?: string; + type?: number; + calendarUID?: string; + priority?: number; + start: string; + finish: string; + duration: string; + actualStart?: string; + actualFinish?: string; + deadline?: string; + startVariance?: string; + finishVariance?: string; + work?: string; + workVariance?: string; + totalSlack?: string; + freeSlack?: string; + cost?: number; + actualCost?: number; + remainingCost?: number; + remainingWork?: string; + actualWork?: string; + milestone: boolean; + summary: boolean; + critical?: boolean; + percentComplete: number; + percentWorkComplete?: number; + notes?: string; + constraintType?: number; + constraintDate?: string; + predecessors: PredecessorModel[]; +}; + +type PredecessorModel = { + predecessorUid: string; + type?: number; + linkLag?: string; +}; + +type ResourceModel = { + uid: string; + id: string; + name: string; + type?: number; + initials?: string; + group?: string; + workGroup?: number; + maxUnits?: number; + calendarUID?: string; + standardRate?: string; + standardRateFormat?: number; + overtimeRate?: string; + overtimeRateFormat?: number; + costPerUse?: number; + work?: string; + actualWork?: string; + remainingWork?: string; + cost?: number; + actualCost?: number; + remainingCost?: number; + percentWorkComplete?: number; +}; + +type AssignmentModel = { + uid: string; + taskUid: string; + resourceUid: string; + start?: string; + finish?: string; + startVariance?: string; + finishVariance?: string; + delay?: string; + milestone?: boolean; + workContour?: number; + units?: number; + work?: string; + cost?: number; + actualCost?: number; + remainingCost?: number; + percentWorkComplete?: number; + overtimeWork?: string; + actualOvertimeWork?: string; + actualWork?: string; + remainingWork?: string; +}; + +type CalendarModel = { + uid: string; + name: string; + isBaseCalendar: boolean; + isBaselineCalendar?: boolean; + baseCalendarUID?: string; + weekDays: Array<{ + dayType: number; + dayWorking: boolean; + workingTimes: Array<{ + fromTime: string; + toTime: string; + }>; + }>; + exceptions: Array<{ + name?: string; + fromDate?: string; + toDate?: string; + dayWorking?: boolean; + workingTimes: Array<{ + fromTime: string; + toTime: string; + }>; + }>; + workWeeks: Array<{ + name?: string; + fromDate?: string; + toDate?: string; + weekDays: Array<{ + dayType: number; + dayWorking: boolean; + workingTimes: Array<{ + fromTime: string; + toTime: string; + }>; + }>; + }>; +}; +``` + +注意: + +- これは STEP 1 の最小モデル案であり、今後拡張の余地がある +- 日付・期間表現は、まず XML と往復しやすい文字列保持を優先する + +## 実装方針 + +STEP 1 の中核処理は、次のような責務に分ける。 + +- `parseXmlDocument(xmlText): XMLDocument` +- `importMsProjectXml(xmlText): ProjectModel` +- `validateProjectModel(model): ValidationIssue[]` +- `exportMsProjectXml(model): string` +- `normalizeProjectModel(model): ProjectModel` + +テストの基本方針: + +- `xml -> model -> xml -> model` のラウンドトリップを確認する +- 比較対象は文字列一致ではなく、正規化後の内部モデル一致とする + +実装判断の原則: + +- 仕様や表現方法に迷った場合は、`MS Project XML` の持ち方を優先する +- 独自に扱いやすいモデル化は許容するが、`MS Project XML` との意味対応を壊さないことを優先する +- 特にタスク階層や依存関係は、独自表現へ寄せすぎず、まず `MS Project` 側の表現を基準に考える + +## テスト方針 + +STEP 1 では、少なくとも次を確認する。 + +- サンプル XML を読み込める +- 内部モデルへ変換できる +- 最小妥当性チェック結果を確認できる +- 再生成 XML を出力できる +- 再生成 XML を再読込できる +- 主要フィールドが保持される + +比較観点: + +- `Project` 基本情報 +- `Tasks` の主要フィールド +- `Resources` の主要フィールド +- `Assignments` の主要フィールド +- 依存関係 + +## 非目標 + +STEP 1 では、次は非目標とする。 + +- MS Project XML の完全再現 +- 元 XML のノード順や空白や書式の完全保持 +- フル機能の編集 UI +- すべての MS Project XML 要素の対応 + +## STEP 1 実装済みメモ + +現時点の STEP 1 実装では、次が入っている。 + +- `types.ts`, `msproject-xml.ts`, `main.ts` への責務分離 +- サンプル XML の読込 +- XML 文字列の import +- 内部モデルから整形済み XML を再生成 +- XML ファイルの export +- `Project / Tasks / Resources / Assignments / Calendars` の簡易プレビュー表示 +- `project / tasks / resources / assignments / calendars` 単位の検証メッセージ表示 +- `mikuproject` 独自の最小妥当性チェック +- `Calendar` の `BaseCalendarUID / WeekDays / WorkingTimes` の round-trip +- `Calendar` の `IsBaselineCalendar / Exceptions / WorkWeeks / Exception WorkingTimes` の round-trip +- `Resource` の `CalendarUID / StandardRate / CostPerUse` の round-trip +- `Resource` の `Work / ActualWork / RemainingWork / Cost / ActualCost / RemainingCost / PercentWorkComplete` の round-trip +- `Assignment` の `StartVariance / FinishVariance` の round-trip +- `Resource` の `WorkGroup` の round-trip +- `Assignment` の `Delay / Milestone / WorkContour` の round-trip +- `Assignment` の `OvertimeWork / ActualOvertimeWork` の round-trip +- `Task` の `Deadline / StartVariance / FinishVariance` の round-trip +- `Task` の `WorkVariance / TotalSlack / FreeSlack / Critical` の round-trip +- `Resource` の `StandardRateFormat / OvertimeRate / OvertimeRateFormat` の round-trip +- `Assignment` の `PercentWorkComplete / ActualWork / RemainingWork` の round-trip +- `Project` の `StatusDate / WeekStartDay / WorkFormat / DurationFormat` の round-trip +- `Project` の `CurrencyCode / CurrencyDigits / CurrencySymbol / CurrencySymbolPosition` の round-trip +- `Project` の `FYStartDate / FiscalYearStart` の round-trip +- `Project` の `CriticalSlackLimit / DefaultTaskType` の round-trip +- `Project` の `DefaultFixedCostAccrual / DefaultStandardRate / DefaultOvertimeRate` の round-trip +- `Project` の `DefaultTaskEVMethod / NewTaskStartDate` の round-trip +- `Project` の `NewTasksAreManual / NewTasksEffortDriven` の round-trip +- `Project` の `NewTasksEstimated / ActualsInSync` の round-trip +- `Project` の `EditableActualCosts / HonorConstraints` の round-trip +- `Project` の `InsertedProjectsLikeSummary / MultipleCriticalPaths` の round-trip +- `Project` の `TaskUpdatesResource / UpdateManuallyScheduledTasksWhenEditingLinks` の round-trip +- `Project` の `OutlineCodes / WBSMasks` の最小 round-trip +- `Project` の `ExtendedAttributes` の最小 round-trip +- `Task` の `ExtendedAttribute` の最小 round-trip +- `Resource` の `ExtendedAttribute` の最小 round-trip +- `Assignment` の `ExtendedAttribute` の最小 round-trip +- `Task` の `Baseline` の最小 round-trip +- `Assignment` の `Baseline` の最小 round-trip +- `Resource` の `Baseline` の最小 round-trip +- `Task` の `TimephasedData` の最小 round-trip +- `Resource` の `TimephasedData` の最小 round-trip +- `Assignment` の `TimephasedData` の最小 round-trip +- `Task / Assignment` の `Cost / ActualCost / RemainingCost` の round-trip +- round-trip テスト + +## Mermaid gantt 出力メモ + +現時点では、確認・共有向けの補助出力として `ProjectModel -> Mermaid gantt` の片方向出力を持つ。 + +目的: + +- `MS Project XML` の全情報保持ではなく、task の時系列と大まかな依存関係を軽量に共有する +- `mikuproject` 内部モデルの内容を、Mermaid 対応環境へ持ち出しやすくする + +現時点の出力方針: + +- summary task は `section` として扱う +- summary ではない task のうち、`Start` と `Finish` を持つものを gantt のタスク行として出力する +- `critical=true` は `crit` として出力する +- `milestone=true` は `milestone` として出力する +- `0 < percentComplete < 100` は `active` として出力する +- `percentComplete >= 100` は `done` として出力する +- task 名や title は Mermaid で壊れやすい一部記号を簡易正規化して出力する +- predecessor は、`単一 predecessor` かつ `FS` かつ `lag なし` かつ `duration` を Mermaid 向けへ素直に変換できる task のみ `after ...` でネイティブ出力する +- 上記に当てはまらない predecessor は、task 名を含むコメント行で補助出力する +- comment 側の `lag` は、可能な範囲で `2h` のような短い人間向け表現に整形して出力する +- `lag` がある場合は、`after Prep + 2h` のような擬似読解用 comment も追加する +- preview と SVG export は native `SVG` 描画を使う +- phase 背景は交互の淡色で視認補助する + +`project_draft_view` からの補完メモ: + +- 通常 task で `planned_start` / `planned_finish` が date-only の場合、内部化時に勤務時間帯として `09:00:00` / `18:00:00` を補完して扱うことがある +- `planned_finish` だけが与えられた通常 task は、まず同日の `planned_start` を補完し、その後に上記の勤務時間帯補完を適用する +- `is_milestone=true` の task には、この勤務時間帯補完を適用しない + +現時点で意図的に落とすもの: + +- `Resources` +- `Assignments` +- `Calendars` +- `Baseline` +- `TimephasedData` +- コスト系の詳細 +- `PredecessorLink` の完全表現 + +注意: + +- これはあくまで片方向の補助出力であり、`Mermaid gantt -> ProjectModel` の往復は対象外とする +- 現時点の dependency 表現は部分的にネイティブ化しているが、複数 predecessor、`FS` 以外の link type、lag あり、複雑な duration はコメント保持のままとする +- どの情報を落としているかは、将来の `CSV + ParentID` 等の交換形式検討と切り分けて扱う + +## CSV + ParentID 交換形式メモ + +`mikuproject` の次段候補として、`CSV + ParentID` を「まず押さえるべき、よくある交換形式」の第1候補とする。 + +目的: + +- 人が表計算ソフトやスプレッドシートで編集しやすい形を持つ +- 独自記法を先に増やしすぎず、一般的な交換形式を先に押さえる +- task 階層を `ParentID` で素直に表現する + +最小列候補: + +- `ID` +- `ParentID` +- `Name` + +実用列候補: + +- `WBS` +- `Start` +- `Finish` +- `PredecessorID` +- `Resource` +- `PercentComplete` + +現時点の整理方針: + +- まずは単一 CSV を前提に考える +- task 階層の正本は `ParentID` とし、`WBS` は補助列として扱う候補とする +- `PredecessorID` は単一値か複数値区切りかを今後決める +- `Resource` は名前で持つか `ResourceID` で持つかを今後決める + +単一 CSV で落ちやすいもの: + +- `Assignments` の完全表現 +- `Calendars` +- `Baseline` +- `TimephasedData` +- コスト系の詳細 + +注意: + +- 現時点では仕様草案段階であり、`CSV + ParentID <-> ProjectModel` の完全往復仕様は未確定 +- 将来必要であれば、`tasks.csv / resources.csv / assignments.csv` の複数表構成も比較対象にする +- 現在の UI では、`CSV + ParentID` は textarea ではなくファイルベースの補助入出力として扱う + - `Input` 側は CSV ファイル読込 + - `Output` 側は CSV ダウンロード + +複数 CSV 構成の比較メモ: + +- `single CSV` の利点は、人が 1 枚の表で task 階層を編集しやすいこと +- `single CSV` の弱点は、`Resource` や `Assignment` を task 行へ押し込むため、正規化されず表現が崩れやすいこと +- `tasks.csv / resources.csv / assignments.csv` の利点は、resource と assignment を独立表現でき、`ResourceID` ベースの安全な往復へ寄せやすいこと +- `tasks.csv / resources.csv / assignments.csv` の弱点は、人が直接編集するには 1 ファイル増えて分かりにくくなること +- 現時点では、まず `single CSV` で task 中心の軽量交換を育て、resource / assignment の保持要求が増えた時点で複数 CSV を比較する方針とする +- その場合の最初の分割候補は `tasks.csv` と `resources.csv` と `assignments.csv` であり、calendar はさらに次段とする + +複数 CSV の最小草案: + +- `tasks.csv` + - 最小列候補: `ID / ParentID / Name` + - 実用列候補: `WBS / Start / Finish / PredecessorID / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / Type / Priority / Work / CalendarUID / ConstraintType / ConstraintDate / Deadline / Notes` +- `resources.csv` + - 最小列候補: `ResourceID / Name` + - 実用列候補: `Initials / Group / CalendarUID / MaxUnits / StandardRate / OvertimeRate / CostPerUse` +- `assignments.csv` + - 最小列候補: `AssignmentID / TaskID / ResourceID` + - 実用列候補: `Start / Finish / Units / Work / PercentWorkComplete` + +草案メモ: + +- `tasks.csv` は現在の `single CSV` の task 列をほぼそのまま引き継げる +- `resources.csv` は name だけでなく `ResourceID` を正本にすることで、同名 resource の衝突を避けやすい +- `assignments.csv` を分けることで、1 task に複数 resource が割り当たるケースを自然に表現できる +- 第1段では `calendar` と `baseline/timephased` は複数 CSV にも入れず、別段とする +- もし複数 CSV に進む場合、最初の実装順は `tasks.csv -> resources.csv -> assignments.csv` が妥当と考える + +`tasks.csv` の最小仕様草案: + +- 目的は task 階層と task 単体属性を、resource / assignment から切り離して安全に往復すること +- 正本の階層表現は `ParentID` とし、`WBS` は補助列扱いとする +- `ID / ParentID / Name` を必須列とする +- `ID` は CSV 内で一意でなければならない +- `ParentID` は空文字を root task とみなし、値がある場合は既存 `ID` を指さなければならない +- `ParentID` の自己参照と循環参照は import error とする +- `Name` は空不可とする +- `PredecessorID` は任意列とし、複数値は `|` を正規表現としつつ、import では `,` `;` `、` も受ける +- `Milestone / Summary / Critical` は `0/1` を正とし、import では `true/false/yes/no` も受ける +- `PercentComplete / PercentWorkComplete` は `0..100` を想定し、範囲外は validation 対象とする +- `Start / Finish / ConstraintDate / Deadline` は `MS Project XML` と同じ日時文字列を前提にする +- `Type / Priority / ConstraintType` は整数列とする +- `Work` は `PT...` 形式の duration 文字列を前提にする + +`tasks.csv` の第1段 scope: + +- 含める: 階層、日付、依存、進捗、milestone/summary/critical、主要 task 属性 +- 含めない: `Baseline`, `TimephasedData`, `ExtendedAttributes`, task ごとの cost 詳細 +- `CalendarUID` は保持対象に含めるが、calendar 実体は別表へ分けず参照値扱いに留める + +`resources.csv` の最小仕様草案: + +- 目的は resource 単体属性を task 行から切り離し、同名 resource を安全に区別できるようにすること +- 正本の識別子は `ResourceID` とし、`Name` は表示用の主要属性として扱う +- `ResourceID / Name` を必須列とする +- `ResourceID` は CSV 内で一意でなければならない +- `Name` は空不可とする +- `Name` の重複は直ちに import error とはしないが、運用上は非推奨とする +- `CalendarUID` は任意列とし、calendar 実体は別表へ分けず参照値扱いに留める +- `MaxUnits / CostPerUse` は数値列とする +- `StandardRate / OvertimeRate` は `MS Project XML` と同じ文字列表現を前提にする +- `Initials / Group` は任意の表示属性とする + +`resources.csv` の第1段 scope: + +- 含める: 識別子、表示名、group/initials、calendar 参照、基本 rate/cost 属性 +- 含めない: `Baseline`, `TimephasedData`, `ExtendedAttributes`, resource ごとの cost 実績詳細 +- `assignments.csv` が別にある前提で、task との紐付けは `resources.csv` に持たせない + +`assignments.csv` の最小仕様草案: + +- 目的は task と resource の関係を独立表現し、1 task に複数 resource が付くケースを正規化して扱うこと +- 正本の識別子は `AssignmentID` とし、参照の正本は `TaskID / ResourceID` とする +- `AssignmentID / TaskID / ResourceID` を必須列とする +- `AssignmentID` は CSV 内で一意でなければならない +- `TaskID` は `tasks.csv` の既存 `ID` を指さなければならない +- `ResourceID` は `resources.csv` の既存 `ResourceID` を指さなければならない +- `TaskID / ResourceID` の組が重複する assignment を許すかは未確定だが、第1段では重複非推奨とする +- `Start / Finish` は任意列とし、assignment 固有の期間がある場合のみ保持する +- `Units / PercentWorkComplete` は数値列とする +- `Work` は `PT...` 形式の duration 文字列を前提にする + +`assignments.csv` の第1段 scope: + +- 含める: task-resource 参照、多重割当、assignment 単体の期間と work/units/進捗 +- 含めない: `Baseline`, `TimephasedData`, `ExtendedAttributes`, assignment ごとの cost 詳細 +- 第1段では `Milestone / Delay / WorkContour / OvertimeWork` などは未保持でもよい + +現時点の判断メモ: + +- 当面は `single CSV` を主系統として維持する +- 理由は、いまの利用目的が「軽量な交換・編集」であり、1 枚の表で task 階層を扱える利点がまだ大きいからである +- `tasks.csv / resources.csv / assignments.csv` は有力な次段候補だが、現時点では仕様草案までに留める +- `single CSV` から複数 CSV へ切り替える判断条件は、少なくとも次のいずれかを満たしたときとする + - 同名 resource を安全に往復したい要求が具体化した + - 1 task に複数 resource を持つ assignment を lossless に扱いたい要求が増えた + - assignment 単体属性を `single CSV` の task 行へ押し込むのが不自然になった + - `ResourceID` 正本での連携が必要になった +- 逆に、task 中心の軽量編集が主目的である間は `single CSV` の方が実用的とみなす + +現時点の実装メモ: + +- `ProjectModel -> CSV + ParentID` の出力を持つ +- 現在の出力列は `ID / ParentID / WBS / Name / Start / Finish / PredecessorID / Resource / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / Type / Priority / Work / CalendarUID / ConstraintType / ConstraintDate / Deadline / Notes` +- `PredecessorID` は複数値を `|` 区切りで補助出力する +- `Resource` は assignment から task 単位で集約した resource 名を補助出力する +- `CSV + ParentID -> ProjectModel` の最小逆変換を持つ +- 最小逆変換では `ID / ParentID / Name` を必須とし、`WBS / Start / Finish / PredecessorID / Resource / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / Type / Priority / Work / CalendarUID / ConstraintType / ConstraintDate / Deadline / Notes` を可能な範囲で復元する +- 最小逆変換では `PredecessorID / Resource` の複数値区切りとして `|` に加えて `,` `;` `、` を受け付け、trim と重複除去を行う +- 最小逆変換では `ID` 重複、空 `Name`、自己参照 `ParentID`、欠落 `ParentID`、循環 `ParentID` を import error として扱う +- UI には `CSV` のダウンロード導線と、CSV ファイル読込導線を追加済み +- 現時点では `Project` 詳細、`Calendars`、`Baseline`、`TimephasedData`、assignment 詳細は CSV から完全復元しない + +## 次に決めること + +STEP 1 の次の検討項目: + +1. サンプル XML の置き場所 +2. 内部モデル型の確定 +3. XML パーサ / シリアライザの実装方針 +4. STEP 1 で実際に保持する必須フィールドの最終確定 +5. ラウンドトリップ比較用の正規化ルール diff --git a/index-src.html b/index-src.html new file mode 100644 index 0000000..3159da6 --- /dev/null +++ b/index-src.html @@ -0,0 +1,358 @@ + + + + + + + + + mikuproject + + + +
+
Local Browser Tool
+

mikuproject

+
Updated: {{BUILD_DATE}}
+ +
+

What is this?

+

+ mikuproject は、MS Project XML を基軸に、変換・可視化・限定編集を行う single-file web app です。 +

+ +
+ +
+ +
+

Features

+
+
+
    +
  • MS Project XML を読み込み、内部モデルへ変換します。
  • +
  • 内部モデルを JSON とサマリとして確認できます。
  • +
  • MS Project XML を再生成できます。
  • +
  • Mermaid gantt テキストと、native SVG の preview / SVG を出力できます。
  • +
+
+
+
    +
  • Project / Tasks / Resources / Assignments / Calendars workbook を XLSX Export / Import できます。
  • +
  • 人が読むための WBS Excel ブック (.xlsx) を出力できます。
  • +
  • CSV + ParentID の生成と解析を行えます。
  • +
  • 生成AI向け JSON projection の出力と草案 JSON の取込ができます。
  • +
+
+
+
+ +
+ +
+

Use Cases

+ +
+ +
+ +
+

How to use

+
    +
  1. Web ブラウザで mikuproject.html を開きます。
  2. +
  3. Load from file から project ファイルを読み込むか、サンプルを使います。
  4. +
  5. 内部モデル、validation、native SVG preview を確認します。
  6. +
  7. 必要に応じて MS Project XMLXLSXWBS Excel ブック (.xlsx)、Mermaid、CSV を保存します。
  8. +
+ +
+ +
+ +
+

Screenshots

+ +
+
+ + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..905df39 --- /dev/null +++ b/index.html @@ -0,0 +1,358 @@ + + + + + + + + + mikuproject + + + +
+
Local Browser Tool
+

mikuproject

+
Updated: 2026-03-30
+ +
+

What is this?

+

+ mikuproject は、MS Project XML を基軸に、変換・可視化・限定編集を行う single-file web app です。 +

+ +
+ +
+ +
+

Features

+
+
+
    +
  • MS Project XML を読み込み、内部モデルへ変換します。
  • +
  • 内部モデルを JSON とサマリとして確認できます。
  • +
  • MS Project XML を再生成できます。
  • +
  • Mermaid gantt テキストと、native SVG の preview / SVG を出力できます。
  • +
+
+
+
    +
  • Project / Tasks / Resources / Assignments / Calendars workbook を XLSX Export / Import できます。
  • +
  • 人が読むための WBS Excel ブック (.xlsx) を出力できます。
  • +
  • CSV + ParentID の生成と解析を行えます。
  • +
  • 生成AI向け JSON projection の出力と草案 JSON の取込ができます。
  • +
+
+
+
+ +
+ +
+

Use Cases

+ +
+ +
+ +
+

How to use

+
    +
  1. Web ブラウザで mikuproject.html を開きます。
  2. +
  3. Load from file から project ファイルを読み込むか、サンプルを使います。
  4. +
  5. 内部モデル、validation、native SVG preview を確認します。
  6. +
  7. 必要に応じて MS Project XMLXLSXWBS Excel ブック (.xlsx)、Mermaid、CSV を保存します。
  8. +
+ +
+ +
+ +
+

Screenshots

+ +
+
+ + + + diff --git a/lht-cmn/FEEDBACK.md b/lht-cmn/FEEDBACK.md new file mode 100644 index 0000000..deb3c6c --- /dev/null +++ b/lht-cmn/FEEDBACK.md @@ -0,0 +1,54 @@ +# lht-cmn Feedback + +## 2026-03-08 `lht-command-block` style contract gap + +- 症状: + - `lht-command-block` をページ側で利用しても、`lht-cmn/css/components.css` だけでは「角丸四角の結果表示ブロック」として視覚的に完成しない + - 実際には `md-code-block` / `md-code` / `md-copy-button` / `md-icon-button.md-copy-button` 相当の見た目をページ側 CSS が別途持っている前提になっている +- 問題: + - `lht-command-block` を共通部品として使っても、利用ページごとに結果表示の見た目が欠けうる + - `lht-cmn` の self-contained 方針とずれている +- 期待: + - `lht-command-block` は `lht-cmn/css/components.css` だけで最低限の完成した見た目になるべき + - 少なくとも以下の visual contract は `lht-cmn` 側に同梱する + - `.md-code-block` + - `.md-code` + - `.md-copy-button` + - `md-icon-button.md-copy-button` + - `md-icon-button.md-copy-button--surface` +- 補足: + - 今回 `docs/prompt/prompt-gen-src.html` では、既存画面に合わせるためページ側へ上記スタイルを追加して回避した + - 根本対応は `lht-cmn` 側で行うべき + +## 2026-03-08 `lht-switch-help` material bundle gap + +- 症状: + - `lht-switch-help` を利用しても、ページ側で `md-switch` が未登録のため fallback 実装に落ちる + - `prompt-gen` では text field は Material 表示なのに switch だけ fallback 表示になる +- 問題: + - `lht-*` を使っても、入力部品ごとに Material / fallback が混在しやすい + - ページ側から見ると `lht-switch-help` の見た目が他の Material 部品と揃わず、利用側で原因が見えにくい +- 期待: + - `lht-switch-help` も `lht-cmn` 側で Material 実装を self-contained に利用できる形に寄せたい + - 少なくとも `md-switch` 用 bundle の vendor / 読み込み導線を `lht-cmn` 側で用意したい + - それが難しい場合でも、README に「switch は fallback 前提になりうる」ことを明記したい +- 補足: + - 現状の `lht-switch-help` は `window.customElements.get("md-switch")` が false のとき fallback DOM を生成する実装になっている + - `lht-cmn/vendor` には `material-web-outlined-text-field.bundle.js` はあるが、`md-switch` 相当の bundle は見当たらない + +## 2026-03-09 `lht-text-field-help` trailing action gap + +- 症状: + - `prompt-gen` で「やりたいこと」入力欄に `×` クリアボタンを付けたかったが、`lht-text-field-help` 自体には trailing action / trailing icon を安全に差し込む契約がない + - 外付け absolute 配置では、Material 側の見た目中心と合いにくく、位置合わせが不安定だった +- 問題: + - 画面ごとに似た「入力クリア」「末尾アイコン」「補助アクション」実装が再発しやすい + - `lht-text-field-help` を使っていても、入力欄内アクションはページ側の局所 CSS に依存しやすい + - fallback 実装と Material 実装で、末尾アクションの見た目や余白が揃いにくい +- 期待: + - `lht-text-field-help` に trailing action slot、または `clearable` のような共通機能を検討したい + - もし汎用化しない場合でも、「入力欄右端に後付けアクションを重ねる時の推奨パターン」を README に明記したい +- 補足: + - 今回は暫定対応として `lht-text-field-help` に `clearable` 属性をローカル追加し、`prompt-gen` ではそれを利用する形へ寄せた + - ただしこれは prompt-gen 都合で先に入れた provisional API なので、`lht-cmn` チーム側では trailing action 全般を扱える正式な契約として見直したい + - 正式方針が固まったら、今回の `clearable` 実装や CSS 調整はレビューのうえ置き換えたい diff --git a/lht-cmn/LICENSE b/lht-cmn/LICENSE new file mode 100644 index 0000000..4bb44d2 --- /dev/null +++ b/lht-cmn/LICENSE @@ -0,0 +1,197 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with the Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/lht-cmn/NOTICE b/lht-cmn/NOTICE new file mode 100644 index 0000000..d1b7fb9 --- /dev/null +++ b/lht-cmn/NOTICE @@ -0,0 +1,11 @@ +Copyright 2026 Toshiki Iga + +This product includes software developed by Toshiki Iga. + +Design direction: +- 本プロジェクトは Material Design 3 の設計原則を参照しています。 + +Third-party component implementation: +- `lht-cmn` の内部実装では、必要に応じて Material Web(`@material/web`)を優先利用します。 +- Material Web のライセンスは Apache License, Version 2.0 です。 +- Source: https://github.com/material-components/material-web diff --git a/lht-cmn/README.md b/lht-cmn/README.md new file mode 100644 index 0000000..e7dad3c --- /dev/null +++ b/lht-cmn/README.md @@ -0,0 +1,408 @@ +# lht-cmn + +`lht-cmn` は `local-html-tools` 全体で共有する UI コンポーネント基盤です。 + +- Version: `v20260308` +- License: Apache License 2.0 (`lht-cmn/LICENSE`) +- Copyright: Toshiki Iga + +## ライセンスと帰属 + +- `lht-cmn` 自体は Apache License 2.0 で配布します。 +- デザイン方針は Material Design 3 の設計原則を参照します。 +- 実装技術として、`lht-cmn` は必要に応じて Material Web(`@material/web`)を優先利用します。 +- Material Web のライセンスは Apache License 2.0 です。 +- 帰属情報の詳細は `lht-cmn/NOTICE` に記載します。 + +## 目的 + +`local-html-tools` では、入力・選択・ヘルプ・コピー・メニューなどの UI を複数ページで繰り返し実装してきました。 +`lht-cmn` はこの重複を減らし、UI を `lht-*` Web Components として共通化するためのレイヤーです。 + +## 基本方針 + +- デザイン基準は Material Design 3 +- 画面側の公開 UI レイヤーは常に `lht-*` とし、`md-*` を直接使わせない +- `lht-*` は self-contained を原則とし、アプリ側へ `md-*` の登録責務を漏らさない +- 実現手段として Material Web を優先利用してよい +- ただし Material 利用の有無に関わらず、`lht-*` は最低保証で壊れないことを優先する +- 内部実装として許可する型は次の 2 つに限定する: + - `md-*` 優先 + fallback + - 完全自前実装 +- 「Material 依存で fallback なし」は原則避け、採る場合は README に明示する +- fallback は Material の完全再現ではなく、公開 API の最低保証に留める + +## メリット + +- 画面ごとの重複実装を削減できる +- 見た目と挙動(必須表示、ヘルプ表示、フォーカス時の挙動)を統一できる +- 変更点を `lht-cmn` に集約でき、保守・レビューがしやすくなる +- 単一HTML生成前提でも、開発時の部品再利用性を維持できる +- 変更点が局所化され、生成AIが誤って別画面を壊す確率が下がる +- UI規約が `lht-*` に集約され、提案が毎回同じ型で出せる +- レビュー時に「画面の見た目差分」より「共通部品の差分」を見ればよくなり、判断が速くなる + +## 運用方針(重要) + +- 画面側(`docs/*-src.html`)は `lht-*` を利用し、`md-*` 直接実装の追加は原則避ける +- `lht-cmn/js/components.js` を共通コンポーネントの正本とする +- `lht-cmn/css/components.css` を実運用スタイルの正本とする +- `lht-cmn/` 配下(特に `js/components.js` / `css/components.css`)の変更は、必ずユーザーの明示許可を得てから実施する +- `md3/` は段階的にリファレンス用途へ縮退し、実運用スタイルは `lht-cmn` に集約する + +## 構成 + +- `lht-cmn/js/components.js` + - 共通 Web Components 定義 +- `lht-cmn/css/components.css` + - 上記コンポーネントの共通スタイル +- `lht-cmn/catalog/index.html` + - 実表示と HTML 利用例を並べて確認するコンポーネントカタログ + +### コンポーネント一覧 + +| コンポーネント | できること | 内部構造(概要) | +|---|---|---| +| `lht-help-tooltip` | `(i)` ヘルプアイコンとツールチップを1タグで配置できる | `md-icon-button` が使える環境ではそれを利用し、未定義時はネイティブ `button` fallback を生成。タグ内HTMLをツールチップ本文へ差し込む | +| `lht-text-field-help` | ラベル付き入力(単一行/複数行)とフォーカス時ヘルプ表示を共通化できる | `md-outlined-text-field` が使える環境ではそれを利用し、未定義時はネイティブ `input` / `textarea` fallback を生成。属性(`field-id`/`label`/`type`/`rows` など)を透過する | +| `lht-select-help` | ラベル付きドロップダウンとヘルプ表示を共通化できる | 内部で `md-outlined-select` を生成し、`` を使用する +3. `lht-select-help` で `