Newer
Older
client_dwatch / docs / handoff / analysis / ddl-diff-parse.md

【注記】 2026-09-03、TeamWorks 提供の実DDL(clean_watch_20260902.sql)と手書き prisma/schema.prisma の答え合わせのために作成した記録です(DDL文を直接パースする方法)。 prisma db pull による照合結果 ddl-diff-dbpull.md と対になる相互検証の記録です。両者を独立に突き合わせるために両方を残しています。 当時の記録であり、現行方針ではありません。 以降の決定は docs/decisions.md と docs/handoff.md を参照してください。

実DDL 直接パースによる独立比較(担当: DDLテキスト解析)

  • 入力1(正): C:\Users\daich\Downloads\clean_watch_20260902.sql(46,390 bytes / mysqldump 10.13, MySQL 8.0.41, DB名 clean_watch)
  • 入力2(比較対象): C:\Users\daich\dev\d-watch\prisma\schema.prisma(790行 / 28 model / 手書き版)
  • 入力3(参考): 定義書転記 01-master.md / 02-clean-error.md / 03-schedule-summary.md
  • MySQL への接続は一切していない(テキスト解析のみ)。d-watch リポジトリは読み取りのみ、変更なし。
  • 相手担当(prisma db pull)の成果物(pulled.prisma / diff.json / diff.txt / 30-dbpull-diff.md)は読んでいない。

1. パースの方法と、パースできなかった箇所

1-1. DDL パーサ(mine/parse_ddl.py)

正規表現による分割は使わず、文字単位の状態機械で処理した。

  1. CREATE TABLE \x` (を起点に、開き括弧から**括弧深度を数えて** depth が 0 に戻る位置までを1テーブルのブロックとして切り出す。 走査中は次を読み飛ばすため、decimal(12,6)やenum('a','b')` の内側の括弧・カンマでは壊れない。
    • シングルクォート文字列(\ エスケープ と '' 二重化の両方に対応)
    • ダブルクォート文字列 / バッククォート識別子
    • /* */ ブロックコメント、-- 行コメント、# 行コメント
  2. ブロック本体を深度0のカンマだけで分割し、1要素 = 1定義(カラム / PRIMARY KEY / UNIQUE KEY / KEY / CONSTRAINT)に落とす。
  3. カラム定義は「識別子 → 型名 → 括弧付きサイズ(これも括弧対応で読む) → 属性列」の順に手で読み進め、 unsigned / zerofill / NOT NULL / DEFAULT / AUTO_INCREMENT / ON UPDATE / COMMENT / 生成列を抽出した。
  4. 閉じ括弧の直後から ; までを table_options として ENGINE / CHARSET / AUTO_INCREMENT=n の取得に使った。

結果: 39テーブル / 372カラム、パース失敗 0件。

健全性チェック(別手段での裏取り): DDL 本文の ^ \名前` 行を grep すると 368 行。 差の 4 行は列名に数字を含むaddr1/addr2`(customers と facilities に各2列)で、grep の文字クラスが数字を含まなかったための取りこぼし。 368 + 4 = 372 でパース結果と一致。取りこぼし・二重取りは無い。

1-2. prisma パーサ

model X { ... } を波括弧深度で切り出し、フィールド行ごとに @@map(物理テーブル名)/ @db.*(MySQL型)/ ?(NULL許容)/ @default(...)(括弧対応で抽出)/ @id / @updatedAt / @relation(fields:..., references:...) / @@index / @@unique を読んだ。 Type[] の配列フィールドと @relation 属性を持たない非スカラーフィールドは DB カラムではないので除外した。

結果: 28 model / 311 カラム、パース失敗 0件。

@db.* → MySQL 型の対応は UnsignedBigInt→bigint unsigned 等の表引きで正規化し、 @db.Timestamp(0) / @db.DateTime(0) の (0) は MySQL 既定精度なので型名からは落として比較した(誤差分を出さないため)。

1-3. パースできなかった / 注意が必要な箇所

