Summary
IUnitOfWork currently exposes every repository in the platform—23 repository properties plus transaction()—and most use cases receive that entire interface regardless of how many repositories they actually need.
packages/domain/src/repositories/unit-of-work.interface.ts includes projects, environments, resources, deployments, servers, backups, notifications, monitoring, templates, tags, SSH keys, Git providers, S3, web-server settings, and more in one contract.
The testing consequence is visible in packages/usecases/src/testing/mock-unit-of-work.ts: every test fixture constructs empty {} placeholders for all unused repositories and then casts the result to IUnitOfWork. This removes compile-time guarantees precisely where tests should catch wiring mistakes.
Reviewed against master at 7f9e26400a474aa5a706d261f24fa2bf3d98ce8c.
Architectural impact
- A feature depends structurally on every repository even when it reads only one aggregate.
- Adding a repository expands a central interface and shared fixture across the entire application.
- Tests can accidentally invoke a missing method on an
{} placeholder at runtime.
- Constructor signatures do not reveal a use case's true persistence needs.
- Transaction boundaries are vague because the same service bag is also used for non-transactional reads and long-running infrastructure operations.
- Feature extraction or modular deployment is difficult because persistence contracts are centralized by technical type rather than business capability.
Proposed direction
- Inject the smallest repository/query ports needed by each use case.
- Introduce feature-scoped repository bundles only where a workflow consistently coordinates the same aggregates, for example:
ProjectWorkspaceStore for project/environment/resource traversal;
BackupStore for schedules/runs/destinations;
NotificationStore for channels/deliveries.
- Replace
transaction(work: (uow) => ...) with an application-owned transaction runner that passes a typed feature transaction context or executes a callback whose dependencies are already scoped.
- Separate read-model query ports from mutation repositories where this reduces multi-repository traversal.
- Keep Drizzle's transaction executor and repository construction inside
@upstand/repositories.
- Migrate use cases incrementally, starting with simple one-repository CRUD operations.
- Delete the unsafe global
mockUnitOfWork; provide typed repository fakes/builders per feature.
- Add a lint/architecture rule discouraging new constructors from accepting the full unit of work without a documented multi-aggregate transaction need.
Acceptance criteria
Suggested migration order
- Read-only and single-repository use cases.
- Simple CRUD mutations.
- Project/environment/resource aggregate traversal.
- Notification and backup workflows.
- Deployment orchestration and other long-running workflows.
- Remove
IUnitOfWork after the remaining explicit transaction contexts are implemented.
Summary
IUnitOfWorkcurrently exposes every repository in the platform—23 repository properties plustransaction()—and most use cases receive that entire interface regardless of how many repositories they actually need.packages/domain/src/repositories/unit-of-work.interface.tsincludes projects, environments, resources, deployments, servers, backups, notifications, monitoring, templates, tags, SSH keys, Git providers, S3, web-server settings, and more in one contract.The testing consequence is visible in
packages/usecases/src/testing/mock-unit-of-work.ts: every test fixture constructs empty{}placeholders for all unused repositories and then casts the result toIUnitOfWork. This removes compile-time guarantees precisely where tests should catch wiring mistakes.Reviewed against
masterat7f9e26400a474aa5a706d261f24fa2bf3d98ce8c.Architectural impact
{}placeholder at runtime.Proposed direction
ProjectWorkspaceStorefor project/environment/resource traversal;BackupStorefor schedules/runs/destinations;NotificationStorefor channels/deliveries.transaction(work: (uow) => ...)with an application-owned transaction runner that passes a typed feature transaction context or executes a callback whose dependencies are already scoped.@upstand/repositories.mockUnitOfWork; provide typed repository fakes/builders per feature.Acceptance criteria
{}casts.Suggested migration order
IUnitOfWorkafter the remaining explicit transaction contexts are implemented.