Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
15 KiB
NX Monorepo Modularization - Scratchpad
⚠️ CRITICAL INSTRUCTION FOR CLAUDE ⚠️
DO NOT CHEAT. When implementing features:
- Work in large chunks before lint/build. Prefer moving a whole coherent slice (e.g. an entire folder or feature) and fixing imports broadly. Only run lint/tests/build at the end of a large unit of work (or when truly blocked). Constant lint/build cycles are too expensive and slow the migration dramatically.
- Actually move/copy the files - don't just create re-exports from the old location
- Update imports in the moved files - fix relative imports to work in new location
- Update consumers - change imports in files that use the moved code
- If you defer work, add a NEW feature entry to features.json for that deferred work
- Only mark "implemented": true when the actual migration is complete, not just scaffolding
If you have the choice between an easy path (re-exports) and the right path (actual migration), ALWAYS choose the right path. If you need to defer harder work to later iterations, add explicit new features to track that work - don't just drop it or pretend it's done.
Temporary Shim Exception (Migration Only)
If a “shim” is required to keep work moving (e.g. to avoid editing dozens of call sites immediately), it must be:
- treated as temporary and minimal (no long-lived architecture)
- tracked explicitly in
features.json(with a removal task) - removed once the owning package/horizontal slice has the real implementation
Analysis Summary (2026-01-15)
Current Codebase Metrics
- Total TypeScript/TSX files: ~2,300+
- Components: 777 files across 42 domain directories
- Lib (actions, models, services, utils): 685 files
- API Routes: 510 files
- Interfaces: 52 files
Existing Modular Patterns
The codebase already uses npm workspaces with this structure:
"workspaces": [
"server",
"ee/server",
"services/workflow-worker",
"services/email-service",
"shared",
"packages/*",
"sdk/*"
]
Existing Packages (15 total)
Located in /packages/:
product-auth-ee- Enterprise authproduct-billing- Billing featuresproduct-chat- Chat functionalityproduct-client-portal-domain- Client portal domain logicproduct-email-domains- Email domain management (consolidated into@alga-psa/integrations/email)product-email-providers- Email provider integrations (consolidated into@alga-psa/integrations/email)product-email-settings- Email configuration (consolidated into@alga-psa/integrations/email)product-ext-proxy- Extension proxyproduct-extension-actions- Extension server actionsproduct-extension-initialization- Extension initproduct-extensions-pages- Extension pagesproduct-extensions- Core extensionsproduct-settings-extensions- Settings extensionsproduct-workflows- Workflow engineui-kit- UI component library
Shared Library Structure
@alga-psa/shared exports:
./types- Type definitions./core- Logger, secret provider./db- Database utilities, admin, connection./events/publisher.js- Event publishing./utils/encryption.js- Encryption utilities./workflow- Workflow core, persistence, streams./models/*- Shared models (client, contact, tag, ticket, user)./extensions/*- Extension domain, installs, types
Identified Feature Domains
Large Domains (>30 component files)
| Domain | Files | Notes |
|---|---|---|
| billing-dashboard | 120 | Invoices, contracts, payments, credits |
| settings | 86 | System configuration |
| ui | 81 | Shared UI components |
| projects | 50 | Project management, kanban, tasks |
| client-portal | 42 | Client-facing portal |
| assets | 37 | Asset management |
| time-management | 32 | Time tracking, timesheets |
| clients | 32 | Client profiles |
Medium Domains (10-30 files)
- surveys (25), workflows (24), user-activities (21)
- tickets (19), documents (18), contacts (12)
- technician-dispatch (13), auth (12), layout (11)
- integrations (11)
Proposed Module Architecture
Horizontal Slices (Shared Infrastructure)
-
@alga-psa/core - Existing shared package, enhance with:
- Logger, config, secrets
- Event publisher
- Encryption utilities
-
@alga-psa/db - Database layer
- Knex configuration
- Tenant context management
- Connection pooling
- Base model patterns
-
@alga-psa/types - Type definitions
- All interface files
- Shared types across features
-
@alga-psa/validation - Validation logic
- Zod schemas
- Form validation utilities
- Business rule validators
-
@alga-psa/ui - UI component library
- Enhance existing ui-kit
- All shared UI components
-
@alga-psa/auth - Authentication
- Auth strategies
- Session management
- Permission utilities
Vertical Slices (Feature Modules)
-
@alga-psa/billing - Billing & Contracts
- Invoicing
- Contracts/contract lines
- Payments
- Credits
- Tax management
-
@alga-psa/clients - Client Management
- Client profiles
- Contacts
- Companies
- Client relationships
-
@alga-psa/projects - Project Management
- Projects
- Tasks/phases
- Kanban boards
- Dependencies
- Resource allocation
-
@alga-psa/tickets - Ticket/Issue Tracking
- Support tickets
- Categories
- SLA management
-
@alga-psa/scheduling - Scheduling & Time
- Time tracking
- Timesheets
- Calendar
- Technician dispatch
- Schedule entries
-
@alga-psa/workflows - Workflow Automation
- Workflow engine
- Triggers
- Actions
- Automation rules
-
@alga-psa/documents - Document Management
- Document storage
- Templates
- Sharing
-
@alga-psa/assets - Asset Management
- Asset tracking
- Categorization
- Service history
-
@alga-psa/surveys - Surveys
- Survey creation
- Responses
- Analytics
-
@alga-psa/integrations - Third-party Integrations
- QuickBooks
- Email providers
- Calendar providers
- Webhooks
-
@alga-psa/client-portal - Client Portal
- Portal UI
- Portal-specific features
- External access
Key Decisions
Decision 1: NX vs Enhanced npm Workspaces
Decision: Use NX Rationale:
- Existing npm workspaces show modular thinking is established
Note: Vitest + Workspace Resolution (2026-01-15)
Some dev/test setups may not have newly-added @alga-psa/* workspace packages linked into node_modules. For Vitest runs from the repo root, add explicit Vite/Vitest aliases (in server/vitest.config.ts) pointing @alga-psa/* imports to packages/*/src to keep unit tests runnable without reinstalling dependencies.
Note: Root tsconfig.json (2026-01-15)
Several packages/*/tsconfig.json files extend ../../tsconfig.json. Ensure tsconfig.json exists at the repo root and extends tsconfig.base.json so those package configs work and editors/tools pick up the shared path aliases.
Note: DB tenant context (2026-01-15)
The @alga-psa/db package now owns tenant context via AsyncLocalStorage (runWithTenant, getTenantContext) and exports createTenantKnex(). The server-side server/src/lib/db/index.tsx continues to handle request/session/header tenant resolution but delegates context storage to @alga-psa/db.
Note: Vitest coverage temp dir (2026-01-15)
Vitest v8 coverage writes a temp directory under server/coverage/.tmp. Ensure it exists during test runs (created in server/src/test/setup.ts) to avoid occasional ENOENT errors when running multiple targeted tests.
Note: Nx project.json coverage (2026-01-15)
Many packages/* were created without project.json, which prevented them from being first-class Nx projects. Added project.json files for all new @alga-psa/* packages (and packages/ui-kit) so nx graph, caching, and affected commands can reason about them.
- NX adds: computation caching, affected commands, dependency graph visualization
- Better for large codebase with 2300+ files
- Enables parallel builds and test optimization
Note: UI package split (2026-01-16)
The existing packages/ui-kit is used by SDK/extension template consumers and should remain Tailwind-free to avoid breaking external usage. The app/server UI components from server/src/components/ui (Tailwind + Radix heavy) were migrated into a new internal package packages/ui (@alga-psa/ui), and server consumers were updated to import from @alga-psa/ui.
Decision 2: Module Boundaries
Decision: Feature-based vertical slices over layer-based Rationale:
- Aligns with existing component organization
- Enables independent deployment/testing
- Clear ownership boundaries
- Reduces cross-team conflicts
Decision 3: Next.js Routes Location
Decision: Keep all routes in single server/ project
Rationale:
- Next.js requirement - App Router needs single entry
- Routes become thin shims calling into feature modules
- API routes can delegate to feature modules
Decision 4: Migration Strategy
Decision: Incremental, bottom-up Rationale:
- Start with horizontal slices (already partially exist in
shared/) - Add vertical slices one feature at a time
- Maintain backwards compatibility during migration
- Can deploy incrementally
Technical Constraints
- Next.js App Router: All routes must remain in single project
- CitusDB: Tenant column requirements affect data layer design
- Enterprise Edition: CE/EE code separation must be maintained
- Existing Workspaces: Must migrate, not break existing package structure
Commands & References
Useful Commands
# Current workspace structure
npm ls --workspaces
# Check package dependencies
npm -w server ls
# Run tests for specific workspace
npm -w server test
Key File Paths
- Root package.json:
/package.json - Server package.json:
/server/package.json - Shared exports:
/shared/package.json - Coding standards:
/docs/AI_coding_standards.md
Open Questions
-
Billing + Contracts: Should these be one module or separate?
- Current thinking: Combined as
@alga-psa/billing(they're tightly coupled)
- Current thinking: Combined as
-
Email modules: Consolidated into
@alga-psa/integrations/email(formerlyproduct-email-domains,product-email-providers,product-email-settings). -
Extension packages: 7 extension-related packages - keep as-is or consolidate?
-
UI components: Current ui-kit is minimal - expand or keep ui in each feature?
- Recommendation: Expand ui-kit as
@alga-psa/uifor all shared components
- Recommendation: Expand ui-kit as
Migration Order (Proposed)
Phase 1: Foundation
- Initialize NX workspace
- Migrate
shared/to@alga-psa/core,@alga-psa/db,@alga-psa/types - Create
@alga-psa/validationfrom existing validation utilities - Expand
ui-kitto@alga-psa/ui
Phase 2: Infrastructure Features
- Create
@alga-psa/authfrom auth actions/lib - Create
@alga-psa/integrations(consolidate email packages + integrations)
Phase 3: Core Business Features
- Create
@alga-psa/clients(clients + contacts) - Create
@alga-psa/billing(invoicing + contracts) - Create
@alga-psa/projects - Create
@alga-psa/tickets
Phase 4: Supporting Features
- Create
@alga-psa/scheduling(time + dispatch + calendar) - Create
@alga-psa/workflows - Create
@alga-psa/documents - Create
@alga-psa/assets - Create
@alga-psa/surveys - Create
@alga-psa/client-portal
Phase 5: Optimization
- Configure NX caching
- Set up affected commands for CI
- Optimize build pipeline
Implementation Notes (2026-01-16)
- @alga-psa/types interface migration: synced
server/src/interfacesintopackages/types/src/interfaces, removed duplicate/stub interface files that caused resolution ambiguity, fixed self-imports inside the types package, and added tests to validate the barrel exports. Inbound email types are exported underInbound*aliases to avoid name collisions with outbound email types. - NX graph/tests:
NX_DAEMON=falseavoids the earlier nx command hangs; added an integration test attools/nx-tests/nxWorkspace.test.tsto validatenx show projects,nx graph --file, and generator dry-run. - Module boundaries: added ESLint rule
custom-rules/no-feature-to-feature-importsto preventpackages/<feature>vertical packages from importing other vertical packages via@alga-psa/*(validated intools/nx-tests/moduleBoundaries.test.ts).nx lintis currently too memory-hungry (heap OOM) to use as an enforcement test in this environment. - npm workspace protocol: removed
workspace:*dependency specifiers frompackages/*/package.json(replaced with*) because npm cannot install/update dependencies whenworkspace:protocol is used. - NX caching + affected: added
npm run test:nx(vitest config fortools/nx-tests) including a cache verification test (nxCache.test.ts) and an affected-project selection test (nxAffected.test.ts); addednpm run affected:testandnpm run affected:buildscripts; updated.github/workflows/typecheck.ymlto runnx affected -t build/test. - @alga-psa/clients vertical slice: migrated client/contacts actions + components into
packages/clientsand updated the/msp/clients+/msp/contactsroutes to import from@alga-psa/clients(and actions from@alga-psa/clients/actions);server npm run buildpasses after import rewiring. - Tax + client type alignment: resolved an
ITaxRateexport collision by selectively exporting tax interfaces from@alga-psa/types(includingITaxRateDetailsalias). Also aligned client/contacts typing by using@alga-psa/typesin key action/components and allowingclient.propertiesto be nullable where DB can return null.
Implementation Notes (2026-01-18)
server/src import cleanup (packages)
- Verified no remaining
from 'server/src'orimport('server/src/...')usages underpackages/**.
Documents storage self-containment
- Added missing documents storage primitives under
packages/documents/src/:config/storage.ts(env/secret-driven storage config + validation)types/storage.ts(provider + file store types)models/storage.ts(FileStoreModelwithoutBaseModel; tenant resolved viarequireTenantId)
- Rewired documents storage imports to stay within
packages/documents/src/**(avoids importing files outside the packagesrc/root). - Removed
@alga-psa/users/actionsdependency from documents storage to avoid pulling incomplete user avatar utilities into core storage logic.
Business-logic tests added
- Scheduling:
packages/scheduling/tests/timePeriodSuggester.test.ts(runnpm -w packages/scheduling test) - Documents:
packages/documents/tests/storageConfig.test.ts(runnpm -w packages/documents test) - Auth: adjusted
packages/auth/src/lib/exports.test.tsto validate RBAC behavior via the subpath export@alga-psa/auth/rbac(keeps the test focused and avoids pulling Next.js UI modules).
Known tooling limitation (out of scope here)
tsc --noEmitin many packages currently fails withrootDir/project-reference issues when TypeScript path aliases pull in other package sources (example: importing@alga-psa/tenancy/actionsfrom another package). Unit tests via Vitest are still runnable and used for verification.