docs: consolidate audit and analysis reports into docs/audits/

Move 36 root-level audit/analysis documents and 7 web app audit documents
into docs/audits/ directory to declutter the project root. Remove stale
EXPLORATION_SUMMARY.txt.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-11 01:37:50 +07:00
parent 64c6074735
commit b8512ebff4
44 changed files with 21507 additions and 301 deletions

View File

@@ -0,0 +1,301 @@
# Test Coverage Quick Reference Guide
## 17 Untested Source Files Overview
### INQUIRIES MODULE (4 files)
```
1. prisma-inquiry.repository.ts — 6 methods to test + 1 private mapper
2. inquiries.controller.ts — 4 endpoints to test + guard validation
3. create-inquiry.dto.ts — 3 field validations
4. list-inquiries.dto.ts — 2 field validations (pagination)
```
### LEADS MODULE (6 files)
```
5. prisma-lead.repository.ts — 6 methods + stats aggregation
6. lead-score.vo.ts — Value object: range 0-100
7. leads.controller.ts — 5 endpoints + class-level role guard
8. create-lead.dto.ts — 6 field validations
9. list-leads.dto.ts — Status enum + pagination
10. update-lead-status.dto.ts — Status enum validation
```
### REVIEWS MODULE (5 files)
```
11. prisma-review.repository.ts — 7 methods + stats with distribution
12. rating.vo.ts — Value object: range 1-5 (integers only)
13. reviews.controller.ts — 5 endpoints + mixed auth
14. create-review.dto.ts — 4 field validations
15. list-reviews.dto.ts — 2 DTOs: ListReviewsByTargetDto, ReviewStatsDto
```
### REFERENCE PATTERNS (2 test files)
```
16. create-inquiry.handler.spec.ts — Handler test pattern
17. create-lead.handler.spec.ts — Handler test pattern
18. reviews.controller.spec.ts — Controller test pattern
```
---
## Quick Test Scenarios by Type
### REPOSITORIES (3 files)
Test checklist for each repository:
- [ ] findById() returns entity or null
- [ ] save() creates record with correct data mapping
- [ ] Paginated methods respect limit cap (100 max)
- [ ] Pagination calculation: skip = (page - 1) * take
- [ ] Relationships are joined correctly
- [ ] Aggregations calculate correctly (stats methods)
- [ ] Optional fields handling (null coercion)
- [ ] ISO date formatting in DTOs
**Specific to PrismaInquiryRepository:**
- countUnreadByAgent() aggregation
- findByListing() includes property.title
- findByAgent() joins through listing.agentId
**Specific to PrismaLeadRepository:**
- findByAgent() optional status filter
- getStatsByAgent() calculates:
- totalLeads count
- byStatus object (dict of counts)
- conversionRate: (CONVERTED / total) * 100 (2 decimals)
- avgScore: average of non-null scores (1 decimal)
**Specific to PrismaReviewRepository:**
- findByUserAndTarget() unique constraint query
- getStats() builds distribution object (keys 1-5)
- averageRating calculation: (sum / total) * 10 / 10 (1 decimal)
---
### VALUE OBJECTS (2 files)
Test checklist:
- [ ] create() with valid value returns Result.ok()
- [ ] create() with invalid value returns Result.err() with correct message
- [ ] Getter returns props.value
- [ ] Invalid cases covered (negative, > max, non-integer, null)
**LeadScore validation:**
```
✓ Valid: 0, 50, 100
✗ Invalid: -1, 101, 2.5, null, "50"
Error: "Điểm lead phải từ 0 đến 100"
```
**Rating validation:**
```
✓ Valid: 1, 2, 3, 4, 5
✗ Invalid: 0, 6, 2.5, null, "5"
Error: "Đánh giá phải từ 1 đến 5 sao"
```
---
### CONTROLLERS (2 files)
Test checklist:
- [ ] Each endpoint dispatches correct command/query type
- [ ] Parameters are mapped correctly from DTO
- [ ] Optional fields become null (e.g., phone ?? null → null)
- [ ] Default pagination values applied (page: 1, limit: 20)
- [ ] CurrentUser decorator extracts user.sub correctly
- [ ] Guard enforcement (@UseGuards, @Roles)
- [ ] Return types match (e.g., { deleted: true })
**InquiriesController specifics:**
- POST /inquiries: phone optional → null
- GET /inquiries/listing/:listingId: requires JWT
- GET /inquiries/agent/me: requires JWT + AGENT role
- PATCH /inquiries/:id/read: requires JWT + AGENT role
**LeadsController specifics:**
- ALL endpoints require JWT + AGENT role (class-level @Roles)
- POST /leads: score optional, score range validation in command
- GET /leads: status filter optional
- GET /leads/stats: aggregation query
- PATCH /leads/:id/status: only status field in command
- DELETE /leads/:id: agentId verification in command
**ReviewsController specifics:**
- POST /reviews: requires JWT (AuthGuard)
- GET /reviews: NO auth required (stats are public)
- GET /reviews/stats: NO auth required
- GET /reviews/me: requires JWT
- DELETE /reviews/:id: requires JWT + ownership check in command
---
### DTOs (10 files)
Test checklist:
- [ ] Required fields throw ValidationException if missing
- [ ] String max/min length validated
- [ ] Number min/max validated
- [ ] Enum @IsIn() validates allowed values
- [ ] Type transformation (class-transformer @Type)
- [ ] Email format validated (@IsEmail)
- [ ] Optional fields (@IsOptional) don't throw if omitted
**Pagination standard (used in 5 DTOs):**
- page: optional, @Min(1), default 1
- limit: optional, @Min(1), @Max(100), default 20
- Both use @Type(() => Number) for string→number transformation
**Enum validations:**
- LeadStatus: ['NEW', 'CONTACTED', 'QUALIFIED', 'NEGOTIATING', 'CONVERTED', 'LOST']
- Used in: ListLeadsDto, UpdateLeadStatusDto
---
## Test Priority Matrix
### 🔴 CRITICAL (Business Logic)
1. PrismaReviewRepository.getStats() - distribution calculation
2. PrismaLeadRepository.getStatsByAgent() - conversion rate formula
3. Rating.vo - must be 1-5 integers only
4. LeadScore.vo - must be 0-100 range
### 🟡 HIGH (Data Integrity)
1. All repository CRUD methods
2. Pagination calculations
3. Relationship mapping (user joins, listing joins)
4. Controller parameter mapping
### 🟢 MEDIUM (Validation)
1. DTO field validations
2. Enum constraints
3. Optional field handling
4. Guard enforcement
---
## Test Execution Order Recommendation
1. **Value Objects** (2 files) - 2 simple test files
2. **DTOs** (10 files) - Use class-validator testing patterns
3. **Controllers** (2 files) - Command/query dispatch tests
4. **Repositories** (3 files) - Data layer tests with mocked Prisma
---
## Mock Setup Template
### For Repositories:
```typescript
const mockPrisma = {
inquiry: { findUnique: vi.fn(), findMany: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), count: vi.fn() },
};
const repo = new PrismaInquiryRepository(mockPrisma as any);
```
### For Controllers:
```typescript
const mockCommandBus = { execute: vi.fn() };
const mockQueryBus = { execute: vi.fn() };
const controller = new InquiriesController(mockCommandBus as any, mockQueryBus as any);
```
### For Value Objects:
```typescript
const result = LeadScore.create(75);
expect(result.isOk()).toBe(true);
expect(result.unwrap().value).toBe(75);
```
### For DTOs:
```typescript
import { validate } from 'class-validator';
const dto = new CreateLeadDto();
dto.name = 'Nguyễn Văn A';
dto.phone = '0901234567';
// ... set other required fields
const errors = await validate(dto);
expect(errors).toHaveLength(0);
```
---
## Key Formulas to Verify
### Pagination:
```
skip = (page - 1) * take
totalPages = Math.ceil(total / take)
take = Math.min(limit, 100)
```
### Lead Conversion Rate:
```
conversionRate = (convertedCount / totalLeads) * 100
Result: rounded to 2 decimals (e.g., 33.33)
```
### Lead Average Score:
```
avgScore = scoreSum / scoreCount (where score !== null)
Result: rounded to 1 decimal (e.g., 75.5)
```
### Review Average Rating:
```
averageRating = (sum / totalReviews)
Result: rounded to 1 decimal (e.g., 4.5)
```
### Review Distribution:
```
distribution: { 1: count, 2: count, 3: count, 4: count, 5: count }
Must initialize all 5 keys, even if 0
```
---
## File Locations for Reference
```
/Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/api/
Inquiries:
src/modules/inquiries/infrastructure/repositories/prisma-inquiry.repository.ts
src/modules/inquiries/presentation/controllers/inquiries.controller.ts
src/modules/inquiries/presentation/dto/create-inquiry.dto.ts
src/modules/inquiries/presentation/dto/list-inquiries.dto.ts
Leads:
src/modules/leads/infrastructure/repositories/prisma-lead.repository.ts
src/modules/leads/domain/value-objects/lead-score.vo.ts
src/modules/leads/presentation/controllers/leads.controller.ts
src/modules/leads/presentation/dto/create-lead.dto.ts
src/modules/leads/presentation/dto/list-leads.dto.ts
src/modules/leads/presentation/dto/update-lead-status.dto.ts
Reviews:
src/modules/reviews/infrastructure/repositories/prisma-review.repository.ts
src/modules/reviews/domain/value-objects/rating.vo.ts
src/modules/reviews/presentation/controllers/reviews.controller.ts
src/modules/reviews/presentation/dto/create-review.dto.ts
src/modules/reviews/presentation/dto/list-reviews.dto.ts
```
---
## Next Steps
1. **Copy reference test patterns:**
- Create inquiry and lead handlers already have good test patterns
- Controller test for reviews shows endpoint testing approach
2. **Start with repositories:**
- Most complex (Prisma mocking)
- Most critical (data layer)
- Established patterns in existing tests
3. **Test DTOs second:**
- Quick feedback (class-validator validation)
- 10 files but mostly simple
4. **Controllers and VOs last:**
- Build on repository/DTO tests
- Depend on handler tests (if testing full flow)