Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
8.3 KiB
PRD — Storage Extraction & Phase 2 Cleanup
- Slug:
storage-extraction-and-phase2-cleanup - Date:
2026-02-19 - Status: Draft
- Analysis source:
.ai/stale-code-and-cross-package-analysis.md
Summary
Single PR combining two concerns: (1) finish Phase 2 cleanup remainders (3 small mechanical fixes), and (2) extract @alga-psa/storage as a new horizontal package from @alga-psa/documents, eliminating ~10 cross-package violations where non-document packages import storage infrastructure from the documents domain package.
Problem
Phase 2 remainders: Three leftover items from previous cleanup phases:
- A broken import in
portal-domain-sessions-prune.ts(references deleted file) - 2 test files still importing from a server-side model that should use the package equivalent
- 1 re-export shim (
server/src/lib/email/index.ts) with 1 source-code caller that should import directly
Storage in documents: The @alga-psa/documents package houses generic file-storage infrastructure (StorageService, StorageProviderFactory, providers, config, types) that has nothing to do with the documents domain. Five packages (billing, client-portal, jobs, server) import storage from documents, creating cross-package coupling. Storage is a horizontal concern that should be its own package.
Goals
- Fix the 3 Phase 2 remainder items (broken import, stale test imports, email shim)
- Create
@alga-psa/storagepackage containing all file-storage infrastructure - Update all consumers (5 external + 5 documents-internal) to import from the new package
- Add re-exports from
@alga-psa/documentsfor backwards compatibility - Maintain build green throughout
- Net reduction in cross-package violations
Non-goals
- No extraction of avatar/image utilities (they depend on documentActions -- circular)
- No extraction of formatting utilities (blocknoteUtils -- separate future PR)
- No extraction of the key-value storage API (
storage/api/-- different system entirely) - No behavioral changes to any storage, email, or document functionality
- No new tests beyond verifying existing ones pass
- No Phase 2g (tax import porting) or Phase 3 work
Users and Primary Flows
Developer experience improvement. No end-user flows affected. File uploads, downloads, image handling, email, and portal domain sessions continue to work identically.
Requirements
Functional Requirements
Part A: Phase 2 Remainders
- FR-01: Fix broken import in
server/scripts/portal-domain-sessions-prune.ts-- change'server/src/lib/models/PortalDomainSessionToken'to'@alga-psa/auth' - FR-02: Migrate 2 test files off
server/src/models/document-association.ts:server/src/test/unit/documentActions.upload.test.ts-- update mock to use@alga-psa/documents/models/documentAssociationserver/src/test/integration/documentPermissionsIntegration.test.ts-- update import to use@alga-psa/documents/models/documentAssociation- Add
DocumentAssociationexport topackages/documents/src/models/index.tsbarrel - Delete
server/src/models/document-association.ts
- FR-03: Update
server/src/services/surveyService.tsto import from@alga-psa/emailinstead of../lib/email- Delete
server/src/lib/email/index.tsif no remaining source-code callers - Keep
server/src/lib/email/README.mdif it exists (documentation only)
- Delete
Part B: Create @alga-psa/storage package
-
FR-04: Create
packages/storage/with standard NX package scaffolding:package.jsonwith name@alga-psa/storage, dependencies on@alga-psa/db,@alga-psa/core,@alga-psa/auth,@alga-psa/event-bus,@alga-psa/shared,@alga-psa/validationproject.jsonwithtags: ["scope:storage", "type:horizontal"]tsconfig.jsonextending rootsrc/index.tsbarrel file
-
FR-05: Move these files from
packages/documents/src/topackages/storage/src/:storage/StorageService.ts->src/StorageService.tsstorage/StorageProviderFactory.ts->src/StorageProviderFactory.tsstorage/providers/StorageProvider.ts->src/providers/StorageProvider.tsstorage/providers/LocalStorageProvider.ts->src/providers/LocalStorageProvider.tsconfig/storage.ts->src/config/storage.tstypes/storage.ts->src/types/storage.tsmodels/storage.ts->src/models/storage.ts
-
FR-06: Update all internal imports within moved files to use relative paths within the new package
-
FR-07: Set up
package.jsonexports for the new package:.-> main barrel (StorageService, StorageProviderFactory, generateStoragePath, types)./StorageService->src/StorageService.ts./types/storage->src/types/storage.ts./providers/StorageProvider->src/providers/StorageProvider.ts./config/storage->src/config/storage.ts
Part C: Update consumers
-
FR-08: Update 5 external consumers of
StorageServiceto import from@alga-psa/storage/StorageService:packages/billing/src/actions/invoiceJobActions.tspackages/client-portal/src/actions/client-portal-actions/client-project-details.tspackages/jobs/src/lib/jobService.tspackages/jobs/src/lib/jobs/jobScheduler.tsserver/src/lib/imports/importActions.ts
-
FR-09: Update 3 server consumers of
StorageProviderFactory/generateStoragePathto import from@alga-psa/storage:server/src/services/pdf-generation.service.tsserver/src/app/api/documents/view/[fileId]/route.tsserver/src/lib/storage/StorageService.ts
-
FR-10: Update 1 consumer of
FileStoretype to import from@alga-psa/storage/types/storage:packages/billing/src/services/pdfGenerationService.ts
-
FR-11: Update 5 documents-internal consumers to import from
@alga-psa/storage/StorageService(or relative within-package path):packages/documents/src/handlers/OfficeDocumentHandler.tspackages/documents/src/handlers/GenericFileDocumentHandler.tspackages/documents/src/handlers/ImageDocumentHandler.tspackages/documents/src/handlers/PDFDocumentHandler.tspackages/documents/src/actions/file-actions/fileActions.tspackages/documents/src/actions/documentActions.ts
-
FR-12: Update
packages/documents/src/lib/entityImageService.ts-- it imports StorageService, update path to@alga-psa/storage/StorageService
Part D: Backwards compatibility
- FR-13: Add re-exports to
packages/documents/:- In
src/index.ts: re-exportStorageProviderFactory,generateStoragePathfrom@alga-psa/storage - In
package.jsonexports: keep./storage/StorageServicepointing to@alga-psa/storage/StorageService(or re-export wrapper) - In
package.jsonexports: keep./types/storagepointing to@alga-psa/storage/types/storage(or re-export wrapper)
- In
- FR-14: Add
@alga-psa/storageas dependency inpackages/documents/package.json
Non-functional Requirements
- Build must be green after the full PR
- No runtime behavioral changes to any storage, upload, download, or email functionality
- The
@alga-psa/storagepackage must be taggedtype:horizontalso the ESLint cross-package rule allows any package to import from it
Data / API / Integrations
No database, API, or integration changes. The external_files table continues to be accessed via FileStoreModel -- just from a different package location.
Security / Permissions
No security implications. All code changes are import-path redirections or file moves with identical implementations.
Rollout / Migration
No migration needed. Changes are internal to the build system. Ship as a single branch merged to main.
The re-exports in @alga-psa/documents ensure any consumers we miss (or that are added between now and merge) continue to work.
Open Questions
None -- all details verified via codebase analysis on 2026-02-19.
Acceptance Criteria (Definition of Done)
server/scripts/portal-domain-sessions-prune.tsimports from@alga-psa/authand compilesserver/src/models/document-association.tsis deleted; tests import from@alga-psa/documents/modelsserver/src/lib/email/index.tsis deleted;surveyService.tsimports from@alga-psa/emailpackages/storage/exists with all 7 moved files- All 14 external + internal consumers updated to import from
@alga-psa/storage @alga-psa/documentsre-exports storage symbols for backwards compatibilitynpm run buildpasses- No new lint errors