Expand production monitoring with full alert coverage for database connections, Redis memory/connections, container resources, disk usage, service health, and backup integrity. Add Alertmanager service with Slack routing for critical and warning alerts, and add automated backup verification to the pg-backup cron schedule. Update runbook with DR validation procedures and quarterly checklist. - Expand Prometheus alert rules from 4 to 24 alerts across 7 groups - Add Alertmanager container (prom/alertmanager:v0.27.0) with Slack routing - Configure inhibition rules (critical suppresses warning for same service) - Schedule automated backup verification at 04:00 UTC daily - Add Alertmanager datasource to Grafana provisioning - Update runbook with Section 9: DR Validation (automated + manual procedures) - Add SLACK_WEBHOOK_URL and Grafana vars to .env.example Co-Authored-By: Paperclip <noreply@paperclip.ing>
12 KiB
GoodGo Platform - Codebase Exploration Summary
📋 Overview
This exploration provides a comprehensive analysis of the GoodGo Platform codebase to establish architectural patterns and best practices for building new Inquiry & Lead Management UI pages.
Two detailed documents have been created:
codebase_exploration.md- Full technical deep-dive with code samplesCODEBASE_QUICK_REFERENCE.md- Quick reference templates and checklists
🎯 Key Findings
Architecture Overview
- Frontend: Next.js 15+ with App Router, TypeScript, Tailwind CSS
- Backend: NestJS with CQRS pattern, modular architecture
- Communication: REST API with JWT + CSRF protection
- State Management: Zustand + React Query
- UI Components: Radix UI-inspired compound components with Tailwind styling
- i18n: next-intl with Vietnamese (vi) and English (en)
- Database: Prisma ORM
Authentication Flow
- Cookies: httpOnly JWT cookies (user management via
useAuthStore) - CSRF: Token-based via
XSRF-TOKENcookie - Authorization: Role-based access (AGENT, ADMIN, USER roles)
- Protected Routes:
/dashboardroutes protected by JwtAuthGuard
📁 Directory Structure (Key Paths)
apps/web/
├── app/[locale]/
│ └── (dashboard)/ ← Place new pages here
│ ├── inquiries/ ← New: /inquiries, /inquiries/[id]
│ └── leads/ ← New: /leads, /leads/[id]
├── components/
│ ├── ui/ ← Reusable base components
│ ├── inquiries/ ← New: domain components
│ └── leads/ ← New: domain components
├── lib/
│ ├── api-client.ts ← Base fetch wrapper
│ ├── inquiries-api.ts ← New: API service
│ ├── leads-api.ts ← New: API service
│ ├── hooks/
│ │ ├── use-inquiries.ts ← New: React Query hooks
│ │ └── use-leads.ts ← New: React Query hooks
│ └── validations/ ← Zod schemas
└── messages/
├── vi.json ← Add inquiries/leads translations
└── en.json ← Add inquiries/leads translations
apps/api/src/modules/
├── inquiries/
│ ├── presentation/controllers/inquiries.controller.ts ✅ EXISTS
│ ├── presentation/dto/ ✅ EXISTS
│ └── domain/repositories/ ✅ EXISTS
└── leads/
├── presentation/controllers/leads.controller.ts ✅ EXISTS
├── presentation/dto/ ✅ EXISTS
└── domain/repositories/ ✅ EXISTS
🔌 Backend API Endpoints (Ready to Use)
Inquiries Module
POST /api/v1/inquiries
GET /api/v1/inquiries/listing/{listingId}
GET /api/v1/inquiries/agent/me
PATCH /api/v1/inquiries/{id}/read
Response Types:
InquiryReadDto- Single inquiry dataPaginatedResult<InquiryReadDto>- List with pagination
Leads Module
POST /api/v1/leads
GET /api/v1/leads
GET /api/v1/leads/stats
PATCH /api/v1/leads/{id}/status
DELETE /api/v1/leads/{id}
Response Types:
LeadReadDto- Single lead dataPaginatedResult<LeadReadDto>- List with paginationLeadStatsData- Statistics
🏗️ Patterns to Follow
1. Page Structure (Follow listings page pattern)
'use client';
// Components + Hooks + Store
import { useTranslations } from 'next-intl';
import { useQuery } from '@tanstack/react-query';
import { useState } from 'react';
// Layout: Header > Stats > Filters > Content
// Features: Stats cards, filter dropdowns, table/grid view, pagination
2. API Service (Use apiClient)
// apps/web/lib/inquiries-api.ts
import { apiClient } from './api-client';
export const inquiriesApi = {
list: (params) => apiClient.get('/inquiries', params),
getById: (id) => apiClient.get(`/inquiries/${id}`),
markAsRead: (id) => apiClient.patch(`/inquiries/${id}/read`, {}),
};
3. React Query Hooks (Use key factory)
// apps/web/lib/hooks/use-inquiries.ts
export const inquiriesKeys = {
all: ['inquiries'] as const,
list: (params) => ['inquiries', 'list', params] as const,
};
export function useInquiries(params = {}) {
return useQuery({
queryKey: inquiriesKeys.list(params),
queryFn: () => inquiriesApi.list(params),
});
}
4. Status Badge Component
// apps/web/components/inquiries/inquiry-status-badge.tsx
// Map status enum to badge variant (success, warning, info, etc.)
5. Translations (Hierarchical JSON)
{
"inquiries": {
"title": "Quản lý Liên hệ",
"status": { "new": "Mới", "read": "Đã xem" }
}
}
🎨 Component Library
Base UI Components (Ready to Use)
Button- Variants: default, outline, ghost, destructiveCard- Compound: CardHeader, CardTitle, CardDescription, CardContentBadge- Variants: default, secondary, destructive, outline, success, warning, infoTable- Compound: TableHeader, TableBody, TableRow, TableHead, TableCellSelect- Native HTML with Tailwind stylingInput- Text input with consistent stylingTextarea- Text area with consistent stylingDialog- Modal dialog componentTabs- Tab navigation componentLabel- Form label component
Styling Conventions
// Grid layout (responsive)
className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"
// Flex layout
className="flex items-center justify-between gap-3"
// Typography
className="text-2xl font-bold" // Heading
className="text-sm text-muted-foreground" // Secondary text
// Status indicators
className="text-green-600 bg-green-50" // Success
className="text-yellow-600 bg-yellow-50" // Warning
className="text-blue-600 bg-blue-50" // Info
Theme Colors (CSS Variables)
- Primary: Green (#36A653)
- Secondary: Light gray-blue
- Accent: Light gray-blue
- Muted: Gray
- Destructive: Red
- Dark mode: Automatically inverted
🔄 Data Flow Example
User clicks filter
↓
setFilters(newFilters)
↓
queryKey changes
↓
React Query automatically fetches
↓
useQuery({ queryKey, queryFn: () => inquiriesApi.list(filters) })
↓
API call to /api/v1/inquiries?status=new&page=1
↓
useAuthStore provides JWT cookie + CSRF token
↓
Response: { items: [], total: 10, page: 1, limit: 20 }
↓
Component re-renders with new data
✅ Implementation Checklist
Phase 1: Setup
- Create
inquiries-api.tsinapps/web/lib/ - Create
leads-api.tsinapps/web/lib/ - Define DTOs matching backend responses
- Test API endpoints with Postman/cURL
Phase 2: Hooks & Queries
- Create
use-inquiries.tshook with React Query - Create
use-leads.tshook with React Query - Test data fetching with loading/error states
Phase 3: Components
- Create
inquiry-status-badge.tsxcomponent - Create
lead-status-badge.tsxcomponent - Create filter bar / filter component
- Test components in isolation
Phase 4: Pages
- Create
/inquiries/page.tsx(list view) - Create
/inquiries/[id]/page.tsx(detail view - if needed) - Create
/leads/page.tsx(list view) - Create
/leads/[id]/page.tsx(detail view - if needed)
Phase 5: i18n & Polish
- Add translations to
messages/vi.json - Add translations to
messages/en.json - Test all languages
- Test dark mode
- Test responsive design (mobile/tablet/desktop)
- Add loading skeletons
- Add error boundaries
- Add empty state messages
Phase 6: Testing & QA
- Unit tests for components
- Integration tests for API calls
- E2E tests for user flows
- Performance testing (React Query caching)
- Accessibility testing (ARIA labels, keyboard nav)
📚 Reference Files
Essential Reading
-
Dashboard Layout -
apps/web/app/[locale]/(dashboard)/layout.tsx- Responsive navigation patterns
- User info display
- Theme toggle
-
Listings Page -
apps/web/app/[locale]/(dashboard)/listings/page.tsx- Complete list view example
- Filter state management
- Grid/table view toggle
- Stats cards
- Pagination pattern
-
Dashboard Page -
apps/web/app/[locale]/(dashboard)/dashboard/page.tsx- Stats card component
- Chart integration
- Market data fetching
-
API Client -
apps/web/lib/api-client.ts- Request wrapper
- CSRF token handling
- Error handling
-
Listings API -
apps/web/lib/listings-api.ts- API service pattern
- Type definitions
- Search params handling
-
Use Listings Hook -
apps/web/lib/hooks/use-listings.ts- React Query pattern
- Key factory pattern
-
Auth Store -
apps/web/lib/auth-store.ts- Zustand pattern
- Async actions
- Error handling
-
Comparison Store -
apps/web/lib/comparison-store.ts- Zustand with persistence
- Complex state management
Backend API Examples
apps/api/src/modules/inquiries/presentation/controllers/inquiries.controller.tsapps/api/src/modules/leads/presentation/controllers/leads.controller.tsapps/api/src/modules/listings/presentation/controllers/listings.controller.ts
🛠️ Development Tips
Local Testing
# Start frontend dev server
cd apps/web && npm run dev
# Start backend dev server (in another terminal)
cd apps/api && npm run dev
# API will be at http://localhost:3001/api/v1
# Frontend will be at http://localhost:3000
API Testing
# Test inquiry list endpoint
curl -H "Authorization: Bearer {token}" \
http://localhost:3001/api/v1/inquiries/agent/me
# Test lead creation
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {token}" \
-d '{
"name": "John Doe",
"phone": "0912345678",
"source": "website",
"score": 80
}' \
http://localhost:3001/api/v1/leads
React Query Debugging
// Add this to see React Query state
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
// In provider:
<ReactQueryDevtools initialIsOpen={false} />
i18n Testing
- Switch language in UI
- Verify all strings translate
- Test RTL (if adding Arabic)
🚨 Common Pitfalls to Avoid
- Forgetting
'use client'- Required for hooks (useQuery, useTranslations) - Not using query key factory - Makes cache invalidation hard
- Hardcoding API URLs - Use environment variables (
NEXT_PUBLIC_API_URL) - Missing error states - Always handle loading/error/empty states
- Not testing pagination - Verify page params work correctly
- Forgetting translations - Add to both vi.json and en.json
- Not handling 401/403 errors - Redirect to login on auth errors
- Ignoring mobile responsive - Test on all breakpoints (sm, md, lg)
- Not using semantic HTML - Use proper heading hierarchy, ARIA labels
- Direct DOM manipulation - Use React state/hooks instead of getElementById
📞 Contact & Questions
For implementation questions:
- Check
codebase_exploration.mdfor detailed explanations - Check
CODEBASE_QUICK_REFERENCE.mdfor code templates - Reference existing pages (listings, dashboard)
- Inspect backend DTOs for API response shapes
📄 Document Files
-
codebase_exploration.md(29.8 KB)- Complete technical deep-dive
- 10 major sections covering all aspects
- Code snippets and examples
- Architecture diagrams in text form
-
CODEBASE_QUICK_REFERENCE.md(12 KB)- Quick reference guide
- Template code snippets
- Checklists
- Key file references
- Development tips
-
EXPLORATION_SUMMARY.md(This file)- High-level overview
- Key findings summary
- Directory structure
- Implementation checklist
Total Exploration: 10 sections, 50+ code examples, 100+ file references
Ready to start building! 🚀