Migrating compliance requirements, review results, and SOV (Statement of Values) review data. Restructuring flat requirements into grouped, hierarchical structure.
Migration of requirements and compliance review data from DTX 1.0 to DTX 2.0. This is Phase 2 — depends on Accounts (Area 2). This area performs the COIRiskProfile backfill on RequirementsGroup records created in Area 4, and creates coverage template records that define what insurance is required.
The requirements table is the central piece: each row defines a complete set of coverage requirements (GL, Auto, WC, UMB, LL, attachment, AM Best) that gets mapped to a COIRiskProfile template with child coverage template records.
Important: Full production data is not available. Migration scripts must be built defensively with dry-run mode, self-validation, and graceful error handling.
| Table | Columns | Rows (sample) | Purpose |
|---|---|---|---|
requirements |
89 | 61 | Master insurance requirements — defines required coverages, limits, booleans per vendor/template |
requirements_audit |
83 | 101 | BEFORE/AFTER audit trail of requirement changes |
review_result |
9 | 101 | Document-level review results (COMPLIANT/NON-COMPLIANT) |
coi_review_result |
8 | 105 | COI certificate review results — serialized PHP form data with per-coverage evaluations |
so_review |
19 | 100 | Aggregated broker/SO compliance summary — reporting table |
| Model | Purpose |
|---|---|
COIRiskProfile |
Template container (is_template=True) defining coverage requirements |
GeneralLiability |
GL coverage template (coi_risk_profile FK) |
AutoLiability |
Auto coverage template |
WorkersCompensation |
WC coverage template |
UmbrellaLiability |
UMB coverage template |
LiquorLiability |
LL coverage template |
PropertyCoverage |
Property coverage template (from user_defined_policy templates) |
OtherCoverage |
Other coverage template (from user_defined_policy templates) |
CarrierRating |
AM Best rating requirement template |
DescriptionOfOperations |
Ops description requirement template |
RequirementsGroup |
Backfill coi_risk_profile FK (already created in Area 4) |
| Item | Estimate |
|---|---|
| COIRiskProfile templates | 5K-20K (one per unique requirements record) |
| GL templates | 4K-18K (most requirements define GL) |
| Auto templates | 3K-15K |
| WC templates | 3K-15K |
| UMB templates | 2K-10K |
| LL templates | 500-5K |
| Property/Other templates | 100-2K (from user_defined_policy templates) |
| CarrierRating templates | 1K-10K |
| DescriptionOfOperations templates | 100-2K |
| RequirementsGroup backfills | 5K-50K |
| Total records created | 20K-150K |
These must be resolved before running the migration.
Priority: HIGH — potential data loss
The requirements table has 8 attachment requirement fields (ATT_W9, ATT_COI, ATT_CG2015, ATT_CG2033, ATT_CG2037, ATT_Primary, ATT_HoldHarmless, ATT_SubrWvd) defining which documents a vendor must provide. These map to DocRequirement records in DTX 2.0, but need DocumentType FK targets.
Action: Verify that DTX 2.0 has DocumentType records for each of these:
| ATT Field | Expected DocumentType | Notes |
|---|---|---|
ATT_W9 |
"W-9" | IRS form |
ATT_COI |
"Certificate of Insurance" | Standard COI |
ATT_CG2015 |
"CG 20 15" | Additional Insured endorsement |
ATT_CG2033 |
"CG 20 33" | Additional Insured endorsement (ongoing ops) |
ATT_CG2037 |
"CG 20 37" | Additional Insured endorsement (completed ops) |
ATT_Primary |
"Primary & Non-Contributory" | Primary insurance endorsement |
ATT_HoldHarmless |
"Hold Harmless Agreement" | Indemnification agreement |
ATT_SubrWvd |
"Waiver of Subrogation" | Subrogation waiver endorsement |
If DocumentType records don't exist, create them as a seed data step. If the names differ, provide a mapping table.
-1 Limit Semantics with DTX 2.0 TeamPriority: HIGH — affects all template coverage records
DTX 1.0 requirements use -1 extensively for limit fields. From sample data:
- GLLimEaOcc="1000000" → "must have at least $1M each occurrence"
- GLLimEaOcc="-1" → "coverage required, no minimum limit threshold"
- GLLimEaOcc=NULL → "not checked / not applicable"
Plan assumes: -1 → store as NULL in template limit field (coverage type IS required because the template record exists, but no specific minimum). Actual dollar values stored as-is.
Action: Confirm with DTX 2.0 evaluation engine: 1. Does a NULL limit on a template coverage record mean "don't check this field"? 2. Or does it mean "any value passes"? 3. Is there a different sentinel value the engine expects?
Priority: HIGH — backfill depends on this
Area 4 created RequirementsGroups from unique (customer_id, requirements_id, document_set_id) combinations. This area needs the mapping file to:
1. Look up which RequirementsGroups reference each requirements_id
2. Backfill RequirementsGroup.coi_risk_profile FK with the newly created COIRiskProfile
Action: Verify id_mapping_requirements_groups.csv exists and contains requirements_id → requirements_group_id associations.
Priority: MEDIUM
Area 5 deferred user_defined_policy template records (where certificate_id=NULL) to this area. These have requirements_id and customer_id and define custom coverage types required for a vendor.
Action: Confirm that Area 5's migration output includes a file listing deferred template records, or that the raw CSV is available for this area to process directly.
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 1 | -1 limit semantics ambiguous — DTX 1.0 uses -1 to mean "required but no minimum." DTX 2.0 coverage template fields are CharField with no documented sentinel. If the evaluation engine doesn't handle NULL correctly, templates with -1 fields will either silently pass everything or silently fail everything. |
Every template coverage record with -1 limits could malfunction |
Pre-Migration Action #2. Default: map -1 → NULL. Log all -1 occurrences for validation. |
| 2 | ATT fields → DocumentType mapping unknown — 8 attachment requirement fields need DocumentType FKs. If DTX 2.0 doesn't have matching DocumentType records, document requirements are lost. |
Document requirements not migrated | Pre-Migration Action #1. Create seed DocumentType records if missing. |
| 3 | coi_review_result contains PHP serialized data — form_data field has nested PHP serialize() output with per-coverage evaluation results, waiver reasons, and policy links. Parsing this is fragile and error-prone. |
Risk of data corruption if parsed incorrectly | Don't migrate as primary data (Area 4 already created evaluations from certificate_status). Parse only for waiver extraction if needed. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 4 | RequirementsGroup.coi_risk_profile backfill is N:1 — Multiple RequirementsGroups can reference the same requirements_id. One COIRiskProfile may serve many groups. If the backfill creates duplicate COIRiskProfiles instead of reusing, the template data fragments. |
Duplicate templates, inconsistent evaluation | Deduplicate: one COIRiskProfile per unique requirements_id. All RequirementsGroups sharing a requirements_id share one COIRiskProfile. |
| 5 | requirements_audit missing columns — Audit table has 83 columns vs requirements' 89. Missing: GLContLiab, GLAddlInsdCompOps, WCExec, OpsDesc, OpsDescReviewStatus, UMBMandatory. Changes to these fields were not audited. |
Incomplete audit history (if audit is migrated) | Note in documentation. Don't migrate audit. |
| 6 | 0000-00-00 00:00:00 timestamps — Multiple requirements records have update_time = "0000-00-00 00:00:00". This is MySQL's zero-date, not a valid datetime. |
PostgreSQL will reject these values | Map 0000-00-00 00:00:00 → NULL. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 7 | Placeholder descriptions — Requirements description field contains " " (single space) and "." (period) as placeholder values. These aren't real descriptions. |
Cluttered UI with meaningless descriptions | Strip to NULL if description is only whitespace or a single punctuation character. |
| 8 | requirements.name ambiguity — Some names are vendor names ("JP Morgan Chase Bank"), others are template tier names ("FULL", "MIN/GL", "MID LEVEL - GL/UMB"). No consistent pattern. | COIRiskProfile.name may be misleading | Store as-is. The name serves as an identifier, not a display label. |
| 9 | so_review data inconsistency — Some broker records have total < compliant + non_compliant + expired. Totals don't sum correctly. |
Unreliable reporting data | Don't migrate — DTX 2.0 computes metrics on-the-fly via ComplianceStatus. |
| 10 | UMBMandatory field has no DTX 2.0 target — NULL in all samples. May indicate "umbrella coverage is mandatory" but the template record's existence already implies this. | Minor data loss | Log all non-NULL values. Drop field. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 11 | review_result.vendor_id always NULL — Links to document_id only. No vendor context for document reviews. | Cannot associate document reviews with vendors | Don't migrate — historical review data. |
| 12 | coi_review_result.login_ip mostly NULL — Only 2 of 105 sample records have IP addresses. | Minor metadata loss | Don't migrate — privacy consideration anyway. |
requirementsRisk Level: HIGH — central to this area
Each requirements record becomes one COIRiskProfile (is_template=True).
For each requirements record:
1. Create COIRiskProfile:
- account = customer_id → Account (via id_mapping_accounts.csv)
- is_template = True
- name = requirements.name
- description = requirements.description (strip placeholder values)
- created = requirements.create_time (preserve timestamp)
- modified = requirements.update_time (if valid, else create_time)
2. Record mapping: requirements_id → coi_risk_profile_id
3. If customer_id not in Account mapping → skip, log to issues CSV
One COIRiskProfile per unique requirements_id. Multiple RequirementsGroups that reference the same requirements_id will share the same COIRiskProfile.
0000-00-00 00:00:00 handlingIf update_time == "0000-00-00 00:00:00":
modified = create_time (fall back to creation time)
If create_time == "0000-00-00 00:00:00":
created = migration_date (should not happen — log if it does)
requirementsRisk Level: HIGH — defines evaluation requirements
For each COIRiskProfile, create child coverage template records from the requirements fields. Only create a template record if the coverage section has at least one populated field.
GL required if: ANY of GLClaims, GLOccur, GLAddlInsd, ..., GLLimEaOcc, GLLimAgg, GLLimProd
is non-NULL
Auto required if: ANY of AutoAddlInsd, AutoSubrWvd, ..., AutoSingle, AutoBodilyPerson
is non-NULL
WC required if: ANY of WCStatutory, WCSubrWvd, ..., WCEachAcc, WCDiseaseEachEmpl
is non-NULL
UMB required if: ANY of UMBAddlInsd, UMBSubrWvd, ..., UMBLimEaOcc, UMBLimAgg
is non-NULL
LL required if: ANY of LLAddlInsd, LLSubrWvd, LLLimEaOcc, LLLimAgg, LLAddlInsdForms
is non-NULL
| DTX 1.0 Value | Template Field Value | Meaning |
|---|---|---|
"yes" (boolean field) |
True |
This flag is REQUIRED to be checked |
NULL (boolean field) |
False |
Not checked / not required |
"1000000" (limit field) |
"1000000" |
Minimum $1M required |
"-1" (limit field) |
NULL |
Coverage required, no minimum limit |
NULL (limit field) |
NULL |
Not checked |
Note: The difference between -1 → NULL (required, no minimum) and NULL → NULL (not checked) is that the TEMPLATE RECORD EXISTS for the first case but not the second.
Row 2295 (customer 630, "Cogent Communications"):
GL: GLOccur=yes, GLAddlInsd=yes, GLSubrWvd=yes, GLLimEaOcc=1000000, GLLimAgg=2000000
→ Create GL template: occurrence=True, additional_insured=True, subrogation_waived=True,
each_occurrence="1000000", general_aggregate="2000000", all others=NULL
Auto: AutoSingle=2000000 (only populated field)
→ Create Auto template: single_limit_per_accident="2000000", all others=NULL/False
WC: WCStatutory=yes, WCEachAcc=1000000
→ Create WC template: statutory_limits=True, disease_accident="1000000"
UMB: UMBCombined=5000000
→ Create UMB template: umbcombined="5000000"
Row 2355 (customer 525, "Stewart") — richest record:
GL: GLOccur=yes, GLAddlInsd=yes, GLSubrWvd=yes, GLLocation=yes, GLAddlInsdForms=yes,
GLLimEaOcc=1000000, GLLimRented=300000, GLLimEaMed=5000, GLLimPerson=1000000,
GLLimAgg=2000000, GLLimProd=2000000, GLPrimary=yes
Auto: AutoSingle=-, but no booleans
WC: WCStatutory=yes, WCEachAcc=1000000, WCDiseaseEachEmpl=1000000, WCDiseasePolicyLimit=1000000
UMB: UMBSubrWvd=yes, UMBOccur=yes, UMBLimEaOcc=-, UMBCombined=1000000, UMBLimAgg=1000000
LL: (all -1 or NULL)
Risk Level: HIGH — links templates to vendor assignments
Area 4 created RequirementsGroups with coi_risk_profile=NULL. This area fills them in.
For each RequirementsGroup in id_mapping_requirements_groups.csv:
1. Look up the requirements_id associated with this group
2. Look up the COIRiskProfile created from that requirements_id (Decision #1)
3. Update RequirementsGroup.coi_risk_profile = found COIRiskProfile
4. If requirements_id is NULL or has no matching COIRiskProfile → leave NULL, log
Important: This is a Django ORM UPDATE, not a CREATE. The RequirementsGroup already exists.
Risk Level: MEDIUM (pending Action #1)
The requirements table has 8 ATT_* fields defining document requirements. These map to DocRequirement records linking RequirementsGroups to DocumentTypes.
For each requirements record where ANY ATT field is truthy ("yes"):
For each truthy ATT field:
1. Look up the corresponding DocumentType (via Action #1 mapping)
2. For EACH RequirementsGroup that references this requirements_id:
Create DocRequirement:
- requirements_group = the RequirementsGroup
- document_type = mapped DocumentType
- status = "In Review" (default — no historical status)
- is_exempted = False
Row 2355 ("Stewart") has: ATT_W9=yes, ATT_COI=yes, ATT_CG2015=yes (3 of 8 populated).
Most other sample rows: all ATT fields NULL.
Risk Level: Low
Requirements OpsDesc field → DescriptionOfOperations template record.
For each requirements record where OpsDesc is truthy ("yes"):
Create DescriptionOfOperations:
- coi_risk_profile = mapped COIRiskProfile
- certificate = NULL (template)
- description_required = True
- All other fields = NULL
Sample: OpsDesc appears to be NULL in most sample rows. The OpsDescReviewStatus field is dropped (review workflow not migrated, consistent with Area 5 Decision #6).
Risk Level: Low
Requirements AMBestRatingOK field → CarrierRating template record on the COIRiskProfile.
For each requirements record where AMBestRatingOK is truthy ("yes"):
Create CarrierRating:
- coi_risk_profile = mapped COIRiskProfile
- certificate = NULL (template)
- avii_or_above = True
- All carrier fields = NULL (requirement-level, not carrier-specific)
Sample: Most rows have AMBestRatingOK=NULL. Some have truthy values. Consistent with Area 5 Decision #5 (certificate-level CarrierRating).
Risk Level: MEDIUM
Area 5 deferred template records from user_defined_policy (where certificate_id=NULL). These define custom coverage types required by a customer.
For each user_defined_policy template record:
1. Find or create the COIRiskProfile for this requirements_id
(should already exist from Decision #1)
2. Classify UDPType → PropertyCoverage or OtherCoverage
(same keyword matching as Area 5 Decision #3)
3. Find or create PropertyCoverageType / OtherCoverageType
(case-insensitive dedup, reuse types created in Area 5)
4. Create coverage template record:
- coi_risk_profile = matched COIRiskProfile
- certificate = NULL
- type = found/created type
- required = UDPRequired ("yes" → True)
- loss_payee = UDPLossPayeeCB (PropertyCoverage only)
- mortgagee = UDPMortgageeCB (PropertyCoverage only)
- limit = UDPLimits (-1 → NULL, else direct)
All 100 sample records are templates (certificate_id=NULL). Single customer 815. Three repeating UDPType values: "Professional Liability", "Cyber Liability", "Pollution Liability". All UDPLimits=-1.
Risk Level: Low
BEFORE/AFTER snapshot audit of requirement changes. 83 columns per row.
Don't migrate. Rationale:
1. DTX 2.0 uses Django's built-in audit trail (django-simple-history or similar) for change tracking
2. Missing 6 columns vs live requirements table — audit is incomplete
3. Historical audit data (2014-2016 in samples) has limited operational value
4. Massive table (82 fields × N rows × 2 for BEFORE/AFTER) for minimal benefit
Keep CSV for reference. Log total record count and date range in migration report.
Risk Level: Low
Simple document review results: document_id → review_status (COMPLIANT/NON-COMPLIANT).
Don't migrate. Rationale:
1. Links to document_id — Area 4 already migrated documents with status
2. vendor_id is NULL in all samples — no vendor context
3. DTX 2.0 uses DocRequirement.status for document compliance tracking
4. Historical review snapshots (2017 samples) — reviews are complete
5. Comments are minimal ("coi" or NULL)
Keep CSV for reference. Cross-reference unique document_ids against Area 4's mapping if validation is needed.
Risk Level: MEDIUM
COI review results with serialized PHP form_data. Contains per-coverage evaluation results that OVERLAP with Area 4's evaluation pipeline (built from certificate_status).
Don't migrate as primary data. Rationale:
1. Area 4 already created Evaluation → EvaluationCoverage → EvaluationDetail from certificate_status
2. Serialized PHP parsing is fragile and error-prone
3. Contains navigation state (coi_prev_page, coi_next_page) not needed in DTX 2.0
4. IP addresses are a privacy concern
However: form_data contains WAIVED statuses with reasons (e.g., ReviewStatus="WAIVED", Reason="gl ok"). This information is NOT in certificate_status.
Waiver extraction (optional post-migration enrichment):
1. Parse form_data for each coi_review_result record
2. For coverage sections with ReviewStatus="WAIVED":
a. Log: certificate_id, coverage_type, Reason, user_id, create_time
b. Output to waiver_candidates.csv
3. DTX 2.0 team can review and create WaiverRequest records if needed
form_data = {
"coi_prev_page": "Acord_25",
"page_name": "Acord_25",
"coi_next_page": "last_page",
"Cert": {
"starting_page": "Acord_25",
"old_broker_id": "114147",
"old_requirements_id": "8666", ← links back to requirements table
"old_document_set_id": "1219" ← links to document_set
},
"GL": {
"GL": {
"DefinedType": "GL",
"DeclaredType": "254240", ← certificate_id
"EvalStatus": "NON-COMPLIANT",
"ReviewStatus": "WAIVED", ← WAIVER INFORMATION
"Reason": "gl ok" ← WAIVER REASON
}
},
"Auto": { ... },
"WC": { ... },
"Other": { ← property/other coverage types
"All Risk": {
"DefinedType": "All Risk",
"EvalStatus": "COMPLIANT",
"PolicyLink": "(serialized carrier + policy info)"
},
"Business Income": { ... },
"Business Personal Property (Content)": { ... }
},
"OpsDescReason": "",
"HolderReason": "",
"notice_action": "send_notice",
"override_reason": ""
}
Risk Level: Low
Aggregated broker/SO compliance summary with counts (total, compliant, non_compliant, expired, etc.).
Don't migrate. Rationale:
1. This is a reporting/summary table, not transactional data
2. DTX 2.0 computes compliance metrics on-the-fly via ComplianceStatus model
3. Data inconsistency: some rows have total < compliant + non_compliant + expired
4. broker_id links to Area 9 (Brokers) — not yet migrated
Keep CSV for reference. Useful for validating post-migration compliance metrics.
Risk Level: Low
These are DTX 2.0-native models with no DTX 1.0 equivalent.
ComplianceStatus:
- Created per-RequirementsGroup AFTER all migration areas complete
- Initial status = "no_requirements" (default)
- Will be recalculated by DTX 2.0's evaluation engine on first run
ComplianceThresholds:
- Created per-Account with defaults AFTER all migration areas complete
- Uses DTX 2.0 default values (warning_days=30, stale_days=7, etc.)
Note: Do NOT create these during Area 6 migration. Create them in a post-migration "bootstrap" step after all areas are complete, or let DTX 2.0 create them lazily on first access.
Risk Level: Low
The comments field contains operational notes like "No WC requirement in Temp License Agmt" and "NO EMPLOYEES!!!!". These are distinct from description.
If requirements.comments is non-NULL and non-whitespace:
Append to COIRiskProfile.description:
description = f"{clean_description}\n\nMigration note: {comments}".strip()
This preserves operational context without creating a new field.
All coverage models have both coi_risk_profile and certificate FKs:
- Template records (this area): coi_risk_profile set, certificate = NULL. Define REQUIREMENTS.
- Certificate records (Area 5): certificate set, coi_risk_profile = NULL. Store ACTUAL VALUES.
The evaluation engine compares template records against certificate records.
-1 Semantics (Pending Action #2)DTX 1.0 limit = "-1" → DTX 2.0 template limit = NULL
Meaning: "This coverage type is required (template record exists),
but no specific dollar minimum."
DTX 1.0 limit = "1000000" → DTX 2.0 template limit = "1000000"
Meaning: "Must have at least $1M."
DTX 1.0 limit = NULL → No template record created for this field/type
Meaning: "Not checked."
requirements → COIRiskProfile| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
requirements_id |
(ID mapping) | → id_mapping_coi_risk_profiles.csv |
customer_id |
account |
Via id_mapping_accounts.csv |
name |
name |
Direct. Mix of vendor names and template tier names |
description |
description |
Strip placeholder values (" ", "."). Append comments if present |
| (hardcoded) | is_template |
True |
create_time |
created |
Direct |
update_time |
modified |
Map 0000-00-00 00:00:00 → create_time |
user_id |
owner |
Via id_mapping_users.csv (if available) |
| GL fields (26) | → GeneralLiability template |
Decision #2 |
| Auto fields (18) | → AutoLiability template |
Decision #2 |
| WC fields (7) | → WorkersCompensation template |
Decision #2 |
| UMB fields (14) | → UmbrellaLiability template |
Decision #2 |
| LL fields (5) | → LiquorLiability template |
Decision #2 |
AMBestRatingOK |
→ CarrierRating template |
Decision #6 |
OpsDesc |
→ DescriptionOfOperations template |
Decision #5 |
OpsDescReviewStatus |
(dropped) | Review workflow not migrated |
| ATT fields (8) | → DocRequirement records |
Decision #4 |
comments |
→ COIRiskProfile.description (appended) |
Decision #13 |
requirements GL fields → GeneralLiability templateCreate if ANY GL field is non-NULL. All *_options FKs = NULL. certificate = NULL.
| DTX 1.0 (requirements) | DTX 2.0 (GeneralLiability) | Notes |
|---|---|---|
| (from parent) | coi_risk_profile |
FK to new COIRiskProfile |
GLClaims |
claims_made |
"yes" → True |
GLOccur |
occurrence |
"yes" → True |
GLAddlInsd |
additional_insured |
"yes" → True |
GLSubrWvd |
subrogation_waived |
"yes" → True |
GLPolicy |
applies_per_policy |
"yes" → True |
GLProject |
applies_per_project |
"yes" → True |
GLLocation |
applies_per_location |
"yes" → True |
GLLimEaOcc |
each_occurrence |
-1 → NULL, else direct |
GLLimRented |
damage_to_premises |
-1 → NULL, else direct |
GLLimEaMed |
medical_expense |
-1 → NULL, else direct |
GLLimPerson |
personal_injury |
-1 → NULL, else direct |
GLLimAgg |
general_aggregate |
-1 → NULL, else direct |
GLLimProd |
products_comp |
-1 → NULL, else direct |
GLOther1LimitDesc |
glotherlimitdesc1 |
Direct |
GLOther1Limit |
glotherlimit1 |
Direct |
GLOther2LimitDesc |
glotherlimitdesc2 |
Direct |
GLOther2Limit |
glotherlimit2 |
Direct |
GLOther3LimitDesc |
glotherlimitdesc3 |
Direct |
GLOther3Limit |
glotherlimit3 |
Direct |
GLPrimary |
primary_non_contributory |
"yes" → True |
GLAddlInsd2033 |
gladdlinsd2033 |
Direct |
GLAddlInsd2037 |
gladdlinsd2037 |
Direct |
GLAddlInsd2040 |
gladdlinsd2040 |
Direct |
GLAddlInsdForms |
additional_insured_forms |
"yes" → True |
GLContLiab |
contractual_liability |
"yes" → True |
GLAddlInsdCompOps |
additional_insured_completed_ops |
"yes" → True |
requirements Auto fields → AutoLiability templateCreate if ANY Auto field is non-NULL.
| DTX 1.0 (requirements) | DTX 2.0 (AutoLiability) | Notes |
|---|---|---|
| (from parent) | coi_risk_profile |
FK to new COIRiskProfile |
AutoAddlInsd |
additional_insured |
"yes" → True |
AutoSubrWvd |
subrogation_waived |
"yes" → True |
AutoAny |
any_auto |
"yes" → True |
AutoOwned |
all_owned_autos |
"yes" → True |
AutoSched |
scheduled_autos |
"yes" → True |
AutoHired |
hired_autos |
"yes" → True |
AutoNonOwned |
non_owned_autos |
"yes" → True |
AutoSingle |
single_limit_per_accident |
-1 → NULL, else direct |
AutoBodilyPerson |
bodily_per_person |
-1 → NULL, else direct |
AutoBodilyAccident |
bodily_per_accident |
-1 → NULL, else direct |
AutoProperty |
property_per_accident |
-1 → NULL, else direct |
AutoOther1LimitDesc |
autodescmisc |
Direct |
AutoOther1Limit |
autolimmisc |
Direct |
AutoOther2LimitDesc |
autodescmisc2 |
Direct |
AutoOther2Limit |
autolimmisc2 |
Direct |
AutoOther3LimitDesc |
(no target) | NULL in all samples. Log if populated |
AutoOther3Limit |
(no target) | NULL in all samples. Log if populated |
AutoAddlInsdForms |
additional_insured_forms |
"yes" → True |
requirements WC fields → WorkersCompensation templateCreate if ANY WC field is non-NULL.
| DTX 1.0 (requirements) | DTX 2.0 (WorkersCompensation) | Notes |
|---|---|---|
| (from parent) | coi_risk_profile |
FK to new COIRiskProfile |
WCStatutory |
statutory_limits |
"yes" → True |
WCSubrWvd |
subrogation_waived |
"yes" → True |
WCExec |
any_excluded |
"yes" → True |
WCEachAcc |
disease_accident |
-1 → NULL, else direct |
WCDiseaseEachEmpl |
disease_each_employee |
-1 → NULL, else direct |
WCDiseasePolicyLimit |
disease_policy |
-1 → NULL, else direct |
WCOther |
wcother |
Direct |
requirements UMB fields → UmbrellaLiability templateCreate if ANY UMB field is non-NULL.
| DTX 1.0 (requirements) | DTX 2.0 (UmbrellaLiability) | Notes |
|---|---|---|
| (from parent) | coi_risk_profile |
FK to new COIRiskProfile |
UMBAddlInsd |
additional_insured |
"yes" → True |
UMBSubrWvd |
subrogation_waived |
"yes" → True |
UMBLiability |
umbliability |
Direct |
UMBExcess |
excess |
"yes" → True |
UMBOccur |
occurrence |
"yes" → True |
UMBClaims |
claims_made |
"yes" → True |
UMBDeduct |
deduct |
"yes" → True |
UMBRetentionCB |
retention |
"yes" → True (checkbox) |
UMBRetention |
retention_cb |
-1 → NULL, else direct (dollar amount) |
UMBLimEaOcc |
each_occurrence |
-1 → NULL, else direct |
UMBCombined |
umbcombined |
-1 → NULL, else direct |
UMBLimAgg |
aggregate |
-1 → NULL, else direct |
UMBAddlInsdForms |
additional_insured_forms |
"yes" → True |
UMBMandatory |
(no target) | NULL in all samples. Log if populated |
requirements LL fields → LiquorLiability templateCreate if ANY LL field is non-NULL.
| DTX 1.0 (requirements) | DTX 2.0 (LiquorLiability) | Notes |
|---|---|---|
| (from parent) | coi_risk_profile |
FK to new COIRiskProfile |
LLAddlInsd |
additional_insured |
"yes" → True |
LLSubrWvd |
subrogation_waived |
"yes" → True |
LLLimEaOcc |
each_occurrence |
-1 → NULL, else direct |
LLLimAgg |
general_aggregate |
-1 → NULL, else direct |
LLAddlInsdForms |
additional_insured_forms |
"yes" → True |
| Source | Field(s) | Reason |
|---|---|---|
requirements |
OpsDescReviewStatus |
Review workflow not migrated |
requirements |
UMBMandatory |
No DTX 2.0 target. NULL in all samples |
requirements |
AutoOther3LimitDesc, AutoOther3Limit |
No DTX 2.0 target. NULL in all samples |
requirements_audit |
(entire table) | Don't migrate (Decision #8) |
review_result |
(entire table) | Don't migrate (Decision #9) |
coi_review_result |
(entire table) | Don't migrate as primary data (Decision #10) |
so_review |
(entire table) | Don't migrate (Decision #11) |
| Model | Field | Value |
|---|---|---|
| All coverage templates | certificate |
NULL — template records |
| All coverage templates | All *_options FKs |
NULL — UI dropdown config |
| All coverage templates | effective_date, expiration_date, policy_number |
NULL — templates don't have dates/policies |
| All coverage templates | carrier_code, carrier_naic, carrier_name |
NULL — templates define requirements, not carriers |
ComplianceStatus |
All fields | Created in post-migration bootstrap |
ComplianceThresholds |
All fields | Created in post-migration bootstrap with defaults |
1. Validate prerequisites:
- id_mapping_accounts.csv exists and is complete
- id_mapping_requirements_groups.csv exists with requirements_id associations
- Pre-migration actions 1-4 resolved
- Area 5's user_defined_policy template records available
2. Dry-run validation report
3. Create COIRiskProfiles from requirements (Decision #1)
4. Create GL templates (Decision #2)
5. Create Auto templates (Decision #2)
6. Create WC templates (Decision #2)
7. Create UMB templates (Decision #2)
8. Create LL templates (Decision #2)
9. Create user_defined_policy templates → PropertyCoverage/OtherCoverage (Decision #7)
10. Create CarrierRating templates (Decision #6)
11. Create DescriptionOfOperations templates (Decision #5)
12. Create DocRequirement records from ATT fields (Decision #4)
13. Backfill RequirementsGroup.coi_risk_profile (Decision #3)
14. Generate and export all ID mapping tables
15. Extract waiver candidates from coi_review_result (Decision #10, optional)
16. Verify
=== DTX 1.0 Requirements & Compliance Migration - Dry Run Report ===
PREREQUISITES:
id_mapping_accounts.csv: ??? records loaded
id_mapping_requirements_groups.csv: ??? records loaded
DocumentType records for ATT fields: ??? of 8 present
REQUIREMENTS:
Total records: ???
Mapped to account: ???
Missing customer_id in mapping:???
Unique customer_ids: ???
Timestamp issues:
update_time = 0000-00-00: ???
create_time = 0000-00-00: ???
Description cleanup:
NULL descriptions: ???
Placeholder (" ", "."): ???
With comments: ???
COI RISK PROFILES TO CREATE: ???
COVERAGE TEMPLATES:
GL templates: ???
GLLimEaOcc populated: ??? (non-NULL, non-"-1")
GLLimEaOcc = "-1": ??? (required, no minimum)
GLAddlInsd = "yes": ???
GLSubrWvd = "yes": ???
GLPrimary = "yes": ???
GLContLiab = "yes": ???
Auto templates: ???
AutoSingle populated: ???
AutoAny = "yes": ???
AutoHired = "yes": ???
AutoOther3LimitDesc populated: ??? (should be 0)
WC templates: ???
WCStatutory = "yes": ???
WCSubrWvd = "yes": ???
WCExec = "yes": ???
UMB templates: ???
UMBLimEaOcc populated: ???
UMBMandatory populated: ??? (should be 0)
LL templates: ???
LLLimEaOcc populated: ???
Total coverage templates: ???
USER DEFINED POLICY TEMPLATES:
Total deferred records: ???
Unique UDPType values: [list all]
Property-classified: ???
Other-classified: ???
CARRIER RATING:
AMBestRatingOK = "yes": ???
AMBestRatingOK = NULL/other: ???
DESCRIPTION OF OPERATIONS:
OpsDesc truthy: ???
OpsDescReviewStatus values: [distribution]
ATTACHMENT REQUIREMENTS:
ATT_W9: ???
ATT_COI: ???
ATT_CG2015: ???
ATT_CG2033: ???
ATT_CG2037: ???
ATT_Primary: ???
ATT_HoldHarmless: ???
ATT_SubrWvd: ???
Total DocRequirement records: ???
REQUIREMENTS GROUP BACKFILL:
Groups with requirements_id: ???
Groups without requirements_id:???
Unique requirements_id values: ???
Groups that will get COIRiskProfile: ???
TABLES NOT MIGRATED (reference counts):
requirements_audit: ??? records, date range: ??? to ???
review_result: ??? records, date range: ??? to ???
coi_review_result: ??? records, date range: ??? to ???
WAIVED statuses found: ???
so_review: ??? records
Issues flagged: ???
Ready to migrate: ???
| Scenario | Behavior |
|---|---|
| customer_id not in Account mapping | Skip requirements record, log to issues CSV |
| requirements_id not in RequirementsGroup mapping | Create COIRiskProfile but skip backfill, log |
0000-00-00 00:00:00 timestamp |
Map to NULL or create_time fallback |
-1 limit value |
Map to NULL in template field |
| ATT field truthy but DocumentType missing | Skip DocRequirement, log |
| user_defined_policy template with no requirements_id match | Create standalone, log |
| Boolean field unexpected value (not "yes"/NULL) | Default to False, log the value |
| Duplicate requirements_id (should not exist) | Use first occurrence, log duplicate |
| Description placeholder (" ", ".") | Strip to NULL |
| PHP serialization parse failure (coi_review_result) | Log and skip that record |
| File | Purpose |
|---|---|
id_mapping_coi_risk_profiles.csv |
requirements_id → coi_risk_profile_id → account_id |
id_mapping_coverage_templates.csv |
requirements_id → coverage_type → template_record_id |
requirements_group_backfill.csv |
requirements_group_id → coi_risk_profile_id → status (updated/skipped) |
doc_requirements_created.csv |
requirements_group_id → document_type → doc_requirement_id |
waiver_candidates.csv |
certificate_id → coverage_type → waived_reason → user_id (from coi_review_result) |
migration_issues.csv |
All flagged records with issue description |
migration_report.txt |
Summary statistics and validation results |
| # | Check | Method |
|---|---|---|
| 1 | COIRiskProfile count | One per unique requirements_id. No duplicates. |
| 2 | COIRiskProfile.is_template | All created profiles have is_template=True |
| 3 | Account linkage | Every COIRiskProfile has a valid Account FK |
| 4 | GL template count | Matches requirements rows with ANY GL field non-NULL |
| 5 | Auto template count | Matches requirements rows with ANY Auto field non-NULL |
| 6 | WC template count | Matches requirements rows with ANY WC field non-NULL |
| 7 | UMB template count | Matches requirements rows with ANY UMB field non-NULL |
| 8 | LL template count | Matches requirements rows with ANY LL field non-NULL |
| 9 | Limit values | Spot-check 20 templates per type — limits match source (with -1 → NULL) |
| 10 | Boolean values | Spot-check 20 templates — booleans match "yes" → True |
| 11 | RequirementsGroup backfill | Every group with a requirements_id now has coi_risk_profile set |
| 12 | Shared COIRiskProfile | Groups sharing a requirements_id share the same COIRiskProfile FK |
| 13 | DocRequirement count | Matches sum of truthy ATT fields × affected RequirementsGroups |
| 14 | DocRequirement uniqueness | No duplicate (requirements_group, document_type) pairs |
| 15 | CarrierRating template count | Matches requirements rows with AMBestRatingOK=yes |
| 16 | DescriptionOfOperations count | Matches requirements rows with OpsDesc=yes |
| 17 | User_defined_policy templates | All deferred template records processed. No orphans. |
| 18 | Timestamps | COIRiskProfile.created matches requirements.create_time |
| 19 | No certificate FKs on templates | All coverage templates have certificate=NULL |
| 20 | ID mapping complete | Every requirements_id in source exists in mapping CSV |
| Depends On | What's Needed |
|---|---|
| Area 2: Customers → Accounts | id_mapping_accounts.csv for customer_id → Account FK |
| Area 4: Certificates & Documents | id_mapping_requirements_groups.csv for RequirementsGroup backfill |
| Area 5: Coverage & Insurance | PropertyCoverageType / OtherCoverageType records (for user_defined_policy template dedup), user_defined_policy template records |
| Depended On By | For |
|---|---|
| Area 5: Coverage & Insurance | Evaluation validation (coverage_type string matching between templates and certificate records) |
| Area 10: Reporting | Compliance metrics depend on COIRiskProfile templates |
More complex than Area 5 due to the structural transformation (flat 89-column requirements → multiple models), cross-area backfill, and ATT → DocumentType mapping.
| Factor | Impact |
|---|---|
| Single 89-column source table → 10+ target models | Significant structural transformation |
| Coverage fields are ACORD-standard and match DTX 2.0 | Reduces field-level mapping complexity |
-1 limit semantics need team confirmation |
Potential blocker if wrong assumption |
| RequirementsGroup backfill is a cross-area UPDATE | Requires Area 4 mapping data |
| ATT → DocumentType mapping requires seed data | Potential blocker if DocumentTypes don't exist |
| 3 of 5 source tables → don't migrate | Reduces scope significantly |
| user_defined_policy templates from Area 5 | Cross-area dependency adds complexity |
| PHP serialized data (coi_review_result) | Parse-only for waivers, not primary migration |
| # | Decision | Status | Approach |
|---|---|---|---|
| 1 | COIRiskProfile creation | Resolved | One per requirements record, is_template=True, with name/description |
| 2 | Coverage templates | Resolved | Create child templates per coverage type if ANY field non-NULL. -1 → NULL |
| 3 | RequirementsGroup backfill | Resolved | Update coi_risk_profile FK on existing groups. N:1 — groups share profiles |
| 4 | ATT → DocRequirement | Pending Action #1 | Create DocRequirement per truthy ATT field × RequirementsGroup. Needs DocumentType mapping |
| 5 | DescriptionOfOperations | Resolved | Create template if OpsDesc=yes. description_required=True |
| 6 | CarrierRating templates | Resolved | Create template if AMBestRatingOK=yes. avii_or_above=True |
| 7 | user_defined_policy templates | Resolved | Route to Property/Other coverage template on matching COIRiskProfile |
| 8 | requirements_audit | Resolved | Don't migrate — incomplete schema, historical |
| 9 | review_result | Resolved | Don't migrate — historical document reviews |
| 10 | coi_review_result | Resolved | Don't migrate as primary data. Parse for WAIVED statuses optionally |
| 11 | so_review | Resolved | Don't migrate — reporting/summary table |
| 12 | ComplianceStatus/Thresholds | Resolved | Create in post-migration bootstrap, not during Area 6 |
| 13 | requirements.comments | Resolved | Append to COIRiskProfile.description |