NGW TECH BLOG
← 記事一覧へ
·#092

決裁に付箋を付けたら、進捗バーが101%になった

起案書・回覧板・決裁書類に「付箋」を付けられるようにした。決裁で試したら、今度は承認の進捗バーが101%になる不具合が出た。付箋とは関係ない、5箇所に同じコードが複製されていた古いバグだった。

付箋を1枚貼っただけで、隣の進捗バーが100を超えた。原因は付箋ではなかった。

起案書や回覧板、決裁書類のヘッダーに、ふせん紙のような付箋を貼れるようにした。画面をまたいだ申し送りをコメント欄に書くのではなく、画面の外に貼っておける。次期Linux版側で先に作っていたものを、今動いている NGW_MASTER(MAMP・PHP7.4)へ移植した。

移植そのものは順調だった。躓いたのは、そのあとに広げていく過程と、決裁で試している最中に出てきたまったく関係の無い不具合のほうだった。


付箋は、画面ごとに作らない

付箋を「起案書用」「回覧板用」と画面ごとに作ると、対応する画面の数だけ保守箇所が増える。そこで、共通テーブル NGWT_FUSEN を1本作り、どの画面に出すかは NGWT_APP_MENU(アプリのメニュー定義テーブル)に3つの設定を足す形にした。

設定項目意味
FUSEN_ENABLEこの画面で付箋パネルを出すか
TARGET_FIELD対象IDをどの hidden フィールドから拾うか
TARGET_CLASS対象の種別(起案書/回覧板/決裁書類…)

これで、新しい画面に付箋を足すのは「コードを書く」ではなく「設定を1行足す」になった。実際、このあと起案書・回覧板から決裁書類、勤怠、休暇申請へと広げていったが、毎回コードは触っていない。

代わりに、広げるたびに別の不具合を踏んだ。


移植した日のうちに出た1つ目

付箋パネルの表示位置は、<header> と #AppMenu の getBoundingClientRect() で計算していた。ヘッダーの下に付箋アイコンを置くだけなので、単純な計算のはずだった。

ところが両方とも、中身が position: fixed の子要素だけで構成されていた。子が fixed だと、親要素はレイアウト上の高さを持たない。親の矩形を測ると、高さ0が返ってくる。付箋パネルは、画面の一番上に潰れて出た。

左右2枚組の図。左は「移植直後:親要素の高さを測る」で、headerと#AppMenuが赤い破線で高さ0と示され、その中に実体のバーnav.fixed-topと.app-menu-barが別に描かれている。付箋パネルはバーに重なって出る。右は「修正後:実体要素を直接測る」で、nav.fixed-topと.app-menu-barそのものを直接測る矢印が描かれ、付箋パネルはバーの直下に正しく着地している

親を測ると高さ0。実際にバーとして立っているのは、fixedな子要素のほうだった。

直したのは、親ではなく実体のバー(nav.fixed-top / .app-menu-bar)を直接測るように変えただけ。移植した当日のうちに気づけたので、傷は浅かった。

広げるたびに出た2つ目:同名の hidden が2箇所にある

起案書・回覧板・決裁書類まで広げたあと、勤怠管理(時間外決裁状況タブ)に広げたら、付箋アイコンが出ない画面が出た。

調べると、対象IDを持つ hidden 要素 fdtJinjJikangaiShinseiId が、画面の中に2箇所あった。タブ初期化で空になる #EditColumn の中と、時間外決裁状況タブの中の #WorkflowEditColumn の中。付箋のコードは先頭に見つかった方(値が空の方)を読んでしまい、対象が無いと判断して何も出していなかった。

タブが表示されているかどうかまで見る必要があるのは勤怠だけの事情だったので、「非表示タブの中は一律に無視する」という一般化はできなかった。決裁画面のほうは hidden がタブ区画の中にあっても普通に読みたいからだ。結局、NGWT_APP_MENU の対象ID指定に id@タブID という書き方を足し、「そのタブが表示中のときだけ、タブ内のhiddenを対象にする」を設定で表現できるようにした。同名 hidden が複数ある場合は、値が入っている方を採用する。

汎用化した設計が、個別事情(勤怠だけタブ連動が要る)にぶつかったとき、コードで分岐するのではなく設定の書き方を1つ増やして吸収した、という話である。


本題:決裁で試したら、進捗バーが101%になった

決裁書類にも付箋を出せるようにしたので、実際に決裁を1件、承認まで通してみた。時間外勤務の申請だった。

承認ボタンを押すと、PDFを作りながら進捗バーが動く。25%・50%・75%でファイルの完成を確認し、見つかったら閉じる作りになっている。ところがこの回だけ、バーが101%まで進んでから閉じた。

付箋とは無関係だった。原因は、時間外勤務申請書のPDF生成(jinjJikangaiShinseiPdf.php)だけが、他の帳票(docuKianPdf など)と違う実装になっていたことだった。

