# Scratchpad: Cross-Package Cleanup P0-P2

## Key Commands Reference

### Build & TypeScript
```bash
# Full build (the definitive check)
npm run build

# TypeScript check on specific package (faster than full build)
cd packages/<pkg> && npx tsc --noEmit
cd server && npx tsc --noEmit
cd ee/server && npx tsc --noEmit
cd ee/packages/workflows && npx tsc --noEmit
```

### Cross-Package Violations (Lint)
```bash
# Authoritative violation count (use this, NOT nx run-many which undercounts ~50%)
npm run lint 2>&1 | grep "no-feature-to-feature-imports" | wc -l

# Per-source package breakdown
npm run lint 2>&1 | grep "no-feature-to-feature-imports" | sed 's/.*Feature package "\([^"]*\)".*/\1/' | sort | uniq -c | sort -rn

# Per-target package breakdown
npm run lint 2>&1 | grep "no-feature-to-feature-imports" | sed 's/.*feature package "\([^"]*\)".*/\1/' | sort | uniq -c | sort -rn

# Violations for a specific source package
npm run lint 2>&1 | grep "no-feature-to-feature-imports" | grep 'Feature package "client-portal"'

# Violations for a specific target
npm run lint 2>&1 | grep "no-feature-to-feature-imports" | grep 'feature package "documents"'
```

### Circular Dependencies
```bash
# Generate Nx graph and check for new cycles
npx nx graph --file=/tmp/graph.json && node scripts/check-circular-deps.mjs /tmp/graph.json --baseline .github/known-cycles.json

# Update baseline after fixing cycles (include tightened baseline in commit)
npx nx graph --file=/tmp/graph.json && node scripts/check-circular-deps.mjs /tmp/graph.json --update-baseline .github/known-cycles.json

# As of 2026-03-17, the root `package.json` override `nx -> brace-expansion@^2.0.2`
# restores `npx nx graph --file=/tmp/graph.json` in this workspace.
```

### Grep Patterns for Finding Violations
```bash
# Find all imports of a package from outside it
grep -r "@alga-psa/documents" --include="*.ts" --include="*.tsx" packages/ | grep -v "packages/documents/" | grep -v node_modules

# Find imports of auth-compat
grep -r "auth-compat" --include="*.ts" --include="*.tsx" -l | grep -v node_modules

# Find type-only cross-vertical imports
grep -rn "import type.*@alga-psa/" packages/ --include="*.ts" --include="*.tsx" | grep -v node_modules

# Check what shared/ imports from workflows
grep -r "@alga-psa/workflows" shared/ --include="*.ts" --include="*.tsx" -l | grep -v node_modules
```

### Testing
```bash
# Run tests locally (requires .env.localtest)
npm run test:local

# Run affected tests only
npx vitest run --changed

# Run specific test file
cd server && npx vitest run path/to/test.test.ts
```

## Decisions

- **2026-03-16:** P0-1 test files moved to `ee/packages/workflows/` (not `packages/workflows/`) because the tests reference EE-specific domain event builders
- **2026-03-16:** `@alga-psa/shared` added as devDependency to `ee/packages/workflows/package.json` for moved test imports
- **2026-03-16:** Removed 18 baseline cycles that all contained the resolved `@alga-psa/shared -> @alga-psa/workflows` edge; used manual baseline pruning because local Nx graph generation is still broken by the `brace_expansion_1.default` runtime error
- **2026-03-17:** Added a root `overrides.nx.brace-expansion = ^2.0.2` pin so `nx`'s bundled `minimatch@9` resolves a compatible `brace-expansion` version and `npx nx graph` works again locally.
- **2026-03-17:** `packages/storage` now owns its document/media workflow-event payload builders and no longer depends on `@alga-psa/auth`, `@alga-psa/shared`, `@alga-psa/workflow-streams`, or `@alga-psa/workflows`; this removed the last unbaselined storage-driven cycles without changing emitted payload shapes.

## Current State (2026-03-17)

