mikuproject は、MS Project XML 形式の入出力を扱うプロジェクト管理アプリとして設計する。
この文書は mikuproject の仕様メモであり、README の代わりではない。利用方法やビルド手順は README.md に置き、未完了タスクは docs/TODO.md に置く。
利用者向けの import / export / 生成AI連携の導線整理は docs/import-export-workflows.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 内完結の大規模操作は優先度を上げすぎない
- 既存WBSの局所修正フローは、UI より
CLI/Agent Skillsを主導線として強化する
STEP 1 の目的は、MS Project XML を意味的に往復できる状態を作ること。
ここでいう「往復できる」とは、次を意味する。
MS Project XMLを読める- 必要な情報を内部モデルへ落とせる
- 内部モデルから
MS Project XMLを再生成できる - 再生成した XML を、少なくとも
mikuproject自身で再読込できる - 主要フィールドが壊れず往復できる
注意:
- 目標は「元の XML と完全一致」ではない
- 目標は「意味的に往復できる」ことである
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 XMLMS Project XML -> ProjectModel -> workbook JSONworkbook 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として、XLSXworkbook の論理構造を JSON へ写して扱うformat = "mikuproject_workbook_json"、version = 1を持つProject / Tasks / Resources / Assignments / Calendars / NonWorkingDaysをsheets配下に持つ- import 時の反映対象列・キー・部分更新ルールは
XLSX Importと同じにする
- 表示専用の
WBSworkbook exportTasks中心の別 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 MarkdownexportWBS 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カレンダー SVGexportWBS XLSXやWBS Markdownと同列の、表示専用の派生出力として扱う- 入力は
ProjectModelとし、正本や限定 import/export の経路とは切り分ける - 出力は単月ではなく、project 期間に含まれるすべての年月を対象にした月別
SVG群とする - 配布単位は全月分をまとめた
ZIPとし、各SVGは 1 か月単位の月間カレンダーとする - 月グリッドは当面
日曜日始まりで固定する - 各日付セルには、その日に関係する
taskやmilestoneを表示する - 通常
taskはStartからFinish当日までを表示範囲とし、日付範囲の解釈は現行のDaily SVG出力と同様に扱う - 通常
taskは平日の各日に表示するが、土日祝日の中間日には表示しない - ただし、
土日祝日であっても、その日がStartまたはFinishに一致する場合は表示する milestoneは単日要素として、その該当日のみに表示するsummary taskは期間中の各日には表示せず、開始日と終了日の日のみに表示する- 日セル内の表示文字列には
WBS番号を含めない - 長い
task名は、セル幅に応じて途中で切って表示してよい - 1 日セル内の表示件数には上限を設け、当面は
3または4件程度を上限目安とし、超過分は省略表示する
- 表示専用の
WBS記述書 MarkdownexportWBSの階層表現そのものとは別物として扱う- 目的は、各 task の意味・成果物・完了条件などを文章で確認しやすくすること
- 当面は export 専用であり、import は扱わない
- 最小設計では、保持元を
Task.ExtendedAttribute主体とし、長文補足のみTask.Notesを使う - 最小設計で扱う項目は、少なくとも次の 5 つとする
TaskPurposeTaskDeliverableTaskOutOfScopeTaskDoneDefinitionTaskOwner
- 上記 5 項目は
Task.ExtendedAttributeのFieldNameで識別する前提とする - 補足本文や自由記述は
Task.Notesを使う - Markdown 出力では、task ごとに 1 節を持つ構成を基本とする
- 各節では、少なくとも
WBS / 名称 / 目的 / 成果物 / スコープ外 / 完了条件 / 担当 / 補足を必要に応じて出す - 未設定の項目は空欄のまま出さず、省略する
WBS記述書 Markdownは、WBS Markdownの代替ではなく、task 説明を補う別出力として扱う- 当面は新規入力 UI を先に増やさず、既存の
ExtendedAttribute/Notesからの export を優先する
WBS Reportには、少なくともXLSX/Markdown/Daily SVG/Weekly SVG/Monthly Calendar SVG/Mermaidを置くDaily SVGは日単位の WBS 俯瞰用 SVG とするWeekly SVGは週単位の WBS 俯瞰用 SVG とするMonthly Calendar SVGは月別カレンダー SVG 群をまとめたZIPとするOverviewの preview は、Daily/Weekly/Monthly Calendarを切り替えられるようにする
ファイル名は当面次を基本とする。
Daily SVG:mikuproject-wbs-daily-<YYYYMMDDHHmm>.svgWeekly SVG:mikuproject-wbs-weekly-<YYYYMMDDHHmm>.svgMonthly Calendar SVG:mikuproject-monthly-wbs-calendar-<YYYYMMDDHHmm>.zipMermaid:mikuproject-wbs-mermaid-<YYYYMMDDHHmm>.mmd
Daily SVG のラベル配置は次の方針とする。
- 基本は task / phase の近接ラベルとする
- 右側へ自然に置ける場合は右側へ表示する
- 左側へ自然に置ける場合は左側へ表示する
- 左側配置は canvas 外へ無制限に広げず、左端で抑える
- 左右どちらにも逃がしにくい場合や、表示範囲いっぱいに近い帯・線については、帯や線の上へラベルを重ねてよい
- 線上ラベルを使う場合は、可読性のために薄い背景を敷いてよい
Weekly SVG のラベル配置も同様に、基本は近接ラベルとしつつ、左側へ無制限に広がらないように扱う。
Outputには、主要成果物をまとめて取得するALLボタンを置くALLは、その時点の内部モデルから再生成した主要出力をまとめたZIPとするALLの保存名はmikuproject-all-<YYYYMMDDHHmm>.zipとするALLZIP の並び順は、概ねREADME.txt -> XML -> workbook -> CSV -> WBS Report -> monthly-calendar -> .editjsonの順に固定してよい
ALL ZIP には、少なくとも次を含める。
README.txtMS Project XML- workbook
XLSX - workbook
JSON CSV + ParentIDWBS XLSXWBS MarkdownDaily SVGWeekly SVGMermaidproject_overview_viewfull bundlephase_detail_view full
Monthly Calendar SVG の扱いは次のとおり。
- 単独出力では、月別
SVG群をまとめたZIPとして配布してよい - 単独出力の
ZIPでも、monthly-calendar/ディレクトリ配下へ月別SVGを格納する - 単独出力の
monthly-calendar/配下のファイル名もYYYY-MM.svgのような短い名前でよい - ただし
ALLZIP の中では、さらに入れ子のZIPにせず、monthly-calendar/ディレクトリ配下へ月別SVGを展開して含める monthly-calendar/配下のファイル名はYYYY-MM.svgのような短い名前でよい
mikuproject は、構造忠実 workbook のテキスト版として mikuproject_workbook_json を持てるようにする。
これは生成AI向け projection JSON とは別物であり、XLSX の写し身として扱う。
- 目的は、構造忠実 workbook をテキストで扱いやすくすること
XLSXと意味を揃えた補助入出力として扱う- 新しい編集モデルや新しい意味体系は持ち込まない
- styling、列幅、merge、塗り色などの表示情報は持たない
CLI を追加する場合も、画面機能をそのまま並べるのではなく、責務ごとに整理する。
ai: AI との契約や spec の取得state:project_draft_viewや Patch JSON を受けた state 生成・更新export:workbook-json/xml/xlsxのような主要交換形式の出力report:wbs-xlsx/wbs-markdown/mermaid/daily-svg/weekly-svg/monthly-calendar-svgのような派生出力
first cut の最小候補は次とする。
mikuproject ai specmikuproject ai export project-overviewmikuproject ai export task-editmikuproject ai export phase-detailmikuproject ai export bundlemikuproject ai detect-kindmikuproject ai validate-patchmikuproject state from-draftmikuproject state summarizemikuproject state diffmikuproject state apply-patchmikuproject export workbook-jsonmikuproject export xmlmikuproject export xlsx
この段階では、report 系は export と混ぜず、別系統の次段候補として扱う。
mikuproject_workbook_json の最小外形は次のとおり。
{
"format": "mikuproject_workbook_json",
"version": 1,
"sheets": {
"Project": [],
"Tasks": [],
"Resources": [],
"Assignments": [],
"Calendars": [],
"NonWorkingDays": []
}
}sheet 名は、構造忠実 workbook の XLSX と同じく次で固定する。
ProjectTasksResourcesAssignmentsCalendarsNonWorkingDays
各 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 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 / ScheduleFromStartTasks:Name / Start / Finish / Duration / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / CalendarUID / Predecessors / NotesResources:Name / Group / MaxUnits / CalendarUIDAssignments:Units / Work / PercentWorkCompleteCalendars:Name / IsBaseCalendar / BaseCalendarUIDNonWorkingDays: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 / Duration / PercentComplete / PercentWorkComplete / Milestone / Summary / Critical / CalendarUID / Predecessors / Notes |
UID をキーに部分更新する |
Resources |
Name / Group / MaxUnits / CalendarUID |
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 |
import 可 |
PercentComplete |
import 可 |
PercentWorkComplete |
import 可 |
Milestone |
import 可 |
Summary |
import 可 |
Critical |
import 可 |
CalendarUID |
import 可 |
Predecessors |
import 可 |
Notes |
import 可 |
Predecessors の workbook import は、現時点では predecessorUid の , 区切り一覧を読む最小対応とする。type / linkLag などの詳細な依存表現は将来拡張とする。
Resources と Assignments が 0 件の workbook では、どの列が import 対象か分かるように、editable 列だけ着色されたダミー行を 1 行出してよい。これは表示補助であり、UID 等のキーが空なので import 時には無視される。
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 用の業務ステータスは、PercentComplete の派生値としてではなく、Task.ExtendedAttribute に保持する前提で扱う。
CompleteとCancelledを区別できるようにするPercentComplete=100とは別軸の状態として保持するMS Project XMLの round-trip で保持しやすい形を優先する
MS Project 互換の観点では、Active=false は「スケジュール対象外」として使いうるが、WBS 上での業務ステータス表示とは役割が異なる。そのため、mikuproject では Cancelled などの業務値を ExtendedAttribute に置く方針を採る。
具体的な FieldID / FieldName / 値候補 は今後の設計項目とする。
XLSX Import 後の validation では、Calendars.BaseCalendarUID が既存 Calendar を指していない場合や、自身を指している場合の warning も、差分要約と並べて確認できるようにする。
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 は、概ね次の 3 画面構成で整理している。
InputLoad from fileからMS Project XML、XLSX、workbook JSON (.json)、生成AI向け編集用 JSON (.editjson)、CSV + ParentIDを読込- サンプル XML の読込
- 生成AIが返した
project_draft_viewの貼り付け取込
Overview- 内部モデルの要約確認
- validation の確認
Daily / Weekly / Monthly Calendarpreview の確認- preview 表示
OutputMS Project XML、XLSX、WBS XLSX、workbook JSON、CSV + ParentIDの保存- Mermaid fenced code block を含む
.mdとDaily / Weekly / Monthly Calendar SVGの保存 - 生成AI向け
project_overview_view/phase_detail_view/task_edit_view/full bundleの.editjson出力
生成AI連携の現状実装範囲:
- 既存 project 向けには
project_overview_view/phase_detail_view/task_edit_view/full bundleの export を持つ - CLI では
mikuproject ai export project-overview|task-edit|phase-detailから projection を出力できる - CLI では
mikuproject ai export bundleからai_projection_bundleを出力できる mikuproject ai export bundleはai export配下に残し、主用途は調査 / デバッグ / 比較検証とするmikuproject ai export task-editはmikuproject_workbook_jsonを入力とし、--task-uid省略時は UI と同様の既定選択でtask_edit_viewを出力するmikuproject ai export task-editは--select auto|first-task|uidを受けるmikuproject ai export phase-detailはmikuproject_workbook_jsonを入力とし、--phase-uid/--select auto|first-phase|uid/--mode/--root-task-uid/--max-depthを受ける--selectは現時点ではtask-edit/phase-detail専用とし、project-overviewには持たせないbundle/detect-kind/validate-patch/state summarize/state diffは現時点で--selectを持たない- CLI では
mikuproject ai validate-patchにより dry-run apply ベースの patch 検査ができる - CLI では
mikuproject ai detect-kind/mikuproject state summarize/mikuproject state diffを使える - CLI では
--in -/--out -により標準入力 / 標準出力を明示指定できる - 同一コマンドで標準入力を読める入力オプションは 1 つだけとする
--in pathがあればそのファイルを優先し、--in -は明示 stdin、--in省略時だけ暗黙 stdin を使う--out pathがあればそのファイルへ書き、--out -または--out省略時は stdout を使う- CLI では
ai export/detect-kind/validate-patch/state summarize/state diff/state apply-patch/export/reportが--diagnostics text|jsonを受け、stderr に構造化メタ情報を出せる jsondiagnostics は少なくともdiagnostics_version/ok/command/context/status/exit_code/warning_count/error_count/io/warnings/errorsを共通キーとする- 異常系 diagnostics では
error_type=usage_error|processing_errorを持てる - 異常系 diagnostics では
error_codeに安定識別子を持てる - 異常系 diagnostics では top-level に
error_detailsを持てる - 異常系 diagnostics の
errors[]要素にもcodeを持てる - 異常系 diagnostics の
errors[]要素にはdetailsを持てる jsondiagnostics はstatus=success|warning|noop|errorを共通で持つ--diagnostics json指定時は、usage error や処理失敗でも stderr に同系統の JSON diagnostics を返す- warning-only は
status=warningかつexit_code=0、no-op はstatus=noopかつexit_code=0、usage error はexit_code=2、processing error はexit_code=1とする - repo には
scripts/cli-ai-workflow-example.mjsとscripts/cli-ai-stdio-example.mjsを置き、file-based と stdio-based の両方で最小 CLI 連携例を示す full bundleには少なくともproject_overview_view/phase_detail_views_full/task_edit_views_fullを含めてよい- 新規生成向けには
project_draft_viewの import を持つ - 既存 project 向けには Patch JSON の
update_project/update_task/update_resource/update_assignment/update_calendar/link_tasks/unlink_tasksfirst cut import / 適用を持つ phase_detail_viewはfullとscopedを持ち、CLI での first cut はscopedを優先するtask_edit_viewは既存 task をuidで特定して出力する個別編集用 projection とするtask_edit_viewは少なくともproject/phase/target_task/parent_task/sibling_tasks/predecessors/successors/assignments/rulesを含むtask_edit_viewのtarget_taskではname/parent_uid/position/is_summary/is_milestone/planned_duration/planned_duration_hours/planned_start/planned_finish/percent_complete/notes/calendar_uid/criticalを見せるtask_edit_view.rules.allow_patch_opsには、少なくともupdate_task/move_task/link_tasks/unlink_tasks/add_task/delete_task/update_assignment/add_assignment/delete_assignmentを含めてよい- Patch JSON のうち
add_task/add_resource/add_assignment/add_calendar/move_task/delete_task/delete_resource/delete_assignment/delete_calendarは first cut を実装済みとする
Patch JSON の次段 MVP 方針:
- 既存 project 向けの AI 返却形式として
Patch JSONを将来追加する - first cut は
operations配列を持つ部分適用 JSON とする - first cut では、少なくとも
update_taskの import / 適用から着手し、依存関係の最小操作としてlink_tasks/unlink_tasksも段階的に含める - first cut では、対象 task は
uidで特定する - first cut では、task の基本計画項目
namenotescalendar_uidpercent_completepercent_work_completecriticalplanned_startplanned_finishplanned_durationplanned_duration_hoursis_milestoneを優先して扱う
- first cut では、project の基本項目
nametitleauthorcompanystart_datefinish_datecurrent_datestatus_datecalendar_uidminutes_per_dayminutes_per_weekdays_per_monthschedule_from_startをupdate_projectで扱う
update_projectはuidを持たず、project 全体に対する単一 op としてfieldsを受けるupdate_project.nameは空でない文字列として扱うupdate_project.title/author/companyは文字列として扱い、空文字を指定した場合はクリアしてよいupdate_project.start_date/finish_date/current_date/status_dateは date-only または date-time を受け、date-only の場合は project 既定勤務時間帯を補完して扱うupdate_project.start_date > finish_dateになる変更は warning として無視するupdate_project.calendar_uidが既存 calendar を指していない場合は warning として無視するupdate_project.minutes_per_day/minutes_per_week/days_per_monthは0より大きい数値として扱うupdate_project.schedule_from_startは boolean として扱う- first cut では、assignment の基本項目
startfinishunitsworkpercent_work_completeをupdate_assignmentで扱う
- first cut では、resource の基本項目
nameinitialsgroupcalendar_uidmax_unitsstandard_rateovertime_ratecost_per_usepercent_work_completeをupdate_resourceで扱う
- first cut では、calendar の基本項目
nameis_base_calendarbase_calendar_uidをupdate_calendarで扱う
- first cut では、assignment の新規追加として
add_assignmentを扱う - first cut では、task の基本計画項目は
update_taskに寄せ、依存関係はlink_tasks/unlink_tasksに分離する update_task.is_milestoneは既存 task の milestone 化 / 解除を扱ってよいupdate_task.notesは task のNotesを更新してよく、空文字を指定した場合はNotesをクリアしてよいupdate_task.calendar_uidは task のCalendarUIDを更新してよく、空文字を指定した場合は個別 calendar 指定をクリアしてよいupdate_task.calendar_uidが既存 calendar を指していない場合は warning として無視するupdate_task.percent_complete/percent_work_completeは0..100の数値として扱うupdate_task.criticalは boolean として扱うupdate_taskでは summary task を milestone 化してはならないupdate_task.is_milestone=trueの場合はplanned_finish = planned_start、planned_duration = 0に正規化するupdate_resourceは既存 resource をuidで特定して部分更新するupdate_resource.nameは空でない文字列として扱うupdate_resource.initials/group/calendar_uidは文字列として扱い、空文字を指定した場合はクリアしてよいupdate_resource.calendar_uidが既存 calendar を指していない場合は warning として無視するupdate_resource.max_unitsは0以上の数値として扱うupdate_resource.standard_rate/overtime_rateは文字列として扱い、空文字を指定した場合はクリアしてよいupdate_resource.cost_per_useは0以上の数値として扱うupdate_resource.percent_work_completeは0..100の数値として扱うupdate_calendarは既存 calendar をuidで特定して部分更新するupdate_calendar.nameは空でない文字列として扱うupdate_calendar.is_base_calendarは boolean として扱うupdate_calendar.base_calendar_uidは文字列として扱い、空文字を指定した場合はクリアしてよいupdate_calendar.base_calendar_uidは既存 calendar を指す必要があり、自身を指してはならないadd_calendarの first cut はuid/nameを必須とするadd_calendarではis_base_calendar/base_calendar_uidを任意で受けてよいadd_calendar.base_calendar_uidは既存 calendar を指す必要があり、自身を指してはならないdelete_calendarの first cut はuidを受け、project / task / resource / 他 calendar のbase_calendar_uidから参照されていない calendar の単純削除だけを扱うdelete_calendarが成功した場合、差分表示では対象 calendar のNameを(deleted)として示すadd_resourceの first cut はuid/nameを必須とするadd_resourceではinitials/group/calendar_uid/max_units/standard_rate/overtime_rate/cost_per_use/percent_work_completeを任意で受けてよいadd_resource.calendar_uidは既存 calendar を指す必要があるadd_resource.max_unitsは0以上の数値として扱うadd_resource.standard_rate/overtime_rateは文字列として扱うadd_resource.cost_per_useは0以上の数値として扱うadd_resource.percent_work_completeは0..100の数値として扱うdelete_resourceの first cut はuidを受け、assignment が付いていない resource の単純削除だけを扱うdelete_resourcefirst cut では assignment が残っている resource は削除できないdelete_resourceが成功した場合、差分表示では対象 resource のNameを(deleted)として示すupdate_assignmentは既存 assignment をuidで特定して部分更新するupdate_assignment.start/finishは date-only または date-time を受け、date-only の場合は project 既定勤務時間帯を補完して扱うupdate_assignment.start > finishになる変更は warning として無視するupdate_assignment.unitsは0以上の数値として扱うupdate_assignment.workは空でない文字列として扱うupdate_assignment.percent_work_completeは0..100の数値として扱うadd_assignmentの first cut はuid/task_uid/resource_uidを必須とするadd_assignment.task_uidは既存 task、resource_uidは既存 resource を指す必要があるadd_assignmentではstart/finish/units/work/percent_work_completeを任意で受けてよいadd_assignment.start/finishは date-only または date-time を受け、date-only の場合は project 既定勤務時間帯を補完して扱うadd_assignment.start > finish、units < 0、空work、percent_work_completeの範囲外は warning として無視するdelete_assignmentの first cut はuidを受け、1 件の assignment を単純削除するdelete_assignmentが成功した場合、差分表示では対象 assignment のTaskUID / ResourceUIDを(deleted)として示すadd_taskの first cut は、単一 task の追加に絞ってuid/name/new_parent_uid/new_indexを受けるadd_task.new_indexは0-basedとし、sibling 範囲外は warning として無視するadd_task.new_parent_uidは root 追加ではnullを許容し、非 root の場合は summary task を指す必要があるadd_taskでは通常 task / milestone / summary task を明示的に追加できる- summary task の追加は「空 summary を 1 件追加する」形で扱い、subtree は同時投入しない
- summary task の子は、後続の
add_task/move_taskで段階的に入れる前提とする - したがって summary task 追加の JSON は、first cut では
uid/name/is_summary=true/new_parent_uid/new_indexを基本とし、子 task 一括定義は持たない add_taskではis_summary=trueとis_milestone=trueを同時に指定してはならないadd_taskではplanned_start/planned_finish/planned_duration/planned_duration_hoursを任意で受けてよいadd_task.planned_start/planned_finishの形式不正や、planned_start > planned_finishは warning として無視するadd_task.is_milestone=trueの場合はplanned_finish = planned_start、planned_duration = 0に正規化するadd_taskに未対応 key が含まれる場合は warning として無視するdelete_taskの first cut はuidを受け、葉 task の削除だけを扱うdelete_taskfirst cut では summary task や子 task を持つ task の削除は扱わないdelete_taskfirst cut では assignment が付いている task の削除は扱わないdelete_taskfirst cut では後続依存から参照されている task の削除は扱わないdelete_taskが拒否される場合、warning にはchildren/assignments/successorsなどの blocker 情報を含めて返すdelete_taskが成功した場合、差分表示では削除対象 task のName / ParentUID / Positionを(deleted)として示すdelete_taskは cascade delete を行わず、削除したい subtree がある場合も、まず葉 task から順に削除する前提とする- 削除前に依存関係や親子関係が blocker になる場合は、先に
unlink_tasksやmove_taskで整理してからdelete_taskを行う move_taskの first cut はuid/new_parent_uid/new_indexを受け、subtree 単位の移動として扱うmove_task.new_indexは0-basedとし、sibling 範囲外は warning として無視するmove_task.new_parent_uidは root への移動ではnullを許容し、非 root の場合は summary task を指す必要があるmove_taskでは task を自身または配下へ移動してはならないmove_taskで結果が変わらない no-op 移動は warning として無視するpredecessorsはupdate_task.fieldsには含めず、依存関係の変更はlink_tasks/unlink_tasksへ分離する方針とする- その理由は、依存関係が単なる field 更新ではなく task 間リンク更新であり、将来の
type / lag拡張や validation と相性がよいためである link_tasksの first draft はfrom_uid/to_uidを必須とし、typeは省略時FSを既定としてよいlink_tasks/unlink_tasksのlagは任意とし、指定する場合はlagまたはlag_hoursのどちらか一方だけを返す。両方を返した場合はlagを優先し、lag_hoursは warning 付きで無視するunlink_tasksの first draft もfrom_uid/to_uidを必須とし、必要ならtypeやlagまたはlag_hoursで解除対象を特定できる形とするunlink_tasksで複数の依存関係が同じ条件に一致した場合は、その条件に一致した link をすべて解除する方針とする- first draft では、依存関係の変更は predecessor 一覧の全置換ではなく、追加と解除を op 単位で返す方針とする
- 未知
op、存在しないuid、不正 field、不正日付は validation または import warning/error の対象とする project_draft_viewは新規草案作成を優先するため、非稼働日を厳密に考慮しなくてもよいproject_draft_viewでは、粗い草案でもよいので task に仮のplanned_start/planned_finishを入れてよい- この仮日付は通常 task だけでなく、summary task と milestone にも入れてよい
- summary task には配下 task を大まかに包む期間、milestone には節目の日付を仮で入れる方針を許容する
- 人間が「とりあえずえいやで日付を入れてよい」と指示している場合は、細かい整合よりも日付充足を優先してよい
calendar_uid = "1"は既定のStandardcalendar を指し、土曜日と日曜日を非稼働日として扱う前提とする- task / resource に個別
CalendarUIDがない場合は、project 既定 calendar を継承する前提で扱う - 稼働日・祝日を考慮した日付補正は、後続の Patch JSON による再計画で扱う
- Patch JSON の
planned_start/planned_finish更新は、原則として非稼働日を避ける前提とする - ただし、人間が明示的に非稼働日での実施を指示した場合は、その指示を優先できる
- 非稼働日ルールより人間指示を優先した場合は、AI 側の説明文でもその例外適用を明示する
ここでいう Overview は、内部実装上の transform 相当タブを、ユーザー向けに読み替えた呼称である。
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 では、MS Project XML のうち、次の情報を優先して扱う。
Project基本情報TasksResourcesAssignments- 必要最小限の
Calendars PredecessorLinkなどの依存関係
NameTitleAuthorCompanyCreationDateLastSavedSaveVersionCurrentDateStartDateFinishDateScheduleFromStartDefaultStartTimeDefaultFinishTimeMinutesPerDayMinutesPerWeekDaysPerMonthStatusDateWeekStartDayWorkFormatDurationFormatCurrencyCodeCurrencyDigitsCurrencySymbolCurrencySymbolPositionFYStartDateFiscalYearStartCriticalSlackLimitDefaultTaskTypeDefaultFixedCostAccrualDefaultStandardRateDefaultOvertimeRateDefaultTaskEVMethodNewTaskStartDateNewTasksAreManualNewTasksEffortDrivenNewTasksEstimatedActualsInSyncEditableActualCostsHonorConstraintsInsertedProjectsLikeSummaryMultipleCriticalPathsTaskUpdatesResourceUpdateManuallyScheduledTasksWhenEditingLinksCalendarUIDOutlineCodesWBSMasksExtendedAttributes
UIDIDNameOutlineLevelOutlineNumberWBSTypeCalendarUIDPriorityStartFinishDurationActualStartActualFinishDeadlineStartVarianceFinishVarianceWorkWorkVarianceTotalSlackFreeSlackCostActualCostRemainingCostRemainingWorkActualWorkMilestoneSummaryCriticalPercentCompletePercentWorkCompleteNotesConstraintTypeConstraintDateExtendedAttributeBaselineTimephasedDataTimephasedDataPredecessorLink
UIDIDNameTypeInitialsGroupWorkGroupMaxUnitsCalendarUIDStandardRateStandardRateFormatOvertimeRateOvertimeRateFormatCostPerUseWorkActualWorkRemainingWorkCostActualCostRemainingCostPercentWorkCompleteExtendedAttributeBaselineTimephasedData
UIDTaskUIDResourceUIDStartFinishStartVarianceFinishVarianceDelayMilestoneWorkContourUnitsWorkCostActualCostRemainingCostPercentWorkCompleteOvertimeWorkActualOvertimeWorkActualWorkRemainingWorkExtendedAttributeBaseline
UIDNameIsBaseCalendarBaseCalendarUIDWeekDaysExceptionsWorkWeeks
STEP 1 では、次のようなものは後回し候補とする。
-
.xlsx importにおける自由編集の全面対応 -
Calendars / Baseline / TimephasedData / ExtendedAttributesの.xlsx編集反映 -
表示設定
-
UI レイアウト情報
-
独自拡張要素
-
完全互換のために必要だが、主要データの意味保持に直結しない補助ノード群
内部モデルは、MS Project XML をそのまま保持するのではなく、意味的に扱いやすい正規化済みのモデルとする。
最小モデル案:
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): XMLDocumentimportMsProjectXml(xmlText): ProjectModelvalidateProjectModel(model): ValidationIssue[]exportMsProjectXml(model): stringnormalizeProjectModel(model): ProjectModel
テストの基本方針:
xml -> model -> xml -> modelのラウンドトリップを確認する- 比較対象は文字列一致ではなく、正規化後の内部モデル一致とする
実装判断の原則:
- 仕様や表現方法に迷った場合は、
MS Project XMLの持ち方を優先する - 独自に扱いやすいモデル化は許容するが、
MS Project XMLとの意味対応を壊さないことを優先する - 特にタスク階層や依存関係は、独自表現へ寄せすぎず、まず
MS Project側の表現を基準に考える - XML parser / serializer 実装は差し替え可能にし、モジュール側は
globalThis.__mikuprojectXmlDom経由で XML DOM を解決する
STEP 1 では、少なくとも次を確認する。
- サンプル XML を読み込める
- 内部モデルへ変換できる
- 最小妥当性チェック結果を確認できる
- 再生成 XML を出力できる
- 再生成 XML を再読込できる
- 主要フィールドが保持される
比較観点:
Project基本情報Tasksの主要フィールドResourcesの主要フィールドAssignmentsの主要フィールド- 依存関係
STEP 1 では、次は非目標とする。
- MS Project XML の完全再現
- 元 XML のノード順や空白や書式の完全保持
- フル機能の編集 UI
- すべての MS Project XML 要素の対応
現時点の 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-tripCalendarのIsBaselineCalendar / Exceptions / WorkWeeks / Exception WorkingTimesの round-tripResourceのCalendarUID / StandardRate / CostPerUseの round-tripResourceのWork / ActualWork / RemainingWork / Cost / ActualCost / RemainingCost / PercentWorkCompleteの round-tripAssignmentのStartVariance / FinishVarianceの round-tripResourceのWorkGroupの round-tripAssignmentのDelay / Milestone / WorkContourの round-tripAssignmentのOvertimeWork / ActualOvertimeWorkの round-tripTaskのDeadline / StartVariance / FinishVarianceの round-tripTaskのWorkVariance / TotalSlack / FreeSlack / Criticalの round-tripResourceのStandardRateFormat / OvertimeRate / OvertimeRateFormatの round-tripAssignmentのPercentWorkComplete / ActualWork / RemainingWorkの round-tripProjectのStatusDate / WeekStartDay / WorkFormat / DurationFormatの round-tripProjectのCurrencyCode / CurrencyDigits / CurrencySymbol / CurrencySymbolPositionの round-tripProjectのFYStartDate / FiscalYearStartの round-tripProjectのCriticalSlackLimit / DefaultTaskTypeの round-tripProjectのDefaultFixedCostAccrual / DefaultStandardRate / DefaultOvertimeRateの round-tripProjectのDefaultTaskEVMethod / NewTaskStartDateの round-tripProjectのNewTasksAreManual / NewTasksEffortDrivenの round-tripProjectのNewTasksEstimated / ActualsInSyncの round-tripProjectのEditableActualCosts / HonorConstraintsの round-tripProjectのInsertedProjectsLikeSummary / MultipleCriticalPathsの round-tripProjectのTaskUpdatesResource / UpdateManuallyScheduledTasksWhenEditingLinksの round-tripProjectのOutlineCodes / WBSMasksの最小 round-tripProjectのExtendedAttributesの最小 round-tripTaskのExtendedAttributeの最小 round-tripResourceのExtendedAttributeの最小 round-tripAssignmentのExtendedAttributeの最小 round-tripTaskのBaselineの最小 round-tripAssignmentのBaselineの最小 round-tripResourceのBaselineの最小 round-tripTaskのTimephasedDataの最小 round-tripResourceのTimephasedDataの最小 round-tripAssignmentのTimephasedDataの最小 round-tripTask / AssignmentのCost / ActualCost / RemainingCostの round-trip- round-trip テスト
現時点では、確認・共有向けの補助出力として 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 は
WBS 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を併記してよい - 現時点の
assignmentsはtask_uid / resource_uid / start / finish / units / work / percent_work_complete程度の最小表現を想定する
現時点で意図的に落とすもの:
CalendarsBaselineTimephasedData- コスト系の詳細
PredecessorLinkの完全表現
注意:
- これはあくまで片方向の補助出力であり、
Mermaid gantt -> ProjectModelの往復は対象外とする - 現時点の dependency 表現は部分的にネイティブ化しているが、複数 predecessor、
FS以外の link type、lag あり、複雑な duration はコメント保持のままとする - どの情報を落としているかは、将来の
CSV + ParentID等の交換形式検討と切り分けて扱う
mikuproject の次段候補として、CSV + ParentID を「まず押さえるべき、よくある交換形式」の第1候補とする。
目的:
- 人が表計算ソフトやスプレッドシートで編集しやすい形を持つ
- 独自記法を先に増やしすぎず、一般的な交換形式を先に押さえる
- task 階層を
ParentIDで素直に表現する
最小列候補:
IDParentIDName
実用列候補:
WBSStartFinishPredecessorIDResourcePercentComplete
現時点の整理方針:
- まずは単一 CSV を前提に考える
- task 階層の正本は
ParentIDとし、WBSは補助列として扱う候補とする PredecessorIDは単一値か複数値区切りかを今後決めるResourceは名前で持つかResourceIDで持つかを今後決める
単一 CSV で落ちやすいもの:
Assignmentsの完全表現CalendarsBaselineTimephasedData- コスト系の詳細
注意:
- 現時点では仕様草案段階であり、
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 の次の検討項目:
- サンプル XML の置き場所
- 内部モデル型の確定
- XML パーサ / シリアライザの実装方針
- STEP 1 で実際に保持する必須フィールドの最終確定
- ラウンドトリップ比較用の正規化ルール