DDL・prisma いずれもパース失敗は 0 件。ただし次の 3 点は解析上の制約として明記する。

# 箇所 内容
P-1 定義書転記 md の「auto increment」 定義書は auto increment を初期値欄ではなく備考欄に書いている。素朴に初期値欄だけを比較すると22テーブルの id が「定義書に初期値なし / DDLはauto increment」という偽の差分になる。備考欄側を見て除外した(§7-8 の件数はこれを除外済み)。
P-2 定義書 controls の id 行 定義書側の通し番号(#)欄が空欄のため、行番号が数字である前提のパーサでは行が落ちる。空欄も許容するよう修正して取り込んだ。
P-3 decimal の unsigned Prisma には unsigned decimal を表現する native type が無い。よって §4 の decimal 6件は「Prisma で表現できない差」であり、手書き版のミスとは言い切れない(ただし DB の実態としては unsigned なので差分として計上する)。

1-4. 作業中に起きた事故(申し送り)

出力先 scratchpad\ddl\ は相手担当(db pull 側)と共有ディレクトリだった。 作業中に相手担当が同名の compare.py を同ディレクトリへ書き込み、当方のスクリプトが上書きされた。 その時点の比較結果 JSON は残っていたため結果への影響は無いが、以後は当方の成果物を scratchpad\ddl\mine\ に隔離した。 なお prisma/schema.prisma の md5 は a1d48b7927c2b93171d3394986abbdf1 で、相手担当が取ったバックアップ schema.prisma.HANDWRITTEN.bak と一致しており、手書き版の本体は書き換えられていないことを確認済み(比較には手書き版を使用)。


2. テーブル単位の差分

Laravel 基盤10テーブル(users / sessions / jobs / migrations / cache / cache_locks / failed_jobs / job_batches / password_reset_tokens / personal_access_tokens、DDL側で計60カラム)は比較から除外。

  • 実DDL 業務テーブル: 29テーブル / 312カラム
  • 手書き prisma: 28モデル / 311カラム
区分 件数 テーブル
実DDL にあり手書きに無い 1 clean_link_schedules
手書きにあり実DDL に無い 0 (なし)
両方にある 28 —

カラム総数の整合(取りこぼしが無いことの確認): 共通カラム 300 + 実DDLのみ3 + clean_link_schedules 9 = 312(DDL業務側と一致)/ 共通カラム 300 + 手書きのみ11 = 311(prisma側と一致)。

clean_link_schedules について

実DDL 上で link_schedules と構造が完全一致(列順まで一致、全カラムの型・unsigned・NULL許容・既定値・AUTO_INCREMENT・ON UPDATE がすべて同一、PK も id、FK も section_id → sections(id) の1本のみ)。詳細は §7-4。


3. カラム単位の差分(テーブルごと)

3-1. 実DDL にあって手書き prisma に無いカラム(3件)

テーブル カラム 実DDL の定義
robot_error_reports responded_at datetime DEFAULT NULL
control_error_histories responded_at datetime DEFAULT NULL
control_reports serial_number varchar(100) NOT NULL

3-2. 手書き prisma にあって実DDL に無いカラム(11件)

テーブル カラム 手書きの定義 判定
robot_error_reports responsed_at DateTime? @db.DateTime(0) 綴り違い(実物は responded_at)
control_error_histories responsed_at DateTime? @db.DateTime(0) 綴り違い(実物は responded_at)
control_reports sireal_number String @db.VarChar(100) 綴り違い(実物は serial_number)
section_robot_statuses indicatived_at DateTime? @db.Timestamp(0) 実DDLに該当列が存在しない(改名先も無し)
section_robot_statuses deleted_at DateTime? @db.Timestamp(0) 実DDLに無い(論理削除なし)
clean_statuses deleted_at DateTime? @db.Timestamp(0) 実DDLに無い(論理削除なし)
clean_schedules started_at DateTime? @db.DateTime(0) 実DDLに無い
clean_schedules ended_at DateTime? @db.DateTime(0) 実DDLに無い
clean_timetable_histories inactive Int @default(0) @db.UnsignedTinyInt 実DDLに無い
robots task_id String? @db.VarChar(20) 実DDLに無い(robot_task_versions 側にのみ存在)
robots version String? @db.VarChar(20) 実DDLに無い(robot_task_versions 側にのみ存在)

うち 3 件(responsed_at×2 / sireal_number)は単純な改名で、実質のカラム欠落は 8 件。

3-3. カラム集合(名前の集合)が完全一致したテーブル: 20 / 28

controls / customers / customer_contacts / customer_error_summaries / customer_summaries / devices / facilities / facility_contacts / facility_error_summaries / facility_summaries / groups / link_schedules / robot_instruct_histories / robot_task_versions / sections / security_statuses / security_status_histories / clean_status_histories / clean_task_reports / clean_timetables

カラム集合が一致しなかった 8テーブル(§3-1 / §3-2 の内訳): robot_error_reports / control_error_histories / control_reports / section_robot_statuses / clean_statuses / clean_schedules / clean_timetable_histories / robots

(型・既定値などの差分はカラム集合が一致していても存在する。§4 を参照。)


4. 型・null許容・既定値の差分

4-1. 型の差分(14件)

テーブル カラム 実DDL 手書き prisma 影響
customer_contacts contact_type bigint unsigned Int @db.UnsignedTinyInt(= tinyint unsigned) 大(Int↔BigInt。§7-6 参照)
facility_contacts email varchar(255) String @db.VarChar(100) 中(100超の値が読める/書けない不整合)
robot_error_reports serial_number varchar(20) String @db.VarChar(50) 中(21〜50文字を書くと切り詰め/エラー)
robot_error_reports product_code varchar(20) String? @db.VarChar(50) 中(同上)
clean_statuses task_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3。Prisma で表現不可)
clean_statuses clean_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3)
clean_status_histories task_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3)
clean_status_histories clean_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3)
clean_task_reports task_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3)
clean_task_reports clean_area decimal(12,6) unsigned Decimal @db.Decimal(12,6) 小(P-3)
customer_summaries task_area decimal(14,6) unsigned Decimal @db.Decimal(14,6) 小(P-3)
customer_summaries clean_area decimal(14,6) unsigned Decimal @db.Decimal(14,6) 小(P-3)
facility_summaries task_area decimal(14,6) unsigned Decimal @db.Decimal(14,6) 小(P-3)
facility_summaries clean_area decimal(14,6) unsigned Decimal @db.Decimal(14,6) 小(P-3)

