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

148 lines
8.6 KiB
Markdown

# 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`:
```diff
- 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