- **Branch:** cleanup/circular_deps (rebased on origin/main)
- **Feature checklist:** complete through `F039`
- **Known cycles baseline:** 11 cycles after the restored Nx graph check and the storage dependency cleanup
- **Authoritative lint count:** 57 `no-feature-to-feature-imports` violations (down from the original 103 baseline)
- **Build / graph status:** `npm run build`, `cd packages/storage && npx tsc --noEmit`, `cd packages/storage && npx vitest run tests/storageService.workflowEvents.test.ts`, and `npx nx graph --file=/tmp/graph.json && node scripts/check-circular-deps.mjs /tmp/graph.json --baseline .github/known-cycles.json` all pass locally

## 2026-03-16 Progress Log

- Verified `shared/` only references `@alga-psa/workflows` in a comment within `shared/types/product-email-domains.d.ts`.
- Verified moved workflow tests compile with `cd ee/packages/workflows && npx tsc --noEmit`; `cd shared && npx tsc --noEmit` also passes.
- `npx nx graph --file=/tmp/graph.json` still fails locally with `brace_expansion_1.default is not a function`, including under Node 20, so cycle-baseline verification currently relies on the removed import edge plus baseline pruning.
- `npm run build` passed from repo root after the workflow test moves and cycle-baseline update; build emitted existing Next.js webpack warnings only.
- Pending workflow-test file moves and the related `ee/packages/workflows/package.json` devDependency update are ready to commit as the final P0-1 code delta.
- Authoritative `npm run lint` baseline is `103` `no-feature-to-feature-imports` violations when run directly from repo root.

### P0-2 Violation Breakdown (from `/tmp/p0-lint.log`)

```text
By source package
38 client-portal
14 workflows
13 tickets
12 clients
10 projects
 9 billing
 3 assets
 2 users
 2 integrations

By target package
39 documents
13 tickets
 9 billing
 8 sla
 7 clients
 6 scheduling
 6 projects
 6 integrations
 5 workflows
 4 users
```