手書き版が実DDLと型・unsigned まで完全一致していた点(差分ゼロだった箇所)で特筆すべきもの:

  • customers.prefecture_cd は実DDL も tinyint(unsigned なし)、facilities.prefecture_cd は tinyint unsigned。 手書き版のコメントにある「テーブル間で型が違う」という指摘は実DDLでもそのままで、手書き版の記述が正しい。
  • robots.status / section_robot_statuses.robot_status はいずれも実DDL も smallint(符号あり)。一致。
  • clean_statuses.clean_status / clean_status_histories.clean_status はいずれも実DDL も tinyint(符号あり)。一致(§7-3)。
  • clean_task_reports.clean_time は実DDL も int unsigned。一致。

4-2. NULL 許容の差分(1件)

テーブル カラム 実DDL 手書き prisma 影響
robot_error_reports errored_at datetime DEFAULT NULL(NULL可) DateTime @db.DateTime(0)(必須) 大。DB には NULL が入り得るのに型は非 null。読み出し時に実行時エラーになる

4-3. 既定値の差分(9件)

テーブル カラム 実DDL 手書き prisma 影響
robots battery DEFAULT '0' @default(100) 大。満充電で作られる想定が実際は 0
clean_timetables precheck DEFAULT '0' @default(9) 大。9 は「本清掃」ではない(§7-7)
robots device_id 既定値なし @default(0) 中。INSERT 時に明示必須
clean_timetables parent_id 既定値なし @default(0) 中。同上
clean_task_reports created_at 既定値なし(timestamp NOT NULL) @default(now()) 中。アプリ側で必ず値を渡す必要がある
clean_task_reports updated_at 既定値なし(timestamp NOT NULL、ON UPDATE も無し) @default(now()) @updatedAt 中。同上
security_status_histories reported_at 既定値なし(timestamp NOT NULL) @default(now()) 中。同上
clean_status_histories id AUTO_INCREMENT なし @default(autoincrement()) 大。採番されない(§4-4)
clean_timetable_histories id AUTO_INCREMENT なし @default(autoincrement()) 大。採番されない

