# Scratchpad: Tax Import Service Porting + BackNav Fix + Notification Reconciliation ## Decisions 1. **Skip adapters and externalTaxImportService** — Moving accounting adapters to `@alga-psa/integrations` creates a circular dependency: integrations→billing→integrations (adapters import `AccountingMappingResolver` etc. from billing; billing imports `QboClientService`/`XeroClientService` from integrations). Deferred to future PR with a strategy to extract shared types to `@alga-psa/types` first. 2. **Adopt package notification email.ts version** — rate limiting is centralized in `TenantEmailService.sendEmail()`, inline check in server version is redundant. 3. **Keep server emailLocaleResolver.ts** — `sendEventEmail.ts` imports it locally. Don't force server infrastructure to import from package. 4. **Delete orphan invoiceAdapters.ts** — zero callers in server; the billing package has its own independent copy at `packages/billing/src/lib/adapters/invoiceAdapters.ts`. 5. **Use `@alga-psa/core` for parseCSV** — csvTaxImportService currently imports from `server/src/lib/utils/csvParser`, but `@alga-psa/core` exports the same function (already used by XeroCsvTaxImportService in the integrations package). ## Key File Paths ### Tax Import Services - Source: `server/src/lib/services/csvTaxImportValidator.ts` (745 LOC) - Source: `server/src/lib/services/csvTaxImportService.ts` (595 LOC) - Source: `server/src/lib/utils/csvFieldNormalizer.ts` (323 LOC) - Target: `packages/integrations/src/services/` and `packages/integrations/src/lib/` - Barrel: `packages/integrations/src/services/index.ts` (currently: `export * from './email'`) - Reference pattern: `packages/integrations/src/services/xeroCsvTaxImportService.ts` - Caller: `server/src/lib/api/controllers/ApiCSVAccountingController.ts` ### BackNav Fix - Fix: `packages/ui/src/components/BackNav.tsx` line 7 - Target: `packages/ui/src/context/UnsavedChangesContext.tsx` (identical API) ### Notification Dual-Copies - Delete: `server/src/lib/notifications/email.ts` (561 LOC) - Delete: `server/src/lib/notifications/emailChannel.ts` (7 LOC, identical to package) - Keep: `server/src/lib/notifications/emailLocaleResolver.ts` (255 LOC) - Keep: `server/src/lib/notifications/emailService.ts` (273 LOC) - Keep: `server/src/lib/notifications/sendEventEmail.ts` (509 LOC) - Keep: `server/src/lib/notifications/NotificationAccumulator.ts` (459 LOC) - Package barrel: `packages/notifications/src/index.ts` — add `getEmailNotificationService` export - Package email.ts: `packages/notifications/src/notifications/email.ts` (504 LOC) - Package emailChannel: `packages/notifications/src/emailChannel.ts` (already in barrel) ### Orphan Deletion - Delete: `server/src/lib/adapters/invoiceAdapters.ts` (0 callers) ## Discoveries ### Circular Dependency: Adapters ↔ Billing - `server/src/lib/adapters/accounting/quickBooksOnlineAdapter.ts` imports from `@alga-psa/billing` (AccountingMappingResolver, CompanyAccountingSyncService, etc.) - `server/src/lib/adapters/accounting/xeroAdapter.ts` imports from `@alga-psa/billing` (same) - `server/src/lib/adapters/accounting/quickBooksCSVAdapter.ts` imports from `@alga-psa/billing` - `server/src/lib/adapters/accounting/xeroCsvAdapter.ts` imports from `@alga-psa/billing` - `packages/billing/src/services/companySync/adapters/xeroCompanyAdapter.ts` imports from `@alga-psa/integrations` - `packages/billing/src/services/companySync/adapters/quickBooksCompanyAdapter.ts` imports from `@alga-psa/integrations` - Adding `@alga-psa/billing` to integrations package.json → circular dependency ### Type Availability - `TaxSource`, `IExternalTaxImport`, `IExternalTaxImportResult` — all in `@alga-psa/types` ✓ - `AccountingExportBatch`, `AccountingExportLine` — in `packages/types/src/interfaces/accountingExport.interfaces.ts` but NOT exported from barrel (needed for future adapter migration) - `parseCSV` — available from `@alga-psa/core` ✓ ### Notification Differences - Server email.ts (561 LOC) vs package email.ts (504 LOC): server has inline rate limiting (lines 399-412) that package removed - emailLocaleResolver: functionally identical between server (255 LOC) and package (212 LOC), just different import paths - emailChannel: byte-for-byte identical (7 LOC each) - Package barrel already exports `emailChannel` but NOT `EmailNotificationService`/`getEmailNotificationService` ## Callers Summary ### csvTaxImportService: - `server/src/lib/api/controllers/ApiCSVAccountingController.ts` — `getCSVTaxImportService` ### email.ts (EmailNotificationService): - `server/src/lib/jobs/handlers/expiringCreditsNotificationHandler.ts` — `getEmailNotificationService` ### emailChannel: - `server/src/lib/eventBus/subscribers/ticketEmailSubscriber.ts` — `getEmailEventChannel` - `server/src/lib/eventBus/subscribers/projectEmailSubscriber.ts` — `getEmailEventChannel` - `server/src/lib/eventBus/publishers/index.ts` — `getEmailEventChannel` - `server/src/lib/api/services/TicketService.ts` — `getEmailEventChannel` - `server/src/test/integration/ticketEmailDelimiters.test.ts` — `EMAIL_EVENT_CHANNEL` ## Implementation Order 1. Move csvFieldNormalizer.ts → packages/integrations/src/lib/ 2. Move csvTaxImportValidator.ts → packages/integrations/src/services/ (update csvFieldNormalizer import) 3. Move csvTaxImportService.ts → packages/integrations/src/services/ (update db, types, parseCSV imports) 4. Update integrations services barrel 5. Update ApiCSVAccountingController.ts caller 6. Delete server copies of tax services + csvFieldNormalizer 7. Fix BackNav.tsx import 8. Add getEmailNotificationService to notifications barrel 9. Update 6 notification callers 10. Delete server email.ts and emailChannel.ts 11. Delete orphan invoiceAdapters.ts 12. Verify build (npm run build && npm run build:shared) ## Gotchas - `parseCSV` signature: verify `@alga-psa/core`'s `parseCSV` returns `string[][]` (same as server's `csvParser`). XeroCsvTaxImportService uses it with `as string[][]` cast. - `csvTaxImportValidator.ts` uses `any` type for knex parameter — keep as-is, don't try to type-narrow in this PR. - The `packages/integrations/src/services/index.ts` currently only exports `./email`. Adding CSV tax exports here. Make sure the export doesn't conflict with any existing names. - After deleting server emailChannel.ts, verify that `sendEventEmail.ts` doesn't import from it (it doesn't — only imports from `emailLocaleResolver`). - **DISCOVERED during implementation**: `emailService.ts` (kept in server) also imports from `./emailChannel` — needed to update this caller too (not in original plan's caller list). Updated to `@alga-psa/notifications`. - **DISCOVERED during implementation**: `UnsavedChangesContext` in `packages/ui/src/context/UnsavedChangesContext.tsx` was declared with `const` (not `export const`). The server version exports it directly. Had to add `export` keyword to the package version for BackNav.tsx to import it. ## Commands ```bash # Verify build after changes npm run build:shared && npm run build # Check for remaining boundary violations grep -r "from 'server/src/lib/services/csvTaxImport" --include="*.ts" --include="*.tsx" | grep -v "docs/" grep -r "from 'server/src/contexts/UnsavedChangesContext" --include="*.ts" --include="*.tsx" packages/ grep -r "from.*lib/notifications/emailChannel" --include="*.ts" --include="*.tsx" server/src/ grep -r "from.*lib/notifications/email'" --include="*.ts" --include="*.tsx" server/src/ ```