Last active
February 25, 2026 01:46
-
-
Save bilalbhojani24/a36a04381d0d75446ab060f46c92c6ce to your computer and use it in GitHub Desktop.
RFC: Decouple Product Imports from Core — Select Components Migration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| font-size: 11pt; | |
| line-height: 1.5; | |
| max-width: 900px; | |
| margin: 40px auto; | |
| padding: 0 20px; | |
| } | |
| h1 { | |
| font-size: 20pt; | |
| border-bottom: 2px solid #333; | |
| padding-bottom: 8px; | |
| } | |
| h2 { | |
| font-size: 16pt; | |
| border-bottom: 1px solid #ccc; | |
| padding-bottom: 4px; | |
| margin-top: 32px; | |
| } | |
| h3 { | |
| font-size: 13pt; | |
| margin-top: 24px; | |
| } | |
| h4 { | |
| font-size: 11pt; | |
| margin-top: 20px; | |
| } | |
| table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| margin: 12px 0; | |
| } | |
| th, | |
| td { | |
| border: 1px solid #ccc; | |
| padding: 6px 10px; | |
| text-align: left; | |
| font-size: 10pt; | |
| } | |
| th { | |
| background: #f0f0f0; | |
| font-weight: bold; | |
| } | |
| code { | |
| background: #f4f4f4; | |
| padding: 1px 4px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 10pt; | |
| } | |
| pre { | |
| background: #f4f4f4; | |
| padding: 12px; | |
| overflow-x: auto; | |
| font-size: 9pt; | |
| font-family: 'Courier New', monospace; | |
| } | |
| strong { | |
| font-weight: bold; | |
| } | |
| ul, | |
| ol { | |
| margin: 8px 0; | |
| } | |
| li { | |
| margin: 4px 0; | |
| } | |
| .risk-low { | |
| color: #2e7d32; | |
| font-weight: bold; | |
| } | |
| .risk-medium { | |
| color: #ef6c00; | |
| font-weight: bold; | |
| } | |
| .risk-high { | |
| color: #c62828; | |
| font-weight: bold; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>RFC: Decouple Product Imports from Core — Select Components Migration</h1> | |
| <h2>Problem</h2> | |
| <p><code>app/core/</code> has product imports (<code>app/products/</code>) in multiple places, violating the module | |
| boundary rule. This RFC focuses on 5 select cell types in Grid plus related imports in <code>GeneratedForm</code>, | |
| <code>dataImport</code>, and <code>inputRenderer</code>.</p> | |
| <h3>Where product imports exist in core today</h3> | |
| <table> | |
| <tr> | |
| <th>Core File</th> | |
| <th>Product Imports</th> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/teamsSelect/TeamsSelectEditor.tsx</code></td> | |
| <td><code>TeamsSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/departmentSelect/DepartmentSelectEditor.tsx</code></td> | |
| <td><code>DepartmentSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/levelSelect/LevelSelectEditor.tsx</code></td> | |
| <td><code>LevelSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/workLocationSelect/WorkLocationSelectEditor.tsx</code></td> | |
| <td><code>LocationSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/jobFunctionSelect/JobFunctionSelectEditor.tsx</code></td> | |
| <td><code>JobFunctionSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>Grid/cellTypes/jobFunctionSelect/JobFunctionSelect.helpers.ts</code></td> | |
| <td><code>convertJobFunctionsToSelectOptions</code> (already moved to core in prior PR)</td> | |
| </tr> | |
| <tr> | |
| <td><code>generatedForm/GeneratedForm.tsx</code></td> | |
| <td><code>Address</code>, <code>DepartmentSelect</code>, <code>LevelSelect</code>, <code>TeamsSelect</code>, | |
| <code>PositionInput</code>, <code>LocationSelect</code>, <code>ManagerSelect</code>, | |
| <code>LookupFieldSelectInput</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>dataImport/.../columnValuesMapSelect.tsx</code></td> | |
| <td><code>JobFunctionSelect</code>, <code>DepartmentSelect</code>, <code>LevelSelect</code>, | |
| <code>TeamsSelect</code>, <code>WorkLocationSelect</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>dataImport/.../uploadCsv.tsx</code></td> | |
| <td><code>uploadToS3</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>inputRenderer/InputRenderer.constants.ts</code></td> | |
| <td><code>LevelSelectRenderer</code></td> | |
| </tr> | |
| </table> | |
| <p><strong>Goal:</strong> Zero product imports in <code>app/core/</code>. If something is used by more than one | |
| product, it should be maintained centrally in core.</p> | |
| <h2>Cross-Product Usage (why central ownership is correct)</h2> | |
| <table> | |
| <tr> | |
| <th>Cell Type</th> | |
| <th># Products Using</th> | |
| <th>Key Products</th> | |
| </tr> | |
| <tr> | |
| <td><code>DEPARTMENT_SELECT</code></td> | |
| <td><strong>10</strong></td> | |
| <td>Hris/Org, Hris/Emp, HeadcountPlanning, Compensation, Payroll, AccountingIntegrations, Ats, TimeTracking, | |
| Hris/Documents, ReviewCycles</td> | |
| </tr> | |
| <tr> | |
| <td><code>WORKLOCATION_SELECT</code></td> | |
| <td><strong>8</strong></td> | |
| <td>Compensation, Hris/Org, HeadcountPlanning, TimeTracking, EEOCReporting, Payroll, AccountingIntegrations, | |
| Hris/Documents</td> | |
| </tr> | |
| <tr> | |
| <td><code>LEVEL_SELECT</code></td> | |
| <td><strong>7</strong></td> | |
| <td>Compensation (9 files), Hris/Org (5), HeadcountPlanning (3), ReviewCycles, Hris/Emp, Hris/Documents, Payroll | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><code>JOB_FUNCTION_SELECT</code></td> | |
| <td><strong>4</strong></td> | |
| <td>Compensation (12 files), HeadcountPlanning (2), ReviewCycles, Hris/Org</td> | |
| </tr> | |
| <tr> | |
| <td><code>TEAMS_SELECT</code></td> | |
| <td><strong>3</strong></td> | |
| <td>HeadcountPlanning, Payroll, Hris/Org</td> | |
| </tr> | |
| </table> | |
| <h2>Approach: Move Everything to Core</h2> | |
| <p>Move select components AND all their product-specific dependencies to <code>app/core/</code>. Original product | |
| files become deprecated re-exports for backward compatibility.</p> | |
| <h2>Dependency Chain Analysis</h2> | |
| <h3>Layer 1: Shared Select Infrastructure (already partially done)</h3> | |
| <p>These utilities are shared across ALL 5 select components:</p> | |
| <table> | |
| <tr> | |
| <th>Item</th> | |
| <th>Current Location</th> | |
| <th>Depends On</th> | |
| </tr> | |
| <tr> | |
| <td><code>withCompositeInput</code> HOC</td> | |
| <td><code>app/products/hr/Hub/inputs/withCompositeInput</code></td> | |
| <td><code>withSpinner</code> (core), Pebble</td> | |
| </tr> | |
| <tr> | |
| <td><code>withSelectVariations</code> HOC</td> | |
| <td><code>app/products/hr/Hub/inputs/withSelectVariations</code></td> | |
| <td>Pebble</td> | |
| </tr> | |
| <tr> | |
| <td><code>PositionInput</code> component</td> | |
| <td><code>app/products/hr/Hub/components/positionInput/</code></td> | |
| <td>PositionContext, PositionInput.actions, PositionInput.types</td> | |
| </tr> | |
| <tr> | |
| <td><code>FLEXIBILITY_TYPES</code> constant</td> | |
| <td><code>app/products/hr/Hub/modules/Positions/actions/common</code></td> | |
| <td>None</td> | |
| </tr> | |
| <tr> | |
| <td><code>isEqualArrayWith</code> util</td> | |
| <td><code>app/products/hr/Hub/utils/common</code></td> | |
| <td>None</td> | |
| </tr> | |
| <tr> | |
| <td>Conversion helpers</td> | |
| <td><code>app/products/hr/*/helpers</code></td> | |
| <td>Already in <code>app/core/utils/selectHelpers/</code> from prior PR</td> | |
| </tr> | |
| </table> | |
| <p><strong>Complexity: <span class="risk-low">LOW</span></strong> — These have no deep product dependencies.</p> | |
| <h3>Layer 2: Select Components Themselves</h3> | |
| <table> | |
| <tr> | |
| <th>Component</th> | |
| <th>Current Location</th> | |
| <th>Product Imports (after Layer 1 is in core)</th> | |
| </tr> | |
| <tr> | |
| <td><strong>TeamsSelect</strong></td> | |
| <td><code>hr/Hris/Org/inputs/teamsSelect/</code></td> | |
| <td><code>Teams</code> component</td> | |
| </tr> | |
| <tr> | |
| <td><strong>DepartmentSelect</strong></td> | |
| <td><code>hr/Hris/Org/inputs/departmentSelect/</code></td> | |
| <td><code>Departments</code> component (dead code), <code>ORG_DATA_DEPARTMENTS_PATH</code> (inline-able string) | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>LevelSelect</strong></td> | |
| <td><code>hr/Hris/Org/inputs/trackLevelSelect/</code></td> | |
| <td><code>Tracks</code> endpoint, <code>routeUtils</code> (inline-able string)</td> | |
| </tr> | |
| <tr> | |
| <td><strong>LocationSelect</strong></td> | |
| <td><code>hr/Hub/inputs/locationSelect/</code></td> | |
| <td><code>Address</code> component, <code>workLocationActions</code>, <code>addPossibleValueToPosition</code></td> | |
| </tr> | |
| <tr> | |
| <td><strong>JobFunctionSelect</strong></td> | |
| <td><code>hr/Compensation/inputs/jobFunctionSelect/</code></td> | |
| <td><code>AddJobFunction</code>, <code>CompensationManagementConfigAPI</code>, <code>useJobFunctionAccess</code>, | |
| <code>COMPENSATION_SETTINGS_DATA_KEYS</code></td> | |
| </tr> | |
| </table> | |
| <h3>Layer 3: Product-Specific Dependencies (the hard part)</h3> | |
| <h4>3A. Teams + Departments (Hierarchy ecosystem)</h4> | |
| <p>Both <code>Teams</code> and <code>Departments</code> share the same <code>Hierarchy</code> component infrastructure | |
| from <code>hr/Hub</code>.</p> | |
| <pre> | |
| Teams.tsx / Departments.tsx | |
| ├── Hierarchy (Hub component) | |
| │ ├── HierarchyView — no product deps | |
| │ ├── HierarchyEdit — no product deps | |
| │ ├── HierarchyNodeRenderer | |
| │ │ └── OrganizationDataDeleteModal (Hris/Org) | |
| │ │ → FlowIds (Hris/Emp), eorRouteUtils (Hub) | |
| │ ├── HierarchyDeleteModal — no product deps | |
| │ └── HierarchyEditModal — no product deps | |
| │ | |
| ├── hierarchyActions (Hub) | |
| │ ├── hierarchy.helpers (Hub) | |
| │ ├── Department endpoint → re-export from app/api/ ✅ | |
| │ ├── Team endpoint → re-export from app/api/ ✅ | |
| │ ├── Level endpoint → re-export from app/api/ ✅ | |
| │ └── JobFunction endpoint (Compensation) → app/api/ + types | |
| │ | |
| └── withSpinner, withRouterLatest → already in core/routes ✅ | |
| </pre> | |
| <p><strong>Total unique product files: ~20</strong><br> | |
| <strong>Products crossed:</strong> Hub, Hris/Org, Compensation (endpoints + types), Hris/Emp (1 constant)<br> | |
| <strong>Complexity: <span class="risk-medium">HIGH</span></strong> — Substantial but self-contained. Teams and | |
| Departments share it, so moving it once covers both. | |
| </p> | |
| <h4>3B. LevelSelect Dependencies</h4> | |
| <pre> | |
| Tracks endpoint → only depends on app/api/baseModel ✅ | |
| routeUtils → pure string function, zero deps ✅ | |
| </pre> | |
| <p><strong>Total product files: 2</strong><br> | |
| <strong>Complexity: <span class="risk-low">SIMPLE</span></strong> | |
| </p> | |
| <h4>3C. LocationSelect Dependencies</h4> | |
| <pre> | |
| Address component (25 product files!) | |
| ├── EmploymentAuthorization endpoints + utils | |
| │ ├── flowInfraRoutesUtils → EmploymentAuth constants, GlobalContractors constants | |
| │ │ └── bulkCensusInfraCommon.service → Documents utils, EorAPIConstants | |
| │ └── Hub/containers/employmentAuthorization utils | |
| ├── Hub/actions/address → app/api only ✅ | |
| └── Hub/modules/Employee/components/setup/setupRegex → app/lib only ✅ | |
| workLocationActions (19 product files!) | |
| └── CrossSell/Triggers/UserEvents/workLocationCrossSell | |
| └── CrossSell/constants → SpendManagement/constants | |
| → Payroll/constants, BillPay types... | |
| addPossibleValueToPosition (2 product files) | |
| └── Hub/modules/Positions/actions/common → no product deps ✅ | |
| </pre> | |
| <p><strong>Total unique product files: ~42</strong><br> | |
| <strong>Products crossed: 7+</strong> (Hris/Emp, EmploymentAuthorization, Hub, Peo, GlobalContractors, | |
| Hris/Documents, growth/CrossSell, finance/SpendManagement, finance/Payroll)<br> | |
| <strong>Complexity: <span class="risk-high">VERY HIGH</span></strong> — Address and workLocationActions have the | |
| deepest, widest dependency chains. | |
| </p> | |
| <h4>3D. JobFunctionSelect Dependencies</h4> | |
| <pre> | |
| AddJobFunction (30+ product files) | |
| ├── JobFunctionAPI → JobFunctionEndpoints, CompanyDetails.actions | |
| │ └── CompanyDetailsPermission.types → platform/HubPlatform/Permissions | |
| ├── useJobFunctionMutation → CrossSell/jobFunctionCrossSell | |
| ├── compensationQueryKeys → Benchmarking types, EquityGrant constants | |
| └── Compensation/types → platform/HubPlatform/superGroup (50+ files) | |
| CompensationManagementConfigAPI → app/api/baseModel only ✅ (1 file) | |
| useJobFunctionAccess → reuses same chains as AddJobFunction (overlapping) | |
| COMPENSATION_SETTINGS_DATA_KEYS → inline-able or 1 file + type chain | |
| </pre> | |
| <p><strong>Total unique product files: ~30+</strong> (heavy overlap between AddJobFunction and | |
| useJobFunctionAccess)<br> | |
| <strong>Products crossed:</strong> Compensation, Hris/Org, growth/CrossSell, platform/HubPlatform<br> | |
| <strong>Complexity: <span class="risk-high">VERY HIGH</span></strong> — Most depth is TYPE-only and can be addressed | |
| via <code>@rippling/types</code>. | |
| </p> | |
| <h2>Migration Plan — PR Breakdown</h2> | |
| <h3>PR 1: Shared Select Infrastructure → Core</h3> | |
| <p><span class="risk-low">LOW RISK</span> — Already partially done for TeamsSelect. Complete for all selects.</p> | |
| <p>Move to <code>app/core/components/selectUtils/</code>:</p> | |
| <ul> | |
| <li><code>withCompositeInput</code> HOC</li> | |
| <li><code>withSelectVariations</code> HOC + <code>useSelectState</code> hook</li> | |
| <li><code>PositionInput</code> component + context + actions + types</li> | |
| <li><code>FLEXIBILITY_TYPES</code>, <code>DATA_KEY</code>, <code>CUSTOM_DATA_KEY_NAMES</code> constants</li> | |
| <li><code>isEqualArrayWith</code> utility</li> | |
| </ul> | |
| <p>Move types to <code>@rippling/types</code>: <code>CompositeInputPropsType</code>, | |
| <code>WithSelectVariationsPropsType</code>, <code>PositionDataType</code></p> | |
| <p>Re-export from original product locations (deprecated).</p> | |
| <p><strong>Files changed:</strong> ~15 new core files, ~8 product re-exports</p> | |
| <h3>PR 2: DepartmentSelect + LevelSelect → Core</h3> | |
| <p><span class="risk-low">LOW RISK</span></p> | |
| <p><strong>DepartmentSelect:</strong></p> | |
| <ul> | |
| <li>Move component to <code>app/core/components/departmentSelect/</code></li> | |
| <li>Remove dead <code>Departments</code> import (<code>showAddModal</code> is never set to <code>true</code>)</li> | |
| <li>Inline <code>ORG_DATA_DEPARTMENTS_PATH</code> string constant</li> | |
| <li>Update Grid editor import, GeneratedForm, dataImport</li> | |
| </ul> | |
| <p><strong>LevelSelect:</strong></p> | |
| <ul> | |
| <li>Move component to <code>app/core/components/levelSelect/</code></li> | |
| <li>Move <code>Tracks</code> endpoint to <code>app/api/endpoints/</code> (only depends on BaseModel)</li> | |
| <li>Inline <code>routeUtils.getTrackListRoute()</code> string</li> | |
| <li>Move <code>LevelSelectRenderer</code></li> | |
| <li>Update Grid editor, GeneratedForm, dataImport, inputRenderer</li> | |
| </ul> | |
| <p><strong>Files changed:</strong> ~10 new core files, ~5 product re-exports</p> | |
| <h3>PR 3: TeamsSelect + Hierarchy Ecosystem → Core</h3> | |
| <p><span class="risk-medium">MEDIUM RISK</span></p> | |
| <p><strong>Key insight: Teams and Departments share the Hierarchy infrastructure. Moving it once unlocks | |
| both.</strong></p> | |
| <p>Move to <code>app/core/components/hierarchy/</code>:</p> | |
| <ul> | |
| <li><code>Hierarchy</code> component (HierarchyView, HierarchyEdit, HierarchyNodeRenderer, etc.)</li> | |
| <li><code>hierarchyActions</code> (Hub)</li> | |
| <li><code>hierarchy.helpers</code> (Hub)</li> | |
| <li>HierarchyDeleteModal, HierarchyEditModal</li> | |
| <li>AssignHierarchyModal + assignDepartment component</li> | |
| </ul> | |
| <p>Move to <code>app/core/components/teamsSelect/</code>:</p> | |
| <ul> | |
| <li><code>TeamsSelect</code> component</li> | |
| </ul> | |
| <p>Handle transitive dependencies:</p> | |
| <ul> | |
| <li>Endpoint re-exports (Department, Team, Level, JobFunction) → already in <code>app/api/</code>, change imports | |
| </li> | |
| <li><code>OrganizationDataDeleteModal</code> → move to core or lazy-load</li> | |
| <li><code>FlowIds</code> constant (Hris/Emp) → inline or move to core constants</li> | |
| <li><code>eorRouteUtils</code> (Hub) → inline route string</li> | |
| <li><code>DarkLaunchConfig</code> (Hub) → evaluate if needed or can be removed from hierarchy code path</li> | |
| </ul> | |
| <p><strong>Files changed:</strong> ~25 new core files, ~10 product re-exports</p> | |
| <h3>PR 4: LocationSelect + Address + workLocationActions → Core</h3> | |
| <p><span class="risk-high">HIGH RISK</span> — Deepest dependency chain. Consider splitting further.</p> | |
| <p><strong>Phase 4A: workLocationActions + addPossibleValueToPosition</strong></p> | |
| <ul> | |
| <li><code>addPossibleValueToPosition</code> → already inlined in prior work</li> | |
| <li><code>workLocationActions</code> → move to <code>app/core/</code></li> | |
| <li>Handle CrossSell dependency: move CrossSell trigger to core or make injectable/optional</li> | |
| </ul> | |
| <p><strong>Phase 4B: Address component</strong></p> | |
| <ul> | |
| <li>Move to <code>app/core/components/address/</code></li> | |
| <li>Handle transitive deps: EmploymentAuthorization, flowInfraRoutesUtils, bulkCensusInfraCommon</li> | |
| <li>Audit which dependencies are actually used at runtime vs. brought in by barrel exports</li> | |
| </ul> | |
| <p><strong>Phase 4C: LocationSelect</strong></p> | |
| <ul> | |
| <li>Move component to <code>app/core/components/locationSelect/</code></li> | |
| <li>All dependencies now in core (from 4A + 4B)</li> | |
| <li>Update Grid editor, GeneratedForm, dataImport</li> | |
| </ul> | |
| <p><strong>Files changed:</strong> ~30+ new core files</p> | |
| <h3>PR 5: JobFunctionSelect + Compensation Dependencies → Core</h3> | |
| <p><span class="risk-high">HIGH RISK</span></p> | |
| <p><strong>Phase 5A: Simple Compensation dependencies</strong></p> | |
| <ul> | |
| <li><code>CompensationManagementConfigAPI</code> → move to <code>app/api/endpoints/</code> (only depends on | |
| BaseModel)</li> | |
| <li><code>COMPENSATION_SETTINGS_DATA_KEYS</code> → inline the specific key or move enum to core constants</li> | |
| <li><code>JobFunctionGroup</code> type → move to <code>@rippling/types</code></li> | |
| </ul> | |
| <p><strong>Phase 5B: AddJobFunction component</strong></p> | |
| <ul> | |
| <li>Move to <code>app/core/components/addJobFunction/</code></li> | |
| <li>Handle transitive deps: JobFunctionAPI, compensationQueryKeys, CrossSell trigger</li> | |
| <li>Compensation types chain → move needed types to <code>@rippling/types</code>; avoid pulling in | |
| <code>platform/HubPlatform/superGroup</code></li> | |
| </ul> | |
| <p><strong>Phase 5C: useJobFunctionAccess hook</strong></p> | |
| <ul> | |
| <li>Move to <code>app/core/hooks/</code> (depends on JobFunctionAPI + query keys from 5B)</li> | |
| </ul> | |
| <p><strong>Phase 5D: JobFunctionSelect</strong></p> | |
| <ul> | |
| <li>Move component to <code>app/core/components/jobFunctionSelect/</code></li> | |
| <li>Update Grid editor, dataImport</li> | |
| </ul> | |
| <p><strong>Files changed:</strong> ~25+ new core files</p> | |
| <h3>PR 6: GeneratedForm + dataImport + inputRenderer Cleanup</h3> | |
| <p><span class="risk-low">LOW RISK</span></p> | |
| <p>After PRs 1-5, all select components are in core. Update remaining core consumers:</p> | |
| <ul> | |
| <li><code>GeneratedForm.tsx</code> → update 8 imports to core paths</li> | |
| <li><code>columnValuesMapSelect.tsx</code> → update 5 imports to core paths</li> | |
| <li><code>uploadCsv.tsx</code> → move <code>uploadToS3</code> to core or inline</li> | |
| <li><code>InputRenderer.constants.ts</code> → update <code>LevelSelectRenderer</code> import</li> | |
| <li><code>ManagerSelect</code> and <code>LookupFieldSelectInput</code> → evaluate separately</li> | |
| </ul> | |
| <p><strong>Files changed:</strong> ~6 files updated</p> | |
| <h3>PR 7: Cleanup + module.config.json</h3> | |
| <p><span class="risk-low">LOW RISK</span></p> | |
| <ul> | |
| <li>Remove all product paths from <code>app/core/components/Grid/module.config.json</code></li> | |
| <li>Update <code>app/core/module.config.json</code> — remove <code>allowedImports</code> for product selects</li> | |
| <li>Update <code>service_catalog.yml</code> — assign ownership for new core files</li> | |
| <li>Run <code>npm run module-boundary:check</code> to verify zero violations</li> | |
| </ul> | |
| <h2>PR Summary</h2> | |
| <table> | |
| <tr> | |
| <th>PR</th> | |
| <th>Scope</th> | |
| <th>Risk</th> | |
| <th>Est. Files</th> | |
| <th>Can Parallelize?</th> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 1</strong></td> | |
| <td>Shared select utils → core</td> | |
| <td><span class="risk-low">Low</span></td> | |
| <td>~23</td> | |
| <td>—</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 2</strong></td> | |
| <td>DepartmentSelect + LevelSelect → core</td> | |
| <td><span class="risk-low">Low</span></td> | |
| <td>~15</td> | |
| <td>After PR 1</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 3</strong></td> | |
| <td>TeamsSelect + Hierarchy → core</td> | |
| <td><span class="risk-medium">Medium</span></td> | |
| <td>~35</td> | |
| <td>After PR 1</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 4</strong></td> | |
| <td>LocationSelect + Address → core</td> | |
| <td><span class="risk-high">High</span></td> | |
| <td>~30+</td> | |
| <td>After PR 1</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 5</strong></td> | |
| <td>JobFunctionSelect + Compensation deps → core</td> | |
| <td><span class="risk-high">High</span></td> | |
| <td>~25+</td> | |
| <td>After PR 1</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 6</strong></td> | |
| <td>GeneratedForm + dataImport cleanup</td> | |
| <td><span class="risk-low">Low</span></td> | |
| <td>~6</td> | |
| <td>After PR 2-5</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PR 7</strong></td> | |
| <td>module.config + service_catalog cleanup</td> | |
| <td><span class="risk-low">Low</span></td> | |
| <td>~3</td> | |
| <td>After PR 6</td> | |
| </tr> | |
| </table> | |
| <p><strong>Total estimated files:</strong> ~140+<br> | |
| <strong>Recommended order:</strong> PR1 → PR2 → PR3 → PR4/PR5 (parallel) → PR6 → PR7 | |
| </p> | |
| <h2>Risk Mitigation</h2> | |
| <ol> | |
| <li><strong>Testing:</strong> Each PR must include running existing unit tests for the moved components. The Grid | |
| cell type tests (<code>__tests__/cellTypes/*.test.tsx</code>) validate renderer/formatter/paste behavior.</li> | |
| <li><strong>Barrel export analysis:</strong> Before moving Address and AddJobFunction, audit which transitive | |
| dependencies are actually used at runtime vs. pulled in by barrel <code>index.ts</code> files. This can | |
| significantly reduce the dependency chain.</li> | |
| <li><strong>Type-only imports:</strong> Many deep dependencies (especially | |
| <code>platform/HubPlatform/superGroup</code>, <code>finance/BillPay</code>) are reached through | |
| <code>import type</code> chains. These can be cut by moving types to <code>@rippling/types</code> without moving | |
| runtime code.</li> | |
| <li><strong>CrossSell dependencies:</strong> Both <code>workLocationActions</code> and <code>AddJobFunction</code> | |
| trigger CrossSell events. These can be made injectable (callback prop) or moved to core as a generic eventing | |
| utility.</li> | |
| <li><strong>Re-exports:</strong> Every moved file gets a deprecated re-export at the original location to avoid | |
| breaking existing consumers. These can be cleaned up later by each product team.</li> | |
| <li><strong>Incremental verification:</strong> After each PR, run <code>npm run module-boundary:check</code>, | |
| <code>npm run ts:check</code>, and <code>npm run lint</code> to catch issues early.</li> | |
| </ol> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment