From 9a4b300114aed139e180f898f9e59a34c5366aad Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Fri, 23 Oct 2026 07:09:26 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E6=97=A2=E7=9F=A5=E3=81=AE=E8=84=86?= =?UTF-8?q?=E5=BC=B1=E6=80=A7=E3=81=8C=E3=81=82=E3=82=8B=E3=83=91=E3=83=83?= =?UTF-8?q?=E3=82=B1=E3=83=BC=E3=82=B8=E3=82=92=E4=BF=AE=E6=AD=A3=E7=89=88?= =?UTF-8?q?=E3=81=B8=E4=B8=8A=E3=81=92=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dotnet list package --vulnerable で High が検出されたため更新する。 - Microsoft.AspNetCore.Components.WebAssembly.Server 10.0.10(GHSA-g27p-qf6j-c96c・GHSA-qjpx-jqm5-h2c4) ほか Microsoft.* の 10.0.10 をすべて 10.0.13 に揃える - System.Security.Cryptography.Pkcs 9.0.4(SqlClient 6.1.1 経由。GHSA-846f-f764-76mx ほか)は Infrastructure から 10.0.13 を直接参照して上書きする - AspNetCore.OpenApi 10.0.13 が要求する Microsoft.OpenApi 2.12.2 へ直接参照も上げる(NU1605 の解消) - dotnet-ef ツールを EF Core と同じ 10.0.13 に揃える Co-Authored-By: Claude Opus 5.5 --- dotnet-tools.json | 2 +- src/MesApp.Api/MesApp.Api.csproj | 10 +++++----- src/MesApp.Client.Web/MesApp.Client.Web.csproj | 8 ++++---- src/MesApp.Core/MesApp.Core.csproj | 2 +- src/MesApp.Infrastructure/MesApp.Infrastructure.csproj | 8 +++++--- tests/MesApp.Api.Tests/MesApp.Api.Tests.csproj | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dotnet-tools.json b/dotnet-tools.json index cce89d8..39007e0 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "dotnet-ef": { - "version": "10.0.10", + "version": "10.0.13", "commands": [ "dotnet-ef" ], diff --git a/src/MesApp.Api/MesApp.Api.csproj b/src/MesApp.Api/MesApp.Api.csproj index 10f09cb..228060b 100644 --- a/src/MesApp.Api/MesApp.Api.csproj +++ b/src/MesApp.Api/MesApp.Api.csproj @@ -12,14 +12,14 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/MesApp.Client.Web/MesApp.Client.Web.csproj b/src/MesApp.Client.Web/MesApp.Client.Web.csproj index 8e0565a..0f9138e 100644 --- a/src/MesApp.Client.Web/MesApp.Client.Web.csproj +++ b/src/MesApp.Client.Web/MesApp.Client.Web.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/src/MesApp.Core/MesApp.Core.csproj b/src/MesApp.Core/MesApp.Core.csproj index 87007c0..ee850e5 100644 --- a/src/MesApp.Core/MesApp.Core.csproj +++ b/src/MesApp.Core/MesApp.Core.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/MesApp.Infrastructure/MesApp.Infrastructure.csproj b/src/MesApp.Infrastructure/MesApp.Infrastructure.csproj index df4494a..250f842 100644 --- a/src/MesApp.Infrastructure/MesApp.Infrastructure.csproj +++ b/src/MesApp.Infrastructure/MesApp.Infrastructure.csproj @@ -5,11 +5,13 @@ - - - + + + + + diff --git a/tests/MesApp.Api.Tests/MesApp.Api.Tests.csproj b/tests/MesApp.Api.Tests/MesApp.Api.Tests.csproj index d01b176..bb1decf 100644 --- a/tests/MesApp.Api.Tests/MesApp.Api.Tests.csproj +++ b/tests/MesApp.Api.Tests/MesApp.Api.Tests.csproj @@ -9,7 +9,7 @@ - + From 9de7a7cea156a237f33355fd79b2d09d5076556b Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Fri, 23 Oct 2026 07:13:24 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=9D=E5=85=A8=E5=AE=9F=E7=B8=BE?= =?UTF-8?q?=E3=81=AE=E7=99=BB=E9=8C=B2=E3=82=92=E4=BF=9D=E5=85=A8=E6=8B=85?= =?UTF-8?q?=E5=BD=93=E8=80=85=E3=81=AB=E9=99=90=E3=82=8B=EF=BC=88E-40-30-0?= =?UTF-8?q?1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 単票API(POST api/maintenance-orders/{id}/record)と実績CSV maintenance-records が 全ロールに開いており、物流・品質の担当者でも在庫の引落し・保全指示の完了・ 設備の稼働可能への復帰・治工具の寿命リセットができた。 Spec.md 7.4 の「異常・使用実績の記録は絞らない」は保全依頼(起票)までで、実績は含まない。 - API・CSVとも MesRoleGroups.MaintenanceManage で絞る - 画面の実績登録フォームも同じ定数で隠す(取消ボタンと同じ範囲にまとめた) - 作業者が単票・CSVのどちらでも登録できず、指示が完了しないことをテストで確認 - Spec.md 改訂144 Co-Authored-By: Claude Opus 5.5 --- Spec.md | 7 ++++--- .../Controllers/MaintenanceOrdersController.cs | 2 ++ src/MesApp.Api/Services/ActualCsvKinds.cs | 2 +- .../Pages/Maintenance/MaintenanceOrdersTab.razor | 7 ++++--- tests/MesApp.Api.Tests/MaintenanceTests.cs | 15 ++++++++++++++- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Spec.md b/Spec.md index 0b30ee7..ac6a036 100644 --- a/Spec.md +++ b/Spec.md @@ -134,6 +134,7 @@ 改訂133: 2026-09-23(**標準時間の見直し候補を生産性モニタリングに追加した**(`api/productivity/standard-time-review`。B-60-10-05)。標準時間の予実は作業指示ごとに並ぶだけで、工順マスタを見直すきっかけにつながっていなかった(実践的MES導入ガイド 8.3.2(4):標準時間などの業務パラメータは定期的に再設計する)。工順の工程ごとに実績の中央値をマスタの現在値と比べ、件数としきい値で候補を挙げる。マスタは書き換えない。新規エンティティは無い。3.2節・6.1節に反映) 改訂134: 2026-09-23(1.3節に**エネルギー管理を[将来拡張]とする**ことを明記した。仕様にエネルギーの記述が無く、対象かどうかが読めなかった(実践的MES導入ガイド 3.4.2・4.4.7・7.2.2 は、MES の役割を FEMS へ製造オーダ別の分母を渡すことと位置づける)。計測・総量監視・ユーティリティ制御は FEMS/FMCS の領域として持たず、実装する場合は設備×期間の使用量をCSVで受け取り稼働区間の時間比で作業指示へ按分する形とした。機能の追加・変更は無い) 改訂135: 2026-09-23(**検査項目・基準に必要スキル・資格を持たせ、検査実績の登録時に検査員と照合する**ようにした(`InspectionItem.RequiredSkillId`。F-20-30-01)。改訂130で保全を実装した際、検査の見直し(改訂125〜128)と衝突するため後回しにしていたもの。必要スキルは発行時に `InspectionOrderItem` へ写し(作業指示の必要スキルと同じ)、発行後にマスタを変えても発行済みの検査の照合条件は変わらない。写す値なので、CSV取込で変えると版数が上がる。判定は差立・着手・保全と同じ `SkillQualificationPolicy`。実績の訂正では照合しない。マスタCSVの検査項目に `RequiredSkillCode` 列を追加(列が無ければ現在値のまま)。3.6節・5.1節・5.4節に反映) +改訂144: 2026-10-23(7.4節・3.x節保全実施・3.8節⑨:**保全実績の登録を保全担当者(`MaintenanceManage`)に限った**。単票API(`POST api/maintenance-orders/{id}/record`)と実績CSV `maintenance-records` が全ロールに開いており、物流・品質の担当者でも在庫の引落し・保全指示の完了・設備の復帰・治工具の寿命リセットができた。7.4節の「異常・使用実績の記録は絞らない」は保全依頼(起票)までで、実績は含まない。画面の実績登録フォームも同じ定数で隠す) 改訂143: 2026-09-24(3.8節:実績CSVに保全計画 `maintenance-plans` を追加した(CSV対応バックログで保留にしていたもの)。計画の登録を `MaintenancePlansController.Create` から `MaintenanceOrderService.CreatePlanAsync` へ移し、単票APIとCSV取込の両方から呼ぶ(API契約は変えない)。計画には番号が無いため、保全指示CSVに `FromPlan` 列を足し、設備と予定日が一致する未指示の計画が1件だけのときにその計画から指示を作る。サンプル `samples/actual-csv/18_maintenance-plans.csv` を追加し、以降のサンプルの番号を1つずつ繰り下げた(19〜30)) 改訂142: 2026-09-24(3.8節:実績CSVに不適合 `nonconformances`・サンプル品保管 `sample-storages` を追加した(CSV-07)。不適合の対応と保管サンプルが画面からしか進められなかった。検査の不合格で自動起票された不適合は、ロット番号で指す(そのロットの未完了の不適合が1件だけのときに限る)。サンプルの採取・保管の終了を `SampleStoragesController` から新設の `SampleStorageService` へ移し、単票APIとCSV取込の両方から呼ぶ(API契約は変えない。サンプル番号の手入力はCSVのみ)。サンプル `samples/actual-csv/28〜29` を追加) 改訂141: 2026-09-24(3.8節:実績CSVに搬送指示 `transfer-orders`・ピッキング指示 `picking-orders`・棚卸指示 `stocktakes`・実棚数 `stocktake-counts` を追加した(CSV-06)。物流の指示系と倉庫業務進捗がサンプルで空のままだった。搬送指示の作成・実行・取消を `TransferOrdersController` から新設の `TransferOrderService` へ移し、単票APIとCSV取込の両方から呼ぶ(API契約は変えない)。ピッキング・棚卸は後続の行・ファイルから指すため番号を手入力にする(CSV-01 の手入力番号)。サンプル `samples/actual-csv/24〜27` を追加) @@ -323,7 +324,7 @@ AGV/AMR連携(D-50-20-02)・リサイクル管理(D-50-30-02)・VMI/外 - 同じ設備の同じ時間帯に複数の作業指示が紐づく場合(まとめ処理。3.9節)は重なりを**按分**する。1つの作業指示が複数設備で動いた場合は産出を稼働時間の比で配分する - 性能稼働率は100%を超えることがある(標準作業時間より速い)。上限で丸めない - **保全計画・指示**:中長期・年次保全計画の作成・変更(E-30-10-01〜03)、保全指示の作成・発行(E-30-20-01)、生産計画への影響連携(E-30-20-02)、計画外の保全依頼(E-30-30-01)。保全指示を発行済みの計画は取り消せない(先に保全指示を取り消す。指示の取消で計画は計画中へ戻る) -- **保全実施**:保全手順確認(E-40-10-01)、作業準備・実施(E-40-20-01〜02)、保全実績登録(消費部材・交換部品・対応人員等。E-40-30-01。設備が保全中なら稼働可能へ戻す。保全中への切替は保全担当が設備台帳で行う)。**消費部材はロットを指定して在庫から引き落とす**(引落しは在庫サービス経由。5.7節) +- **保全実施**:保全手順確認(E-40-10-01)、作業準備・実施(E-40-20-01〜02)、保全実績登録(消費部材・交換部品・対応人員等。E-40-30-01。**登録は保全担当者(`MaintenanceManage`)に限る**。設備が保全中なら稼働可能へ戻す。保全中への切替は保全担当が設備台帳で行う)。**消費部材はロットを指定して在庫から引き落とす**(引落しは在庫サービス経由。5.7節) - **消耗材モニタリング**:期間内に保全で消費した部材を品目別に集計し、現在庫と並べて補充の要否を判断する(E-20-10-04) - **治工具管理**:治工具マスタと在庫管理(E-60-10-01/03/04。在庫オペレーションと共通)、**寿命管理**(作業指示との紐付けによる利用実績記録(E-60-20-01)、閾値到達前の交換・廃棄通知(E-60-20-02)、**寿命分析**(E-60-20-03。期間内の使用ペースから寿命到達の見込み日を出す。使用実績のあった日で割り、閾値未設定・使用なし・到達済みは見込みを出さない))、治工具メンテナンスの指示・実施・実績(E-60-30-01〜03) - 予兆保全(E-20-20-01)は[将来拡張] @@ -360,7 +361,7 @@ AGV/AMR連携(D-50-20-02)・リサイクル管理(D-50-30-02)・VMI/外 - 監査ログ(実績訂正・検査訂正・マスタ変更等の変更履歴。7.6節) - **マスタのCSV一括入出力**:各マスタ(品目/MBOM/工順/工程/作業区/設備/設備の保全部品/治工具/ロケーション/検査項目・基準/**検査機・測定器**/工程管理項目/チェックリスト/作業手順書/勤務シフト/スキル・資格/ユーザー/ユーザーのスキル資格/**保全手順書**)のCSV出力・テンプレート出力・一括取込。保全手順書(`maintenance-procedures`)は単票APIと同じく保全の権限(`MaintenanceManage`)で取り込み、取込欄は保全管理画面の保全手順書タブに置く(一括ZIPでは最後の番号。対象設備・治工具・必要スキルをコードで参照するため)。取込はコード(自然キー)によるupsertで、他マスタはコードで参照する。文字コードはUTF-8/Shift_JISを自動判別し、出力はExcel互換(UTF-8 BOM+CRLF)。行単位で検証し、**1行でもエラーがあれば全件ロールバック**して行番号付きのエラー一覧を返す。反映せず検証のみ実行するモードを持つ。**参照されている状態のマスタを無効化できないという制約は、単票APIと同じ判定をCSV取込にも通す**(工順から参照中の作業手順書、在籍中の従業員が所属する直など)。片方にしか書かないとCSVから迂回できてしまうため、判定はポリシーへ集約する。なお**マスタの無効化は各マスタ画面から、再有効化はCSV取込の `IsActive` 列から**行う(全マスタ共通。画面に再有効化の導線は持たせていない) - **生産計画(`production-plans`)は取込の仕組みだけをこれに乗せる**。生産計画はマスタではなく日付を持つ業務データだが、改訂のたびに同じ計画を上書きしたいので、常に新規登録する実績CSVではなくキーで上書きするマスタCSVの取込を使う(A-30-10-01)。キーは `BusinessDate, ProductCode, ProcessCode, WorkCenterCode(任意)` で、同じキーなら計画数量(と `Note` 列があれば備考)を上書きし、無ければ追加する。**`WorkCenterCode` が空の行も1つのキーとして扱い**、同じ製造日・品目・工程の作業区なしの計画を上書きする(二重に追加しない)。計画数量は0以上。ファイル内で同じキーが複数行にあればエラー。取り込んだ後に同じ製造日・品目・工程で作業区の範囲が重なる行(既存の計画との間・ファイル内とも)もエラー。数量とキーの判定は単票API(`api/production-plans`)と共通の `ProductionPlanPolicy` に置く。取込の権限は単票の登録と同じ `ProductionManage`(種別の `WriteRoles`)。取り込み直しても変わらない行は更新日時を動かさない。**マスタではないので一括ZIPの取込・出力には含めない**(日々増えるデータを、マスタの移行や全件出力に巻き込まないため。ZIPに入っていれば取込を拒む)。取込は生産計画画面の計画登録タブから1ファイルずつ行い、出力は一覧と同じ絞り込み(製造日の期間・品目・工程・作業区)の `api/production-plans/csv` で行う -- **実績のCSV一括取込**:試験・移行・教育用に、実績(取引データ)をCSVで一括登録する(`api/actuals/csv/{kind}`。テンプレート出力と取込。対応種別は受入 `receiving`・製造指図 `manufacturing-orders`・段取り実績 `setup-records`・チェックリスト実施 `checklist-records`・部材投入 `consumptions`・生産実績 `production-records`・製造条件データ `data-records`・検査 `inspections`・作業時間 `work-time-records`・製造トラブル報告 `trouble-reports`・設備稼働記録 `equipment-logs`・出荷指示 `shipping-orders`・出荷判定 `shipment-judgments`・出荷実行 `shipments`・保全計画 `maintenance-plans`・保全指示 `maintenance-orders`・保全実績 `maintenance-records`・治工具の利用実績 `tool-usages`・治工具の引当 `tool-issues`・検査機の校正 `calibrations`・在庫オペレーション `inventory-operations`・搬送指示 `transfer-orders`・ピッキング指示 `picking-orders`・棚卸指示 `stocktakes`・実棚数 `stocktake-counts`・不適合 `nonconformances`・サンプル品保管 `sample-storages`)。マスタCSVと同じく**1行でもエラーがあれば全件ロールバック**し、行番号付きのエラー一覧を返し、検証のみのモードを持つ。マスタCSVとの違いは次のとおり。①**取込は常に新規登録**で既存の実績を更新しない(実績の訂正は理由付きの訂正機能で行う)。②行ごとに**単票APIと同じ業務サービスを通す**(受入は `ReceivingService`、製造指図は `ManufacturingOrderService`、作業指示の実行記録は `WorkOrderExecutionService`、検査は `InspectionService`、作業時間・トラブル報告は `ShopFloorReportService`、出荷指示・出荷実行は `ShippingService`、出荷判定は `ShipmentJudgmentService`、保全指示・保全実績は `MaintenanceOrderService`、治工具の利用実績は `ShopFloorReportService`、治工具の引当は `ToolIssueService`、校正は `InspectionDeviceService`、在庫オペレーションは `LotOperationService`、搬送は `TransferOrderService`、ピッキングは `PickingService`、棚卸は `StocktakeService`、不適合は `NonconformanceService`、サンプル品保管は `SampleStorageService`)——実績は在庫・ロット・状態履歴を連鎖して動かすため、行をエンティティへ直接写すと判定や監査ログが迂回される。③取込の権限は**種別ごとに単票APIと同じロールグループ**(受入は在庫・物流オペレーション)。④行は保存しながら進めるので、後の行は前の行の結果(登録済みロット番号の重複判定など)を前提にでき、検証のみも実際に登録してからロールバックする。他のマスタ・実績はIDではなくコード・番号で参照する。⑤**作業指示は「指図番号+工程順序」で指す**。自動採番の指図番号は取込前に分からないため、製造指図CSVに限り指図番号の手入力を許す(自動採番の形式 `MO〜` と重なる番号は、採番テーブルの連番と後で衝突するため拒否)。製造指図CSVは1行で登録・承認・工程展開まで進められるが、承認は省略できない(展開は承認済みの指図だけ)。⑥**実行記録の記録者は取込を実行したユーザー**とし、作業者を指定する列は持たない(他人名義の実績を作れると、記録者に意味が無くなる)。投入ロットはロット番号で、日時はオフセットの無い値を工場の時刻として読む。生産実績の直は開始日時で決まる。⑦**検査CSVは `InspectionKey` が同じ行を1件の検査指示にまとめる**。キーはファイルの中だけの名前でDBに残さない(検査指示番号は自動採番のままにし、後続のCSVから検査指示を指す必要も無いため)。まとまりに含まれる検査項目がその指示の対象になり、`Judge=true` なら実績に続けて総合判定する(ロットの状態反映・不合格時の不適合起票も単票APIと同じ)。⑧**出荷は指示・判定・実行の3種別に分ける**(判定は品質保証、指示と実行は物流の権限で、1種別にまとめると③を満たせない)。出荷指示CSVは出荷番号が同じ行を1件の指示(1行=1品目の明細。同じ品目を2行書けない)にまとめ、後続の判定・実行CSVから番号で指せるよう**出荷番号を必須の手入力**とする(⑤と同じ理由で自動採番の形式 `SH〜` と重なる番号は拒否)。出荷判定CSVは1行=1件の判定で、`Approve=true` なら続けて承認する。出荷実行CSVは出荷番号が同じ行を1回の出荷にまとめ、**承認済みの判定(可・特採)とロットの使用可否は単票APIと同じく出荷実行の処理で判定する**(判定の無い指示を含むファイルは全件取り消し)。⑨**保全は指示と実績の2種別に分ける**。保全指示CSVは1行=1件の指示で、保全実績CSVから指せるよう**保全指示番号を必須の手入力**とする(⑤と同じ理由で `MT〜` は拒否)。単票APIと同じく突発依頼は誰でも、計画保全の指示は保全担当者(`MaintenanceOrderService.PlannedOrderRoles`)だけが登録でき、CSVでは行ごとに取り込んだユーザーのロールで判定する。**保全計画CSV**は1行=1件の計画で常に新規登録する(設備×年度×区分でも同じ区分の計画が複数ありうるため自然なキーが無く、マスタCSVのように上書きしない。権限は単票と同じ `MaintenanceManage`)。計画には番号が無いので、保全指示CSVの `FromPlan=true` の行は**設備と予定日が一致する未指示の計画が1件だけのとき**にその計画から作り、計画を指示済みにする(0件・2件以上は行エラー。同じ設備の計画は予定日を分ける)。保全実績CSVは保全指示番号が同じ行を1件の実績にまとめ、1行に消費部材を1つ(ロット番号・払出元・数量)書ける。実施者は取り込んだユーザーで、手順書の必要スキルもこのユーザーと照合する。登録で指示は完了するので、1件の指示に実績は1件だけ。資産管理部品を書いた行・在庫不足は単票と同じく拒否する。⑩**番号の無い記録は1行で完結させる**。治工具の引当CSVは1行=1件の引当で、`Issue`・`Return` の列で払出・返却まで進め、後のファイルからは指さない(引当・払出の両方で `ToolIssuePolicy` が使用中・メンテ中・寿命到達を拒否する)。治工具の利用実績CSVは記録日時(`RecordedAt`)を指定でき、空欄なら取り込んだ時刻とする(寿命の累計はメンテで寿命をリセットした時刻より後の記録だけを数えるので、リセットより前の日時の記録は累計に入らない)。検査機の校正CSVは1行=1回の校正で、単票と同じく検査機の最終校正日・次回期限(省略時は校正周期から)を更新する。⑪**在庫オペレーションは1種別にまとめ、`Operation` 列で操作を選ぶ**(移動・数量調整・状態変更・分割・統合・振替・廃棄・返品・払出戻し。操作ごとに種別を分けると取込画面のパネルが9枚増えるため)。1行=1操作で、単票と同じ `LotOperationService` の同名メソッドを呼ぶ。操作ごとの必須列はコードで検査する(数量調整の理由は単票でも必須)。分割・振替は新ロット番号(`NewLotNumber`)を指定できるので、同じファイルの後の行から新しいロットを指せる。ロット系譜・状態履歴・監査ログは単票と同じに残る。⑫**物流の指示**:搬送指示CSVは番号が無いので1行=1件で、`Execute` の列で移動の実行まで進める。ピッキング指示CSVはピッキング番号(必須の手入力。`PK〜` は拒否)が同じ行を1件の指示にまとめ、1行=1明細(品目と数量)。ロット・ロケーションは単票と同じく先入れ先出し(有効期限優先。期限切れは引き当てない)で自動引当し、`Execute` で払出まで進める。棚卸指示CSVは棚卸番号(必須の手入力。`ST〜` は拒否)と対象ロケーションで作り、作成時点の在庫が明細になる。実棚数CSVは棚卸番号と明細のロット番号+ロケーションで指し、`Finalize` で確定(差異の棚卸調整)まで進める。⑬**不適合CSVは1行=1件の不適合**で、不適合番号(未登録なら新規起票。`NC〜` は拒否)か、番号を空欄にしてロット番号で指し、`Action`(対応指示)→`ActionRecord`(対応記録)→`Approve`(承認)の列があればその順に進める。検査の不合格で自動起票された不適合は番号が取り込むまで分からないため、**ロット番号で指せるのはそのロットの未完了(クローズ前)の不適合が1件だけのとき**に限る(0件・2件以上は行エラー。どれを進めるかを推測で決めない)。起票と対応記録は誰でも、対応指示と承認は単票と同じく品質管理の担当者だけ(行ごとに取り込んだユーザーのロールで判定)。⑭**サンプル品保管CSV**は1行=1件で、未登録のサンプル番号(`SP〜` は拒否)なら採取(在庫から抜く)、`Close`(払出・廃棄)を書けば保管を終える。登録済みの番号の行は保管の終了だけを行う +- **実績のCSV一括取込**:試験・移行・教育用に、実績(取引データ)をCSVで一括登録する(`api/actuals/csv/{kind}`。テンプレート出力と取込。対応種別は受入 `receiving`・製造指図 `manufacturing-orders`・段取り実績 `setup-records`・チェックリスト実施 `checklist-records`・部材投入 `consumptions`・生産実績 `production-records`・製造条件データ `data-records`・検査 `inspections`・作業時間 `work-time-records`・製造トラブル報告 `trouble-reports`・設備稼働記録 `equipment-logs`・出荷指示 `shipping-orders`・出荷判定 `shipment-judgments`・出荷実行 `shipments`・保全計画 `maintenance-plans`・保全指示 `maintenance-orders`・保全実績 `maintenance-records`・治工具の利用実績 `tool-usages`・治工具の引当 `tool-issues`・検査機の校正 `calibrations`・在庫オペレーション `inventory-operations`・搬送指示 `transfer-orders`・ピッキング指示 `picking-orders`・棚卸指示 `stocktakes`・実棚数 `stocktake-counts`・不適合 `nonconformances`・サンプル品保管 `sample-storages`)。マスタCSVと同じく**1行でもエラーがあれば全件ロールバック**し、行番号付きのエラー一覧を返し、検証のみのモードを持つ。マスタCSVとの違いは次のとおり。①**取込は常に新規登録**で既存の実績を更新しない(実績の訂正は理由付きの訂正機能で行う)。②行ごとに**単票APIと同じ業務サービスを通す**(受入は `ReceivingService`、製造指図は `ManufacturingOrderService`、作業指示の実行記録は `WorkOrderExecutionService`、検査は `InspectionService`、作業時間・トラブル報告は `ShopFloorReportService`、出荷指示・出荷実行は `ShippingService`、出荷判定は `ShipmentJudgmentService`、保全指示・保全実績は `MaintenanceOrderService`、治工具の利用実績は `ShopFloorReportService`、治工具の引当は `ToolIssueService`、校正は `InspectionDeviceService`、在庫オペレーションは `LotOperationService`、搬送は `TransferOrderService`、ピッキングは `PickingService`、棚卸は `StocktakeService`、不適合は `NonconformanceService`、サンプル品保管は `SampleStorageService`)——実績は在庫・ロット・状態履歴を連鎖して動かすため、行をエンティティへ直接写すと判定や監査ログが迂回される。③取込の権限は**種別ごとに単票APIと同じロールグループ**(受入は在庫・物流オペレーション)。④行は保存しながら進めるので、後の行は前の行の結果(登録済みロット番号の重複判定など)を前提にでき、検証のみも実際に登録してからロールバックする。他のマスタ・実績はIDではなくコード・番号で参照する。⑤**作業指示は「指図番号+工程順序」で指す**。自動採番の指図番号は取込前に分からないため、製造指図CSVに限り指図番号の手入力を許す(自動採番の形式 `MO〜` と重なる番号は、採番テーブルの連番と後で衝突するため拒否)。製造指図CSVは1行で登録・承認・工程展開まで進められるが、承認は省略できない(展開は承認済みの指図だけ)。⑥**実行記録の記録者は取込を実行したユーザー**とし、作業者を指定する列は持たない(他人名義の実績を作れると、記録者に意味が無くなる)。投入ロットはロット番号で、日時はオフセットの無い値を工場の時刻として読む。生産実績の直は開始日時で決まる。⑦**検査CSVは `InspectionKey` が同じ行を1件の検査指示にまとめる**。キーはファイルの中だけの名前でDBに残さない(検査指示番号は自動採番のままにし、後続のCSVから検査指示を指す必要も無いため)。まとまりに含まれる検査項目がその指示の対象になり、`Judge=true` なら実績に続けて総合判定する(ロットの状態反映・不合格時の不適合起票も単票APIと同じ)。⑧**出荷は指示・判定・実行の3種別に分ける**(判定は品質保証、指示と実行は物流の権限で、1種別にまとめると③を満たせない)。出荷指示CSVは出荷番号が同じ行を1件の指示(1行=1品目の明細。同じ品目を2行書けない)にまとめ、後続の判定・実行CSVから番号で指せるよう**出荷番号を必須の手入力**とする(⑤と同じ理由で自動採番の形式 `SH〜` と重なる番号は拒否)。出荷判定CSVは1行=1件の判定で、`Approve=true` なら続けて承認する。出荷実行CSVは出荷番号が同じ行を1回の出荷にまとめ、**承認済みの判定(可・特採)とロットの使用可否は単票APIと同じく出荷実行の処理で判定する**(判定の無い指示を含むファイルは全件取り消し)。⑨**保全は指示と実績の2種別に分ける**。保全指示CSVは1行=1件の指示で、保全実績CSVから指せるよう**保全指示番号を必須の手入力**とする(⑤と同じ理由で `MT〜` は拒否)。単票APIと同じく突発依頼は誰でも、計画保全の指示は保全担当者(`MaintenanceOrderService.PlannedOrderRoles`)だけが登録でき、CSVでは行ごとに取り込んだユーザーのロールで判定する。**保全計画CSV**は1行=1件の計画で常に新規登録する(設備×年度×区分でも同じ区分の計画が複数ありうるため自然なキーが無く、マスタCSVのように上書きしない。権限は単票と同じ `MaintenanceManage`)。計画には番号が無いので、保全指示CSVの `FromPlan=true` の行は**設備と予定日が一致する未指示の計画が1件だけのとき**にその計画から作り、計画を指示済みにする(0件・2件以上は行エラー。同じ設備の計画は予定日を分ける)。保全実績CSVは保全指示番号が同じ行を1件の実績にまとめ、1行に消費部材を1つ(ロット番号・払出元・数量)書ける。実施者は取り込んだユーザーで、手順書の必要スキルもこのユーザーと照合する。権限は単票と同じ `MaintenanceManage`。登録で指示は完了するので、1件の指示に実績は1件だけ。資産管理部品を書いた行・在庫不足は単票と同じく拒否する。⑩**番号の無い記録は1行で完結させる**。治工具の引当CSVは1行=1件の引当で、`Issue`・`Return` の列で払出・返却まで進め、後のファイルからは指さない(引当・払出の両方で `ToolIssuePolicy` が使用中・メンテ中・寿命到達を拒否する)。治工具の利用実績CSVは記録日時(`RecordedAt`)を指定でき、空欄なら取り込んだ時刻とする(寿命の累計はメンテで寿命をリセットした時刻より後の記録だけを数えるので、リセットより前の日時の記録は累計に入らない)。検査機の校正CSVは1行=1回の校正で、単票と同じく検査機の最終校正日・次回期限(省略時は校正周期から)を更新する。⑪**在庫オペレーションは1種別にまとめ、`Operation` 列で操作を選ぶ**(移動・数量調整・状態変更・分割・統合・振替・廃棄・返品・払出戻し。操作ごとに種別を分けると取込画面のパネルが9枚増えるため)。1行=1操作で、単票と同じ `LotOperationService` の同名メソッドを呼ぶ。操作ごとの必須列はコードで検査する(数量調整の理由は単票でも必須)。分割・振替は新ロット番号(`NewLotNumber`)を指定できるので、同じファイルの後の行から新しいロットを指せる。ロット系譜・状態履歴・監査ログは単票と同じに残る。⑫**物流の指示**:搬送指示CSVは番号が無いので1行=1件で、`Execute` の列で移動の実行まで進める。ピッキング指示CSVはピッキング番号(必須の手入力。`PK〜` は拒否)が同じ行を1件の指示にまとめ、1行=1明細(品目と数量)。ロット・ロケーションは単票と同じく先入れ先出し(有効期限優先。期限切れは引き当てない)で自動引当し、`Execute` で払出まで進める。棚卸指示CSVは棚卸番号(必須の手入力。`ST〜` は拒否)と対象ロケーションで作り、作成時点の在庫が明細になる。実棚数CSVは棚卸番号と明細のロット番号+ロケーションで指し、`Finalize` で確定(差異の棚卸調整)まで進める。⑬**不適合CSVは1行=1件の不適合**で、不適合番号(未登録なら新規起票。`NC〜` は拒否)か、番号を空欄にしてロット番号で指し、`Action`(対応指示)→`ActionRecord`(対応記録)→`Approve`(承認)の列があればその順に進める。検査の不合格で自動起票された不適合は番号が取り込むまで分からないため、**ロット番号で指せるのはそのロットの未完了(クローズ前)の不適合が1件だけのとき**に限る(0件・2件以上は行エラー。どれを進めるかを推測で決めない)。起票と対応記録は誰でも、対応指示と承認は単票と同じく品質管理の担当者だけ(行ごとに取り込んだユーザーのロールで判定)。⑭**サンプル品保管CSV**は1行=1件で、未登録のサンプル番号(`SP〜` は拒否)なら採取(在庫から抜く)、`Close`(払出・廃棄)を書けば保管を終える。登録済みの番号の行は保管の終了だけを行う - **CSVのZIP一括取込・一括出力**:複数のCSVをまとめたZIPを1回で取り込む(マスタは `POST api/masters/csv/bundle`、実績は `POST api/actuals/csv/bundle`)。**ファイル名の昇順に取り込み、種別はファイル名の最初の「_」より後ろで決める**(`01_work-centers.csv` → `work-centers`。同じ種別を番号違いで複数入れてよい)。CSV以外のファイル(README.md等)は無視する。**全ファイルを1つのトランザクションで処理し、どれか1ファイルでもエラーがあれば全ファイルを取り消す**(後のファイルが前のファイルの登録結果を参照するのでファイルごとに保存はするが、途中まで反映された状態が残るとどこから取り込み直せばよいか分からなくなるため)。エラーが出たファイルより後は処理せず、未処理として名前を返す。**マスタと実績が混ざったZIPは受け付けない**(取込の権限も対象画面も異なるため、別のZIPにする)。取込には**ZIPに含まれる全種別の取込権限**が要り、1種別でも権限が無ければ何も取り込まない。種別が分からないファイルは取り込む前に拒否する。ZIP爆弾対策として、CSVの数・1ファイルと合計の展開後サイズに上限を設け、読みながら数えて超えたら打ち切る。一括出力(`GET api/masters/csv/bundle`)は全マスタを取り込む順の番号付きファイル名でZIPにし、そのまま一括取込に使える(参照を絞っている種別は権限が無ければ含めない。ユーザーはパスワードを出力しないため、新しいDBへ移すときはユーザー系のファイルに初期パスワードを書き足す)。実績の一括出力は持たない - バーコード/QRスキャン共通コンポーネント(ブラウザのカメラAPI or USB HIDリーダー入力) @@ -684,7 +685,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと - **参照系と更新系の線引き**:参照系は認証済みユーザー全員に開放し、更新系のみロールで絞る。ただし**コントローラのクラスに `[Authorize(Roles = ...)]` を付けてはならない**。認可属性はクラスとアクションで合成されるため、クラスで絞るとアクション側の `[Authorize]` では参照系を開放できない(出荷・出庫・棚卸で実際に、出荷判定を担う品質保証ロールが出荷指示を参照できなくなっていた)。クラスは `[Authorize]` とし、更新系のアクションへ個別にロールを付ける - **製造実行の記録の権限**:着手・段取り・チェックリスト・部材投入・実績報告・製造条件データ・作業時間の記録は、システム管理者・生産管理担当者・現場作業者に限る(`RoleGroups.ShopFloorRecord`)。現場作業者ロールの定義(1.2節)がまさにこの範囲であり、品質・保全・物流の担当者が製造実績を報告できる状態は監査上説明できないため - **CSV取込の権限は単票APIに揃える**:マスタCSVの取込に必要なロールは、そのマスタの単票API(`POST`/`PUT`)と同じにする。CSVは同じマスタへの別の入口であり、片方だけ緩いと「画面のフォームからは登録できないマスタが、CSVからは書き換えられる」状態になる(スキル・資格で実際に起きていた)。種別ごとの必要権限は`MasterCsvKinds`が持ち、`MasterCsvController`はそれを見て判定する -- **異常・使用実績の記録は絞らない**:設備稼働報告・治工具使用実績・保全依頼・不適合報告は、認証済みであればロールを問わず記録できる(上の「更新系はロールで絞る」の意図的な例外)。気づいた人がその場で上げられることを優先し、絞って報告が落ちるほうが害が大きいと判断する。これらに対する**指示・承認・判定は従来どおりロールで絞る** +- **異常・使用実績の記録は絞らない**:設備稼働報告・治工具使用実績・保全依頼・不適合報告は、認証済みであればロールを問わず記録できる(上の「更新系はロールで絞る」の意図的な例外)。気づいた人がその場で上げられることを優先し、絞って報告が落ちるほうが害が大きいと判断する。これらに対する**指示・承認・判定は従来どおりロールで絞る**。**保全実績の登録はこの例外に含めない**(保全依頼と違い、在庫の引落し・保全指示の完了・設備の稼働可能への復帰・治工具の寿命リセットまで動かす。報告ではなく作業の完了の記録なので、保全担当者 `MaintenanceManage` に限る) - **初回パスワード変更の強制**:初期管理者のシードおよび管理者によるユーザー作成・パスワードリセットで発行した資格情報は、パスワード変更が済むまでパスワード変更以外のAPIを使えない。アクセストークンに未変更を示すクレームを載せ、API側(`Api/MustChangePasswordFilter`)が参照系も含めて403で拒否する(クライアント側の画面誘導だけでは、デスクトップ配布で画面に表示する初期パスワード(7.8節)のまま全APIを操作できてしまうため) ### 7.5 性能・規模 diff --git a/src/MesApp.Api/Controllers/MaintenanceOrdersController.cs b/src/MesApp.Api/Controllers/MaintenanceOrdersController.cs index 0864e2b..3e88eb9 100644 --- a/src/MesApp.Api/Controllers/MaintenanceOrdersController.cs +++ b/src/MesApp.Api/Controllers/MaintenanceOrdersController.cs @@ -89,8 +89,10 @@ public async Task> Create( /// /// 保全実績の登録(E-40-30-01)。登録と同時に指示は完了。元計画は完了、 /// 治工具メンテでresetToolLife指定時は寿命カウンタをリセットする(E-60-30)。 + /// 在庫の引落し・設備の復帰・寿命のリセットまで動かすため、突発依頼と違い保全ロールに限る(Spec.md 7.4)。 /// [HttpPost("{id:int}/record")] + [Authorize(Roles = MesRoleGroups.MaintenanceManage)] public async Task> AddRecord( int id, MaintenanceRecordRequest request, CancellationToken ct) { diff --git a/src/MesApp.Api/Services/ActualCsvKinds.cs b/src/MesApp.Api/Services/ActualCsvKinds.cs index 955c020..a0281e8 100644 --- a/src/MesApp.Api/Services/ActualCsvKinds.cs +++ b/src/MesApp.Api/Services/ActualCsvKinds.cs @@ -238,7 +238,7 @@ public static class ActualCsvKinds new("PartLocationCode", "払出元ロケーションコード", false, "消費部材を書くときは必須"), new("PartQuantity", "消費数量", false, "消費部材を書くときは必須"), new("PartNote", "部材の備考", false, null), - ]), AnyRole), + ]), MesRoleGroups.MaintenanceManage), new(new CsvKindInfo(ToolUsages, "治工具の利用実績", false, [ new("ToolCode", "治工具コード", true, "登録済みで有効な治工具"), diff --git a/src/MesApp.Client.Web/Pages/Maintenance/MaintenanceOrdersTab.razor b/src/MesApp.Client.Web/Pages/Maintenance/MaintenanceOrdersTab.razor index 621b4fd..5c6dac5 100644 --- a/src/MesApp.Client.Web/Pages/Maintenance/MaintenanceOrdersTab.razor +++ b/src/MesApp.Client.Web/Pages/Maintenance/MaintenanceOrdersTab.razor @@ -121,8 +121,10 @@ } + @* 保全実績の登録・取消は保全ロールだけ(APIと同じ定数。突発依頼の起票は全ロールに開いている) *@ @if (order.Status == MaintenanceOrderStatus.Instructed) { +
@@ -184,10 +186,9 @@
- - - +
+ }
} diff --git a/tests/MesApp.Api.Tests/MaintenanceTests.cs b/tests/MesApp.Api.Tests/MaintenanceTests.cs index 2356d58..e7dc155 100644 --- a/tests/MesApp.Api.Tests/MaintenanceTests.cs +++ b/tests/MesApp.Api.Tests/MaintenanceTests.cs @@ -972,7 +972,7 @@ public async Task 指示発行済みの保全計画は指示を取り消すま } [Fact] - public async Task 突発の保全依頼は作業者も起票できるが計画保全は保全ロールのみ() + public async Task 突発の保全依頼は作業者も起票できるが計画保全と保全実績は保全ロールのみ() { using var factory = new ApiFactory(); using var admin = await TestAuth.CreateAdminClientAsync(factory); @@ -996,6 +996,19 @@ public async Task 突発の保全依頼は作業者も起票できるが計画 var plan = await operator_.PostAsJsonAsync("/api/maintenance-plans", new MaintenancePlanRequest(equipment.Id, MaintenanceCategory.Periodic, 2026, null, null, null)); Assert.Equal(HttpStatusCode.Forbidden, plan.StatusCode); + + // 保全実績の登録は保全ロールのみ(在庫の引落し・設備の復帰・寿命のリセットを動かすため)。単票もCSVも同じ + var order = await spot.Content.ReadFromJsonAsync(); + var record = await operator_.PostAsJsonAsync($"/api/maintenance-orders/{order!.Id}/record", + new MaintenanceRecordRequest(DateTimeOffset.Now.AddHours(-1), DateTimeOffset.Now, null, "点検完了", null)); + Assert.Equal(HttpStatusCode.Forbidden, record.StatusCode); + var csv = await Phase3TestData.PostActualCsvAsync(operator_, "maintenance-records", $""" + MaintenanceNo,StartedAt + {order.OrderNo},2026-09-24 09:00 + """); + Assert.Equal(HttpStatusCode.Forbidden, csv.StatusCode); + var unchanged = await admin.GetFromJsonAsync($"/api/maintenance-orders/{order.Id}"); + Assert.Equal(MaintenanceOrderStatus.Instructed, unchanged!.Status); } [Fact] From 547d5e1551407a4312effcfc3307f66f7109cd33 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Fri, 23 Oct 2026 08:08:37 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BE=9D=E5=AD=98=E3=83=91=E3=83=83?= =?UTF-8?q?=E3=82=B1=E3=83=BC=E3=82=B8=E3=81=AE=E6=9B=B4=E6=96=B0=E7=A2=BA?= =?UTF-8?q?=E8=AA=8D=E3=81=A8=E8=84=86=E5=BC=B1=E6=80=A7=E3=83=81=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=82=AF=E3=82=92=E5=AE=9A=E6=9C=9F=E5=AE=9F=E8=A1=8C?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dependabot(nuget・github-actions):毎週月曜 09:00(JST)に確認し、dev 向けの PR を作る。 担当者を自分に割り当て、GitHub の通知(Inbox)と Assigned の一覧に出す。 Microsoft.* / System.* は版ずれ(NU1605)を避けるため1つの PR にまとめる - Vulnerability ワークフロー:push・PR と週1回の定期実行で、推移的な依存も含めて 既知の脆弱性を一覧にし、見つかったら失敗させる。復元時の NuGet 監査は警告がエラー扱いで 一覧が出る前に落ちるため、復元では止めてこの手順で判定する Co-Authored-By: Claude Opus 5.5 --- .github/dependabot.yml | 51 ++++++++++++++++++++++ .github/workflows/vulnerability.yml | 66 +++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/vulnerability.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0031fbc --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,51 @@ +# 依存パッケージの更新確認(週1回)。更新があれば dev 向けの PR を作る +# PR は担当者に自分を割り当て、GitHub の通知(Inbox)と「Assigned」の一覧に出す +version: 2 +updates: + - package-ecosystem: nuget + directory: / + target-branch: dev + schedule: + interval: weekly + day: monday + time: "09:00" + timezone: Asia/Tokyo + assignees: + - msmsrep + commit-message: + prefix: "依存更新" + groups: + # Microsoft.* / System.* は同じサービシングで揃えて上げる(版がずれると NU1605 の格下げエラーになる) + dotnet: + patterns: + - "Microsoft.*" + - "System.*" + update-types: + - minor + - patch + others: + patterns: + - "*" + exclude-patterns: + - "Microsoft.*" + - "System.*" + update-types: + - minor + - patch + + - package-ecosystem: github-actions + directory: / + target-branch: dev + schedule: + interval: weekly + day: monday + time: "09:00" + timezone: Asia/Tokyo + assignees: + - msmsrep + commit-message: + prefix: "依存更新" + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/vulnerability.yml b/.github/workflows/vulnerability.yml new file mode 100644 index 0000000..eeec040 --- /dev/null +++ b/.github/workflows/vulnerability.yml @@ -0,0 +1,66 @@ +# 依存パッケージの既知の脆弱性チェック(推移的な依存も含む)。見つかったら失敗させる +# コードを触っていない期間に公開された脆弱性にも気づけるよう、週1回の定期実行もかける +# (定期実行は既定ブランチ main で動く) +name: Vulnerability + +on: + push: + branches: [main, dev] + pull_request: + schedule: + # 毎週月曜 09:00(JST)。Dependabot の確認と同じ時刻 + - cron: "0 0 * * 1" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: vulnerability-${{ github.ref }} + cancel-in-progress: true + +jobs: + vulnerable-packages: + # ソリューションに MesApp.Desktop(net10.0-windows)を含むため Windows で復元する + runs-on: windows-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + # 警告をエラーにしているため、復元時の NuGet 監査(NU1901〜1904)で先に落ちて一覧が出ない。 + # 復元では監査を止め、次の手順でパッケージ・重大度・アドバイザリを一覧にして判定する + - name: 復元 + run: dotnet restore ParallelFactoryMES.slnx -p:NuGetAudit=false + + - name: 脆弱なパッケージの確認 + shell: pwsh + run: | + $json = dotnet list ParallelFactoryMES.slnx package --vulnerable --include-transitive --no-restore --format json | Out-String + if ($LASTEXITCODE -ne 0) { Write-Output $json; exit 1 } + $report = $json | ConvertFrom-Json + $found = foreach ($project in $report.projects) { + foreach ($framework in @($project.frameworks)) { + foreach ($package in @($framework.topLevelPackages) + @($framework.transitivePackages)) { + if (-not $package) { continue } + foreach ($v in @($package.vulnerabilities)) { + [pscustomobject]@{ + Project = Split-Path $project.path -Leaf + Package = $package.id + Version = $package.resolvedVersion + Severity = $v.severity + Advisory = $v.advisoryurl + } + } + } + } + } + if ($found) { + $found | Sort-Object Package, Advisory -Unique | Format-Table -AutoSize | Out-String -Width 300 | Write-Output + Write-Output "::error::既知の脆弱性があるパッケージが $(@($found | Sort-Object Package -Unique).Count) 件あります。修正版へ更新してください。" + exit 1 + } + Write-Output "脆弱なパッケージはありません。"