---
title: "監査法人の工数管理：構築中に見つけた4つの見えないミス"
description: "監査法人の工数管理を構築する中で、画面には出ない4つのミスを見つけました。報告の合計の不足、偽の保存完了、機密クライアントの漏えい、却下の隠蔽です。"
url: "https://madsalt.tech/ja/blog/time-tracking-for-audit-firms/"
author: "Denys Zaichenko"
language: "ja"
published: 2026-10-19
---

# 監査法人の工数管理：構築中に見つけた4つの見えないミス

TL;DR

監査法人の工数管理で大事なのは、タイマーではありません。2つのことです。誰がどのクライアントの工数を見られるか、そしてレポートの合計が正しいか。ある監査法人のために工数管理アプリを構築する中で、どの画面にも表れない4つのミスを見つけました。気づかないうちに低く出てしまうレポートの合計、何も保存されていないのに「保存しました」と表示する約30の操作、レポートやタグの件数から存在が漏れる機密クライアント、そして後の承認で隠れてしまう却下済みのエントリです。どれも、購入したツールでも自作のツールでも、数分あれば確認できます。

Denysです。フルスタック・AIエンジニアです。2026年5月から10月にかけて、ある監査法人は、誰もがすべてのクライアントを開けるツールから、その法人のためだけに私が388コミットで構築したアプリへ移行しました。法人名はここでは伏せます。この記事は、法人を運営し、ツールを選ぶ立場の方に向けたものです。監査法人が工数管理に求めること、見つけた4つのミス、そしてどのツールでもそれを確認する方法を紹介します。

## 監査法人は工数管理に何を求めるのか？

監査法人が売っているのは時間です。工数管理は、事業全体が拠って立つ記録になります。私が構築した法人に必要だったのは次のものです。

- **クライアント・プロジェクト・タスクごとの工数。** すべてのエントリは1つの契約に属するため、工数をクライアント別、プロジェクト別、個人別に見られます。
- **承認つきの週次タイムシート。** スタッフが1週間分を提出し、プロジェクト管理者が各エントリを承認または却下します。カウントされるのは承認済みの工数だけです。
- **リマインダー。** 期限までにタイムシートが空のままの人には、メールが届きます。2026年9月以降は、未入力の工数についてのみ通知し、稼働可能時間がゼロの人は対象外です。
- **リソース配分。** 今後数週間、誰がどの契約に就くかを、各人の稼働可能時間と照らして管理します。
- **機密クライアント。** オーナーは、クライアントとそのプロジェクト、タスク、工数を、選んだメンバーだけに制限できます。
- **削除せず、アーカイブする。** 退職したメンバーは無効化して匿名化し、終了したプロジェクトはアーカイブして、タイムシートの履歴をそのまま残します。

請求書は発行しません。プロジェクトの請求形態と工数予算は別の権限の背後にあり、請求は法人の会計システムで行います。