updated_at について: 実DDL では clean_task_reports と section_robot_statuses の updated_at だけ ON UPDATE CURRENT_TIMESTAMP が付いていない(他の全テーブルは付いている)。 手書き版はどちらにも @updatedAt を付けているが、@updatedAt は Prisma 側で値を作るので実害は無い。ただし DB 直更新では自動更新されない点に注意。

4-4. 主キー / ユニークキーの差分(PK 2件 + UNIQUE 2件)

テーブル 実DDL 手書き prisma
clean_status_histories PRIMARY KEY なし。UNIQUE KEY clean_status_histories_id_unique (id) のみ。id は bigint unsigned NOT NULL(AUTO_INCREMENT なし) id BigInt @id @default(autoincrement())
robot_error_reports PRIMARY KEY なし。UNIQUE KEY robot_error_reports_report_id_unique (error_id) のみ。id は varchar(50) NOT NULL で制約なし id String @id @db.VarChar(50)(error_id 側に @unique なし)

この2件は実装への影響が大きい。

  • robot_error_reports は Prisma が id を一意識別子として扱うが、DB 上の一意制約は error_id にしかない。 id の重複を DB が止めないため、findUnique({ where: { id } }) が「一意でないキーでの検索」になる。 逆に error_id に @unique が無いので findUnique({ where: { error_id } }) は書けない。
  • 両テーブルの id は AUTO_INCREMENT でないため、採番はアプリ責任。

4-5. インデックスの差分(6件 / 4テーブル)

テーブル 実DDL にのみある KEY 手書きにのみある @@index
clean_timetable_histories clean_schedule_id, start_at, end_at —
control_reports control_id —
link_schedules section_id —
robot_task_versions — clean_schedule_id

robot_task_versions.clean_schedule_id は実DDL ではインデックスも外部キーも無い(robot_id にしか KEY が無い)。 この列での絞り込みはフルスキャンになる。


5. 外部キーの差分

実DDL の業務テーブル FK は計 48本(KEY 67本 / UNIQUE 2本)。 48本すべてが ON DELETE / ON UPDATE の指定なし(= RESTRICT 相当)。 手書き版も onDelete を一切指定していないため、この点は一致。

区分 件数 内容
実DDL にあって手書きに無い FK 0 (なし)
手書きにあって実DDL に無い FK 3 下表
テーブル 手書きのリレーション 実DDL の状態
clean_statuses clean_timetable_id → clean_timetables(id) FK なし(KEY も無い)
clean_status_histories clean_timetable_id → clean_timetables(id) FK なし(KEY も無い)
robot_task_versions clean_schedule_id → clean_schedules(id) FK なし(KEY も無い)

いずれも「参照整合性が DB では担保されていない」方向の差分。 Prisma のリレーションとしては動作するが、DB 側は孤児行を許す。

一方、手書き版が clean_timetable_id をあえてリレーションにしなかった robot_error_reports と clean_task_reports は、実DDL でも FK なし・KEY なしで判断が正しかった。 clean_timetables.parent_id の自己参照を張らなかったのも実DDL と一致(FK なし、KEY はある)。

controls.facility_id は実DDL に FK あり。手書き版(TeamWorks B-2 回答を反映済み)と一致。


6. 一致していたテーブル

カラム集合・型・unsigned・NULL許容・既定値・PK・UNIQUE・FK のすべてが一致した 11テーブル:

