Skip to content

TRD: Replace relative imports with path aliases in libs/ui - #456

Merged
mnindrazaka merged 1 commit into
feat/import-aliasfrom
claude/serene-clarke-0ipmyt
Sep 13, 2026
Merged

TRD: Replace relative imports with path aliases in libs/ui#456
mnindrazaka merged 1 commit into
feat/import-aliasfrom
claude/serene-clarke-0ipmyt

Conversation

@mnindrazaka

Copy link
Copy Markdown
Collaborator

Summary

This adds a Technical Requirements Document (TRD) that proposes a phased migration to replace relative imports with path aliases across libs/ui and the frontend apps. The migration addresses three concrete costs of relative imports: ambiguous paths that don't indicate their target, cross-project boundary violations, and a load-bearing Jest mapper regex that breaks silently on import shape changes.

Key changes

  • New document: docs/trd-import-alias-migration.md (643 lines)
    • Comprehensive audit of 1,664 relative imports across 730 files in libs/ui/src
    • Proposes two new path aliases: @ui/* for internal deep paths and @gatherloop-pos/api-contract/client for a previously-unaliased export
    • Defines 13 phases of phased delivery, each independently verifiable and revertible
    • Documents 10 design decisions (D1–D10) with alternatives rejected and rationale
    • Identifies 8 risks (R1–R8) with mitigations, and 3 open questions (OQ1–OQ3) to settle in Phase 1 review
    • Specifies acceptance criteria for each phase, including six resolver targets that must be proven (tsc, Jest, Next, Metro, Storybook, Playwright)

Notable design decisions

  • D1: Internal aliases use @ui/* namespace, not @gatherloop-pos/ui/*, to preserve the structural guarantee that apps cannot deep-import and to make the distinction visible in diffs
  • D2: Aliases are path-equivalent; no import is redirected to a barrel, preserving the module graph and bundle-size properties
  • D3: Same-directory imports stay relative; only cross-directory imports are aliased
  • D5: The .storybook/mocks/mockData.ts file moves to libs/ui/src/__fixtures__/mockData.ts to make it addressable by the @ui/* alias and to fix the architectural inversion of unit tests importing from Storybook config
  • D7: Root .eslintrc.json must allow @ui/* in the @nx/enforce-module-boundaries rule to permit self-imports through the internal alias
  • D8: Enforcement lands last as a single PR, adding eslint-plugin-no-relative-import-paths and fixing three lint rules the migration invalidates

Phased delivery structure

The migration is split into 13 phases:

  • Phase 0: This TRD (decision gate)
  • Phase 1: Enabling change + resolver spike (4 imports, proves all 6 resolvers)
  • Phase 2: Cross-project imports + Jest mapper (53 imports, fixes the load-bearing regex)
  • Phases 3–11: Per-directory conversions (1,607 imports across 730 files, independent and reorderable)
  • Phase 12: e2e projects (27 imports)
  • Phase 13: Enforcement + cleanup (adds lint rules, deletes codemod)

Each phase is one PR that leaves main green and the product shippable. Phases 3–11 are independent of each other (D10) and may be parallelized or reordered.

Verification strategy

Because CI runs no lint, typecheck, or build (only npx nx run ui:test and npx nx run api:test), every phase PR must include output from six targets in its description:

  • npx tsc -p libs/ui/tsconfig.lib.json --noEmit
  • npx nx run ui:lint
  • npx nx run ui:test
  • npx nx run pos-web:build
  • npx nx run order-web:build
  • npx nx run ui:build-storybook

Plus a Metro bundle and e2e suites in Phase 1 and Phase 13.

Open questions for Phase 1 review

  • OQ1: Use @ui/* or @gatherloop-pos/ui/*? (D1 argues for @ui/*; must decide before Phase

https://claude.ai/code/session_0184EpDzDv6jRR4pDooUiBCN

Plans the migration of 1,664 cross-directory relative imports in libs/ui
and 33 in the frontend apps to path aliases, split into 14 PR-sized
phases.

Key decisions captured: a separate @ui/* namespace for intra-library
deep imports so the public @gatherloop-pos/ui entry points stay narrow;
path-equivalent rewrites only, so the module graph is unchanged; and a
Phase 1 spike to prove the six resolvers (tsc, two Jest configs, Next,
Metro, Storybook, Playwright) before 730 files are touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0184EpDzDv6jRR4pDooUiBCN
@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gatherloop-order Ready Ready Preview Sep 12, 2026 11:17pm UTC
gatherloop-pos Ready Ready Preview Sep 12, 2026 11:17pm UTC
gatherloop-ui-storybook Ready Ready Preview Sep 12, 2026 11:17pm UTC

@mnindrazaka
mnindrazaka changed the base branch from main to feat/import-alias September 13, 2026 06:29
@mnindrazaka
mnindrazaka merged commit 0220582 into feat/import-alias Sep 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants