|
|
@@ -0,0 +1,166 @@
|
|
|
+# Story 007.007: Merchant Module Multi-Tenant Replication
|
|
|
+
|
|
|
+## Status
|
|
|
+
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+
|
|
|
+**As a** system administrator,
|
|
|
+**I want** to replicate the merchant module with multi-tenant support,
|
|
|
+**so that** merchants can be managed in a tenant-isolated environment while maintaining full compatibility with the existing single-tenant system.
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+
|
|
|
+1. **AC 1**: Successfully replicate `@d8d/merchant-module` as `@d8d/merchant-module-mt` with proper package configuration
|
|
|
+2. **AC 2**: Create multi-tenant merchant entity `MerchantMt` with tenant ID field and table name `merchants_mt`
|
|
|
+3. **AC 3**: Update all merchant CRUD operations to automatically include tenant filtering and set tenant ID on creation
|
|
|
+4. **AC 4**: Verify merchant data isolation works correctly across different tenants
|
|
|
+5. **AC 5**: Maintain full compatibility with existing single-tenant merchant module functionality
|
|
|
+6. **AC 6**: All existing single-tenant API interfaces remain unchanged and functional
|
|
|
+7. **AC 7**: Complete integration tests demonstrate tenant isolation and functionality
|
|
|
+8. **AC 8**: Performance impact is less than 5% compared to single-tenant version
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+
|
|
|
+- [ ] Replicate merchant module as multi-tenant version (AC: 1)
|
|
|
+ - [ ] Copy `packages/merchant-module` to `packages/merchant-module-mt`
|
|
|
+ - [ ] Update package configuration to `@d8d/merchant-module-mt`
|
|
|
+ - [ ] **Clean single-tenant files**: Remove all single-tenant related files from multi-tenant package to avoid naming conflicts
|
|
|
+ - [ ] Update dependencies:
|
|
|
+ - [ ] Replace `@d8d/user-module` with `@d8d/user-module-mt`
|
|
|
+ - [ ] Replace `@d8d/auth-module` with `@d8d/auth-module-mt`
|
|
|
+ - [ ] Replace `@d8d/file-module` with `@d8d/file-module-mt`
|
|
|
+
|
|
|
+- [ ] Update multi-tenant merchant entity (AC: 2)
|
|
|
+ - [ ] Create `MerchantMt` entity with table name `merchants_mt`
|
|
|
+ - [ ] Add `tenantId` field with proper TypeORM configuration
|
|
|
+ - [ ] Keep all other fields consistent with single-tenant version
|
|
|
+
|
|
|
+- [ ] Update multi-tenant merchant service (AC: 3, 4)
|
|
|
+ - [ ] Create `MerchantServiceMt` service extending GenericCrudService
|
|
|
+ - [ ] All query operations automatically add tenant filtering
|
|
|
+ - [ ] Create operations automatically set tenant ID
|
|
|
+ - [ ] Update login statistics methods to support tenant isolation
|
|
|
+ - [ ] Update username lookup methods to support tenant filtering
|
|
|
+
|
|
|
+- [ ] Update multi-tenant route configurations (AC: 3)
|
|
|
+ - [ ] Update user routes to use multi-tenant entity and service
|
|
|
+ - [ ] Update admin routes to use multi-tenant entity and service
|
|
|
+ - [ ] Maintain API interfaces consistent with single-tenant version
|
|
|
+ - [ ] Update authentication middleware to support tenant ID extraction
|
|
|
+
|
|
|
+- [ ] Update Schema definitions (AC: 3)
|
|
|
+ - [ ] Create multi-tenant merchant schema `MerchantSchemaMt`
|
|
|
+ - [ ] Create multi-tenant user merchant schema `UserMerchantSchemaMt`
|
|
|
+ - [ ] Create multi-tenant admin merchant schema `AdminMerchantSchemaMt`
|
|
|
+ - [ ] Add tenant ID field definitions
|
|
|
+
|
|
|
+- [ ] Implement tenant data isolation API tests (AC: 7)
|
|
|
+ - [ ] Add tenant isolation test cases in `packages/merchant-module-mt/tests/integration/user-routes.integration.test.ts`
|
|
|
+ - [ ] Add cross-tenant merchant access security validation in `packages/merchant-module-mt/tests/integration/admin-routes.integration.test.ts`
|
|
|
+ - [ ] Create dedicated tenant isolation test file `tenant-isolation.integration.test.ts`
|
|
|
+ - [ ] Verify tenant filtering functionality in existing feature tests
|
|
|
+
|
|
|
+- [ ] Validate single-tenant system integrity (AC: 5, 6)
|
|
|
+ - [ ] Run single-tenant merchant module regression tests
|
|
|
+ - [ ] Verify single-tenant API interfaces unaffected
|
|
|
+ - [ ] Confirm single-tenant database table structure unchanged
|
|
|
+
|
|
|
+- [ ] Execute performance benchmark tests (AC: 8)
|
|
|
+ - [ ] Run multi-tenant merchant module performance tests
|
|
|
+ - [ ] Compare single-tenant vs multi-tenant performance differences
|
|
|
+ - [ ] Ensure performance impact less than 5%
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### Previous Story Insights
|
|
|
+
|
|
|
+**Critical lessons learned from Story 007.006 (Address Module):**
|
|
|
+- **Shared CRUD library execution order**: Must ensure tenant validation occurs BEFORE data permission validation in GenericCrudService.getById method [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
|
|
|
+- **Test data tenant ID management**: Test data factories must explicitly set tenantId field to avoid constraint errors [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
|
|
|
+- **Cross-tenant access status codes**: Should return 404 (Not Found) instead of 403 (Forbidden) for cross-tenant access [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
|
|
|
+- **File naming conventions**: Strictly use `.mt.ts` suffix for multi-tenant files [Source: epic-007-multi-tenant-package-replication.md#最佳实践]
|
|
|
+- **Database synchronization**: Use `fileParallelism: false` in vitest config to avoid database conflicts [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
|
|
|
+
|
|
|
+### Data Models
|
|
|
+
|
|
|
+**Merchant Entity Structure:**
|
|
|
+- Table name: `merchants_mt` (multi-tenant version)
|
|
|
+- Tenant ID field: `tenantId` (required, indexed)
|
|
|
+- Core fields: `name`, `username`, `password`, `phone`, `realname`, `loginNum`, `loginTime`, `loginIp`, `lastLoginTime`, `lastLoginIp`, `state`, `rsaPublicKey`, `aesKey` [Source: source-tree.md#商户管理模块]
|
|
|
+- User tracking fields: `createdBy`, `updatedBy` [Source: source-tree.md#商户管理模块]
|
|
|
+- Timestamp fields: `createdAt`, `updatedAt` [Source: source-tree.md#商户管理模块]
|
|
|
+
|
|
|
+### API Specifications
|
|
|
+
|
|
|
+**User Routes:**
|
|
|
+- Path: `/api/merchants` (user-specific)
|
|
|
+- Authentication: `authMiddleware` from `@d8d/auth-module-mt` [Source: source-tree.md#商户管理模块]
|
|
|
+- Data permission: Enabled with `userIdField: 'createdBy'` [Source: source-tree.md#商户管理模块]
|
|
|
+- Search fields: `['name', 'username', 'realname', 'phone']` [Source: source-tree.md#商户管理模块]
|
|
|
+
|
|
|
+**Admin Routes:**
|
|
|
+- Path: `/api/admin/merchants` (full access)
|
|
|
+- Authentication: `authMiddleware` from `@d8d/auth-module-mt` [Source: source-tree.md#商户管理模块]
|
|
|
+- Data permission: Disabled for admin routes [Source: source-tree.md#商户管理模块]
|
|
|
+
|
|
|
+### Component Specifications
|
|
|
+
|
|
|
+**Merchant Service Methods:**
|
|
|
+- `updateLoginStats(merchantId, loginTime, loginIp)`: Update merchant login statistics [Source: source-tree.md#商户管理模块]
|
|
|
+- `findByUsername(username)`: Find merchant by username with tenant filtering [Source: source-tree.md#商户管理模块]
|
|
|
+- `getByState(state)`: Get merchants by state with tenant filtering [Source: source-tree.md#商户管理模块]
|
|
|
+
|
|
|
+### File Locations
|
|
|
+
|
|
|
+**Source Files to Create:**
|
|
|
+- `packages/merchant-module-mt/src/entities/merchant.mt.entity.ts` (multi-tenant entity)
|
|
|
+- `packages/merchant-module-mt/src/services/merchant.mt.service.ts` (multi-tenant service)
|
|
|
+- `packages/merchant-module-mt/src/routes/user-routes.mt.ts` (multi-tenant user routes)
|
|
|
+- `packages/merchant-module-mt/src/routes/admin-routes.mt.ts` (multi-tenant admin routes)
|
|
|
+- `packages/merchant-module-mt/src/schemas/merchant.mt.schema.ts` (multi-tenant schemas)
|
|
|
+- `packages/merchant-module-mt/tests/integration/tenant-isolation.integration.test.ts` (tenant isolation tests)
|
|
|
+
|
|
|
+**Files to Remove (Single-tenant cleanup):**
|
|
|
+- All files without `.mt.ts` suffix in multi-tenant package
|
|
|
+- Any single-tenant specific configurations
|
|
|
+
|
|
|
+### Technical Constraints
|
|
|
+
|
|
|
+**Database Indexing:**
|
|
|
+- Must create index on `tenantId` field for performance [Source: epic-007-multi-tenant-package-replication.md#数据库迁移策略]
|
|
|
+- Composite indexes for common query patterns (tenantId + state, tenantId + username)
|
|
|
+
|
|
|
+**Authentication Integration:**
|
|
|
+- Use updated `authMiddleware` from `@d8d/auth-module-mt` that extracts tenant ID from user context [Source: epic-007-multi-tenant-package-replication.md#租户上下文管理]
|
|
|
+- Tenant ID should be automatically set from authenticated user context
|
|
|
+
|
|
|
+### Testing
|
|
|
+
|
|
|
+**Testing Standards:**
|
|
|
+- **Test file location**: `packages/merchant-module-mt/tests/integration/` [Source: testing-strategy.md#集成测试]
|
|
|
+- **Test framework**: Vitest + hono/testing + shared-test-util [Source: testing-strategy.md#集成测试]
|
|
|
+- **Test patterns**: Use test data factories with explicit tenantId setting [Source: testing-strategy.md#测试数据管理]
|
|
|
+- **Coverage target**: ≥ 60% integration test coverage [Source: testing-strategy.md#各层覆盖率要求]
|
|
|
+- **Database strategy**: Use test database with transaction rollback [Source: testing-strategy.md#数据库测试策略]
|
|
|
+
|
|
|
+**Specific Testing Requirements:**
|
|
|
+- Tenant isolation validation: Verify merchants from different tenants cannot access each other's data
|
|
|
+- Cross-tenant access: Should return 404 status code for cross-tenant access attempts
|
|
|
+- Login statistics: Verify login stats update correctly within tenant context
|
|
|
+- Username uniqueness: Ensure username uniqueness is enforced per tenant, not globally
|
|
|
+
|
|
|
+## Change Log
|
|
|
+
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|---------|
|
|
|
+| 2025-11-14 | 1.0 | Initial story creation with comprehensive lessons learned from previous stories | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+*This section will be populated by the development agent during implementation*
|
|
|
+
|
|
|
+## QA Results
|
|
|
+
|
|
|
+*This section will be populated by the QA agent during quality assurance review*
|