![1週間の工数、入力からレポートまで。工数は、プロジェクト管理者が承認して初めてレポートに反映されます。承認された週：スタッフ → 提出済みの週 → 管理者 → 週を承認 → レポート、却下されたエントリ：スタッフ → 提出済みの週 → 管理者 → 理由つきで差戻し。](https://madsalt.tech/charts/ja/time-tracking-for-audit-firms-week.svg)

*図1. 監査法人の工数管理アプリにおける週次タイムシートの流れ。却下されたエントリは、入力した本人に戻ります。*

## 監査法人では、誰が誰の工数を見られるべきか？

このプロジェクトの前は、法人の全員がすべてのクライアントと全員の工数を開けました。監査法人にとってこれは、ソフトウェアの問題である前に守秘義務の問題です。すべてのメンバーがすべてのクライアントを見る必要はなく、同僚の1週間は、承認する立場でなければ誰も見る必要がありません。

法人が確認したアクセスモデルは次のとおりです。

| ロール             | 見られる範囲                           | 承認できる範囲                 |
| ------------------ | -------------------------------------- | ------------------------------ |
| スタッフ           | 自分の工数のみ                         | なし                           |
| プロジェクト管理者 | 自分のプロジェクトのチームの工数       | そのプロジェクトでのチームの週 |
| オーナー           | すべてのクライアント、プロジェクト、人 | すべて                         |
| 機密クライアント   | オーナーが選んだメンバーにのみ見える   | —                              |

![誰が誰の工数を見られるか。法人が確認したアクセスモデル。画面ではなくデータベースが強制します。スタッフ：スタッフ → 自分の工数のみ、管理者：管理者 → 自分の担当チーム → チームの週を承認、オーナー：オーナー → 全クライアント・全員、機密クライアント：制限クライアント → 選ばれたメンバーのみ。](https://madsalt.tech/charts/ja/time-tracking-for-audit-firms-roles.svg)

*図2. 監査法人の工数管理アプリの既定のロール。オーナーは権限マトリクスで各ロールを変更できます。*

オーナーは、領域と操作を組み合わせたチェックボックスのマトリクスで各ロールを調整します。すべてのルールは画面ではなくデータベースにあるため、データベースが拒否するものを画面が表示することはありません。各チェックボックスは、リリース前に本番のコピーでテストしました。その方法と見つかったことは、[Supabase RLSのテスト](https://madsalt.tech/ja/blog/how-to-test-supabase-rls/)にまとめています。

マトリクスでは答えられなかった問いが、法人自身から出ました。2026年6月、最も権限の限られたロールのメンバーが、配分画面に他のメンバーとそのプロジェクトが表示されることに気づきました。本人は、自分自身と同僚1人だけが見えるはずだと考えていました。制限付きのメンバーは、自分のプロジェクトにいる人を見てよいのか。決まったルールは、見てよい。ただし共有しているプロジェクトに限り、他の人の稼働可能時間と休暇は隠す、というものです。

法人が本当に納得するアクセスモデルは、どうすれば得られるのか。クライアントに記憶から説明してもらうことはしませんでした。9つのセクション、72の質問からなるアンケートを送り、権限のグリッドには、2026年8月7日時点で稼働中のシステムが実際にそうなっていた状態で、あらかじめチェックを入れておきました。クライアントは間違っている箇所を直し、変更されたセルにはすべて印をつけました。人は、現実を説明するより、現実を直すほうが得意です。

## ミス1：レポートの合計が低く出るはずだった

タイムシートのページには、法人全体の「今四半期」と「年初来」のビューがあります。これらは、範囲内のすべての工数エントリを1回のリクエストで読み込んでいました。アプリの裏にあるデータベースAPIは、1リクエストあたり最大1,000行を返し、1,000行で止まってもエラーは出しません。最初の1,000行を返すだけです。

Supabaseはこの既定値を文書化しています。API設定で上限を変えない限り、[プロジェクトが返す行は最大1,000行です](https://supabase.com/docs/reference/javascript/select)。

そのため、ある範囲のエントリが1,000件を超えると、メンバーや週がビューから落ち、画面には何も表示されないまま合計が低く出ることになります。週に約70件のペースでは、年初来ビューは2026年11月中旬ごろに1,000件を超える見込みでした。2026年9月24日のコード監査で、それが起きる前に見つかりました。修正は、すべての範囲をページごとに読み込む方式で、レポートのエクスポートもすべて同じようにページ分割で読み込みます。

**自分のツールを確認する方法：** 長い期間を選び、生のエントリをエクスポートして、自分で合計し、レポートの合計と比べます。両者が違えば、レポートは行を切り捨てています。

## ミス2：何も保存されていないのに「保存しました」

権限が理由で、あるいはルールが二要素のサインインを求めているためにデータベースが変更を拒否した場合、エラーなしで「0行変更」と答えることがあります。レコードを更新または削除するアプリの約30か所は、この答えを成功と読み取り、「保存しました」と表示していました。本人は次に進みます。変更は一度も行われていません。

修正は、失敗側に倒すことです。1行も触れていない書き込みはエラーとして扱い、エラーとして表示します。そして今は、すべての書き込み経路がそう扱うことをテストで確認しています。

**自分のツールを確認する方法：** 編集する権利のないメンバーとしてサインインし、編集を試みて、ページを再読み込みします。「保存しました」と表示されたのに古い値に戻っていたら、そのツールは保存について嘘をついています。

## ミス3：機密クライアントがレポートから漏れた

契約によっては、関わる人だけが知っているものがあります。2026年8月24日から、オーナーはクライアントを指名したメンバーに限定できるようになりました。それ以外の人には、そのクライアントも、プロジェクトも、タスクも、工数も何も返りません。オーナーは常にアクセスでき、そのアクセスは現在オーナーのロールを持つ人から都度計算され、保存はされないため、ロールが移れば一緒に移ります。

クライアント一覧から隠すのは簡単な部分でした。漏れは、横の入り口にありました。2026年9月8日のレビューで、次のことが見つかりました。

- **3つのレポート関数が制限を無視していました。** 通常のアクセスルールを飛ばす権限で動いていたため、機密クライアントの工数がレポートに現れる可能性がありました。
- **管理画面のタグ概要の使用件数**が、機密クライアントのプロジェクトとタスクを数えていました。契約が存在すること、そしておおよその規模が分かってしまいます。
- **エラーメッセージで違いが分かりました。** 実在するが隠されたレコードの変更を試すと「forbidden」、でっち上げのレコードを試すと「not found」が返り、誰でも機密クライアントの存在を探れました。

3つとも、メインのテーブルと同じチェックを適用するようにし、隠されたレコードは、存在しないレコードとまったく同じに見えます。機密クライアントからプロジェクトやエントリを移動するには、オーナーか専用の権限も必要で、すべての移動が記録されます。

**自分のツールを確認する方法：** 1人だけにクライアントを制限します。そのうえで別の人として、すべてのレポートを実行し、すべての件数とフィルターを確認し、クライアント名を検索し、そのプロジェクトの1つへの直接リンクを開きます。エラーメッセージも含めて、痕跡は何も見つからないはずです。

## ミス4：後の承認で却下が隠れることがあった

1週間には複数のプロジェクトのエントリがあり得るため、承認者も複数います。あるプロジェクト管理者がエントリを却下し、別の管理者が後から自分の担当分を承認すると、後の承認が週全体を確定させて、却下を覆い隠すことがありました。エントリをタスク間で移動したり、週を再オープンしたりしても、同じように隠れることがありました。

2026年9月24日に承認ロジックを変更しました。有効な却下済みエントリが残っている間は、その週は却下のままです。また、プロジェクト管理者が却下済みエントリをアーカイブできるのは、自分が却下した場合だけです。今は、データベースのプローブがこれらのケースをそれぞれ実行し、すべてでPASSと表示されなければなりません。

**自分のツールを確認する方法：** 1つの週に承認者を2人用意します。1人目として1つのエントリを却下し、2人目としてそれ以外をすべて承認して、週がどの状態で終わるかを見ます。

## 監査法人の工数管理は、買うか作るか？

まずは買いましょう。Toggl、BigTime、ZenWorkflowなどのツールは、タイマー、週次承認、クライアントへの請求をすでにカバーしていて、今週から使い始められます。自作が意味を持つのは、製品では表現できないルールが法人にある場合です。たとえば、指名したメンバーにだけ見える機密クライアント、1週間に複数のプロジェクト管理者が承認する仕組み、オーナーがチェックボックス単位で形を決めたいロールなどです。

どちらを選んでも、上の4つの確認は午後1回あれば終わり、機能の一覧より多くのことが分かります。製品ページはどれも「きめ細かな権限」と謳っています。チェックボックスを外したときに何が起きるかを見せるところは、ほとんどありません。

## このレポートの限界

- **1つの法人だけ。** アクセスモデル、週に約70件というボリューム、アンケートは、1つの法人のものです。
- **ミス1は、発生する前に見つかりました。** 11月中旬という日付は、法人のエントリ数のペースからの予測であり、実際に起きた事故ではありません。
- **請求書の発行はなし。** このアプリは工数、請求形態、工数予算を保持しますが、クライアントへの請求は行わないため、工数から請求までの流れについては語れません。

ここでのアクセスルールは、PostgresのRow Level Securityです。ロールのマトリクスでは見つからない2つの抜け穴は、別記事にまとめています。[2つの組織に属するユーザー](https://madsalt.tech/ja/notes/supabase-rls-user-in-two-organizations/)と、[NULLで通り抜けてしまうIF](https://madsalt.tech/ja/notes/plpgsql-if-not-null-fails-open/)です。構築そのものは[監査法人の工数管理の事例](https://madsalt.tech/ja/work/audit-firm-time-tracking/)にあり、この種の仕事は[社内ツールとダッシュボード](https://madsalt.tech/ja/services/internal-tools-dashboards/)に当たります。

自社に合う工数管理を選んでいる、または作ろうとしていませんか？

アクセスルールや承認について、情報交換しましょう。売り込みはしません。

[お問い合わせ](https://madsalt.tech/ja/#contact)