- Migrated `ee/server/src/app/api/extensions/_auth.ts` to call `getSession()` directly from `@alga-psa/auth`, removing its dependency on `@/lib/auth-compat`.
- Migrated `ee/server/src/app/api/provisioning/tenants/route.ts` to call `getSession()` directly from `@alga-psa/auth`, leaving `server/src/lib/auth-compat.ts` with no remaining callers.
- Deleted `server/src/lib/auth-compat.ts`; the compatibility wrapper is fully retired in favor of `getSession()` from `@alga-psa/auth`.
- `npm run build` still passes after deleting `server/src/lib/auth-compat.ts`; only pre-existing webpack warnings were emitted.
- Auth-compat retirement is now represented by the committed `F008`-`F011` change series, so the P1-3 code path is fully checked in.
- Added `export * from './assets'` to `packages/msp-composition/src/index.ts` to expose the existing assets composition barrel from the package root.
- Added `export * from './billing'` to `packages/msp-composition/src/index.ts` so billing composition helpers are reachable from the main barrel.
- Added `export * from './clients'` to `packages/msp-composition/src/index.ts`; the root barrel now exposes assets, billing, clients, tickets, projects, and scheduling.
- `npm run build` passes with the expanded `@alga-psa/msp-composition` barrel; no new build regressions surfaced.
- The `msp-composition` export wiring is now fully committed via the `F013`-`F016` change series.
- P2-5a inventory: `packages/projects/src/actions/projectActions.ts` is the active `projects -> clients` direct import (`getContactByContactNameId`); `packages/scheduling/src` currently has no direct `@alga-psa/clients` imports.
- Verified `packages/clients/src/context/ClientCrossFeatureContext.tsx` already exports the client cross-feature provider + hook surface needed for composition-layer injection.
- Verified `packages/msp-composition/src/clients/MspClientCrossFeatureProvider.tsx` already bridges tickets/surveys/assets callbacks into the clients context.
- Current lint baseline has `0` active `projects -> clients` and `0` active `scheduling -> clients` warnings; the lone remaining direct import in `packages/projects/src/actions/projectActions.ts` is an intentionally justified server-action exception.
- P2-5a is effectively green in the current tree: the most recent root `npm run build` passed, and the client-related pair counts are already reduced to zero warnings.
- P2-5a now closes as verification/bookkeeping only because the context/provider migration had already landed before this plan pass.
- P2-5b inventory from the authoritative lint log: `documents` is still the top target with 39 warnings sourced from `projects` (10), `clients` (10), `client-portal` (7), `tickets` (5), `assets` (3), `users` (2), `workflows` (1), and `billing` (1). Common import shapes are entity-image helpers, document utilities, `Documents`/`DocumentUpload` UI, and KB types.
- Moved the public `uploadEntityImage` / `deleteEntityImage` entrypoint to `@alga-psa/storage` and updated the `client-portal`, `teams`, `users`, `tenancy`, and `clients` callers to import from the horizontal package instead of `@alga-psa/documents`.
- Added a horizontal `DocumentsCrossFeatureContext` to `@alga-psa/core` so remaining document UI imports can be replaced without introducing new vertical-to-vertical dependencies.
- `DocumentsCrossFeatureContext` must stay off the root `@alga-psa/core` barrel because exporting a client-only React context there causes server imports of `@alga-psa/core` to fail Next.js builds.
- T001 verified that `shared/` only mentions `@alga-psa/workflows` in the comment inside `shared/types/product-email-domains.d.ts`; there are no actual code imports left.
- T002 verified `cd ee/packages/workflows && npx tsc --noEmit` succeeds after the ten test-file moves.
- T003 verified a fresh repo-root `npm run build` succeeds after the workflow moves, auth cleanup, and storage entity-image extraction work.
- T004 hit the documented local skip condition: `npx nx graph --file=/tmp/graph.json` still fails with `brace_expansion_1.default is not a function`, so cycle verification continues to rely on the pruned baseline and removed import edge.
- T005 confirmed `.github/known-cycles.json` now contains `12` baselined cycles, down from the prior `30`.
- T006 reconfirmed that the direct lint command remains the authoritative measurement path; after the later document cleanup it reports `98` current violations.
- T007 reconfirmed the per-source lint breakdown pipeline; the latest run is led by `client-portal`, `workflows`, `tickets`, `clients`, and `projects`.
- T008 reconfirmed the per-target lint breakdown pipeline; `documents` remains the top target even after the entity-image move, followed by `tickets`, `billing`, and `sla`.
- T009 verified there are no remaining `auth-compat` source references anywhere in the repo.
- T010 verified `ee/server/src/app/api/extensions/_auth.ts` now imports `getSession` directly from `@alga-psa/auth`.
- T011 verified `ee/server/src/app/api/provisioning/tenants/route.ts` now imports `getSession` directly from `@alga-psa/auth`.
- T012 confirmed `server/src/lib/auth-compat.ts` no longer exists on disk.
- T013 reuses the latest repo-root green build to validate the auth-compat removal end-to-end.
- T014 verified `packages/msp-composition/src/index.ts` exports `./assets` from the root barrel.
- T015 verified `packages/msp-composition/src/index.ts` exports `./billing` from the root barrel.
- T016 verified `packages/msp-composition/src/index.ts` exports `./clients` from the root barrel.
- T017 reuses the latest repo-root green build to validate the expanded `msp-composition` barrel.
- T018 verified the current lint output has `0` active `projects -> clients` violations, which is below the historical non-zero starting point for P2-5a.
- T019 verified `packages/clients/src/context/ClientCrossFeatureContext.tsx` exists and exports the expected provider/hook pair.
- T020 reuses the latest repo-root green build to validate the current client-composition setup.
- T021 verified the latest lint run has `34` `documents`-target violations, which is below the `<36` target in the plan.
- T022 verified no vertical package now imports `uploadEntityImage` or `deleteEntityImage` from `@alga-psa/documents`; those callers now resolve through `@alga-psa/storage`.
- T023 reuses the latest repo-root green build to validate the current document-cleanup changes.
- F028 conditions are met in the current tree: repo-root build passes and the `documents` target is down to `34` warnings from the earlier `39` baseline.
- The current document-cleanup series is committed through `F025`, `F026`, and the follow-up barrel fix, so the implemented P2-5b work is fully checked in.
- Rolled the `DocumentsCrossFeatureContext` out into composition providers for MSP and client-portal shells, then migrated the remaining client-side document UI/util callers in `assets`, `tickets`, and `client-portal` to consume the context instead of importing `@alga-psa/documents` directly.
- Moved the client-portal document provider out of `packages/client-portal` and into `server/src/app/client-portal/ClientPortalDocumentsProvider.tsx` after lint exposed that a local provider would itself create a new `client-portal -> documents` violation.
- Validation after the provider rollout: `npm run lint` now reports `91` total `no-feature-to-feature-imports` warnings and only `27` targeting `documents` (down from `98`/`34` before this pass); repo-root `npm run build` also passes.
- F030 categorization snapshot from `/tmp/alga-lint-f030.log`: `client-portal` now has `34` remaining warnings. `6` are clearly fixable (`client-kb.ts`, `ClientKBArticleView.tsx`, `ClientKBPage.tsx` via `@alga-psa/types`; `ProjectDetailView.tsx` via a composition facade). The other `28` are inherent composition edges across `tickets`, `billing`, `clients`, and `users`, where client-portal is intentionally orchestrating vertical feature APIs/components and is a reasonable candidate for justified `eslint-disable` comments in F031.
- Acceptable/inherent client-portal edges: `client-billing.ts`, `client-tickets.ts`, `clientPaymentActions.ts`, `BillingOverview.tsx`, `ClientInvoicePreview.tsx`, `ClientProfile.tsx`, `ClientDetailsSettings.tsx`, `ClientPasswordChangeForm.tsx`, `UserManagementSettings.tsx`, `ClientAddTicket.tsx`, `TicketDetails.tsx`, `TicketDetails.originBadge.contract.test.ts`, and `TicketList.tsx`.
- Fixable client-portal edges queued for later items: `client-kb.ts`, `ClientKBArticleView.tsx`, `ClientKBPage.tsx` (type-only `documents` imports for P2-6), plus `ProjectDetailView.tsx` (presentation imports from `projects`, a good `client-portal` composition-facade candidate for F032).
- Added file-level `custom-rules/no-feature-to-feature-imports` disables with explicit justification comments to the acceptable/inherent client-portal composition files; a fresh `npm run lint` now reports `63` total violations and only `6` remaining `client-portal` warnings, all in the previously identified fixable KB/project files.
- Created a new horizontal `@alga-psa/client-portal-composition` package and moved the project metrics card composition there via `ClientPortalProjectMetrics`; `packages/client-portal/src/components/projects/ProjectDetailView.tsx` no longer imports from `@alga-psa/projects` directly.
- Validation after F032: `cd packages/client-portal && npx tsc --noEmit`, `cd server && npx tsc --noEmit`, and `npm run lint` all pass; only `3` `client-portal` violations remain, all from the KB type-only imports targeted by P2-6.
- Re-ran the full repo-root `npm run build` after the new `@alga-psa/client-portal-composition` package landed; the build is green, so the client-portal cleanup track is now blocked only on the planned P2-6 type extraction.
- The client-portal cleanup series is now fully checkpointed through `F030`-`F034`: acceptable edges are documented and justified, the project-detail composition moved to a horizontal package, the build is green, and only the KB type-only imports remain for P2-6.
- F035 inventory: the meaningful remaining P2-6 candidates are the KB types `IKBArticleWithDocument` and `ArticleType`, imported type-only from `@alga-psa/documents/actions` in `packages/client-portal/src/actions/client-portal-actions/client-kb.ts`, `packages/client-portal/src/components/kb/ClientKBArticleView.tsx`, and `packages/client-portal/src/components/kb/ClientKBPage.tsx`. The broader grep also finds many same-package or horizontal-package type imports, but those are not cross-vertical cleanup targets.
- Moved the KB domain types into `packages/types/src/lib/knowledgeBase.ts` and exported them from `@alga-psa/types`; `packages/documents/src/actions/kbArticleActions.ts` now consumes those shared definitions instead of owning them locally.
- Validation after F036: `cd packages/types && npx tsc --noEmit`, `cd packages/client-portal && npx tsc --noEmit`, and `cd packages/documents && npx tsc --noEmit` all pass.
- Updated the three client-portal KB callers (`client-kb.ts`, `ClientKBArticleView.tsx`, `ClientKBPage.tsx`) to import the extracted KB types from `@alga-psa/types`; `npm run lint` now reports `0` remaining `client-portal` feature-import warnings and `57` total violations repo-wide.
- Re-ran the full repo-root `npm run build` after the KB type import swap; build stays green, and the lint baseline remains at `57`, down from the original authoritative `103` count.
- The P2-6 type extraction series is now fully checkpointed through `F035`-`F039`: candidates identified, KB types moved into `@alga-psa/types`, callers updated, build re-verified, and the feature checklist is complete.
- Root-cause for the old `nx graph` failure: `nx`'s bundled `minimatch@9.0.3` was resolving the repo-level `brace-expansion@5`, which breaks `braceExpand()` at runtime. Pinning `overrides.nx.brace-expansion` to `^2.0.2` and refreshing `node_modules` restored `npx nx graph`.
- Removed stale `packages/storage` dependencies on auth/shared/workflows and replaced its `@alga-psa/workflow-streams` payload-builder imports with local equivalents in `packages/storage/src/workflowEventPayloads.ts`; this eliminated the remaining storage-driven graph cycles while preserving the same published event payload fields.
- Validation for the storage cleanup: `cd packages/storage && npx tsc --noEmit`, `cd packages/storage && npx vitest run tests/storageService.workflowEvents.test.ts`, `npx nx graph --file=/tmp/graph.json && node scripts/check-circular-deps.mjs /tmp/graph.json --baseline .github/known-cycles.json`, and repo-root `npm run build` all pass.
- T024 now passes end-to-end: the restored graph run reports `11` total cycles, `.github/known-cycles.json` has been tightened from `12` to `11`, and the checker reports `No new circular dependencies.`
- T025 verified the client-portal cleanup end-to-end: `npm run lint` now reports `0` remaining `Feature package "client-portal"` violations, which means every prior client-portal edge was either removed via composition/type extraction or intentionally suppressed with a justification comment.
- T026 reuses the latest repo-root green `npm run build` after the client-portal composition package and KB type-extraction changes, confirming the client-portal cleanup series remains build-safe.
- T027 verified `grep -rn "import type.*@alga-psa/documents" packages/client-portal/ --include='*.ts' --include='*.tsx'` now returns `0` matches.
- T028 verified the new shared KB definitions live in `packages/types/src/lib/knowledgeBase.ts` and are exported through `packages/types/src/index.ts`.
- T029 reuses the latest repo-root green `npm run build` after the KB type extraction and caller migration.
- T030 confirmed the authoritative lint count is now `57`, which is substantially below the P0-2 baseline of `103`.

## Remaining Open Work

- None. Feature and test checklists are complete.

## Gotchas

- `npm run lint` is the correct command (not `npx nx run-many --target=lint` which misses ~50% of violations)
- The repo engine range is `>=20 <25`; under the current local Node `v25.8.1`, `npm install` emits `EBADENGINE` warnings even though the verified commands above still pass.
- Never create re-export shims when migrating — update all callers directly
- `client-portal` is inherently a composition layer — some violations may be acceptable with eslint-disable
- When adding context facades, providers must go in `DefaultLayout.tsx` (not per-page) because DrawerOutlet renders at layout level
- `msp-composition` is a horizontal package so it's allowed to import from verticals — its internal violations are by design