// 他の帳票はここで dest / WorkflowPdfPath を受け取り、
// dest=='F' ならファイル保存(F)、それ以外は画面表示(I) に分岐する
// → jinjJikangaiShinseiPdf.php だけ、この分岐が無く常にインライン出力(I)だった
$ObjPdf->Output($pdfName, 'I');

進捗バー側は、承認のたびに「決められた場所にPDFファイルができているか」をポーリングして完成を判定する。ところがこの帳票はファイルを一切保存せず、毎回ブラウザへ直接流し込んでいた。ポーリングはファイルを永遠に見つけられない。

承認ボタンから進捗バー・ポーリングまでの流れを示す図。上段は正常系で、25%・50%でファイルを探し50%で見つかって閉じる。下段は時間外勤務申請書で、25%・50%・75%と探しても見つからず、dest/WorkflowPdfPathを受け取らず常にインライン出力していたためと説明がある。その下にコード風の枠でparsent++が25/50/75で止まらず上限も無いまま増え続けること、$(".progBar .percent").html(parsent+"%")で101%・102%と表示されること、_MAKE_PDF_MAX_WAIT_TIME_(既定15秒)まで待ってあきらめて閉じることが書かれ、最下部に修正内容としてdest=='F'分岐の追加とMath.min(parsent,100)での頭打ちが同一コード5箇所にあったと書かれている

見つからないまま数え続けた。数え方自体に上限が無かった。

見つからないまま、パーセントを数えるカウンタ (parsent++。variable名の綴りも歴代のコピペそのまま) は25%・50%・75%のチェックポイントで止まらず、上限も無いまま増え続けていた。既定15秒のタイムアウト(_MAKE_PDF_MAX_WAIT_TIME_)まで律儀に数えた結果が「101%」だった。表示だけの見た目のバグで、承認自体は通っていたが、見た人は不安になる。

直したのは2つ。

  1. jinjJikangaiShinseiPdf.php に、他の帳票と同じ dest=='F' 分岐を足した。
  2. パーセント表示を Math.min(parsent, 100) で頭打ちにした。同一のカウンタ処理が 5つのファイルにそのままコピペされていたので、5箇所を同時に直した。

数日後、休暇申請でも決裁を1件通したら、まったく同じ形の不具合が出た。jinjKyukaSinseiPdf.php も、時間外勤務申請書と同じ抜けを持っていた。コピペ元が同じなら、抜けもコピペされる。次期Linux版側の同名ファイルにも同じ修正を先に入れてあったので、そちらは今回も揃えて直した。


数字で見る

項目値
付箋を出せるようにした画面起案書・回覧板・決裁書類・勤怠(時間外)・休暇申請
付箋の実装で増えたコード量に対して設定で吸収した箇所画面追加は原則コード0行(設定のみ)、タブ連動のみ設定記法を追加
位置バグを直すまでの時間移植した当日
進捗バーが101%になっていた理由と無関係だったもの付箋機能そのもの
同じ「頭打ち忘れ」コードが重複していた箇所数5ファイル
同じ「dest=F無視」が見つかった帳票数2(時間外勤務申請書・休暇申請)

決裁の進捗バーの不具合は、付箋を1枚も貼らなくても、いつか誰かが踏んでいたはずのものだった。


AIとの協働作業での学び

関係ない不具合を、関係あるものとして持ち込まない。 「付箋を付けたら進捗バーがおかしい」という報告のされ方をすると、まず付箋側のコードを疑いたくなる。実際には無関係で、原因はPDF生成側の実装漏れだった。AIに「付箋と進捗バーの間に依存関係があるか」を先に聞いておくと、疑う場所を早く絞れる。逆に言うと、聞かずに付箋側のコードを読み始めていたら、無駄な時間を使っていた。

コピペの箇所を、AIは正確に数えてくれる。 同じカウンタ処理が5ファイルに複製されていることは、人が1つずつ開いて見比べるより、grepと横並び比較を頼んだほうが早く、かつ漏れが無い。ただし「複製されていそうだ」と疑うところまでは人の勘だった。1箇所直して終わりにしていたら、残り4箇所は101%のまま残っていた。

禁止したはずの呼び方を、コミットメッセージで自分が使っていた。 このリポジトリの CLAUDE.md には「次期Linux版を『212』のような曖昧な呼び方で呼ぶのは禁止」と、事故防止のために明記してある。ところが実際のコミットメッセージには「212側の同ファイルにも同じ修正を適用済み」と、禁止したはずの呼び方がそのまま残っていた。ルールを文書に書くのと、AIとの日々のやり取りでそのルールを毎回守るのは、別の作業だということに気づいた。今回は実害が無かったが、次は無いとは言えない。

汎用化は、個別事情を消さない。 NGWT_APP_MENU の設定だけで画面を増やせる形にしたのに、勤怠のタブ連動だけは結局、設定の書き方(id@タブID)を1つ増やす必要があった。「全部を設定で統一する」ことにこだわるより、「大半は設定、例外は例外として設定に書き足せる形にする」ほうが、実際に広げていくときには軽かった。