JSAセミナー二日目 Audit Finds System

企業向けの二日間のセミナー リモートなのでコミュニケーションが難しい

Audit Finds System 審査計画の統合

指摘作成(AUD-TOP)から入ると、規格ごとに審査計画が裏で作られる(被審査組織 × 対象ISO × 審査種別で一意)、しかし複数のISOシステムの統合(複合)審査がある
同じ被審査組織の同じ審査(例:QMS と EMS の統合審査)が別々の計画になったとき、後から1つの計画(統合審査計画書)にまとめる

確定した規則
項目規則
入口統合先の AUD-PLAN(表示)に[他の計画を統合]
管理者(role 1/5)だけに出す
統合できる計画同じ被審査組織
どちらも Close 前
規格が重ならない(同じ規格を持つ計画は種別が違っても不可)
予約組織「その他」は不可
移す側の計画削除し、統合の記録を残す(取り消しは無い)
指摘番号移す側の指摘は、統合先の続き番号を振り直す(移す側の番号順を保つ)
審査部署同名の部署は1つにまとめる(統合先の部署に指摘を移す)
チェックシート統合先を残す
移す側に記入があれば確認画面で示す(記入内容は統合の記録に写しを残す)
審査チーム合わせる
移す側のリーダーはメンバーにする
期間両方を含むよう広げる
権限管理者だけ

JSAでセミナー二日間 Audit Finds System

商工会議所のJSAに、今日と明日はリモートである組織のセミナーを実施する

Audit Finds System再構築

変更内容
対象 内容
指摘一覧(AUD-FLIST)の[開く]指摘の詳細(AUD-FIND-M1)を最初から開いた状態で表示する
指摘リスト(AUD-FIND の表・審査日・件数)は出さない
AI 支援直接開いた表示でも使える。AI 支援を閉じると(反映しなくても)指摘の詳細に戻る(ia-support.js が閉じたことを知らせるイベントを出すようにした)
[是正処置](新設)指摘一覧の不適合の行に追加。是正処置報告書(AUD-CA)の「指摘一覧へ」で、絞り込みのまま一覧へ戻る(保存後も戻り先を引き継ぐ)
戻り先の検証(App\Support\FindingListReturn・新規)戻り先 URL は利用者が書き換えられるため、指摘一覧のパスだけを受け付け、相対 URL に組み直す(よそのサイト・別の画面・javascript: は無視して初期表示の指摘一覧へ)
他の部署の指摘 ID無視して通常の AUD-FIND を表示する
タブ直接開いた表示では[指摘一覧]タブを選んだ状態
変えていないもの指摘の保存処理(部署単位の一括保存と楽観ロック)/AUD-PLAN・AUD-SUM から AUD-FIND に入る使い方/画面コード(M1 は AUD-FIND のモーダルのまま)
ヘルプ・文書指摘一覧のヘルプ(【開く】【是正処置】)/CLAUDE.md §1・§6(判断25・統合の確定事項)/audit-ui スキル
検証
検証結果
php artisan test562 passed(2737 assertions)C7FindingListTest に2本追加
(直接開く・戻り先の検証・他の部署の ID・是正処置の戻り先/Close 済みは見るだけ)
npm run build実行済み
(ia-support.js を変えたため成果物をコミット)
ブラウザ
(一時 SQLite・管理者)
一覧(製造部で絞り込み)→[開く]→ 詳細が開き指摘リストは出ない → 内容を直して「決定・保存」→ 絞り込みのまま一覧へ戻り修正が反映
「キャンセル」・Esc でも戻る
AI 支援を開いて閉じると詳細に戻る
(AI 支援中の Esc では移動しない)
[是正処置]→「指摘一覧へ」で絞り込みのまま戻る
Close 済みは保存ボタンなし。画面のエラー 0 件
マイグレーションなし
MariaDB での
audit:smoke-check
未実施(PC の Claude Code が §10 の手順で実施)
今回は DB の処理を変えていない

QMACサイト改善

朝から小雨が降る 広島みなと公園にキクと散歩
5.Google Search Console
  • ドメインプロパティ qmacサイト を office QMAC 名義で登録し、確認は Xserver の DNS に TXT を追加(既存のSPF の行は変更していない)
  • TXT レコードは削除しないこと(削除すると所有権の確認が外れる)、サイトマップ(wp-sitemap.xml)を2026-10-06 に送信

QMACサイトの改善

1.サイトのセキュリティ
  • 発見した問題:管理者のログイン名が REST API とサイトマップで公開されていた(id=1)
  • 対処:管理者アカウントを新規作成して旧アカウントを削除・・qmac-core に security-hardening.php を新設し、バージョン表示・XML-RPC・RSD・未ログイン時の REST ユーザー一覧・投稿者サイトマップ・投稿者ページを閉じた(テーマを替えても消えないようプラグイン側に配置)
  • 既存の防御:cloudsecure-wp-security のログイン試行制限(30秒5回で600秒ロック)・ユーザー名列挙防止・XML-RPC 無効化が有効、管理者ログイン通知を有効化
  • 復旧手順:締め出し時の手順を「10分待つ → 再設定メール → SSH でパスワード変更 → 設定の書き換え→ プラグイン停止(設定の控えから復元)」の順に整理し、world で検証
2.資料室の作成(運営委員向け・非公開資料)
  • 既存の作り(公開フォルダ外への保存、PHP 経由の配信、30日で自動削除)が要件を満たしていることを確認
  • 追加:操作記録(誰が・いつ・どのファイルを提出/取得/削除したか。表示名のみ記録、1年保存)、自動削除の最終実行の表示と48時間超の警告、利用案内(ダウンロード記録とサーバのバックアップに最大14日残)
3.SEO対策
  • 基本設定:Title(ページ題名:ページの主題が伝わり、クリックされやすくなる)、Description(説明文:開く前に内容が分かる)、h1(見出し:何のページかを検索エンジンに正しく伝える)、Canonical(正式な住所:同じページの評価が分散しない)、言語・スマホ表示:スマホ基準の評価、年度ページ・静的アーカイブに h1、サイドパネルを nav 化、一覧系に canonical、全ページに OGP と twitter:card、トップに rganization・WebSite、予定の行事に Event(会場住所、会場とオンラインの併用、画像、説明文)
  • 第2弾:旧サイト URL の転送を35本から大幅に拡充し、旧ディレクトリは 410 に、旧 URL が無関係なページへ飛ばされていた WordPress の推測転送を防止、誤字スラッグ4件の修正と、新規行事への英数字スラッグ(開催日+ID)の自動付与
  • 確認結果:リッチリザルトテストで、トップ(組織・地域のお店やサービス)と行事(イベント)がいずれも有効、エラー0件、残る任意の指摘は offers・performer のみ(事務局の入力負担を増やさないため対応しない)
  • OGP 画像:協会ロゴと名称入りの 1200×630 画像を作成・配置。共有プレビューで表示を確認
4.訪問者カウンター設置
  • 目的:Xserver のアクセス解析はBOTを含み実態が不明、実際の訪問をカウント
  • 仕組み:ページ表示後に JavaScript が通知を送り、サーバ側で検証して日付×ページの件数だけを保存、ボット・ログイン中の利用者・資料室は数えない
  • プライバシー:IP アドレスと Cookie は保存しない。重複判定用の値は当日だけ使い、翌朝までに破棄(受信時とサーバの cron の両方で実行)
  • 事務局のダッシュボード「アクセス状況」に今月の訪問数・閲覧数、先月比、閲覧の多いページ上位10件。計測開始は 2026-10-05(初日は TAM の確認の閲覧を含む)

キクと散歩 サイトのセキュリティとバックアップ

昨日に続いて、今日も雨の中、みなと公園にキクの散歩

1.QMACサイトの画面の改善

1-1. 静的アーカイブ(2007年以前のHP)をテーマの枠中に

1992〜2007年度の旧サイトHTML 39本が、ヘッダー・サイドバー・フッターの外に置かれていた
原本は書き換えず、配信のたびにPHPで変換する方式とした・・旧サイトの記録としての価値を損なわずに、見た目だけを揃る

/archive/2007/ → 00Index/Activities/2007(H19).htm を読む
→ の中身だけ抽出
→ 挿入ナビ・SSIコメント・重複フッターを除去
→ 相対パスを絶対URLに変換
→ .qmac-legacy で包んでテーマのテンプレートに流し込む

1-2. その他の改善
  • 連絡先の移動・・ フッターは画面下端で見えないため、サイドバー最下部へ
  • フッター 「© 2026 中国地区品質経営協会」のみ中央寄せ
  • マニュアル
    管理者・編集者以外にはサイドバーに表示しない
  • ログインボタン
    ヘッダー右下。未ログイン時「ログイン」、ログイン時「管理画面」

2.QMACサイトのセキュリティ対策

2-1. 現状調査
観点評価
攻撃されやすさ 良好 — プラグイン1本、パーミッション適正、改ざんなし
侵入時の被害 やや弱い — 管理者が管理画面からPHPを書き換えられた
気づけるか 弱い — 改ざん検知なし
戻せるか最も弱い — バックアップが全て同一サーバー内
続けられるか最も弱い — プラグイン・テーマの自動更新がオフ

WordPressサイトの多くは「プラグイン20本・未更新・権限管理なし」という状態にあることが多い

主な発見

発見深刻度
プラグイン・テーマの自動更新がオフ高
バックアップが同一サーバー内のみ高
XML-RPC が有効(system.multicall が使える)中
WWWアドレスが暗号化されず表示中
セキュリティヘッダがほぼ未設定中
検証環境に wp-config.php.orig(DBパスワードが平文) 中
公開フォルダに.bak系が25本低
DISALLOW_FILE_EDIT が未設定 中
2-2. 実施した対策
  • ① wp-config.php.orig の削除・・検証環境の公開フォルダに、DBのパスワードが平文で書かれたファイルが置かれていた・・.orig はPHPとして処理されないため、Basic認証が外れた瞬間に中身がそのまま読める
  • ② .bak 系61本を公開フォルダ外へ・・.bak → .new → php -l → mv という作業手順を守った結果、2日間で61本が蓄積していた・・手順そのものは正しいが、公開領域に残す理由がない
  • ③ DISALLOW_FILE_EDIT・・管理画面からのテーマ・プラグイン編集を禁止・・管理者が乗っ取られても、PHPを書き込まれない・・ISALLOW_FILE_MODS は入れていない(自動更新まで止まるため)