controls / customers / customer_error_summaries / devices / facilities / facility_error_summaries / groups / link_schedules / robot_instruct_histories / sections / security_statuses

ただし link_schedules は @@index([section_id]) が手書きに無い(§4-5)。 インデックスまで含めて完全一致なのは残り 10テーブル。

customer_summaries / facility_summaries は decimal の unsigned(P-3、Prisma 表現不可)以外は一致。 facility_contacts は email のサイズ以外は一致。customer_contacts は contact_type の型以外は一致。


7. 定義書(転記)と 実DDL の食い違い ★この担当だけが出せる情報★

定義書転記の集計: 29テーブル / 317カラム(makers を含む)。

7-1. responsed_at の実際のカラム名 → responded_at(正しい綴り)

定義書 実DDL 該当テーブル
responsed_at responded_at robot_error_reports(datetime DEFAULT NULL)
responsed_at responded_at control_error_histories(datetime DEFAULT NULL)

定義書の綴りが誤記だった。 TeamWorks 確認項目 C-1 はこれで解決。 手書き版は「実DDL 入手まで定義書表記のまま」という方針で responsed_at としているので、2箇所とも改名が必要。

7-2. その他の綴り違い 3件の決着

定義書の綴り 実DDL 判定
control_reports.sireal_number serial_number 定義書が誤記。定義書の索引欄が fk_control_reports_serial_number だった方が正しく、定義書内の矛盾は serial_number 側で決着
clean_timetables の索引対象 secction_id section_id(索引名も clean_timetables_section_id_foreign) 定義書が誤記。手書き版が section_id と解釈したのは正しい
section_robot_statuses.indicatived_at 該当列が存在しない 綴り違いではなく列そのものが廃止(indicated_at という列も無い)。§7-5

7-3. 定義書の「-1」問題(clean_status)が実DDL でどう解決されているか

定義書は clean_status を unsigned tinyint としながら、備考に -1: 清掃完了(セキュリティ無効) と書いており、 unsigned では格納できない値を要求する自己矛盾があった(clean_statuses と clean_status_histories の2箇所)。

実DDL の答え: 両テーブルとも clean_status tinyint NOT NULL DEFAULT '0'(unsigned なし = 符号あり)。 -1 は格納可能。定義書の型表記が誤りで、備考の値定義が正しかった。

  • TeamWorks 回答 A-2(-1 があるため符号あり tinyint)は実DDL で裏が取れた。
  • 手書き版は A-2 を反映して Int @db.TinyInt にしており、実DDL と一致。この箇所は修正不要。
  • 併せて確認: 同テーブルの clean_status_trans / clean_error は実DDL でも tinyint unsigned(負値なし)。手書き版と一致。
  • robots.clean_status / section_robot_statuses.clean_status は実DDL でも tinyint unsigned のままで、 A-2 の -1 再定義はこの2テーブルには及んでいない。手書き版も unsigned のままで一致。

7-4. 定義書に無い clean_link_schedules は何をするテーブルか

事実(DDL から確定できること):

カラム 型 NULL 既定値 備考
id bigint unsigned NOT NULL — AUTO_INCREMENT, PRIMARY KEY
section_id bigint unsigned NOT NULL — FK → sections(id)、KEY あり
type tinyint unsigned NOT NULL 1
weeks varchar(7) NOT NULL —
intervals varchar(120) NOT NULL —
inactive tinyint unsigned NOT NULL 0
created_at timestamp NOT NULL CURRENT_TIMESTAMP
updated_at timestamp NOT NULL CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
deleted_at timestamp NULL NULL
  • 既存の link_schedules(定義書では「通信スケジュール」)と構造が完全一致。 列名・列順・型・unsigned・NULL許容・既定値・AUTO_INCREMENT・ON UPDATE がすべて同一、PK も id、FK も section_id → sections(id) の1本のみ。機械的に照合済み。
  • table_options に差がある: link_schedules は AUTO_INCREMENT=10、 clean_link_schedules は AUTO_INCREMENT= の記載自体が無い。 mysqldump は次回採番値を出すので、これは clean_link_schedules に一度も行が挿入されていないことを示す。

