## 02_02_client_table.md # 顧客マスタ 設計書 **版**: v3.1 実装の状況は `work_order_db_migration.md`(作業書)を見る **マスタ本体保存先**: DB の `clients`、`client_branches`、`persons`、`client_contacts`、`meishi_history`、`client_types`(`00_07_database.md` 5.3節)。名刺画像のファイルは `/backoffice/data/clients/meishi/` **対象**: 営業管理担当・案件管理担当・全管理者 --- ## 1. 位置づけ 顧客マスタは、SPS(個人事業)・SCSPS(法人)**共通**で参照する組織台帳である。 ただし、組織の先に紐づく個人(自然人)の識別情報は、情報の主体が個人であるため、 事業主および指定された権限者のみアクセス可能とする(2節参照)。 本マスタは「顧客=発注元の組織」を管理するものであり、個別案件ごとの依頼内容・ 実施記録(当事者情報含む)は対象外。それらは案件データ(`data/cases/`配下)に 個人事業/法人で完全分離した状態で保持する(`00_経営理念_事業構造.md`5節の 情報分離原則)。 --- ## 2. アクセス制御方針 区別の基準は「SPS案件かSCSPS案件か」ではなく、**「情報の主体が組織か個人か」**。 | 区分 | 主体 | アクセス制御 | |---|---|---| | S保険会社/A代理店/L弁護士事務所/C法人/G団体/D調査会社/F個人事業主 | 組織 | 通常権限(`client_view`)で共有 | | 組織の先に紐づく個人(依頼者本人・契約実態が個人の対象者等)、K完全個人、P法人会員の個人 | 個人 | `client_view_cross`/`client_edit_cross`のみ | - 業務窓口としての担当者情報(会社電話・業務メール・役職)は組織情報として共有可 - 特定個人の依頼内容に紐づく識別情報・契約実態が個人である対象者の情報は制限対象 - 職責・役職は判定に使用しない。`window.spsUser.permissions.xxx === true` でのみ判定する ### 2.1 権限キー | 権限ID | 説明 | 対象範囲 | レベル | |--------|------|----------|--------| | `client_view` | 顧客マスタ(組織情報)を閲覧する | all | 1 | | `client_edit` | 顧客マスタ(組織情報)を編集する | all | 2 | | `client_view_cross` | 顧客マスタの個人識別情報を閲覧する | all | 1 | | `client_edit_cross` | 顧客マスタの個人識別情報を編集する | all | 2 | ※ `06_permission/06_01_permission_design.md` 2.10節に反映済み。 --- ## 3. データ構造 ### 3.1 マスタの分離方針(4マスタ構造) 1社に数百人の担当者や複数拠点、担当者の移籍(転職)に対応するため、データを以下の**4つのマスタに分離**する。 1. **顧客マスタ** (`clients`):会社・組織自体の情報。 2. **拠点・部署マスタ** (`client_branches`):各社の支店・営業所・部署。 3. **人物マスタ** (`persons`):**個人**の情報。氏名、生年月日、個人携帯等。転職しても不変(`person_id`)。 4. **所属(担当者)マスタ** (`client_contacts`):**所属と接点**の情報。`person_id` を参照し、会社、拠点、役職、会社用連絡先、名刺画像(`meishi_history`)、期間(`valid_from`/`valid_to`)を保持する。 ### 3.2 顧客区分コード(確定) | コード | 区分 | 備考 | |-------|------|------| | S | 損害保険会社 | | | A | 損保代理店 | | | L | 弁護士 | | | C | 法人(Corporation) | 旧H(法人・法人格)を統合。SPS/SCSPS共通 | | G | 団体 | | | D | 調査会社 | | | E | その他 | | | F | 個人事業主(Freelance) | 事業(屋号)としての依頼。SPS専用 | | K | 完全個人 | プライベートな個人としての依頼。SPS専用 | | P | 法人会員の個人(Personnel) | 法人(C)に紐づく従業員。SCSPS専用。親法人のIDを `parent_client_id` に保持する | **区分の利用範囲ルール**: - SPS(個人事業)画面:すべての区分を選択可能。 - SCSPS(法人)画面:K(完全個人)は選択不可。それ以外(S, A, L, C, G, D, E, F, P)を選択可能。 ### 3.2.1 表示順(sort_order) 顧客区分のマスタは、画面上の表示順(プルダウンの並び順など)を制御するために `sort_order` フィールドを持つ。 - 数値が小さいほど上に表示される。 - 管理画面で「上へ」「下へ」ボタンにより順番を入れ替え可能とする。 - 新規追加時は、現在の最大値+1の `sort_order` が自動付与される。 ### 3.3 顧客コード(`client_id`)の採番ルール - 形式:**顧客区分コード(1文字) + 3桁の連番(001〜999)** - 例:`S001`(損保1件目)、`L101`(弁護士101件目)、`C001`(法人1件目) - **P(法人会員の個人)の形式**:**親法人ID + ハイフン + 支部2桁 + 個人2桁** - 例:親法人が `C001` の場合、`C001-0101`(01支部の01人目)、`C001-0201`(02支部の01人目) - 採番タイミング:新規顧客登録時 - 採番主体:営業管理担当(管理画面またはAPIにて自動採番) - 不変性:一度採番したコードは変更禁止(履歴管理のため) ### 3.4 各マスタのデータ構造(APIの入出力の形。テーブルは `00_07_database.md` 5.3節) #### ① 顧客マスタ(`clients`) ```json { "clients": [ { "client_id": "S101", "type": "S", "name": "テスト損害保険株式会社", "postal_code": "100-0001", "address": "東京都千代田区千代田1-1", "business_phone": "03-1234-5678", "business_email": "info@example.com", "active": true, "created_at": "2026-10-24", "created_by": "SPS01-99999", "parent_client_id": null } ] } ``` #### ② 拠点・部署マスタ(`client_branches`) ```json { "branches": [ { "branch_id": "BR-001", "client_id": "S101", "branch_name": "東京本社", "department_name": "自動車保険部", "active": true } ] } ``` #### ③ 人物マスタ(`persons`) ```json { "persons": [ { "person_id": "P-001", "name": "山田 太郎", "name_kana": "ヤマダ タロウ", "birthday": "1980-01-01", "personal_mobile": "090-1234-5678", "personal_email": "yamada.taro@example.com", "created_at": "2026-10-24" } ] } ``` #### ④ 所属(担当者)マスタ(`client_contacts`) ```json { "contacts": [ { "contact_id": "CT-001", "person_id": "P-001", "client_id": "S101", "branch_id": "BR-001", "role": "係長", "grade": "管理職", "is_window": false, "company_phone": "03-1234-5678", "direct_phone": "03-1234-5679", "company_mobile": "090-1234-5678", "company_email": "yamada@example.com", "meishi_history": [], "valid_from": "2024-04-01", "valid_to": null, "active": true } ] } ``` ### 3.5 名刺交換履歴(meishi_history) 名刺画像のファイルのパスとOCR抽出データ、交換履歴は、`meishi_history` テーブルに保持する(1枚1行。`contact_id` で所属マスタに紐づく)。APIの入出力では、担当者の `meishi_history` 配列として返す。形は次のとおり。 ```json "meishi_history": [ { "meishi_id": "M-001", "person_id": "P-001", "contact_id": "CT-001", "image_front": "/data/clients/meishi/M-001_front.jpg", "original_file": "/data/clients/meishi/M-001_original.pdf", "ocr_data": { "company": "株式会社A", "name": "山田 太郎", "phone": "03-1234-5678", "email": "yamada@example.com" }, "received_by": "SPS01-99999", "exchanged_at": "2026-10-24", "exchanged_place": "東京ビッグサイト", "tags": ["見込み客", "展示会"] } ] ``` ### 3.6 フィールド定義 #### 顧客マスタ(`clients`) | フィールド | 必須 | 備考 | |-----------|------|------| | `client_id` | ○ | 顧客区分+3桁連番(例: `S001`, `L101`)。Pの場合は「親法人ID-支部2桁-個人2桁」(例: `C001-0101`)。一度決めたら変更しない | | `type` | ○ | 3.2節の顧客区分コード | | `name` | ○ | 組織名(K/Pの場合は個人名) | | `maiden_name` | - | 個人(K/P)の場合の旧姓。改姓時に使用 | | `parent_client_id` | - | P(法人会員の個人)または枝番の場合、親となる法人のID | | `postal_code` | - | 郵便番号 | | `address` | - | 組織所在地(請求書送付先等) | | `business_phone` / `business_email` | - | 組織の代表連絡先 | | `active` | ○ | 論理削除フラグ。物理削除禁止 | | `created_at` / `created_by` | - | 作成日・作成者 | #### 拠点・部署マスタ(`client_branches`) | フィールド | 必須 | 備考 | |-----------|------|------| | `branch_id` | ○ | 拠点ID(例: `BR-001`) | | `client_id` | ○ | 顧客ID | | `branch_name` | ○ | 拠点名(支店・支社・センター等) | | `department_name` | - | 部署名(部・課等) | | `section_name` | - | 係名 | | `active` | ○ | 論理削除フラグ | #### 人物マスタ(`persons`) | フィールド | 必須 | 備考 | |-----------|------|------| | `person_id` | ○ | 人物ID(例: `P-001`)。転職しても不変 | | `name` / `name_kana` | ○ / - | 氏名・氏名カナ | | `birthday` | - | 生年月日(機密項目) | | `personal_mobile` / `personal_email` | - | 個人の連絡先(機密項目) | | `created_at` | - | 作成日 | #### 所属(担当者)マスタ(`client_contacts`) | フィールド | 必須 | 備考 | |-----------|------|------| | `contact_id` | ○ | 所属ID(例: `CT-001`) | | `person_id` | ○ | 人物ID | | `client_id` | ○ | 顧客ID | | `branch_id` | - | 拠点ID(拠点を持たない場合は空) | | `role` | ○ | 役職(例:係長、課長代理、弁護士)。名刺がなく役職のない窓口の人は「担当」とする | | `is_window` | - | 窓口担当の印(真偽)。顧客との連絡の受け口になる人に付ける。複数人に付けてよい | | `grade` | - | 職位(例:管理職、一般職) | | `company_phone` / `direct_phone` / `company_mobile` / `company_email` | - | 会社電話、ダイヤルイン、会社携帯、業務メール | | `valid_from` / `valid_to` | - | 着任日・退任日。履歴参照用 | | `active` | ○ | 現在の担当者かどうか(退任済みはfalse) | #### 顧客の別名(`client_aliases`) | フィールド | 必須 | 備考 | |-----------|------|------| | `alias_id` | ○ | 別名ID | | `client_id` | ○ | 顧客ID | | `alias_name` | ○ | 別名(通称、略称、旧称、窓口が名乗る事務所名の表記 など) | | `note` | - | 備考 | - 1つの顧客に、複数の別名を持てる。顧客の検索と名寄せ(`check_duplicate.php`)は、`name` と別名の両方を対象にする。 #### 顧客区分マスタ(`client_types`) | フィールド | 必須 | 備考 | |-----------|------|------| | `code` | ○ | 3.2節の区分コード | | `name` | ○ | 区分名 | | `applicable_companies` | ○ | 使える会社(SPS/SCSPS。DBでは `client_type_companies` に1社1行) | | `sort_order` | ○ | 表示順(3.2.1節) | | `active` | ○ | 論理削除フラグ | - 個人識別情報の制限(`restricted`)の判定は、顧客区分(K、P)と、人物マスタの項目による(案。2節)。 ### 3.7 名称変更・枝番運用ルール 1. **社名・個人名の変更(実体が変わらないもの)** - コードは変更せず、`name` を上書きする。改姓の場合は `maiden_name` に旧姓を保持する。 2. **組織変更(合併・分割等で実体が変わるもの)** - 既存のコード(例: `C001`)は `active: false` で無効化する。 - 新しいコード(例: `C001-01`)を新規追加し、`parent_client_id` に旧コードを設定する。 - 新規案件のプルダウンには `active: true` のレコードのみを表示する。 ### 3.8 担当者の異動履歴の管理方針 担当者が異動・退任した場合、**ID(`contact_id`)は変更せず**、既存レコードの `valid_to` に退任日を設定し、`active` を `false` にする。 同じ人物が新しい部署に異動した場合は、**同じ `person_id` で新しい `branch_id` を持つレコードを追加**する。これにより、枝番のようにコードが長大化するのを防ぎ、一貫したIDで履歴を追跡できる。 **役職・職位の変更(昇進・昇格など)も同じ扱いとする。** 同じ部署のままでも、旧レコードの `valid_to` に変更の前日(または退任日)を設定して `active` を `false` にし、新しい `role`・`grade` を持つレコードを追加する。担当者の配置換え・昇進の履歴は、この所属マスタの期間管理(`valid_from`/`valid_to`)が持つ。変更履歴(`change_history`)には、二重に記録しない。 ### 3.8.1 窓口と、複数の弁護士がいる拠点 - 1つの拠点に、複数の弁護士(所属)がいてよい。同じ人物が、複数の拠点に同時に所属することは想定しない。 - 窓口は、弁護士本人とは限らない。たとえば「大平昇法律事務所」という顧客に対し、連絡は「大平法律事務所事務局 中川」から来る。この場合、顧客の下に部署「事務局」を登録し、中川さんをその部署の所属(役職は「担当」)として登録し、`is_window` を真にする。 - 窓口が名乗る事務所名の表記が、顧客の名称と違う場合は、別名(`client_aliases`)に登録する。 ### 3.9 変更履歴との関係(`00_10_change_history.md`) | 変更の内容 | 履歴の持ち方 | |---|---| | 顧客(組織)の名称・住所・電話・メールの変更 | `name` などを上書きし、変更履歴(`change_history`)に、「いつから・何が・何から何へ・理由(任意)」を記録する(区分A)。有効日・理由は保存時に任意で入力する | | 顧客の組織変更(合併・分割など実体が変わるもの) | 3.7節のとおり、旧コードを無効化し、新コードを追加する(履歴は旧コードに残る) | | 担当者の異動・退任・昇進・昇格 | 3.8節のとおり、所属マスタ(`client_contacts`)の期間管理で持つ(変更履歴には記録しない) | | 人物(`persons`)の氏名・個人連絡先の変更(改姓を含む) | 上書きし、変更履歴に記録する(区分A)。氏名・個人連絡先の履歴は機密項目(`change_history_view_sensitive` が必要) | - 誤字などの訂正は、長く残さない。「訂正」か「変更」かは、修正した本人が選ばない。別の権限者が確認して決める(`00_10`)。 - 顧客・人物の保存API(`save_client.php`、`save_person.php`)は、更新と履歴の記録を、同じ処理の中で行う。 - 顧客の編集画面に「履歴」ボタンを置く(`change_history_view` が必要)。 - 本節の区分は案。真柴さんの承認で確定する。 --- ## 4. 依頼者情報との区別(対象外事項) リピーターではない一回限りの当事者は本マスタに含めない。 案件データ(`data/cases/[private|corporate]/[案件番号]/case.json`)側に自由記述で保持する。 ただし、個人(K)や法人会員の個人(P)であってもリピーターになり得る場合や、請求管理のためにマスタ登録が必要な場合は、顧客マスタに登録することができる。 --- ## 5. API | エンドポイント | 用途 | 備考 | |--------------|------|------| | `GET /clients/api/get_clients.php` | 顧客一覧取得 | `visibility: restricted`のmembersはサーバー側で権限判定の上フィルタして返却する | | `GET /clients/api/get_client_detail.php` | 顧客詳細取得 | 4マスタを結合して返却 | | `GET /clients/api/get_client_types.php` | 顧客区分マスタ取得 | プルダウン用。`sort_order` 昇順で返却する | | `GET /clients/api/get_persons.php` | 人物一覧・検索 | | | `POST /clients/api/save_client.php` | 顧客の新規作成・更新 | `client_edit`・`client_edit_cross`で権限分岐 | | `POST /clients/api/save_client_type.php` | 顧客区分マスタの保存 | `client_edit`権限が必要。並び替え(`move`)アクション含む | | `POST /clients/api/save_person.php` | 人物保存 | | | `POST /clients/api/ocr_meishi.php` | 名刺OCR・解析 | | | `POST /clients/api/save_meishi.php` | 名刺画像保存・紐付け | | | `GET /clients/api/check_duplicate.php` | 名寄せチェック | | - 顧客一覧・検索の API(`get_clients.php`、`check_duplicate.php`)は、顧客の別名も検索の対象にする - サーバー側で`client_view_cross`を持たないユーザーには`individual_subject`やP、Kのmembersを返却しない(クライアント側JSでのフィルタは不可・必ずAPI側で判定) --- ## 6. 案件管理との連携 ### 6.1 依頼元プルダウンの契約仕様(input.html向け) - `input.html`の依頼元プルダウンは `GET /clients/api/get_clients.php` を呼び、 `client_view`権限で取得可能な組織一覧を参照する - プルダウン表示値:`client_id` / `name` / `type`(区分コード) - 顧客区分(S, A, L等)でフィルタリングしてから顧客名を選択するカスケード形式とする - **カスケード選択**:顧客選択後、拠点・部署・係(`client_branches` の `branch_name`・`department_name`・`section_name`)→担当者(`client_contacts`)の順に選択肢を絞り込む - **窓口**:担当者の候補は、窓口担当(`is_window` が真)を先頭に表示する - **担当者選択後**:登録されている電話番号・メール・携帯が自動入力される(手入力による誤字防止) - 案件のデータ側には`client_id`およびスナップショットを保存し、名称等は毎回マスタ参照とする(コードは不変、名称は変更可のため) - **P(法人会員の個人)の退職チェック**:`active: false` または `valid_to` が過去のPが選択された場合、警告を表示し、「個人(K)として登録し直す」か「保存をブロック」する ### 6.2 役割分担 - 委託元(調査会社等)を通じて受注した個別案件の記録・進行管理は案件管理担当の設計範囲 - 営業管理担当は委託元(組織)の顧客マスタ登録・管理のみを担当する --- ## 7. 今後の課題 - 外部ストレージ(委託元システム等)との直接連携:将来検討事項(今回スコープ外) - 顧客区分マスタ(`client_types`)の管理画面実装(`clients/client_type_edit.html`) --- ## 8. 改訂履歴 | 日付 | 版 | 担当 | 内容 | 理由・影響範囲 | |------|----|------|------|--------------| | 2026-03-20 | 0.1 | 全体管理者 | 仮ファイル作成 | インデックスからのリンク先として用意 | | 2026-09-26 | 1.0 | 営業管理担当(初代) | 初版設計策定 | | | 2026-09-26 | 1.1 | 営業管理担当(初代) | 委託元の`individual_subject`member記述を削除 | 誤認識の訂正 | | 2026-09-26 | 1.2 | 営業管理担当(初代) | 6節を6.1・6.2に分割・具体化 | 提案 | | 2026-09-26 | 1.3 | 全体管理者(12代目) | 3.3節JSON例等の実名記述を架空例に修正 | 文書管理 | | 2026-09-26 | 1.4 | 全体管理者(12代目) | マスタ保存先を`data/clients/clients.json`に修正 | 3層構造原則 | | 2026-10-08 | 1.5 | 全体管理者(12代目) | ファイル名規則の機械的置換 | 規則変更 | | 2026-10-23 | 1.6 | 全体管理者(12代目) | ①顧客区分の統合(H廃止→C、F・K・Pの新設)。②階層構造の拡張と役職・職位の追加。③履歴管理の追記。④Pの退職チェック仕様の追記。⑤案件管理連携の追記 | 案件入力画面の要件確定に伴う更新 | | 2026-10-23 | 1.7 | 全体管理者(12代目) | `client_id` の形式を「3桁の連番(例: 001)」に変更。Pの場合は「親法人ID-4桁連番(例: 001-0001)」に変更。3.3節に顧客コード採番ルールを新設 | 顧客の目視識別性向上と、案件データ等での参照の簡便化のため | | 2026-10-23 | 1.8 | 全体管理者(12代目) | 顧客コードの採番ルールを「顧客区分コード + 3桁連番(例: S001, L001, P001)」に確定。JSON例およびPの親子関係(`parent_client_id`)の記述を修正 | システム優先のゼロパディング(001〜)方針確定に伴う更新 | | 2026-10-23 | 1.9 | 全体管理者(12代目) | P(法人会員の個人)の顧客コードの形式を「親法人ID-支部2桁-個人2桁(例: C001-0101)」に変更。JSON例およびフィールド定義(`branch_code`追加)を修正 | 支部と個人の紐付けを明確にし、法人会員の管理体制を強化するため | | 2026-10-24 | 2.0 | 全体管理者(12代目) | 名称変更・枝番運用ルール(3.6節)を追加。顧客コードの不変性と、実体変更時の枝番追加(無効化+新規)ルールを明記 | 社名変更等の履歴を保持し、過去案件の参照整合性を維持するため | | 2026-10-24 | 2.1 | 全体管理者(12代目) | 3.2.1節「表示順(sort_order)」を新設。顧客区分マスタに並び順を持たせ、管理画面で入れ替え可能とする仕様を追加。API仕様(5節)に並び替えアクションを追記 | 実務において受託の多い区分を上位に表示させる要望に対応するため | | 2026-10-24 | 2.2 | 全体管理者(12代目) | 3.5節フィールド定義に `postal_code`(郵便番号)を追加 | 案件登録や請求書発行時における住所入力の利便性向上のため | | 2026-10-24 | 2.3 | 全体管理者(12代目) | データ構造を3マスタ(顧客・拠点・担当者)に分離。担当者マスタにダイヤルイン・共有携帯・誕生日を追加。担当者の履歴管理方針を明確化(枝番ではなく期間管理) | 大規模法人(損保等)の数百人規模の担当者管理、および履歴の正確な追跡に対応するため | | 2026-10-24 | 2.4 | 全体管理者(12代目) | 担当者マスタをさらに「人物マスタ(persons.json)」と「所属マスタ(client_contacts.json)」に分離し、4マスタ構造に変更 | 担当者の転職・移籍時にも名刺や接点の履歴を途切れさせないため | | 2026-10-24 | 2.5 | 全体管理者(12代目) | 3.5節に名刺交換履歴(`meishi_history`)の仕様を追加。名刺管理機能(`04_04_01_meishi_management.md`)との連携仕様を追記 | 名刺管理機能の導入に伴い、担当者ごとの名刺・接点履歴を保持する必要があるため | | 2026-10-29 | 2.6 | 全体管理者(14代目) | ①JSON例の実在の会社名(保険会社)・住所を架空の例(`テスト損害保険株式会社` ほか)に差し替え、IDを `SPS01-99999` に。②3.8節に、役職・職位の変更(昇進・昇格)も所属マスタの期間管理で持つ旨を追記。③3.9節「変更履歴との関係」を新設(案)。④末尾の余分な記号を削除 | 公開サイトに実名を出さないため、変更履歴仕様(`00_10`)の反映。影響範囲:`save_client.php`、`save_person.php`、顧客の編集画面、`change_history` | | 2026-10-29 | 3.0 | 全体管理者(14代目) | DB前提に書き直し。保存先を6つのテーブルに(先頭、3.1節、3.4節、3.5節)。3.6節を、現行の4マスタ構造と実データの項目に合わせて全面更新(旧構造の `branches[]`・`departments[]`・`sections[]`・`members[]` の記述を削除し、`section_name` を拠点・部署マスタに、担当者の会社携帯を `company_mobile` に統一)。顧客区分マスタ(`client_types`)の項目を追加。6.1節のカスケードを新構造に | 仕様書をDB前提に統一(作業書 J-02)。実データ(顧客45件、人物6件、所属6件)との突き合わせ(作業書 D-01、D-02)。影響範囲:`00_07` 5.3節、`schema_clients.sql` | | 2026-10-29 | 3.1 | 全体管理者(14代目) | ①所属マスタに窓口担当の印(`is_window`)を追加。名刺がなく役職のない窓口の人の役職は「担当」。②顧客の別名(`client_aliases`)を追加し、検索と名寄せの対象に。③3.8.1節(複数の弁護士がいる拠点と窓口の扱い)を新設。④6.1節に窓口を先頭に表示する旨を追記 | 真柴さんの指示(弁護士事務所の運用)。影響範囲:`00_07` 5.3節、`schema_clients.sql`、`get_clients.php`、`check_duplicate.php` |