2-3.自動更新の有効化

公式テーマとXserver製プラグインの自動更新で壊れる確率は低いので、自動更新にする
cloudsecure-wp-security → 自動更新 ON
twentytwentyfive(親) → 自動更新 ON
qmac / qmac-core(自作) → 対象外

2.4.HTTPS常時化とセキュリティヘッダ

http://qmac.jp/ がそのまま200で表示されていた。暗号化されない経路が生きている状態
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Header always set X-Content-Type-Options “nosniff”
Header always set X-Frame-Options “SAMEORIGIN”
Header always set Referrer-Policy “strict-origin-when-cross-origin”

Strict-Transport-Security と Content-Security-Policy は入れていない。設定ミスでサイトが開かなくなり、HSTSはブラウザが記憶するため取り消しが効きにくい

2-4.XML-RPC の無効化

system.multicall は1リクエストに数百通りのパスワードを詰められる。ログイン試行制限を実質的に回避される・・無効化の前に POST system.listMethods が 78メソッドを返すことを実測し、変更後に403になることを確認

▶この続きを見る・・・・

キクと散歩 QMACサイトの本格的稼働

なぎさ公園をキクと散歩 小雨が降っている

QMACサイトの本格的稼働

1.本番切替(.jp)

テスト用に.worldを構築していたので、その内容を本番の.jpに移行

  • ドメイン付け替え 旧アカウント(awl-web)から削除 → 協会の新サーバーのアカウント(xsXXXX66)へ追加
  • サイト配置 事前構築済みの qmac_jp_build を rsync。DB は xsXX5766_wp2
  • URL置換 qmac.world → qmac.jp 640件(事前算出値と完全一致)
  • DNS・SSL Aレコード XX.XXX.221.147、無料独自SSL発行
  • 旧サイト保全 2.5GB・11,373件・・手元とサーバーに二重保管
2.行事の新規・修正の管理画面改善

行事を作成・修正する編集画面は、Wordpressの標準から独自のソフトで構築したため、編集機能の右サイドバーメニューの縦側が大幅に長くなって、かなり下までスクロールしないと、編集作業ができないばかりか、良く機能が分からない状態だったので、UIを含めて大幅な改善をする

  • 管理バーから「サイトを編集」を削除(開いても編集できず表示が崩れるため・・Wordpress標準だが使えない)
  • 抜粋の改行バグを修正(改行だけ残ると一覧が空白になる)・・保存時に post_excerpt を trim(不要な空白等を自動削除)
  • 行事リストで内容が分からないので、行事一覧にタイトル+副題の連結する、開催日列の書式・ソート
  • 使用しないアイキャッチを非表示(行事・固定ページ・投稿)
  • 写真の代替探索を削除(削除しても消えない問題を解消)
  • トップの写真帯を行事ごとにグループ化
  • 年の桁数を4桁に制限、全画面モード既定OFF、スラッグ欄を編集者から非表示
3.右サイドバーメニューの縦方向圧縮

幅を420pxに広げ、2列化。写真と資料のパネル分離、▲▼での並べ替え、複数枚の一括選択、重複除外を実装

  • 2,849px → 約1,600px(−44%)
  • 行事の詳細 589px →313px
  • 写真・資料
    1,685px→
    917px(写真/資料に分離)
4.マニュアル更新

パネル名・ボタン名の変更に伴う15か所、さらに古くなった記述6件を修正・・抜粋の説明を新規追加

▶この続きを見る・・・・

キクの脱走 QMACサイトの新サーバ構築

また、朝キクが脱走していて、犬を散歩させている近くの叔母さんが、連れて来てもらった・・・急に、脱走し始めたのでどこに原因があるかを探すと、カレーの厨房に2カ所に抜道を発見、さっそく合板で穴を塞ぎ、ついでに長い間て片付けていなかったカレーの厨房と中庭、バルコニーを全員で大掃除
かなりの不要材を整理する
甲斐犬のキクの脱走はすっかり近所では有名になり、マークされる存在となった
2~3日前から、少し喉が痛い
昼からは何となく寒くなり、夕方まで寝て過ごす

QMACサイト本番用のDB作成

QMACサイトの新しいサーバにはテスト用の.worldのDBがあり、新しく本番用のDBをMysqlで作成して、管理者パスワードを設定し、.worldの内容を本番用にコピーして、BASIC認証は削除する

  • cp -a ファイルを複製 → qmac_jp_build/
  • wp db export DBをテキストに書き出し → qmac_cutover.sql
  • wp db import 別のDBに流し込み → xs815766_wp2
  • dry-run 640件と予告(DBは無傷)
  • 本実行 640件を書き換え
  • 残存確認 0件 → 漏れなし
wp-config.php を新DB用に書換

変更箇所

  • DB_NAME → xs815766_wp2
  • DB_USER / DB_PASSWORD → 管理者パスワード
  • コピーした認証キー8行(AUTH_KEY 等のSALT)を差し替え — https://api.wordpress.org/secret-key/1.1/salt/ で生成して差し替えする
  • 認証キーについて、wp-config.php の中に、WordPressが自動生成した8行の鍵・・不正アクセスが疑われるとき、管理者が交代したときは、wp config shuffle-salts で作り直す
甲斐犬のキク

シルバーウイーク QMACサイトの移行について

今日からシルバーウイークだが、台風の影響もあり天気が悪いので、キャンプは中止・・家でノンビリ・・・・敬老の日での町内会からのお祝い
切替で何が起きるか
レコード切替前切替後
NS ×5ns1〜5.xserver.jp変わらない
A(3本)XXX.XX.XXX.XXX協会サーバーのIP(自動設定)
MXXXXX.jp自動で再作成される
TXT(SPF)svXXXX を含む自動生成され、内容が変わる

★注意:旧アカウントから削除した瞬間、ゾーン全体が消えます・・Aレコードが古いまま残る状態より深刻で、ドメインそのものが引けなくなります(名前解決エラー)・・・削除と追加は連続して、間を空けずに実施してください。数分以内が理想

TTLについて

全レコードが3600秒(1時間)です。切替の前日に、Aレコード3本のTTLを300秒に下げておいてください。 切替後の反映待ちが1時間から5分程度に縮みます・・切替が落ち着いたら3600に戻します。

QMACサイトの移行について

DNSレコードの役割
種別役割無いとどうなるか
NSこのドメインの電話帳をどのサーバーが管理しているかを示すドメイン全体が引けない
Aホスト名をIPアドレスに変換Webの接続先
サイトが表示されない
MXメールの配送先を指定メールが届かない
TXT任意の文字列
SPF(送信元の正当性宣言)や所有権確認に使う
なりすましを防げない
認証できない
CNAME別のホスト名の別名(今回は未使用)—

Web(A)とメール(MX)は完全に独立しています・・片方を変えてももう片方に影響しません。今回メールを使っていないので、実質Aレコードだけの話になります

  • NS ×5(ns1〜ns5.xserver.jp)この5本が今回の移行を非常に楽にしています・・ドメインの管理をXserverのDNSサーバーに委任している状態・・旧アカウントも協会アカウントも同じXserverのNSを使うため、アカウントを移してもNSは変わりません→ レジストラ(ドメイン登録業者)側の設定変更が不要、世界中のDNSに伝播する48時間待ちも発生しません・・変わるのはAレコードの値だけ
  • A:XXX.jp → XXX.XX.XXX.XXX・・・現在の旧サーバーのIPです・・切替で変わるのはここ1行(+www・ワイルドカード)・・協会アカウントにドメインを追加すると、Xserverが自動でそのアカウントのサーバーIPに書き換えます・・手で入力する必要はない
  • A:www.qmac.jp → 同じIPwww.qmac.jp でもアクセスできるようにするもの・・ただし切替後、www 有り/無しのどちらかに統一する必要があります。両方が同じ内容で表示されると、検索エンジンから重複コンテンツと見なされます(.htaccess で301リダイレクト)
  • A:*.qmac.jp → 同じIP(ワイルドカード)・・存在しないものを含む、あらゆるサブドメインを受け付ける設定で、abc.qmac.jp でも test.qmac.jp でも、すべてこのサーバーに来ます・・削除は切替が完全に落ち着いてからに
  • MX:XXX.jp(優先度0)・・@XXX.jp 宛のメールを「XXX.jp のAレコードが指すサーバー」に配送する設定、メールを使用していないので機能していませんが、MXが存在する以上、外部から送られたメールは受理されます・・ 受け皿が無ければ捨てられるか、エラーで返ります
  • TXT:SPFレコード・・v=XXX +a:svXXX.xserver.jp +a:qmac.jp +mx include:XXX.sender.xserver.jp ~all、「@qmac.jp を名乗って送信してよいのは、ここに書かれたサーバーだけ」という宣言です。なりすまし対策に使用・・注目すべき点:svXXXX.xserver.jp — これは旧アカウントのサーバー名です。協会アカウントは svXXXX なので、切替後この記述は無意味になります

キクと元宇品の散歩 awl-web.com 保守

キクと元宇品の森を散歩

awl-web.com 保守作業

サーバー環境
  • WordPress 7.1
  • PHP 8.3.33(対応済み)
  • MariaDB 10.5.26
  • テーマ Parabola 2.4.3
  • パーマリンク /archives/%post_id%
  • サーバー応答中央値 199ms(良好)
  • uploads 52.33 GB
  • データベース 321.50 MB
  • themes + plugins 約 180 MB

想定より健全だった。特にパーマリンクが投稿ID方式のため、カテゴリやタグを変更してもURLが壊れない構造になっている。10年分の被リンクが守られる良い設計・・・一方、uploads 52GB は一括バックアップが現実的でないサイズで、実質「バックアップが無い」状態だった。これが最大のリスクと判断

テーブル接頭辞(重要)・・このサイトのテーブル接頭辞は wp_ ではなく action_・・・SQL を書く際は必ずこれに合わせる

  • データベース名: awlweb_db
  • 投稿テーブル: action_posts
  • 設定テーブル: action_options
  • Relevanssiインデックス: action_relevanssi

実施内容