★以下は推測(DDL からは確定できない)★

  • 「清掃スケジュールに紐づく通信スケジュール」を link_schedules から分離する目的で作られた、 もしくは link_schedules を clean_link_schedules へ改名する移行の途中である可能性が高い。 構造が完全一致で中身が空という組み合わせは、改名・複製の作りかけに典型的なパターン。
  • clean_ 接頭辞は他の清掃系テーブル(clean_schedules / clean_timetables / clean_statuses)の命名に揃えたものと見える。 ただし clean_schedules への FK は無く、section_id しか持たないので、清掃スケジュールとの直接の紐付けは DDL 上に存在しない。
  • どちらが有効なテーブルなのかは DDL からは判定不能。TeamWorks への確認事項とすべき。 現時点では link_schedules にのみデータがあるため、実装は link_schedules を使うのが安全。

7-5. 定義書にあって実DDL に無いもの(廃止されたもの)

テーブル 1件:

定義書 実DDL 補足
makers(メーカー) 無い TeamWorks 回答 A-1「makers テーブルは提供されない」が実DDLで裏付けられた。devices.maker_id は実DDL でも tinyint unsigned で FK なし。手書き版の扱いと一致

カラム 11件(うち3件は §7-1/7-2 の改名なので、実際の廃止は 8件):

テーブル 廃止されたカラム 定義書での定義
robots task_id varchar(20) — robot_task_versions 側にのみ残る
robots version varchar(20) — robot_task_versions 側にのみ残る
clean_schedules started_at datetime(定義書のキー欄は idx だが索引欄に対応行が無かった列)
clean_schedules ended_at datetime(同上)
clean_statuses deleted_at timestamp — 論理削除が廃止
section_robot_statuses deleted_at timestamp — 論理削除が廃止
section_robot_statuses indicatived_at timestamp(状態変更日時)
clean_timetable_histories inactive unsigned tinyint — 履歴に無効フラグは不要という判断か

clean_schedules.started_at / ended_at の廃止は、定義書側の「キー欄は idx なのに索引欄に対応エントリが無い」という 不整合が「列自体が無くなった」形で決着したことを意味する。手書き版が @@index を書かずに保留したのは結果的に妥当だった。

同様に clean_timetable_histories の索引 idx_..._started_at / idx_..._ended_at は、 実DDL では clean_timetable_histories_started_at_index (start_at) / clean_timetable_histories_ended_at_index (end_at) として存在する。 つまり索引名は started_at / ended_at のまま、対象カラムは start_at / end_at。 定義書の「索引名と実カラム名が一致しない」という指摘は実DDL でもそのまま残っている(索引名だけが古い)。

7-6. 定義書が正しく、TeamWorks 回答が実DB に反映されていない箇所 ★要注意★

テーブル.カラム 定義書 TeamWorks 回答 (B-6) 実DDL 手書き版
customer_contacts.contact_type unsigned bigint 「typo。unsigned tinyint に修正」 bigint unsigned Int @db.UnsignedTinyInt
facility_contacts.contact_type unsigned tinyint 「unsigned tinyint」 tinyint unsigned Int @db.UnsignedTinyInt
customer_contacts.email varchar(100) — varchar(100) @db.VarChar(100)
facility_contacts.email varchar(255) 「typo。varchar(100) に修正」 varchar(255) @db.VarChar(100)

定義書の記載(両テーブルで型・サイズが不揃い)が実DB の実態と一致していた。 TeamWorks が「typo なので揃える」と回答した2点は、実DB には適用されていない。 手書き版は回答を信じて揃えてしまったため、この2箇所が実DDL とずれている(§4-1)。

これは「定義書 vs 実DDL」ではなく「TeamWorks 回答 vs 実DDL」の食い違いであり、 回答が将来の修正予定なのか、回答が誤りなのかを確認する必要がある。

7-7. 定義書の precheck 逆転問題の決着

