Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

8.6 KiB

PRD: Tax Import Service Porting + BackNav Fix + Notification Reconciliation

Date: 2026-02-20 PR scope: Single PR combining 3 cleanup items from the ongoing server-to-package migration


Problem Statement

The codebase has accumulated stale code patterns from the server-to-package migration:

  1. CSV tax import services remain in server/src/lib/services/ despite having a natural home in @alga-psa/integrations (where XeroCsvTaxImportService already lives as a reference)
  2. BackNav.tsx has a package-to-server boundary violation — imports UnsavedChangesContext from server/src/contexts/ despite an identical copy already existing in the same package at packages/ui/src/context/
  3. Notification email files are duplicated between server/src/lib/notifications/ and packages/notifications/src/notifications/ with diverged implementations (server has inline rate limiting that's been centralized elsewhere)
  4. An orphan file server/src/lib/adapters/invoiceAdapters.ts has zero callers

Goals

  • Port csvTaxImportValidator.ts and csvTaxImportService.ts (+ dependency csvFieldNormalizer.ts) to @alga-psa/integrations
  • Fix BackNav.tsx boundary violation (1 import change)
  • Reconcile notification dual-copies: delete server email.ts and emailChannel.ts, update callers to use package versions
  • Delete orphan server/src/lib/adapters/invoiceAdapters.ts

Non-Goals

  • Moving externalTaxImportService.ts (depends on accounting adapters which have a circular dependency with @alga-psa/billing — deferred)
  • Moving accounting adapters from server/src/lib/adapters/accounting/ (circular dep: integrations→billing→integrations — needs separate strategy)
  • Moving accountingExportService.ts to a package (has many server-internal deps)
  • Moving notification server-only files (emailService.ts, sendEventEmail.ts, NotificationAccumulator.ts)
  • Deleting server emailLocaleResolver.ts (still imported locally by sendEventEmail.ts)
  • Creating new facade packages

Detailed Changes

Work Item 1: CSV Tax Import Services → @alga-psa/integrations

Files to move:

Source Destination LOC
server/src/lib/utils/csvFieldNormalizer.ts packages/integrations/src/lib/csvFieldNormalizer.ts 323
server/src/lib/services/csvTaxImportValidator.ts packages/integrations/src/services/csvTaxImportValidator.ts 745
server/src/lib/services/csvTaxImportService.ts packages/integrations/src/services/csvTaxImportService.ts 595

Import changes needed in moved files:

Old Import New Import Files Affected
createTenantKnex from ../db @alga-psa/db csvTaxImportService
TaxSource from ../../interfaces/tax.interfaces @alga-psa/types csvTaxImportService
parseCSV from ../utils/csvParser @alga-psa/core (already used by XeroCsvTaxImportService) csvTaxImportService
csvFieldNormalizer from ../utils/csvFieldNormalizer ../lib/csvFieldNormalizer (relative within package) csvTaxImportValidator
csvTaxImportValidator from ./csvTaxImportValidator stays relative csvTaxImportService

Callers to update:

File Old Import New Import
server/src/lib/api/controllers/ApiCSVAccountingController.ts ../../services/csvTaxImportService @alga-psa/integrations/services

Barrel updates:

  • packages/integrations/src/services/index.ts — add exports for csvTaxImportValidator, csvTaxImportService

Package.json: No new dependencies needed. @alga-psa/core, @alga-psa/db, @alga-psa/types are already in integrations package.json.

Work Item 2: BackNav.tsx Fix

Single import change in packages/ui/src/components/BackNav.tsx:

- import { UnsavedChangesContext } from 'server/src/contexts/UnsavedChangesContext';
+ import { UnsavedChangesContext } from '../context/UnsavedChangesContext';

The context at packages/ui/src/context/UnsavedChangesContext.tsx has identical API: setHasUnsavedChanges, hasAnyUnsavedChanges, confirmNavigation, unregister, useUnsavedChanges(), useRegisterUnsavedChanges().

Work Item 3: Notification Dual-Copy Reconciliation

Delete server copies (adopt package versions):

  • server/src/lib/notifications/email.ts (561 LOC) — package version (504 LOC) is correct; inline rate limiting was moved to TenantEmailService
  • server/src/lib/notifications/emailChannel.ts (7 LOC) — identical to package version, already exported from @alga-psa/notifications barrel

Keep in server (not touched):

  • emailLocaleResolver.ts — still imported by sendEventEmail.ts locally
  • emailService.ts, sendEventEmail.ts, NotificationAccumulator.ts — server infrastructure

Package changes needed:

  • Export getEmailNotificationService from @alga-psa/notifications barrel (currently only accessible via relative import within package)

Server callers to update:

File What it imports New import source
server/src/lib/jobs/handlers/expiringCreditsNotificationHandler.ts getEmailNotificationService @alga-psa/notifications
server/src/lib/eventBus/subscribers/ticketEmailSubscriber.ts getEmailEventChannel @alga-psa/notifications
server/src/lib/eventBus/subscribers/projectEmailSubscriber.ts getEmailEventChannel @alga-psa/notifications
server/src/lib/eventBus/publishers/index.ts getEmailEventChannel @alga-psa/notifications
server/src/lib/api/services/TicketService.ts getEmailEventChannel @alga-psa/notifications
server/src/test/integration/ticketEmailDelimiters.test.ts EMAIL_EVENT_CHANNEL @alga-psa/notifications

Work Item 4: Orphan Deletion

Delete server/src/lib/adapters/invoiceAdapters.ts — zero callers. The billing package has its own independent copy at packages/billing/src/lib/adapters/invoiceAdapters.ts.

Implementation Order

  1. Move csvFieldNormalizer.ts to integrations package (prerequisite for validator)
  2. Move csvTaxImportValidator.ts to integrations package (update csvFieldNormalizer import)
  3. Move csvTaxImportService.ts to integrations package (update all imports: db, types, parseCSV, validator)
  4. Update integrations services barrel to export new modules
  5. Update ApiCSVAccountingController.ts caller
  6. Delete server copies of tax import services + csvFieldNormalizer
  7. Fix BackNav.tsx import
  8. Add getEmailNotificationService export to notifications package barrel
  9. Update 6 notification callers to import from @alga-psa/notifications
  10. Delete server email.ts and emailChannel.ts
  11. Delete orphan invoiceAdapters.ts
  12. Verify build

Risks

  1. csvTaxImportService uses parseCSV from server utils — must switch to @alga-psa/core (same function, already used by XeroCsvTaxImportService in the same package). Verify function signature compatibility.
  2. Notification rate limiting removal — The server email.ts had inline rate limiting that the package version doesn't. Risk mitigated: TenantEmailService already handles rate limiting centrally.
  3. Package notifications barrel change — Adding getEmailNotificationService export. Verify no naming conflicts.

Acceptance Criteria

  • npm run build succeeds
  • npm run build:shared succeeds
  • server/src/lib/services/csvTaxImportValidator.ts deleted
  • server/src/lib/services/csvTaxImportService.ts deleted
  • server/src/lib/utils/csvFieldNormalizer.ts deleted
  • server/src/lib/notifications/email.ts deleted
  • server/src/lib/notifications/emailChannel.ts deleted
  • server/src/lib/adapters/invoiceAdapters.ts deleted
  • BackNav.tsx imports from ../context/UnsavedChangesContext
  • packages/integrations/src/services/csvTaxImportValidator.ts exists
  • packages/integrations/src/services/csvTaxImportService.ts exists
  • packages/integrations/src/lib/csvFieldNormalizer.ts exists
  • getEmailNotificationService importable from @alga-psa/notifications
  • Grep for boundary violation patterns returns 0 source matches (outside docs/)

Deferred Items (future PRs)

These were explored but deferred due to circular dependency blockers:

  • externalTaxImportService.ts — depends on concrete adapter classes (QuickBooksOnlineAdapter, XeroAdapter) which import from @alga-psa/billing
  • Accounting adapters (7 files, 3,369 LOC) — create circular dep: integrations→billing→integrations. Need to extract shared types to @alga-psa/types first, or use runtime subpath strategy.
  • accountingExportAdapter.ts interface types — candidate for @alga-psa/types in future PR