バックアップ体制の確立
  • “Dropbox\04稼動中WebSite\awl-web.com保守”にバックアップ
  • wp-config.php / .htaccess  FTPで手動取得 ・・・完了
  • データベース Xserver サーバーパネル > MySQLバックアップ・・・完了
  • themes / plugins / mu-plugins  FTPで取得(約180MB)・・・完了
  • uploads  年別フォルダごとに取得 ・・・2010年分まで完了
不要ファイルの削除
  • Starter Templates & Sites Pack テーマのデモ読み込み用・・稼働中サイトには不要・・脆弱性報告のある系統
  • WP Fast Search バージョン 0.1 の放置プラグイン・・Relevanssi と機能重複
  • wp-kougabu (778 KB )削除済みプラグインの残骸
  • al2fb_last_error (39 KB )Add Link to Facebook のログ
  • bfa_ata4 (17 KB )削除済みプラグイン
  • ShareAndFollowAdminOptions(13 KB )Share and Follow
  • apl_backup_update_*( 各8KB程度 )Advanced Post List の設定バックアップ(2017〜2020年)
  • hu_theme_options( 7.2 KB )旧テーマ Hueman の設定

QMACサイトの再編とWordPress化

朝は甲斐犬のキクを連れて、元宇品の森に・・かなり涼しくなった

4. 構築過程で発見・対処した問題

8件すべて、実際に動かして判明した内容

  • .htpasswd が公開ルート直下に置かれ、.htaccess は全行コメントアウト(旧サイトの重大な設定不備)
  • 管理画面でカスタムフィールドが編集できない(supports に custom-fields 欠落)
  • 中身のない年度18本もリンク表示され、空ページへ飛ぶ状態
  • 年度アーカイブが機能せず、ブログ形式・投稿日で表示
  • 一括投入で画像圧縮が効かない経路があり、原本1.71MBが残る
  • 静的アーカイブが全ページ文字化け(HTTPヘッダのcharsetがmetaより優先)
  • マニュアルの開催日入力手順が実際の画面と相違(手順どおりに操作すると失敗する)
  • 空の画像ブロック20個がすべて検証エラー

5. 旧サイト由来の誤記(原本どおり投入・訂正待ち)

行事名が空 2件 旧サイトが行事名自体をPDFリンクにしていた
日付の年が1年ずれ 3件 2008年度、曜日は正しく年だけ誤り
曜日が合わない4件 2020〜2023年度
表記の重複誤記 3件 「先進企業視察会視察会」
名簿の疑わしい記載 6件 「幹事→監事」「㈱ダイクレ㈱」等

6. 事務局向けマニュアル

780行・9章+付録2

対象を事務局に絞り、管理者向けの内容とは分けた・・・マニュアルは公開サイト上の固定ページとして設置している・・・更新経路は「ページ上で直接編集」に一本化・・・ 変換スクリプトとページ編集の二経路があると、どちらかの修正が失われる・・・スクリプトは移行用の一度きりのものとして明記のうえ保管

1. 移行前の状態と課題

構成 frameset ベースの静的HTML
規模 773ファイル / 2.74GB
制作 Dreamweaverで約15年間
スマホ対応 なし

2. 資産の棚卸し

破棄したもの

運営委員会PDF 1,534本 / 206MB パスワード運用ごと廃止
死蔵HTML 654本 トップから到達不能な滞留分
制作元データ(.mif / .pef)207MB サイト運用に不要

移行したもの

行事 192件(2008〜2025年度・18年分)
添付ファイル 368件 / 84MB(写真138・PDF230)
固定ページ 8本(協会案内5・名簿2・マニュアル1)
静的アーカイブ 16本(1992〜2007年度)

3. 設計の要点

3-1. データと見た目の分離
親テーマtwentytwentyfive(WordPress公式) 本体と同時に更新される基盤
子テーマqmac(新規作成) 配色・レイアウト・動的ブロック
プラグインqmac-core(新規作成) 投稿タイプ・分類・管理画面整理
3-2. ブロックテーマの子テーマ方式を採用

当初はクラシックテーマを検討したが撤回した・・・クラシックテーマはWordPress本体の更新に追従しにくく、ブロックエディタで書かれた投稿との整合が崩れやすい・・子テーマ方式なら親テーマが本体と一緒に更新され、独自の差分だけを自前で保守すればよい。保守性と自由度が両立する・・・・親テーマが公式テーマである点も重要で、コアチームが保守しており、第三者テーマのように開発停止で行き詰まるリスクが小さい

3-3. 事務局が壊せる箇所を構造的に減らした

「マニュアルに書いてあるから大丈夫」ではなく、そもそも触れないようにする方針

権限 編集者権限(外観・プラグイン・ツールに到達不可)
左メニュー 5項目に限定
ブロック 102種を非表示にし、17種のみ許可
パターン 挿入可能なパターンを0本に
テンプレート 編集欄を非表示にしたうえ、保存自体を拒否
3-4. 年度アーカイブの自動化

現行運用で最も手間だった作業を自動化・・・開催日を入力するだけで、年度タームの作成・付与・サイドパネルへの反映がすべて自動で行われる・・事務局の手作業はゼロ・・・・年度末の切替も、状態を「予定 → 終了」に変えるボタン1つ(取り消し可)に集約

更新の担い手事務局
行事の追加管理画面で入力
年度末の切替ボタンで切り替え
過去年度リンク完全自動
写真の掲載ドラッグで追加(自動圧縮)
スマホ対応あり
▶この続きを見る・・・・

広島競輪場 建設アシストのWebsiteのSEO対策

新しく改築された競輪場に、ホテルのレストランに行ったが予約が無いとだめだった
最初の予定通り、回転ずしに・・・ここも超満員で30分ほど待ちました

対象:https://sys-assist.co.jp/(WordPress / Parabolaテーマ)

作業一覧

サイトタイトルの全角スペース削除管理画面
キャッチフレーズ設定管理画面
サンプル投稿「Hello world!」とコメントの削除管理画面
コメント機能の全面停止 管理画面
開発者プロフィールページの新設 固定ページ
会社概要ページの新設 固定ページ
ISO 14001:2026改訂の解説記事を公開固定ページ
SEO基盤の導入(メタ情報・OGP・構造化データ)mu-plugin 1ファイル
プロフィール写真とOGP画像の作成画像加工
見出し・表・段組みの表示調整追加CSS
日本語URL 4本の英字化管理画面
旧URLから新URLへの301リダイレクトRedirectionプラグイン
パーマリンク構造を「投稿名」に変更管理画面
Google Search Console の登録外部サービス
サイトマップの404不具合の修正と送信 | | mu-plugin修正

個別の施策の意味

meta description

検索結果に表示される説明文です。順位そのものには影響しませんが、クリックされるかどうかを決めます・・今回はページごとに手動で設定しました・・設定していないページは本文の冒頭120文字が自動で使われますが、それでは表の中身が流れ込むなど、不適切な文章になることがあります

OGP(Open Graph Protocol)

SlackやTeams、LINE、X などにURLを貼ったとき、タイトル・説明文・画像のカードとして表示させるための情報です・・BtoBでは、担当者が社内チャットにURLを貼って共有する場面が必ずあります・・ここで無地のリンクが出るか、製品名と写真の入ったカードが出るかで、受け手の反応が変わります・・今回、1200×630ピクセルのOGP画像を作成しました

構造化データ(JSON-LD)

人間には見えない、機械向けの説明書きです。ページのHTMLに埋め込まれ、Googleに次のような情報を明示的に伝えます。

Organization有限会社システムアシストという組織が運営している
WebSite このサイトの正式名称は「建設アシスト」である
SoftwareApplication 建設アシストは業務用のソフトウェア製品である
WebPage / BreadcrumbListこのページの位置づけと階層

文章から推測させるのではなく、決まった形式で直接伝えるため、誤解が起きません。将来的に、検索結果でのリッチな表示(星評価や階層表示など)の土台にもなります

見出し構造(h1 / h2 / h3)

見出しは文字を大きくする装飾ではなく、文書の階層を示す指定です。h1が章、h2が節、h3が項にあたります・・Googleはこの階層を読んで文書の構成を把握します。h1の次がいきなりh5だと、「大見出しが存在しない文書」と解釈されます・・文字の大きさはCSSで自由に変えられます。 見た目のためにタグのレベルを下げる必要はありません。今回、追加CSSでh2を約20pxに調整し、タグは正しい階層のまま使えるようにしました

301リダイレクト

転居届にあたります。 「このURLは、この新しいURLに恒久的に移りました」という宣言です・・301(恒久的)と302(一時的)があり、URL変更時は301を使います。Googleは301を見て、旧URLの評価を新URLに引き継ぎます・・設定しないと、旧URLはただの404(ページなし)になります。これまでに得た評価も、他サイトからのリンクも、すべて失われます・・今回は4本のURLを変更したため、Redirectionプラグインで301を設定しました。

日本語URLを英字にした理由

日本語のURLは、コピーすると次のように変換されます
https://sys-assist.co.jp/%e5%bb%ba%e8%a8%ad%e3%83%97%e3%83%ad%e3%82%b8…
これが200文字以上続きます。メールに貼っても、資料に載せても読めません。他サイトからリンクを張ってもらう際にも敬遠されます・・・投稿が0件の今のうちに変更したのは、影響を受けるURLが最も少ないタイミングだったためです。 記事が増えてから変更すると、大量の301を管理することになります

サンプル投稿の削除

「Hello world!」は、WordPressをインストールすると最初から入っているサンプル記事です・・・これが公開されたまま残っているサイトは、「作りかけで放置されている」と判断されます・・人間にもクローラにも、同じ印象を与えます。SEOの技術論以前の問題として、削除が必要でした

SEOとは何をすることなのか

「SEO対策」という言葉は範囲が広すぎて、何をしているのか分かりにくくなります。実際には、性質の違う4つの層に分かれています。今回の作業も、この4層のどこかに必ず属しています。

層1 見つけてもらう(クロールとインデックス)