定義書では clean_timetables.precheck の既定値が 9(備考: 0: 本清掃, 1: 1回目, 2: 2回目 ...)、 clean_timetable_histories.precheck の既定値が 0(備考: 0: 未設定, ... 9: 本清掃)で、 初期値とコード値の対応がテーブル間で逆転していた。

実DDL の答え: 両テーブルとも precheck tinyint unsigned NOT NULL DEFAULT '0'。

TeamWorks 回答 B-1(0: 本清掃 / 1: 1回目 / 2: 2回目、clean_timetables の定義が正)と整合する。 定義書の clean_timetables 側の既定値 9 が誤り。 手書き版は「既定値 9 の意図は未確認」として @default(9) を維持しているので、@default(0) へ修正が必要。

7-8. 定義書の初期値と実DDL の DEFAULT の食い違い(6件)

(P-1 の「auto increment が備考欄」による偽陽性 22件を除外した実差分)

テーブル.カラム 定義書 実DDL
robots.battery 100 0
clean_timetables.precheck 9 0(§7-7)
robots.device_id 0 既定値なし
clean_timetables.parent_id 0 既定値なし
clean_task_reports.created_at システム日付 既定値なし
clean_task_reports.updated_at システム日付 既定値なし
security_status_histories.reported_at システム日付 既定値なし

(表は7行。clean_timetables.precheck を §7-7 と重複計上しない場合は 6件。)

robots.battery の 100 → 0 は定義書と実DDL の実質的な食い違いで、 手書き版も定義書に従って @default(100) としているため要修正。

7-9. 定義書の型・サイズ・NULL許容と実DDL の食い違い(9件)

テーブル.カラム 定義書 実DDL 備考
clean_statuses.clean_status unsigned tinyint tinyint §7-3。定義書の型が誤り
clean_status_histories.clean_status unsigned tinyint tinyint §7-3。同上
clean_status_histories.task_area decimal(12,6) decimal(12,6) unsigned 定義書内で表記が不統一だった箇所(clean_statuses だけ unsigned decimal)。実DDL は3テーブルすべて unsigned
clean_status_histories.clean_area decimal(12,6) decimal(12,6) unsigned 同上
clean_task_reports.task_area decimal(12,6) decimal(12,6) unsigned 同上
clean_task_reports.clean_area decimal(12,6) decimal(12,6) unsigned 同上
robot_error_reports.serial_number varchar(50) varchar(20) 定義書の方が大きい
robot_error_reports.product_code varchar(50) varchar(20) 同上
robot_error_reports.errored_at 必須(○) DEFAULT NULL(NULL可) §4-2

定義書の decimal 表記の不統一(転記者が「矛盾点7」として挙げていた箇所)は、 実DDL では6カラムすべて unsigned で決着した。

7-10. 定義書の fk 指定と実DDL の外部キーの食い違い(4件)

テーブル.カラム 定義書のキー欄 実DDL
clean_statuses.clean_timetable_id fk FK なし(KEY も無し)
clean_status_histories.clean_timetable_id fk FK なし(KEY も無し)
robot_task_versions.clean_schedule_id fk FK なし(KEY も無し)
controls.facility_id (空欄) FK あり → facilities(id)

controls.facility_id は定義書内でも矛盾していた(カラム表のキー欄は空欄、索引欄には fk_controls_facility_id あり)。 実DDL は索引欄の側が正しく、FK は存在する。 TeamWorks 回答 B-2 と整合。

逆に clean_timetable_id / clean_schedule_id の3本は、定義書が fk と書いているのに実DB には無い。 手書き版は定義書に従ってリレーションを張っているため、実DDL とずれている(§5)。

7-11. 実DDL 側の自己矛盾(索引名と対象カラムの不一致、3件)

DDL 自身の中に残っている命名のズレ。実害は無いが、索引名で列を推測すると誤る。

テーブル 索引 名前から推測される列 実際の対象列
clean_timetable_histories KEY clean_timetable_histories_started_at_index started_at start_at
clean_timetable_histories KEY clean_timetable_histories_ended_at_index ended_at end_at
robot_error_reports UNIQUE KEY robot_error_reports_report_id_unique report_id error_id

