--- name: pleasanter-site-spec description: Pleasanterのサイト設定JSON(get-site-config.js / api-site-get の getsite レスポンス)から、SiteSettingsを読み解いたMarkdown仕様書を生成し、Scripts/Styles/ServerScripts/Processesの抽出・編集・反映(extract-site-config.js / build-desired-config.js / apply-site-config.js)を行う。また、ユーザー/組織/グループのマスターデータ取得(get-master-data.js)、別サイトへのSiteSettings丸ごと適用や項目の追加・連番リネームといった構造変更(restructure-site-*.js / apply-to-site-*.js)、権限(Permissions)の名前指定での追加(apply-permission-grant.js)にも対応する。「仕様書を作って」「サイト仕様書」「SiteSettingsをドキュメント化」「スクリプトを抜き出して」「プロセス設定を直して反映して」「別サイトに丸ごと適用して」「項目を追加して連番をズラして」「この人と同じ権限を追加して」「site-spec」等の依頼で使う。 --- # Pleasanter サイト仕様書生成・構成管理 `configs/site-{SiteId}_{サイト名}/sitesettings/site-{SiteId}_latest.json`(`getsite` APIレスポンス、`Response.Data` 配下にサイト情報)を読み解き、 `configs/site-{SiteId}_{サイト名}/docs/site-{SiteId}_spec.md` として日本語のMarkdown仕様書を出力する。 ## フォルダ構成(configs/ 配下) ``` configs/ master/ … ユーザー/組織/グループのマスターデータ(get-master-data.js) master_users.json master_depts.json master_groups.json site-{SiteId}_{サイト名}/ sitesettings/ … getsiteの生JSON(get-site-config.jsが保存。latest.json + タイムスタンプ付き履歴) site-{SiteId}_latest.json site-{SiteId}_{timestamp}.json scripts/ styles/ serverscripts/ html/ processes.json / manifest.json … extract-site-config.js による分割済みファイル(従来通り) docs/ … 仕様書(.md)や改善要望プラン等、sitesettings以外の関連ドキュメント modify/{リクエストラベル}/ … 修正依頼のたびに新規作成。変更前後のconfigファイル・ 差分プレビュー・送信結果に加え、summary.md(後述)を 必ずひとまとめに保管する ``` 修正を1件でも反映した場合、`modify/{リクエストラベル}/` フォルダに機械可読な生JSON(差分プレビュー・送信結果)だけでなく、 人間が読めるサマリー `summary_{timestamp}.md` を必ず作成・保存する(ユーザーの明示指示が無くても毎回行う)。 `{timestamp}` は同じ反映で生成される送信結果ファイル(`site-{SiteId}_full_update_result_{timestamp}.json` 等)と 揃える。`summary.md` のような固定名で毎回上書きせず、反映のたびに別ファイルとして残す。記載内容の目安: - 対象サイト・反映日時・反映方法(実行したコマンド)・反映結果(HTTPステータス・メッセージ) - 依頼内容ごとの変更点(変更前 → 変更後を表や箇条書きで) - 保留・見送りにした事項(あれば) `.md`ファイルのため、内容を原始人口調で書くか通常の日本語で書くかは、他のテキストファイル生成と同様に一度だけユーザーに確認する。 パス解決は `site-paths.js` に共通化されている(`findSiteDir` / `ensureSiteDir` / `sitesettingsDir` / `docsDir` / `newModifyDir` / `latestModifyDir` / `latestJsonPath`)。新しいスクリプトを書くときはここを再利用し、 パス組み立てを重複させない。 ## 入力の特定 1. ユーザーがJSONファイルパスやSiteIdを指定した場合はそれを使う。 2. 指定がなければ `configs/site-*/sitesettings/site-*_latest.json` を探す。複数ある場合はユーザーに確認する。 3. 対象サイトの `sitesettings/site-{SiteId}_latest.json` が無ければ、先に `node get-site-config.js` の実行を提案する (エンドポイントは `/api/items/{SiteId}/getsite` を使うこと。`/api/items/{SiteId}/get` はアイテム一覧取得APIであり別物なので注意)。 ## 出力ファイル `configs/site-{SiteId}_{サイト名}/docs/site-{SiteId}_spec.md`(既存があれば上書きしてよい)。 ## 仕様書の構成(この順番・見出しレベルを踏襲する) ```markdown # サイト仕様書:{Title}(SiteId: {SiteId}) - 取得元データ: [site-{SiteId}_latest.json](../sitesettings/site-{SiteId}_latest.json) - 取得日時: {UpdatedTime}(サイト更新日時)/設定バージョン `Ver: {Ver}` ## 1. サイト基本情報 (TenantId, Title, ReferenceType, ParentId, InheritPermission, Publish, DisableCrossSearch, Creator/Updator, CreatedTime, SiteSettings.Version を表形式で) ## 2. アクセス権限(Permissions) (Permissions配列を 種別/対象ID/権限レベル の表に分解。可能であれば `resolve-names.js` の `resolveName` でユーザー名・組織名・グループ名も併記する。 InheritPermissionが自サイト以外を指している場合は、権限の実体はそちらのサイトにある旨を明記し、 継承元サイトのPermissionsも取得できていれば併せて記載する。 「権限値はビットフラグの加算方式のため正確な意味は環境のロール定義に依存する」旨を注記) ## 3. 画面構成 ### 3.1 一覧画面(GridColumns) (GridColumns配列を 順番/列名/表示ラベル の表に。ラベルはColumns配列から解決、 無ければ「項目種別の判定ルール」のデフォルト名を使う) ### 3.2 編集画面レイアウト(EditorColumnHash / Sections) (EditorColumnHashの各タブ配列を 順番/項目名(内部名)/ラベル名 の表に。 `_Section-N` はラベル名欄に「―(セクション「{LabelText}」開始)」と記載。 続けてSections配列を Id/ラベル/AllowExpand/Expand の表で示す) ### 3.3 タイトル表示(TitleColumns / TitleSeparator) (TitleColumns配列をTitleSeparatorで連結した式を明記) ## 4. 項目定義(Columns) (Columns配列を 列名(内部)/種別/表示ラベル/説明・入力ガイド/備考 の表に。 種別は下記「項目種別の判定ルール」で推定。 備考にはNoWrap, FieldCss, ExtendedHtmlAfterControlの有無などを記載) ### 4.1 項目ごとの補足HTML(ExtendedHtmlAfterControl) (該当項目があれば 列名/色(styleやclassから読み取れれば)/内容 の表。無ければこの節は省略) ## 5. 作成・更新権限(フィールド単位) (PermissionForCreating / PermissionForUpdating を表で。無ければ「設定なし」と明記) ## 6. 集計設定(Aggregations) (存在する場合のみ。Id/GroupBy/Type/Target を表で) ## 7. 他サイト連携(Links / ルックアップ) (存在する場合のみ。起点列/参照先SiteId/参照先の値→自コピー先/JsonFormat を表で。 「参照先サイトの{From}列の値を、このサイトの{To}列にコピーする」という関係性を文章でも補足) ## 8. プロセス設定(Processes) (存在する場合のみ。定義ファイルへのリンク ../processes.json を明記した上で、 Id/Name・DisplayName/実行条件(CurrentStatus→ChangedStatus)/動作(OnClick等)/成功メッセージ を表で) ## 9. スタイル(Styles) (存在する場合のみ。Id/Title/適用範囲(New/Edit/Index等のフラグ)/ファイルへのリンクを表で。 CSS本体はMarkdownに貼らず、抽出済みファイルへのリンクのみとする) ## 10. スクリプト(Scripts)/サーバースクリプト(ServerScripts) (存在する場合のみ。Id/Title/適用画面/ファイルへのリンクを表で。 スクリプト本体はMarkdownに貼らず、抽出済みファイルへのリンクのみとする。 概要は「何をするスクリプトか」を1〜2行で要約。 本文中にAPIキー・Webhook URL・パスワード等の秘密情報らしき文字列(`API_KEY`, `SECRET`, `Bearer `, URLに埋め込まれたトークン等)を見つけた場合は、値そのものをMarkdownに転記せず、 「気になる点」に必ずセキュリティ上の指摘として記載する) ## 11. その他設定 (NoDisplayIfReadOnly, HideLink, SectionLatestId, 各種ガイド文の設定有無, Commentsの使用有無など) --- ## 気になる点(レビュー観点) (プレースホルダーらしき文言、権限設定の偏り、項目単位の権限の抜け、 未設定のガイド文など、気づいた点を箇条書きで) ``` ## 項目種別の判定ルール(Columns内 ColumnName のプレフィックスから推定) | プレフィックス/名前 | 種別 | |---|---| | ClassA〜Z | 文字列(分類) | | Class001〜040等(3桁連番) | 文字列(拡張分類)。`Hide: true`の場合が多く、他項目のルックアップ先の値を裏で保持する用途が多い | | NumA〜Z | 数値 | | DateA〜Z | 日付 | | DescriptionA〜Z | 説明(複数行文字列) | | CheckA〜Z | チェックボックス | | AttachmentsA〜Z | 添付ファイル | | Owner, Manager, Assignee等 | ユーザー選択 | | Status | 状態 | | {対象}Id(ResultId, IssueId等) | 自動採番ID | | Title | タイトル | | Comments | コメント欄 | 「予定/実行/無し/備考」の4列1組パターン(`DateNNN`/`Date(NNN+100)`/`Check(NNN+100)`/`ClassNNN`、NNNは3桁ゼロ埋め連番)が 繰り返し登場するサイトもある。この場合 `DateNNN.Description` が入力担当(部署名等)、`DateNNN.GridLabelText` が 項目の表示名を表す。詳細は下記「クロスサイト構造変更(新項目追加・連番リネーム)」を参照。 ## 注意事項 - SiteSettingsに存在しない項目・空の設定(例: `ClassHash`, `NumHash` などのラベル定義ハッシュが `{}`)は 「標準ラベルのまま」として仕様書に明記し、存在しないかのように省略しない。 - 表形式を基本とし、箇条書きより表を優先する(今回のレビューで「編集画面レイアウトは項目名とラベル名を併記」との 指摘を受けた経緯があるため、内部名とラベル名は必ず併記する)。 - 出力言語は日本語。 ## 関連ツール:Scripts/Styles/ServerScripts/Processesの抽出・編集・反映 仕様書化とは別に、「スクリプトを個別ファイルに分けて」「プロセス設定を直して反映して」等の依頼では、 以下のツールチェーンを使う(詳細は `README.md` 参照)。 1. `node get-site-config.js` … `configs/site-{SiteId}_{サイト名}/sitesettings/site-{SiteId}_latest.json` を取得し、 続けて自動的に抽出も行う(`extract-site-config.js` が内部から呼ばれ、`configs/site-{SiteId}_{サイト名}/` に以下を分割保存する。未取得なら先にこれを実行) - `scripts/{Id}_{Title}.js`(クライアントスクリプト本体) - `styles/{Id}_{Title}.css`(スタイル本体) - `serverscripts/{Id}_{Title}.js`(サーバースクリプト本体) - `html/{GuideName}.html`(GridGuide等のガイドHTML。SiteSettingsではなくサイトデータ直下の項目) - `processes.json`(`SiteSettings.Processes` の定義ファイル、1ファイルにまとめる。分割しない) - `manifest.json`(上記ファイルとId/Titleの対応表。再構成に必須) - `config.json` の `SiteId` はカンマ区切りで複数指定可能。また、取得したサイトの `InheritPermission` が 自サイト以外を指している場合、権限の実体を持つそのサイトも自動的に追いかけて取得する(後述)。 - 抽出だけをやり直したい場合(`latest.json`は既に取得済み)は `node extract-site-config.js` を単独実行してもよい - **注意**: `get-site-config.js` を再実行すると、その時点のサイトの生の状態で `scripts/` `styles/` 等が 上書きされる。あるサイトの内容を「別サイトへ適用するための下書き」として編集している最中に、 同じサイトへ `get-site-config.js` を再実行すると編集内容が失われるので、クロスサイト作業中は むやみに元サイトを再取得しない(詳しくは後述の「クロスサイト構造変更」参照)。 - **下書きファイルの整理**: `scripts/` `styles/` `serverscripts/` 配下に `_修正` 等のサフィックス付きで `manifest.json` 未登録の下書きファイルが残っていることがある(過去に本文を直接編集した際の作業ファイル)。 再取得後は、この下書きファイルと対応する正規ファイル(`manifest.json` の `File` に記載された方)を diffで比較する。内容が完全一致していれば、下書きの編集内容は既にサイトへ反映済みということなので、 その下書きファイルは削除してよい。内容が異なる場合は未反映の編集が残っている可能性があるため、 削除せずユーザーに確認する。 2. ユーザーの指示に従い、`scripts/*.js` 等の中身を直接編集する(`manifest.json` のId/メタ情報は変更しない)。 新規追加の場合は `manifest.json` に対応エントリ(`Id`は既存と重複しない値、`File`名)を追加してからファイルを作成する。 3. `node build-desired-config.js site-{SiteId}` … 分割ファイルを再構成し `desired_config.json` を生成(送信なし)。 フォルダ名はサイト名まで含む正式名(`site-{SiteId}_{サイト名}`)だが、`site-{SiteId}` の前方一致指定でも `configs/`配下から自動解決される 4. `node apply-site-config.js` … ドライラン確認(差分・送信Body・curlコマンド表示のみ、送信なし) 5. 内容をユーザーに確認してもらい、問題なければ表示されたcurlコマンドをユーザー自身が手動実行する ## 関連ツール:ユーザー/組織/グループのマスターデータ取得 権限(Permissions)やスクリプト内の担当者振り分けなどをID表記ではなく名前で扱いたい場合に使う。 1. `node get-master-data.js` … `configs/master/` へ以下を取得・保存する(ページング自動対応。 `/api/users/get` はレスポンスの `TotalCount` が1回あたりの件数を超えることがあるため、 トップレベルの `Offset` パラメータで全件を取得しきるまでループする)。 - `master_users.json`(`UserId` / `LoginId` / `Name` / `DeptId` 等) - `master_depts.json`(`DeptId` / `DeptCode` / `DeptName`) - `master_groups.json`(`GroupId` / `GroupName` / `GroupMembers[]` / `GroupChildren[]`) - 参照した公式マニュアル: [ユーザ取得(全て)](https://pleasanter.org/ja/manual/api-user-get-all) / [組織取得](https://pleasanter.org/ja/manual/api-dept-get) / [グループ取得](https://pleasanter.org/ja/manual/api-group-get) 2. `resolve-names.js` をスクリプトから `require` して使う: - `loadMasterData(baseDir)` … 3つの `master_*.json` を読み込む - `resolveName(master, { Type: "User"|"Dept"|"Group", Id })` … IDから名前を引く - `resolveId(master, { Type, Name })` … 名前から一致するIDの配列を引く(完全一致。0件/複数件はエラーとして扱う) ## 関連ツール:クロスサイト構造変更(項目追加・連番リネーム・別サイトへの丸ごと適用) 「Aサイトを土台に項目を追加してBサイトへ適用して」「この項目の後ろに新しい項目を追加して、以降の連番を ズラして」のような依頼で使うパターン。2026-07-16に SiteId 480111 → 496626 への適用(「解体紹介料申請」項目の 追加・連番リネーム・GridDesign一括改修・改善要望3件の反映)で実際に使った構成を一般化したもの。 `restructure-site-480111.js` / `apply-to-site-496626.js` / `apply-permission-grant.js` は、その際の実例 (そのまま次回動かせるテンプレートとして残っている)。**次回別の依頼が来たら、これらをコピーして 対象サイトIDやフェーズの中身を書き換えて使う**(汎用パラメータ化はしていない。要望ごとに列の増減や チェックリストの中身が違うため、都度スクリプトとして書き下ろす方が確実)。 ### 全体の流れ 1. **マスターデータ+サイト情報の取得**: `node get-master-data.js` → `node get-site-config.js` (`config.json` の `SiteId` を一時的に `"元サイトId,対象サイトId"` にして実行し、終わったら単一IDへ戻す)。 `InheritPermission` が自サイト以外を指していれば、その継承元サイトも自動的に追いかけて取得される。 2. **抽出済みScripts/Stylesの編集**: 元サイトの `configs/site-{元SiteId}_.../scripts/*.js` 等を直接編集する。 ⚠️ ここは元サイト自身の抽出フォルダなので、元サイトを `get-site-config.js` で再取得すると 編集内容が消える。編集後は速やかに restructure スクリプト(次項)を走らせて `modify/` フォルダへ 本文を取り込んでおくこと。 3. **`restructure-site-{元SiteId}.js`(新規作成)**: 元サイトの `sitesettings/latest.json` を読み込み、 構造変更(列の挿入・連番リネーム・GridDesign書き換え等)を行い、`manifest.json` 経由で 編集済みのScripts/Styles本文を組み込んだ上で、対象サイトの `modify/{リクエストラベル}/` フォルダへ `site-{元SiteId}_updated.json` として書き出す(`site-paths.js` の `findSiteDir` / `newModifyDir` を使う)。 同じフォルダへ対象サイトの変更前スナップショット(`before_site-{対象SiteId}_latest.json`)も コピーしておく。書き込み前に、想定した件数増分・重複の有無などの整合性チェックを必ず入れる (今回の実装では「フェーズA:事前ガード」「フェーズH:整合性チェック」として実施)。 4. **`apply-to-site-{対象SiteId}.js`(新規作成)**: `modify/` フォルダの `site-{元SiteId}_updated.json` を `updatesite`(`Mode:"full"`)で対象サイトへ送る。`Title`/`ReferenceType`/`ParentId`/`InheritPermission`は **対象サイト自身の現状値**から取得し、`SiteSettings`のみ元サイト由来の内容で置き換える。 `Permissions`は送信ボディに含めない(対象サイトが権限を継承している場合、直接の書き込み対象ではないため。 継承有無は `InheritPermission` で判定する)。デフォルトは差分プレビュー+アーティファクト保存のみ、 `--execute` 指定時のみ実際に送信する。差分プレビュー・送信結果は同じ `modify/` フォルダへ保存する。 5. **権限を名前指定で追加する場合**: `apply-permission-grant.js` のパターンで、対象サイトの `InheritPermission` が指す継承元サイトに対して行う(対象サイト自身の `Permissions` は空配列=継承の ままにしておき、直接は変更しない)。`Permissions` はサイトデータ直下の項目で `"Type,Id,PermissionType"` 形式の文字列配列(例: `"User,579,15"`)。`updatesitesettings`(部分更新)APIはPermissionsを更新対象に 含まないことを公式マニュアルで確認済みのため、`updatesite`(全体更新)を使い、継承元サイトの `SiteSettings` 等は一切変更せずそのまま再送信しつつ `Permissions` のみ新規エントリを追加する。 ⚠️ 公式マニュアルには `updatesite` のリクエストボディで `Permissions` を指定できるという明記が 無いため、実行前に必ずプレビュー出力をユーザーに確認してもらうこと。 6. **内容確認 → 実行**: 生成された `modify/` フォルダの中身(`before_*.json` / `site-*_updated.json` / `*_diff_*.txt`)をユーザーに提示し、レビューを受けてから `--execute` を実行する。 ### 厳守事項(安全設計、クロスサイト構造変更にも適用) - **`apply-site-config.js` は常にドライラン。Claude自身がAPIへ実送信することはしない** (`ENABLE_ACTUAL_SEND` を有効化する改修や、curlコマンドの代理実行も行わない)。これは変更しない。 - 一方で `apply-to-site-{対象SiteId}.js` / `apply-permission-grant.js` のような**専用の直接実行スクリプト**は、 ユーザーがその場で明示的に「今回は直接実行してよい」と許可した場合に限り作成・実行してよい (2026-07-16の実例)。これは **その依頼一回限りの例外** であり、標準運用(ドライラン+手動反映)を 恒久的に変更するものではない。次回以降も、実送信を伴うスクリプトを作る/`--execute` を走らせる前には、 改めてユーザーに差分プレビューを提示し、明示的な許可を得ること。 - `build-desired-config.js` が作る `desired_config.json` は `Mode:"partial"`(`updatesitesettings`)専用。 Scripts/Styles/ServerScripts/Processes以外のサイト設定には触れない。Columns/EditorColumnHash/Sections/ GridColumns/Permissions等の構造変更は、この節で説明した `restructure-site-*.js` パターンで行う。 - ガイドHTML(`html/*.html`)は `updatesitesettings` では反映できない(サイト直下の項目のため)。 反映が必要なら `Mode:"full"`(`updatesite`)用の別JSONが要ることをユーザーに伝える。自動生成はしない。 - 抽出したスクリプト・サーバースクリプトの中に **APIキーやWebhook URL等の秘密情報がハードコードされている場合がある** (実例あり)。抽出・編集作業でこれらの値を見つけたら、チャット上にそのまま貼り付けず、ユーザーに直接ファイルを確認してもらう。 また `configs/` フォルダと `config.json` は `.gitignore` 済みだが、誤ってコミットしないよう注意喚起する。 - 権限変更・別サイトへの丸ごと上書きはブラスト半径が大きい。実行前に必ず差分プレビューを提示し、 対象サイトIDや継承関係(`InheritPermission`)の理解が誤っていないか、実行のたびに確認する。