Googleは「クローラ」というプログラムを走らせ、Web上のページを片端から読み込んでいます。読み込んだページを整理して保管することを「インデックスに登録する」と言います
インデックスに登録されていないページは、検索結果に絶対に出ません。 順位が低いのではなく、そもそも存在しないものとして扱われます
今回この層に効いた作業
 ・サイトマップの修正と送信(#15, #14)
 ・日本語URLの英字化(#11)
サイトマップは「このサイトにはこういうページがあります」という一覧表です。これがGoogleに届いていなければ、クローラは自力で探し回るしかありません・・実際、今回のサイトではサイトマップが404エラーを返しており、Googleが一覧表を受け取れない状態でした

層2 内容を正しく伝える

インデックスに登録されても、Googleが「このページは何について書かれているか」を誤解すれば、見当違いの検索キーワードで表示されてしまいます
ここで働くのが、ページの見出し構造とメタ情報です
今回この層に効いた作業
 ・meta description の設定(#8)
 ・見出し構造の整理(#10)
 ・構造化データ JSON-LD の出力(#8)
 ・サイトタイトルの修正(#1, #2)

層3 信頼される

Googleは近年、「誰が書いたのか」を強く見ます。 E-E-A-T(経験・専門性・権威性・信頼性)と呼ばれる評価軸です
特に、お金や健康や安全に関わる分野では厳しく評価されます。建設業の安全管理と法規制は、まさにこの分野です。 匿名の記事と、17年間・延べ630回の審査経験をもつ主任審査員が書いた記事とでは、扱いが変わります
ただし、Googleは経歴を推測してくれません。サイトに書いていなければ、存在しないのと同じです
今回この層に効いた作業
 ・開発者プロフィールページ(#5)
 ・会社概要ページ(#6)
 ・構造化データによる組織情報の明示(#8)
作業前のサイトには、誰が作っているのか、どこの会社なのかが一切書かれていませんでした。これはSEO以前に、人間の読み手が判断できない状態でした。

層4 選ばれる

Googleは近年、「誰が書いたのか」を強く見ます。 E-E-A-T(経験・専門性・権威性・信頼性)と呼ばれる評価軸です
特に、お金や健康や安全に関わる分野では厳しく評価されます。建設業の安全管理と法規制は、まさにこの分野です・・匿名の記事と、17年間・延べ630回の審査経験をもつ主任審査員が書いた記事とでは、扱いが変わります・・ただし、Googleは経歴を推測してくれません・・サイトに書いていなければ、存在しないのと同じです
今回この層に効いた作業
 ・title の整理(#1, #8)
 ・meta description の設定(#8)
 ・OGP画像の作成(#9)

建設アシストのWebsiteのSEO対策の実施

実測での変化

ページ数5(うち1件はサンプル投稿)8
<title>建設アシスト …(先頭に全角空白4個)建設作業所の法規制・安全管理をAIで支援するクラウドシステム
meta description 0件全8ページに出力
OGP / Twitter Card0件 全ページに出力
構造化データ(JSON-LD)0件全ページに出力
URL形式日本語(1本あたり200文字超)英字(/about/ /company/ 等)
サイトマップGoogleが取得できない状態正常に処理・登録済み
Google Search Console未登録 登録済み・サイトマップ送信済み
▶この続きを見る・・・・

キクの散歩

今日は少し曇り 京橋川の土手を散歩

システム言語の研究

AIで作成させるシステムでTypeScriptTypeScript、Next.js、Vercel、Supabaseが良いと聞いたので、AIに説明をしてもらった

name役割 Laravel版での相当物
TypeScript 言語(型付きJS)PHP 8.3
Next.js フレームワーク(画面+API一体) Laravel + Blade
Vercel ホスティング(サーバーレス) Xserver
Supabase DB+認証+ストレージ MariaDB + Breeze

利点

  • 1. 型がAIの間違いを機械的に潰す、AIは存在しないプロパティやメソッドを平気で書きます–TypeScriptならビルド時に落ちるので、実行して気づくのではなく書いた瞬間に分かる・・これがAI開発で一番効く要素です。
  • 2. フロントとバックが1言語1リポジトリ、Blade + Alpine.js + PHPのように「JSとPHPの境界」がないので、Claude Codeに渡すコンテキストが一続きになります・・・4,300行のインラインJS外部化のような問題が構造的に発生しません
  • 3. push即プレビューURL、ブランチごとに本番同等の検証環境が自動で立つ。SupabaseもDBブランチを作れるので、DB込みで検証できます。サーバー・ネットワークの知識がほぼ不要です

欠点

  • Next.js 16のApp Router / React Server Componentsは、AIが古い書き方を出す、Pages Router時代のコードが学習データに大量に残っていて、use clientの付け方やデータ取得の作法を混ぜてきます。「AI向き」と言われる割に、ここだけは頻繁に手戻りが出ます。
  • Supabaseのマルチテナント分離はRLS(Row Level Security)が生命線、今のBelongsToTenantグローバルスコープ +AuthorizesTenantAccessは、アプリ層でLaravelが守る構造・・Supabaseはクライアントから直接DBを叩けるので、RLSポリシーを1本書き忘れたテーブルは全テナント筒抜けになります・・・モデル分のポリシーをAIに書かせて、その正しさを検証する体制が新たに必要になる。しかもRLS環境はテストが書きにくい(テストユーザーのJWTをモックするか、service_roleでバイパスするかの判断が要る)。セキュリティ設計の厳しさを一番重視されている方には、ここは素直に減点材料です
  • サーバーレスの実行時間制限、マスキング→Anthropic API→結果整形という監査支援モジュールの処理は、秒数がかさむと関数タイムアウトに当たります・・・Xserverの普通のPHPプロセスのほうが素直な領域です。
  • 従量課金でドル建て、支出上限が設定しづらい、Xserverの固定費に慣れていると読みにくい。数社規模なら安いですが、予測可能性は下がります。

PHPアプリをローカルで開発する環境

PHPアプリをローカルで開発する環境

PHPアプリをローカルで動かすには
  • PHP — コードを実行する
  • Webサーバ — ブラウザからの要求を受け取り、PHPに渡す
  • データベース — データを保存する
方式A:php artisan serve(localhost:8000)

Laravelに付属する開発用の簡易サーバ
ブラウザ → localhost:8000 → PHPの内蔵サーバ → アプリ
コマンドを打っている間だけ動き、ウィンドウを閉じると止まる

  • 利点 — 設定不要。すぐ起動できる
  • 欠点 — 1度に1リクエストしか処理できない(同時アクセスに弱い)、本番と構成が違う。ポート番号がURLに出る

8000 はポート番号で、同じPC内で複数のサーバを区別する番号です。アプリを2つ動かすなら 8000 と 8001 のように分けます。

方式B:Herd(.test ドメイン)

常駐型のWebサーバで、バックグラウンドで動く
ブラウザ → XXXX.test → hosts → 127.0.0.1 → Herd(nginx) → PHP → アプリ

  • 名前解決 — qmac.test を自分のPC(127.0.0.1)に向ける
  • Windowsの hosts ファイルに 127.0.0.1 qmac.test と書かれることで実現します。herd link を実行したときに Herd が自動で書き込みます。
  • 振り分け — どのフォルダを見せるか決める
  • herd park でフォルダを登録すると、その配下の各フォルダがフォルダ名.test で自動的に開けるようになります。C:\Users\syste\Herd を park してあるので、その中の XXXX が XXXX.test になりました。
  • 利点 — 常時起動。複数サイトを同時に動かせる。本番に近い構成(nginx+PHP-FPM)。ポート番号が要らない
  • 欠点 — 最初の設定が要る。名前解決でつまずくことがある
Laravel Herd(常駐型Webサーバ)
DBngin(データベースを担当)
DBngin の役割

これはデータベースだけを担当します。Webサーバとは無関係です
アプリ → 127.0.0.1:3306 → MariaDB
複数のバージョン(MySQL 5.7 / 8.0 / MariaDB 10.11 …)を並べて入れ、必要なものだけ起動できるのが特徴です。本番と同じバージョンを選べるので、XXXXX_app では 10.11 系を選びました。
停止していると、アプリは起動してもデータベース接続エラーになります

Herd と DBngin の両方が起動していないと動きません。片方だけだと、サイトは開くがデータが出ない、あるいはそもそも開かない、という状態になります。

php artisan serve は「ちょっと動かす」用、Herd は「開発環境として据える」用、という使い分けです。今回のように複数プロジェクトを並行させるなら Herd が向いています。

肖像画 監査における指摘に対するAI支援

Fさんから贈ってもらった絵 池田満寿夫のリトグラフ

内部監査AI支援 — 使い方と考え方

AIは判断材料を整え、判断は監査員が下す–これが全体を貫く原則

AIがすること監査員がすること
事実が十分か確認する質問を出す質問に事実で答える
事実を監査記録の文体に整える内容を確認・修正する
該当しそうな規格条項を3つ提示するどの条項にするか決める
指摘文の案を作る文面を確認・修正して確定する

AIは「答えを出す装置」ではなく、監査員が見落としがちな点を問い、 候補と根拠を示し、文章化の手間を減らす役割

AIの提案に対する反論
誤った反論が通らない設計– 誰でも反論できますが、通るのは規格に照らして正しい反論だけ—これによって、間違った学習が防がれます

応答意味対応
認める反論が正しい。修正案を提示「この内容で生成し直す」を押す
部分的に認める争点の一部だけ修正 内容を見て判断
維持する反論が誤り、または根拠不足。理由を示して現状維持納得すれば従う。しなければ手で編集

監査におけるAIによる解釈原則

AI支援の判断規律を定める「解釈原則」は現在、Dropbox内のマークダウンファイルを直接編集し php artisan ia:import-principles –force で投入する運用になっている・・・このため原則を1行足すのにファイル編集とコマンド実行が必要で、監査作業の流れが途切れる・・・原則を画面から編集できるようにし、気づいた瞬間に追記できる状態にする

種別編集できる人効果範囲
共通原則(company_id = NULL) システム管理者(role=1)のみ全テナント
テナント原則(company_id = 値) 管理責任者 / 会社管理者自社のみ

会社概要ページの「内部監査」カードに「解釈原則設定」ボタンを追加する。

  • 表示条件: 管理責任者 / 会社管理者 / システム管理者
  • 既存の「監査員設定」(AUD-USER)と並べて配置し、同じ扱いにする
  • 共通原則: システム管理者でログインしている場合のみ [編集][削除][+追加] を表示
  • 自社の追加原則: 管理責任者・会社管理者に [編集][削除][+追加] を表示
  • 章立て(■1.、■2.…)は本文中の見出しとして扱う——現在の原則集はマークダウンの見出し+番号付き項目という構造なので、無理にDB上で章と項目に正規化せず、1レコード=原則集全体のテキストという現行構造を維持する(ia_principles.body は既にテキスト全体を保持している)

現在の原本は Dropbox 内の audit_assist_proto/principles/audit_principles.md
画面編集を導入するとDBが原本になり、ファイルとの二重管理になる。

現在の原本は Dropbox 内の audit_assist_proto/principles/audit_principles.md
画面編集を導入するとDBが原本になり、ファイルとの二重管理になる

原則集のマークダウンをリポジトリ内に移す
(例: docs/audit_principles.md)。機密ではないためgit管理して問題ない

  • ファイルは初期投入用のシードと位置づけ、以後の編集は画面から行う
  • ia:import-principles コマンドは新規環境の初期セットアップ用として残す
    (本番デプロイ時の初回投入に使う)
  • この位置づけを README またはコマンドのdocblockに明記すること

AIを育てる — 2つの経路

原則udit_principles.md憲法に当たるものであり、常に効く、判断の規律を伝える原則にすべきもの:
同じ型の誤りが2回以上起きた
規格の記述に基づいて一般化できる
審査員としての規律に関わる(過大解釈の抑制、表現の強度など)
事例判例であり、似たときだけ効く、具体的な紐づけと力点を伝える指摘を「決定・保存」すると、その判断が次回以降の参考事例になります–特別な作業は不要です。監査業務そのものが教材を生みます

原則は事例の誤りを打ち消せます–事例に古い判断が混じっていても、原則が効いてAIはそれを真似しません

原則については、AIの判断に繰り返し違和感があるとき、原則を1行足します
「解釈原則設定」→ 編集して保存
次のAI呼び出しから効きます。版が記録され、履歴から復元もできます

内部監査システムの再構築

監査システム全体のUI再構築

基本的なUIを整理
  • タブメニューの並び(監査モジュール)
  • 「戻る」ボタンの見直し
  • 用語の統一
  • 画面・モーダルの識別コード表示
  • ボタンサイズの統一
  • 監査ページの配色とコントラスト
個別監査の完了機構

以下をすべて満たすとき完了操作が可能:

  1. チェックリストが作成され、記入されている——段階6-Bの3段階判定で「記入済み」
  2. 不適合の指摘がある場合、その是正処置が完了している(完了月日が入力済み)。
    不適合が0件の場合はこの条件は自動的に満たされる

監査計画ごとの対象ISOシステム選択

実務では「第1回はQMS/EMS/OHSMSの統合監査、第2回はEMSのみ」のように、監査計画ごとに対象規格が異なる(認証機関の審査でも一般的)。従来は会社が採用している全規格を計画へ自動同期しており、計画ごとに選べなかった。これを計画ごとの選択制に変更する

監査の流れの再構築と名前の統一

全体の監査の流れのフロー図 頭を整理するために作成、かなり明確になり不足が分かる

内部監査支援(AI/IA支援)機能 引き継ぎメモ

(1)AI内部監査支援 実装済みコンポーネント一覧と場所

Phase1: 匿名化(マスキング)エンジン

監査で使用する固有名詞等を匿名化してAIに送るシステム

  • app/Services/InternalAudit/MaskingRuleEngine.php — 固有名詞検出エンジン本体。Python版audit_case_extract/masking_rules.py(rules.json v1.3)のPHP移植。検出のみ(置換はしない)
  • config/ia_masking_rules.json — ルール定義(35ルール、block 13 / warn 22)
  • tests/Unit/InternalAudit/MaskingRuleEngineTest.php/tests/Fixtures/ia_masking_test_vectors.json(50件、Python版と両方でPASS必須)
Phase2: データ基盤
  • migration 6本: 2026_08_08_100001〜100006(ia_reference_cases / ia_sessions / ia_dictionary_terms / ia_allowed_terms / ia_principles / ia_ai_logs)
  • モデル: IaReferenceCase(トレイトなし・全社共通の読み取り専用マスタ) / IaSession・IaDictionaryTerm・IaAllowedTerm・IaAiLog(BelongsToTenantDirect) / IaPrinciple(BelongsToTenantNullable、company_id NULL=共通・値ありはテナント)
  • app/Services/InternalAudit/BigramVectorizer.php — 文字バイグラム+TF-IDFコサイン類似度の共通処理
  • app/Services/InternalAudit/CaseSearchService.php — 類似事例検索(ia_reference_cases+テナント確定指摘の2種、テナント指摘を優先)
  • artisanコマンド: ia:import-reference-cases {csvPath} / ia:import-principles {mdPath} {–force}
  • config/audit.php に finding_rank_slots / reference_rank_slots / slot_groups / slot_expression_strength を追記
Phase3: AIサービス統合
  • app/Services/InternalAudit/AiGatewayService.php — 全AI呼び出しの唯一の経路。送信ゲート(MaskingRuleEngine)→AnthropicClient→ia_ai_logs記録→JSON解析失敗時1回だけ自動リトライ
  • ClarifyService.php(確認質問) / FactDraftService.php(事実文ドラフト) / CandidateService.php(条項候補Top-3+2分類推定+文書化根拠AI判定+手入力整合検証) / GenerateService.php(指摘文生成) / PrincipleProvider.php(解釈原則の取得結合)
  • app/Exceptions/MaskingGateBlockedException.php / AiJsonParseException.php
  • config/anthropic.php に internal_audit 用途を追記 / config/ia_support.php(用途別max_tokens、confusion_pairs)
  • app/Services/InternalAudit/IsoClauseCatalog.php — 条項マスタの実在番号一覧(TTL1時間キャッシュ)。Phase4.3で条項ハルシネーション対策として追加
  • app/Services/InternalAudit/TenantDictionaryProvider.php — block級テナント辞書の合成(手動登録ia_dictionary_terms+既存マスタ自動導出)。TTL10分、IaDictionaryTermの更新は即時キャッシュ無効化
Phase4〜4.3: 画面組み込み
  • app/Http/Controllers/IaSupportController.php — 9アクション(storeSession/check/clarify/factDraft/candidates/checkClauseFit/recordClauseFitDecision/generate/adopt/storeAllowedTerm)。ルートはroutes/web.phpのia_support.*(9本)
  • resources/views/audits/findings/_ia_support_modal.blade.php + resources/js/audits/ia-support.js — Alpine CSPコンポーネント(iaSupportModal)。STAGE 3-C方式(JSON設定タグ経由で設定値を受け渡し)
  • resources/views/audits/findings/edit.blade.php — 詳細編集モーダル(findingsEditor)に「✨ AI支援」ボタン。別AlpineスコープのiaSupportModalとはwindow.dispatchEventのカスタムイベント(ia-support:open-request / ia-support:applied)で疎結合連携
  • AuditFinding.php(ia_session_idをfillableに追加) / AuditFindingController.php(upsert時にia_session_idを素通し)
  • tests/Feature/IaSupportControllerTest.php(12件)

(4) 未対応の既知課題リスト

  1. IsoClauseCatalogキャッシュの無効化がCSV取込に連動していない。IsoClauseControllerの管理画面CSV全置換後、最大1時間は古い条項番号一覧のままになりうる(候補生成・手入力マスタ実在チェックの両方に影響)。Cache::forget(IsoClauseCatalog::cacheKey($code))をCSV取込処理に追加すべきだが未着手。
  2. モーダルを途中で閉じた場合、ia_sessions.status=0のまま残る(プロトと同じ既知の割り切り。クリーンアップ/バッチ処理は未実装)。
  3. AnthropicClientへのtemperature任意パラメータは未追加(Phase3完了報告の「将来の小改善候補」)。JSON解析失敗時の1回リトライで実運用上は担保しているが、応答安定性が問題化した場合は呼び出し元4箇所への影響を含めて検討要。
  4. ランクマスタの完全テナント可変化(ia_rank_master)は未着手。現状スロット対応はconfig/audit.phpのみで完結させており(Phase2完了報告に明記)、テナントごとのランク名称カスタマイズはPhase5相当として先送り。
  5. resolveAdoptedRank等のメトリクス(candidate_adopted_rank/group_selected等)は記録のみで分析・活用先が未実装。ia_sessionsに溜まっているだけで、これらを使った改善ループ(候補精度の可視化等)は今後の課題。
  6. Phase4.2/4.3は指示書のみでDropbox側の完了報告mdが作成されていない(本メモ作成時点で確認)。次に大きな変更を入れる際は、まずコード側コメント(IaSupportController/CandidateServiceのdocblock)を一次情報として参照し、必要なら完了報告を追補すること。

(2) 設計上の重要な規約

  1. AIはaudit_findingsに一切書き込まない。サーバ書き込みは既存の一括upsert API(AuditFindingController::update)のみ。IaSupportControllerはia_sessionsへの経過記録のみ行う。反映(adopt)後もクライアント側でfindingsEditorのフォームへセットするだけで、ユーザーが「決定・保存」を押した時点で初めて保存される。
  2. 送信ゲートの不変条件: AiGatewayService::send()に渡す$messagesは、実際にAnthropicClient::messages()へ渡すオブジェクトと完全に同一でなければならない。ゲート検査対象(extractUserText())と実送信内容が別経路で構築されることは厳禁(迂回防止)。新しいフィールド(部署名・条項等)を追加する場合は必ず各サービスのbuildUserPrompt()内で$messagesの文字列に組み込むこと。回帰はAiGatewayServiceTestで確認。
  3. doc_basisの(e)完全一致規約: docBasis === ‘(e)’の場合のみ意見系(改善の機会)調を適用する。それ以外の非空文字列(複数選択で(e)+他根拠を含む場合も含む)はすべて「根拠あり」として通常の指摘調になる。IaSupportController::resolveDocBasis()が唯一の解決箇所(改ざん耐性のためクライアントからはトグルの状態のみ受け取り、詳細文言はサーバ側保存済みのdoc_basis_judgmentから都度組み立てる)。
  4. 条項はマスタ実在のみ(IsoClauseCatalog::validClauseNumbers())。AI候補・手入力とも、実在しない条項番号はCandidateService::filterValidCandidates()で除外する(2026-08-08の条項ハルシネーション事故対応)。マスタが空(未整備)の場合は安全側でフィルタしない。除外時の代替候補への繰り上げはしない(見せる候補が減るだけ、TAM指定の方針)。
  5. ユーザーには事実のみを尋ね、判定はAIが提示する(CLAUDE.md原則の実装例)。文書化根拠(doc_basis_judgment)はAIが質疑応答から判定して宣言文で提示し、ユーザーは上書きトグルで検証・反転のみ行う(「根拠がありますか」とは質問しない)。手入力条項の整合検証も同様で、mismatch時は強制ブロックせず「選び直す/このまま生成する」の選択肢を提示するのみ(条項の最終権威は監査員)。
  6. warn級は自動伏字化、block級は修正必須(Phase4.3)。次ステップへ進む操作の時点で未処置warnヒットを○○(カテゴリ)形式へ自動置換し、以後の全処理(AI送信含む)にその置換後テキストを使う。warn_passed_countの意味は「無処置通過数」ではなく「自動伏字化数」(列コメント参照)。
  7. モデル自身の内部状態でウェイトUXを実装(ai_modal.blade.phpは使わない)。同一モーダル内で複数回AI呼び出しを行う多段ウィザードはai_modal.blade.php(単発処理→リダイレクト専用)と構造的に不適合なため、iaSupportModal自身のloading/timedOut/elapsedSecondsで待機UXを実装している(CLAUDE.md原則からの意図的逸脱、完了報告に理由記載済み)。

(3) 触ってはいけないもの/前提を誤解しやすいもの

  • database/seeders/IsoClauseSeeder.php は化石。初期セットアップのフォールバックに過ぎず、第2階層まで・要約文言なしの不完全データ。正式マスタはIsoClauseController.phpの管理画面CSV取込(指定ISOシステムの条項を全置換)であり、本番・開発とも既にCSV取込済みの充実データが入っている。環境再構築時にこのSeederだけを実行すると、既存マスタより貧弱なデータで上書きしてしまう。CSV原本はD:\Dropbox\03システムアシスト\00-Bulid-Assist\内部監査\のISO9001-2015_要求事項要約.csv等。
  • AuditFindingのclient_key対応バックエンドは意図的に残置。Phase4.3でopenCorrectiveReport()撤去に伴い現在フロントからの送信元は無いが、「未保存行から確定IDを引きたい」将来用途のためのバックエンド仕組みとして削除しない(AuditFindingController.phpのコメント参照)。
  • config/audit.phpのreference_rank_slotsのキーはia_reference_cases.rank_labelの実データ値そのもの(改善指摘A/改善指摘B/懸念領域/観察事項/改善の機会/充実点/参考)。既存finding_ranks(iso_app本体の語彙)とは別語彙であり、変換・正規化は一切していない。キー名を「綺麗に」リネームすると初期コーパスとの対応が壊れる。
  • FactDraftServiceは解釈原則(PrincipleProvider)を付加しない。Clarify/Candidate/Generateの3サービスとは非対称(app.py精読で判明した既存プロトの仕様を忠実踏襲。「揃えたほうが綺麗」に見えても直さないこと)。
  • IsoClauseCatalogはTTL1時間キャッシュだが、CSV取込側にキャッシュ無効化処理が無い(現状把握。詳細は(4)参照)。
  • similar_text()によるedit_ratioはバイト単位の近似値であり、Python版(difflib.SequenceMatcher、文字単位)との厳密一致は保証しない。単調性(修正が多いほど値が大きくなる)のみ担保。厳密な一致を要求する変更をしないこと。
  • AnthropicClient.php本体・既存4呼び出し元は無改修のまま。internal_audit用途はconfig追記のみで対応しており、system/temperatureパラメータをAPIに渡さない既存インターフェースを崩していない(IA側は役割定義+原則をuser roleメッセージ先頭に折り込む方式)。

Claudeで内部監査システムの構築

五日市の埋立を甲斐犬のキクと散歩

雑用がようやく片付いたので、再びClaudeで内部監査システムの構築を始める
監査での事実をClaudeのLLMで、条項及び指摘分を作成するシステムのテスト運用が終わったので、いよいよ建設アシストの内部監査に組込みを実施
Claude-Webで実施計画を検討して、Claude Codeへの実装指示書を作成、その指示書を実行させ、実際のコードをもとに計画書を作成させて、課題・懸念事項などを再びClaude-Webで検証させ、TAMが判断と指示をする
この繰り返して、コードの実装を行ってゆく

Claude Codeのターミナルの画面 PCのファイル操作ができる(Sonnet 5)
ClaudeのWeb画面(Fable-5) Fable-5にしていたら一気にトークンを消費した

墓参り

墓を掃除して花を入れて・・・暑い
週末からのキャンプ道具を詰め込み

内部監査支援システムの構築

LLM(AI)に対するセキュリティ対策

AIに監査の内容を検討依頼するにはセキュリティの観点から、固有名詞等は排除しなくてはならない
固有名詞辞書を作成して、入力後チェックが行われるようにするが、まだ色々と誤検知が多いので修正

  • 工種辞書(一般的な工事種別のストップワード化)、建設業の一般工種は固有名ではない。stopwordsに追加:PC杭打工事, 杭打工事, 杭工事, 土工事, 鉄筋工事, 型枠工事, 躯体工事, 仮設工事・・・・
  • 関係節ガード:名前部分に連体修飾の接続語が含まれる場合は名称でなく説明文なので検出しないに関する|に係る|を伴う|における|についての|に対する(例:「騒音に関する工事」「振動を伴う工事」は非検出)
  • 接頭辞の反復剥がし:検出語の先頭から以下を繰り返し除去し、残りが工種辞書・stopwordsに一致すれば非検出とする(例:「各工区の土工事」→「各」除去→「工区の」除去→「土工事」=工種辞書→非検出)
パターン照合には原理的な精度限界があるため、確度に応じて扱いを分ける:
  • ブロック級(修正しないと先に進めない。従来通り):
  • 会社形態(株式会社/㈱等)、敬称付き人名(〜さん/氏/様)、識別子(認証番号等)、動的辞書・user_stopwords外のラベル由来一致
  • 注意級(黄色ハイライト+「固有名の可能性。問題なければそのまま進めます」。
    クリック不要で続行可能):
    工事名catch-all、作業所/建物、地名系(市/川/駅等)、役職付き人名、部署系

ハイライト色を分け(赤=ブロック級、黄=注意級)、注意級のみの場合は次へ進むボタンを有効のままとする。metrics.jsonlに「注意級を残したまま進んだ件数」を記録(実運用での注意級の妥当性評価用)。
v1.1の「一般名称として許可」ボタンは両級で引き続き有効。

待ち時間UX(API呼び出し中の表示)

全API呼び出し(/api/clarify, /api/factdraft, /api/candidates, /api/generate)に:

  • ボタンを即時無効化+スピナー表示(二重送信防止)
  • 段階メッセージを表示: 例
    candidates: 「類似事例を検索しています…」→(API送信後)「条項を判定しています…」
    factdraft: 「事実文を作成しています…」
    generate: 「指摘文案を作成しています…」
  • 経過秒数を小さく表示(「(12秒)」)
  • 可能なら /api/generate と api/factdraft はストリーミング応答(SSE)で文章を逐次表示する。実装が重い場合はスピナー+段階メッセージまでで可(その場合はREADMEに今後の課題として記載)
  • タイムアウト(120秒)時は再試行ボタンを表示

ひろしまみなとマルシェに 内部監査支援システム開発

朝は元宇品に散歩に行き、帰りにひろしまみなとマルシェに寄ってみる・・・炎天下の下、出店している人たちには脱帽ものです・・やはりお客は少なく営業的には苦しい・・・よしろう農園でしばらく雑談して帰宅、シャワーを浴びたらもう昼食
帰って月下美人を見ると昨晩に咲いていた・・残念見ることができなかった

ひろしまみなとマルシェでVFKさんとキク

内部監査支援システム開発

内部監査の指摘では、監査員の力量に左右されて的確な条項に基づく指摘が出来ていないのが実情である・・・今回、力量の不足をAIによって支援するシステムのモデルを構築する・・以下の課題は2点がメインだが、TAMの監査指摘4年分をデータ化し構造化することによって支援の形態が現実的に見えてきた

  • AIに情報を渡すが、その情報が漏洩リスクとならないために、固有名詞などを送らせない
  • 具体的な支援方法について、イメージが具体的にならない
内部監査システム構築のためのステップ
  • STEP 1-1: 事実メモを箇条書きで入力(固有名チェックあり。通らないと進めない)
  • STEP 1-2: AIが事実の不足を質問(最大3問×2ラウンド。スキップ可)
  • STEP 1-3: 対話結果から事実文を自動文書化 → 監査員が修正・確定
  • STEP 2: 条項候補Top-3+境界注記 → 選択または手入力
  • STEP 3: ランク選択 → 指摘文案生成 → 修正
  • STEP 4: 確定 → 事例DBに蓄積(次回のAI参照例に自動反映)
これまでに構築したもの
  • [TAMの審査記録xlsx 4年分をデータ化してサンプルとする] : audit_case_extract(抽出+三段匿名化: パターン/辞書/ローカルLLM検査)
  • [匿名化済み事例DB cases.csv 388件] :clause_bench(条項マッチング実力測定)
  • [実測: ゼロショット85.5%/適合性系93.8% → RAGで88.1%・混同半減] :検討結果書(二層アーキテクチャ: 規格層=共通/流儀層=組織別)
  • [audit_assist_proto(動くプロトタイプ)] :事実引き出し対話 → 匿名化ゲート → 条項候補 → 人間確定 → 事例蓄積(自己学習)
主要な実測値(仕様書の根拠数字)
  • 条項マッチング(Top-3実務粒度): ゼロショット全体85.5% / 適合性系93.8%
  • 粒度規約+TAM事例RAG(v2b): 全体88.1%、最大混同ペア(8.1↔6.1.2)半減
  • ランク別定型句の対応(388件分析): 改善の機会=「推奨します」、観察事項= 「検討の余地があります」が相互汚染ゼロの完全分離 → 文章生成テンプレートに採用
  • 適合性系(観察事項・懸念領域・改善指摘)と意見系(改善の機会・充実点)の 2群構造を確認 → ランクはAIが当てず、2分類推定+監査員選択の設計に
実地試用の状況と次回のTODO

済み: 2022年審査データで10件試用・・「力量ある監査員には良い指標」との評価・・記録済みデータ: confirmed_cases.csv・metrics.jsonl に実データ10件保持
次回確認すること:

  • v1.1修正の適用確認(重要): v1.2完了報告にv1.1(過剰検知修正・許可ボタン・ ランク2分類化)の適用言及がない。「建築部」「工務課長」「2件の作業所」が ブロックされないか確認し、未適用ならv1.1指示書を先に適用させる
  • 採用率18.2%の原因調査: 体感(「非常によくできている」、明確な条項誤りは1件)と 記録上の採用率18.2%が大きく乖離している。候補カードをクリックせず手入力で 条項を入れる操作習慣だと、候補が正しくても「手入力=不採用」と記録される。 metrics.jsonlの確定条項の生値と候補を突合し、指標定義の問題か候補品質の問題かを 切り分ける(次回セッションでmetrics.jsonlをアップロードすれば分析可能)
  • 1.2の意地悪テスト: 最低品質のメモ(「・教育記録を確認 ・不十分」)への AIの質問が、TAMが新人に返す問いと一致するか 試用を10〜20件継続し、指標の推移を観察
▶この続きを見る・・・・

暑い朝の散歩 ローカルLLM(Ollama)の構築

朝から纏わりつくような暑さ、キクも暑い

ローカルLLM(AI)の構築

ローカルLLMとして、Ollamaを選択、ローカルでOpenAI互換APIを提供、Laravelから通常のAPI呼び出しと同じ形式でローカルLLMを叩ける
インストールするWindowsPCは、・マザー ASUS ROG STRIX B550-A GAMING、CPU Ryzen9 3950X(16C32T 3.5-4.7GHz)、メモリ DDR4 PC4-28800 3600MHz 2✕32GB=64GB、グラフィックボード GeForce RTX™ 4070 Ti、M.2SSD PCle4.0 NVMe M.2 Kingston KC3000 1021GB、 PCIe Gen 4.0 x4 70000MB/Sで、GPUが少し不足気味だが、Ollama Qwen2.5 14B (Q4量子化 約9GB)が動きそうなのでインストールして試行する

Ollama本体のインストール

https://ollama.com/download/windows からOllamaSetuo.exeをダウンロード 実行してインストール、インストール後、Ollamaは常駐サービスとして起動します(タスクトレイにラマのアイコン)

NVIDIAドライバの確認

nvidia-smiを実行して、ドライババージョンとRTX 4070 Ti、VRAM 12288MiBが表示されればOK

モデルの取得と実行

ollama pull qwen2.5:14bをダウンロード完了したら、ollama run qwen2.5:14bで起動して、プロンプトから質問できる

GPU配分の確認

ollama psと入力して、OROCESSORが100%GPUとなっているので、VRAMに全部納まっている

API経由での動作確認(サーバ連携の予行)

Ollamaは自動的にhttp://localhost:11434でAPIを開いているので、Laravelから叩く検証ができる

Jeepの車検

甲斐犬のキク・・タヌキ?と遭遇
J58 Jeepの車検 今年も無事に終わりました

今朝も暑い、キクを連れて元宇品を散歩、キクはタヌキを見つける・・・走りすぎてバテてました・・・午前中に、J58の車検に、無事に終わって、今回はブレーキオイルを入れ替えたので¥5万程、昼からNGIさんが訪ねて来て久しぶりに雑談

会社概要登録画面を刷新
マネジメントシステム登録画面をモーダル化
▶この続きを見る・・・・

日赤の定期診断 CodeX(GPT-5.6 Sol)

今日は3か月ごとの定期診断と栄養指導で、広島日赤病院に朝から、血液を採取して診断、前回は血糖値が悪かったが、今回は改善していた・・夕食を減らして、体重を2㎏程減量した効果が出たようだが、クレアチンは少し高くなっていた・・まあ、ほとんど体調は変更なしということか

日赤での定期診断 病院にスターバックスがある  血糖値が改善した

帰ってから、ログイン画面から会社概要への遷移が気に入らなかったので、修正して、会社概要ページを大幅に修正する・・ここに内部監査の計画及び実施状況をまとめる予定で、スペースを開けておく

会社概要のページを変更

Claude Fable5の試用期間が20日まで再び延長となった・・・OpenAIのGPT5.6のリリースで競争が激しくなった結果のようだ・・・GPT5.6はSol / Terra / Lunaのクラスがあり、Solは、Claude Fable5と同じ性能のようだ、GPT5.6のCodexはコーディング作業を支援する製品・エージェントという位置づけが明確になり、Claude Codeのプラグインとして使用できる
Claude Code(要件整理、設計、実装、リファクタリング)
Codex(セキュリティレビュー、バグ検出、性能改善)
さっそくClaude CodeにcodeX 5.6 solをプラグインで使えるように、指示してインストールを任せて、それと同時にChatGPTを無料版からPlusの有料版に切り替え、Claude CodeへのCodeXプラグインの設定は、便利なのもので調べる必要はなくすべてClaude Codeが以下のように実施してくれる

  1. Codex CLI更新: 0.130.0 → 0.144.4(GPT-5.6対応版)
  2. config.toml設定: C:\Users\syste.codex\config.toml の先頭に2行追記、model = “gpt-5.6-sol”、model_reasoning_effort = “medium”
  3. 既存の設定(プラグイン・trust設定)は無変更です
  4. 動作確認: テスト実行でヘッダーに model: gpt-5.6-sol / OpenAI Codex v0.144.4 を確認し、正常に応答が返りました

Claude Codeのcodexプラグインはモデル未指定時にconfig.tomlのデフォルトを使うため、今後 /codex:rescue やレビュー依頼はすべてSolで実行されます。推論の深さを変えたい場合は model_reasoning_effort を low / high に変更できます。

/codex:rescueメインの依頼コマンド。調査・修正・実装タスクをCodex(GPT-5.6 Sol)に委譲
/codex:review現在の変更をCodexにレビューさせる
/codex:adversarial-reviewより厳しい敵対的レビュー
/codex:status実行中ジョブの状況確認
/codex:resultバックグラウンドジョブの結果取得
/codex:cancel実行中ジョブの中止
/codex:setupCLI接続確認・設定

普段使いは /codex:rescue に続けて依頼内容を書くのが基本です。例:/codex:rescue 工程表の印刷でヘッダーがずれる原因を調査して
また、コマンドを打たなくても、会話の中で「これはCodexに調査させて」「Codexで直して」と指示してもらえれば、こちらからCodexエージェントを起動して結果を報告します。どちらでも同じSolが使われます

キクと散歩 工事一覧の変更

体が少し重い 今日はみなと公園で軽くキクを散歩させる

システムログインでは、最初に会社概要に遷移し、工事一覧と進んでいたが、最初に工事一覧へ遷移するように切り替え、工事一覧のデザインを変更して、工事のサムネイルが表示されるようにした・・・バタバタと変更するが、じっくり見るとボタンの配置が雑多なので、少し変更することにする

五日市埋立で散歩

五日市の埋め立てでキクを散歩
昼食はボンベイで、ここはナンが美味しい
4.結果
  • mainマージ+本番デプロイ3回、すべて成功・稼働確認済み(最終コミット bd1cf1b)
  • 自動テスト: 106件(うち5件失敗)→ 119件全パス(テスト14件新規追加・失敗0)
  • 外形確認済み: セキュリティヘッダー出力・CookieのSecure属性・自己登録の閉鎖・診断ページの撤去
  • 2026-07-11再検証の指摘は完了。システムは「Critical/High/Medium指摘ゼロ・依存脆弱性ゼロ(リスク受容2件は記録済み)」の状態
5.残課題(急ぎでない・別フェーズ)
  • H-3: CSPのunsafe-inline除去(インラインJSの外部化 or nonce方式・大きめの作業)
  • L-3: 同時編集ロックの精度向上(lock_version整数化)
  • vite 4→8 メジャー更新(開発サーバー限定の脆弱性解消)
  • x-data-spreadsheet(表エディタ)の代替検討 — XSS修正版が存在しないため。現状は同一会社内の編集権限者に限られるためリスク受容中
  • 動作中の旧式遷移ボタン6箇所の data-href 方式への移行(1と同時に実施が効率的)

セキュリティ再検証・是正作業 全体総括

1.目的

システム全体を改めて検査(再検証)し、見つかった弱点を重要度順にすべて是正して本番に反映する

2.計画

4つの観点(認証・テナント分離・インジェクション対策・設定/依存関係)で並列監査を実施し、指摘を重要度別に整理 → Critical 0件・High 4件・Medium 9件・Low 9件・依存脆弱性多数・・・中核部分(認証・会社間のデータ分離・SQL/XSS対策)は基準適合と評価

区分内容
バッチ1緊急度の高いもの:テンプレート操作の権限制限・AI生成HTMLのXSS対策・不要ファイル削除
バッチ2入力データの保存範囲固定・Cookie保護の既定化・セキュリティヘッダー補強・古いテストの整理
バッチ3依存パッケージの脆弱性解消・細かな改善9件(L-1〜L-9)
確認事項5件確認事項5件
3.実施

バッチ2

  • 現場情報の保存を「検証済みの項目だけ」に固定 — 従来は細工したデータ送信で現場の所属会社を書き換えられる余地があった(調査中に登録処理側にも同じ問題を発見し、両方修正)
  • セッションCookieのSecure属性を既定でON — 設定漏れがあっても自動的に安全側になる
  • セキュリティヘッダー補強 — カメラ・マイク等のブラウザ機能無効化、クリックジャッキング・フォーム送信先の制限
  • 実態と合わなくなっていた古いテスト5件を「現仕様の回帰検知」に書き換え

バッチ3

  • 依存パッケージの脆弱性: composer 26件 → 0件(Excel処理ライブラリの重大な脆弱性含む)、npm 18件 → 4件(残りは開発環境限定等で影響なし・記録済み)
  • パスワード変更・リセット時に他の端末のログインを即時無効化(乗っ取り後の締め出し対策)
  • ファイル保存名のランダム化、デバッグ出力の削除、旧Gemini設定の廃止 ほか

確認事項

  • 変更履歴(UserChangeLog): 会社間分離の仕組みを適用(設計どおり)
  • 本番設定: 現地確認の結果、実は問題なし(APP_ENVは行なしでも本番扱い・GEMINIキーも本番には無かった)
  • プロキシ設定: 診断ページを一時設置しTAMの実測で「前段プロキシなし」と確定 → IP偽装を許す設定を撤去
  • 過去のAI生成データ: 一括洗浄コマンドを作成 → 本番で確認した結果、対象0件(すべて安全なデータのみ)
  • 旧GeminiAPIキー: TAMがGoogle側で失効済み



元宇品の森を歩く ユーザー管理の検証

元宇品の森を歩く

ユーザー管理検証

1.ユーザー管理・基盤是正の検証とリリース

今回反映された機能

  • パスワードリセットのレート制限復活
  • ログの日付別ファイル化(info・30日保持)※本番.envも書き換え済み
  • パスワード強度10文字以上・英数字必須(日本語エラー)
  • ユーザー無効化(is_active)+ログイン中セッション即時遮断
  • 認証ログauth_logs(ログイン失敗・ロックアウト・無効化ブロック)
  • 仮登録トークン72時間二段期限(承認時再セット)
2.検証中に発見・修正したmain由来バグ(3件)

検証したからこそ見つかった、以前から存在した問題:

  • 新IPログイン通知メールが未捕捉 — メールサーバー障害時、初IPユーザーが全員ログイン500になるリスク → try-catch+警告ログ化
  • 本登録リンクの無効/期限切れメッセージが非表示 — redirect(‘/’)経由でメッセージが捨てられていた → ログイン画面のメール欄下に表示
  • パスワードリセット画面のルート喪失 — 「パスワードをお忘れですか」リンクが非表示になり機能の入口が無かった → ルート復活(既知テスト失敗も1件解消)
3.追加実施
  • 認証まわりの日本語化: リセット画面・リセットメール本文・ログイン失敗/ロックアウトメッセージ(lang/ja.json・passwords.php・auth.php新設)
  • パスワード変更専用ページ: 既存の/profileが導線ゼロで放置されていたのを発見。パスワード変更専用に改修し、ヘッダー右上に「PW変更」ボタンを設置。自己退会・自己情報変更はルートごと廃止(405)し、管理者経由+is_active無効化運用に一本化
4.検証で手間だった点と今後の改善
  • メール確認: Mailtrap接続切れ→MAIL_MAILER=log化→メール本文がLOG_LEVEL=infoで消える、と二段のハマり。今後はローカル検証開始時にstorage/logs/mail.logの動作確認を最初にやる
  • 「操作したつもりが反映されていない」事例が2回(更新ボタン未押下・ログイン済みウィンドウでのログイン試行)。検証はDBの記録とセットで確認するのが確実(今回はその方式で全件裏取りした)
  • 419/500エラーは検証の中断ポイントになった。今後の検証手順書には「必ずCtrl+F5してから操作」を明記する
5.残課題(別起票)
  • 既知テスト失敗5件(logout外部リダイレクト・パスワード確認・registration無効化×2・トップ302)
  • script-srcの’unsafe-inline’除去(別フェーズ)
  • フェーズ1候補: login_successのauth_logs統合・activitylog・SoftDeletes・uncompromised()・2FA
テスト基準(今後の比較用)

92パス / 5失敗(失敗はすべて上記の既知5件)。mainは 8e3b354

VFKさんが来る 建設アシスト 品質・セキュリティ改善 総括

朝は京橋川を散歩させて、シャワーを浴びて五日市の病院に、帰りに元宇品の森でキクを散歩させていたらVFKさんから電話、昼は近くの『はる』でお好み焼きを食べて、晩秋には北海道へJeepでキャラバンすることで盛り上がる・・・夕方に、贈り物がしたいということなので、洋酒の酒店に行く、ウイスキーが好みだそうで2種類を購入、TAMにも一本贈り物として頂いた

朝は甲斐犬のキクを京橋川で散歩 夏の日差しが暑い

建設アシスト 品質・セキュリティ改善 総括

1.目的

建設アシストは、現場マネジメントDXの実践アプリケーションで、本プロジェクトの目的は以下の3点

  • 大手組織のセキュリティ審査に耐えるシステムにする 複数テナント(会社)が同居するSaaSとして、テナント間のデータ分離を構造的に保証する
  • AIに投げる情報の管理と漏洩リスクの低減 工事情報・現場情報をAI APIに送信する以上、何をどう送り、何を記録するかを一元的に管理できる構造にする
  • 今後の機能追加に耐える保守性の確保 一人開発で継続的に機能を追加していくため、重複コード・デッドコードを排除し、「1箇所直せば全体に効く」構造を作る
2.出発点の課題(Fable 5による全体検証の結果)

セキュリティ(フェーズ1)

  • Critical 7件・High 12件。中心はIDOR(他社データへの越境アクセス)で、工程表・安全パトロール・RA・施工計画書の主要機能に集中していた
  • テナント分離がコントローラの手動認可(authorizeProject)に全依存しており、
    1箇所の実装漏れがそのままデータ漏洩に直結する構造だった
  • 当時の評価:「現時点では大手組織のセキュリティ監査に耐えられない」

保守性(フェーズ2)

  • AI呼び出しが8箇所に散在し、URL・タイムアウト・エラー処理がコピペ重複
  • 工程表のJS約4,100行がBladeにインラインで埋め込まれ、CSP強化の障害に
  • テナント設計が未完了のモデル(company_id未設定)が多数
  • デッドコード(未完成のWord/Excel出力サービス、旧版施工計画書、孤立したAIサービス等)が大量に残存。

バグ(フェーズ3)

  • 確定バグ14件。空CSVで法規制マスタが全削除される致命的バグ、工程表の無限ループ、祝日計算誤りによるCPMの1日ズレ等
  • トランザクション欠落が主要機能に多数(途中失敗で中途半端なデータが残る)
  • 同時編集の保護が皆無(後勝ち上書きで先の編集が無警告で消える)。
VFKさん、久しぶりにJeepで
アイリッシュウイスキー バスカー シングルモルト
▶この続きを見る・・・・

元宇品を散歩

キクと元宇品の森を散歩
その他の改善
  • キャンバス表示範囲の拡張:工期ぴったりの表示から「工期の前後1ヶ月」に拡張。工期前後への工程配置が可能になり、読込時は工期開始位置へ自動スクロール。印刷は従来どおり指定範囲のみ
  • 印刷範囲外工程の除外:バーチャートの印刷で範囲外の工程・接続線が出力される問題を修正。あわせてアノテーション(テキスト・フリー線)が印刷範囲変更時にずれる問題も修正(日付アンカー方式を導入)
  • フリー線の太さ・矢印修正:太さ変更が即反映されない問題と、1pxで矢印が見えなくなる問題を修正(矢印を固定サイズに変更)
  • ダブルクリック編集の修正:委譲化により発生した問題。DOM再構築のタイミング制御(requestAnimationFrame遅延・3px閾値)で解消
結果
テストTenantIsolationTest 33件パス維持(全修正通じて)
主な成果アノテーション機能の2画面統一・印刷品質の大幅改善
特記印刷残像の根本原因はデバッグコードの消し忘れ1行だった

工程表(バーチャート・ネットワーク)の品質改善

アノテーション機能の全面整備(メイン作業)

背景:2画面でアノテーション(テキストボックス・フリー線)の実装がバラバラで、barchartに欠けている機能が多かった・・設計書を作成してから4段階で実装した

1networkのイベント処理を委譲方式に統一(個別リスナー8箇所を撤去)
2barchartにnetwork同等の機能を追加(ドラッグ移動・端点編集・描画プレビュー等)
3UXルール統一(配置後即モーダル表示・ワンショット化)
4共通コード(schedules-common.js)として抽出・約230行の重複削減

あわせてモーダルのUI表記も両画面で統一(ボタンラベル・フォント選択肢・フリー線太さをselect化等)・・・P4完了後に発覚した退行(barchartのテキストボックス):長文・大フォントで文字が枠からはみ出し、クリック・ダブルクリックが効かなくなる問題。原因はforeignObjectの固定サイズ・・・networkにあった「文字量に合わせた自動拡大」が移植漏れだったため、共通モジュールに追加して解消

印刷機能の連続修正
問題原因
印刷後に背面に残像が残る
プレビュー表示中も残像が見える
try/finally未実装で復元処理が漏れる可能性
描画凍結中にpaintが完了しない
そもそも消えないデバッグ用のコメントアウトが残ったまま
月境界線が太すぎ・テキストの上に乗る旧レイアウト時代の「貫通線」が残存していた
月境界線が「時々」途切れるUTC変換による日付の1日ずれ(タイムゾーンバグ)

楽観ロック実装

楽観ロックとは

複数ユーザーが同じデータを同時に編集した際、後から保存した人の内容が前の人の変更を上書きしてしまう問題を防ぐ仕組み

共通基盤の構築

4ファイルを新規作成して土台を整備

ファイル役割
ChecksOptimisticLock.php(トレイト)サーバー側の照合・トランザクション・409返却
optimistic-lock.jsフロント共通ミックスイン(トークン保持・競合処理)
conflict-modal.blade.php競合通知モーダル(退避DL・最新読込ボタン)
OptimisticLockTest.php検証テスト
▶この続きを見る・・・・

山口で仕事して、帰ってからコード修正

今日は朝から山口で仕事、天気は良さそうだ、ここの組織も長い・・今回はメンバーなので若い社長と懇談
のぞみにギリで乗れたので、夕方は少し早く広島に帰る

ホテルで朝食をゆっくり頂いて
国道376にある道の駅 仁保の郷 最近リニューアルされた
ちょっと洒落たデザインだった

■昨日はグローバルスコープ化について、「親テーブル1段経由」だったが、「2〜3段経由」でテナント絞り込みが必要なモデル群の処理をする

系統対象モデル数
系統1監査木(指摘・是正処置・チェックシート系)5モデル
系統2工程表(ネットワーク・バーチャート系)4モデル
系統3施工計画(項目・画像・セクション)3モデル
系統4安全パトロール写真1モデル

■最終テスト結果:TenantIsolationTest 33件パス(46アサーション)

▶この続きを見る・・・・