3件目は特に紛らわしい。robot_error_reports に report_id という列は無く(report_id は clean_task_reports の PK)、 一意制約が乗っているのは error_id。

7-12. 定義書 vs 実DDL の食い違い 件数まとめ

種類 件数
テーブル(定義書のみ / 実DDLのみ) 2(makers / clean_link_schedules)
カラム(定義書のみ) 11(うち改名3・実質廃止8)
カラム(実DDLのみ) 3(すべて §7-1/7-2 の改名先)
型・unsigned 6
サイズ 2
NULL許容 1
既定値 6
外部キー 4
合計 35

(別枠)TeamWorks 回答が実DB に反映されていない箇所: 2(§7-6) (別枠)実DDL 内部の索引名と対象列の不一致: 3(§7-11)


付録: 差分の総件数(手書き prisma vs 実DDL)

種類 件数
テーブル(実DDLのみ) 1
テーブル(手書きのみ) 0
カラム(実DDLのみ) 3
カラム(手書きのみ) 11
型・サイズ・unsigned 14
NULL 許容 1
既定値 9
主キー 2
ユニークキー 2
外部キー(手書きのみ) 3
外部キー(実DDLのみ) 0
インデックス 6
合計 52

実装に影響する差分(優先度順)

  1. robot_error_reports.responsed_at → responded_at に改名(列が存在しないためクエリが即エラー)
  2. control_error_histories.responsed_at → responded_at に改名(同上)
  3. control_reports.sireal_number → serial_number に改名(同上)
  4. robot_error_reports の PK / UNIQUE: DB の一意制約は error_id のみ。id に一意制約なし。@id の置き方とアプリ側の採番方針を決める必要がある
  5. robot_error_reports.errored_at を nullable に(DB は NULL 可。非 null 型のままだと読み出しで実行時エラー)
  6. clean_status_histories / clean_timetable_histories の id から @default(autoincrement()) を外す(DB は AUTO_INCREMENT でない。採番はアプリ責任)
  7. clean_status_histories の PK: DB は PRIMARY KEY を持たず UNIQUE(id) のみ
  8. customer_contacts.contact_type は bigint unsigned(Int → BigInt に変更。TeamWorks B-6 回答と実DB が食い違っており要確認)
  9. robots.battery の既定値 100 → 0
  10. clean_timetables.precheck の既定値 9 → 0
  11. facility_contacts.email は varchar(255)(B-6 回答と実DB が食い違っており要確認)
  12. robot_error_reports.serial_number / product_code は varchar(20)(50 のまま書くと切り詰め・エラー)
  13. 廃止列 8件の削除: robots.task_id / robots.version / clean_schedules.started_at / clean_schedules.ended_at / clean_statuses.deleted_at / section_robot_statuses.indicatived_at / section_robot_statuses.deleted_at / clean_timetable_histories.inactive
  14. FK 3本は DB に無い: clean_statuses.clean_timetable_id / clean_status_histories.clean_timetable_id / robot_task_versions.clean_schedule_id。参照整合性が担保されていないので孤児行を前提にしたコードが必要
  15. clean_task_reports.created_at / updated_at、security_status_histories.reported_at に DB 既定値が無い(INSERT で必ず値を渡す)
  16. clean_link_schedules の扱いを TeamWorks に確認(link_schedules と構造完全一致・データ0件。改名途中の可能性)
  17. robot_task_versions.clean_schedule_id はインデックスすら無い(この列での絞り込みはフルスキャン)

使用スクリプト(当方の成果物、scratchpad\ddl\mine\)

  • parse_ddl.py — DDL を括弧対応でパースし ddl_parsed.json を生成
  • cmp2.py — インデックス差分 / DDL内部の索引名不一致 / 定義書 vs DDL のテーブル・カラム・型差分
  • cmp3.py — 定義書 vs DDL の初期値差分 / fk 指定差分
  • cmp4.py — clean_link_schedules と link_schedules の構造一致検証