-- Preflight checks before Goose 00021+ IAM hardening migrations. -- Run against target environment; fix reported rows before applying FK constraints. -- 1. Orphan project_members (user_id not in users) SELECT pm.id, pm.project_id, pm.user_id, pm.project_role, pm.status FROM project_members pm LEFT JOIN users u ON u.id = pm.user_id WHERE u.id IS NULL; -- 2. Projects with NULL or demo creator (legacy public visibility) SELECT p.id, p.code, p.name, p.creator_user_id FROM projects p WHERE p.creator_user_id IS NULL OR p.creator_user_id = 1; -- 3. Duty assignments without active project membership (after instances exist) SELECT d.id, d.doc_task_instance_id, d.author_user_id, d.reviewer_user_id, d.approver_user_id, wi.project_id FROM document_duty_assignments d JOIN project_doc_task_instances ti ON ti.id = d.doc_task_instance_id JOIN project_stage_instances si ON si.id = ti.stage_instance_id JOIN project_workflow_instances wi ON wi.id = si.workflow_instance_id WHERE NOT EXISTS ( SELECT 1 FROM project_members pm WHERE pm.project_id = wi.project_id AND pm.user_id IN (d.author_user_id, d.reviewer_user_id, d.approver_user_id) AND pm.status = 'active' ); -- 4. Stage instances with invalid position (all zero) SELECT workflow_instance_id, stage_key, position, status FROM project_stage_instances GROUP BY workflow_instance_id, stage_key, position, status HAVING position = 0; -- 5. Users with role bindings but inactive role SELECT b.user_id, b.role_id, r.status AS role_status FROM user_role_bindings b JOIN system_roles r ON r.id = b.role_id WHERE r.status IS NOT NULL AND r.status <> 'active';