update DOC

This commit is contained in:
2026-05-12 07:18:09 +00:00
parent efa97b6c71
commit f2bc048219
14 changed files with 549 additions and 219 deletions

205
AGENTS.md
View File

@@ -3,19 +3,25 @@
> **Trước khi làm việc, đọc các file quan trọng:**
> - `CODEBASE_SNAPSHOT.md` — Toàn bộ cấu trúc codebase (thay vì scan lại code)
> - `TASKS_ROADMAP.md` — Roadmap: đã làm, đang làm, sẽ làm
> - `PROGRESS.md` — Lịch sử tiến độ hoàn thành
> - `docs/I18N_GUIDE.md` — Hướng dẫn đa ngôn ngữ
> - `docs/ENUM_GUIDE.md` — Hướng dẫn thêm Enum mới
> - `luutru/` — Archive các file đã lỗi thời (tham khảo nếu cần)
>
> **File đã lỗi thời trong luutru/:** PROGRESS.md, SOP_des.md, AI_01/02/03, CHANGELOG.md, README.md gốc, SYSTEM_ASSESSMENT_PROPOSALS.md
## Overview
AfterSales CRM is a real-estate after-sales customer care system built with **Laravel 13.6** + **Filament 5.6**.
Hệ thống có **2 Filament Panel**:
- `/admin` — Admin Panel: đầy đủ tất cả modules (Contract, Handover, Service, User/Role...)
- `/support` — Support Panel: rút gọn, tập trung Feedback (Feedback, Customer, Product, Channel, Tag, ActivityLog)
## How to Run
```bash
cd /home/phuongtc/vibecode/minicrm
php artisan migrate:fresh --seed
php artisan serve
# Open http://localhost:8000/admin
# Admin panel: http://localhost:8000/admin
# Support panel: http://localhost:8000/support
```
### Test Accounts (seeded)
@@ -51,8 +57,30 @@ php artisan test # run pest tests
php artisan app:export-backup
php artisan app:export-backup --path=/custom/path --pretty
php artisan app:export-backup --tables=feedback,customers,products
# Import data from Excel
php artisan app:import-cskh ai_instructions/CSKH.xlsx --dry-run
php artisan app:import-cskh ai_instructions/CSKH.xlsx
```
## Dual Panel Architecture
Hệ thống có 2 Filament Panel độc lập:
### Admin Panel (`/admin`) — `AdminPanelProvider.php`
Đầy đủ tất cả modules, bao gồm:
- Feedback, Customer, Product, Contract, FeedbackChannel, FeedbackTag
- User, Role (admin-only)
- 3 Dashboard widgets: ResolvedTicketsWidget, AvgProcessingTimeWidget, HandlerPerformanceWidget
### Support Panel (`/support`) — `SupportPanelProvider.php`
Rút gọn, chỉ tập trung vào quy trình xử lý feedback:
- Feedback, Customer, Product, FeedbackChannel, FeedbackTag, ActivityLog
- 3 Dashboard widgets giống Admin panel
- Không có: Contracts, Users, Roles, Handovers, ProductServices
Cả 2 panel dùng chung: Models, Services, Policies, Database, Translations.
## Directory Structure
```
@@ -60,6 +88,9 @@ minicrm/
├── app/
│ ├── Filament/
│ │ ├── Resources/
│ │ │ ├── ActivityLogs/ # NEW: Audit trail (read-only)
│ │ │ │ ├── ActivityLogResource.php
│ │ │ │ └── Pages/ListActivityLogs.php
│ │ │ ├── Feedback/
│ │ │ │ ├── FeedbackResource.php
│ │ │ │ ├── Schemas/FeedbackForm.php
@@ -67,79 +98,101 @@ minicrm/
│ │ │ │ ├── Pages/{Create,Edit,List}Feedback.php
│ │ │ │ └── RelationManagers/InteractionsRelationManager.php
│ │ │ ├── Products/
│ │ │ │ └── RelationManagers/{Contracts,Handovers,ProductServices}RelationManager.php
│ │ │ ├── Customers/
│ │ │ │ └── RelationManagers/FeedbacksRelationManager.php
│ │ │ ├── Contracts/
│ │ │ ├── FeedbackChannels/
│ │ │ ├── FeedbackTags/
│ │ │ ├── Contracts/
│ │ │ ├── Users/
│ │ │ └── Roles/
│ │ └── Widgets/
│ │ ├── ResolvedTicketsWidget.php # Dashboard: resolved tickets table
│ │ ├── AvgProcessingTimeWidget.php # Dashboard: stats overview
│ │ └── HandlerPerformanceWidget.php # Dashboard: bar chart per handler
│ ├── Console/Commands/
│ │ ├── ImportCskh.php # app:import-cskh
│ │ └── ExportBackup.php # app:export-backup
│ ├── Enums/
│ │ ├── ContractType.php
│ │ ├── ContractStatus.php
│ │ ├── HandoverStatus.php
│ │ └── ServiceType.php
│ ├── Http/
│ │ ├── Controllers/Controller.php
│ │ └── Middleware/HandleUploadErrors.php
│ ├── Models/
│ │ ├── User.php # HasRoles (Spatie), isAdmin(), isManager()
│ │ ├── Department.php # NEW: name, manager_id → User
│ │ ├── Product.php
│ │ ├── ActivityLog.php # NEW: Audit trail model
│ │ ├── Contract.php
│ │ ├── Customer.php
│ │ ├── CustomerProduct.php
│ │ ├── Feedback.php # added: current_department_id, is_escalated, transferLogs
│ │ ├── Department.php
│ │ ├── Feedback.php
│ │ ├── FeedbackAttachment.php
│ │ ├── FeedbackChannel.php
│ │ ├── FeedbackTag.php
│ │ ├── FeedbackInteraction.php
│ │ ├── FeedbackAttachment.php # added: uuid, disk, collection
│ │ ── TicketTransferLog.php # NEW: department-to-department transfer history
│ │ ├── FeedbackTag.php
│ │ ── Handover.php
│ │ ├── Product.php
│ │ ├── ProductService.php
│ │ ├── TicketTransferLog.php
│ │ └── User.php # HasRoles (Spatie), isAdmin(), isManager()
│ ├── Policies/
│ │ ├── FeedbackPolicy.php # Spatie hasRole() checks
│ │ ├── ProductPolicy.php
│ │ ├── ActivityLogPolicy.php # NEW
│ │ ├── ContractPolicy.php
│ │ ├── CustomerPolicy.php
│ │ ── FeedbackChannelPolicy.php
│ ├── Services/
│ │ ├── FileService.php # Upload, validation, temp URLs, collections
│ │ ├── TransferService.php # Cross-dept transfer + notification
│ │ └── ClosingService.php # Role-gated closing + evidence check
│ ├── Rules/
│ │ └── RequireProofOfResolution.php # Custom validation: proof_of_resolution required for close
│ │ ── FeedbackChannelPolicy.php
│ ├── FeedbackPolicy.php
│ │ ├── ProductPolicy.php
│ │ ├── RolePolicy.php
│ │ └── UserPolicy.php
│ ├── Notifications/
│ │ ├── TicketTransferred.php # DB + Mail for department transfer
│ │ └── TicketClosed.php # DB + Mail for ticket closure
── Providers/Filament/
── AdminPanelProvider.php
├── lang/ # i18n translation files
│ ├── en/
│ │ ── app.php # General UI labels, navigation, status, widgets
│ ├── feedback.php # Feedback domain: services, notifications, interactions
── enums.php # Enum labels
└── vi/
│ ├── app.php
── feedback.php
│ └── enums.php
│ │ ├── TicketTransferred.php
│ │ └── TicketClosed.php
── Providers/Filament/
── AdminPanelProvider.php # Panel đầy đủ (/admin)
└── SupportPanelProvider.php # Panel rút gọn (/support)
│ ├── Rules/
│ │ ── RequireProofOfResolution.php
└── Services/
── ActivityLogger.php # NEW: static log() cho audit trail
├── ClosingService.php
│ ├── FileService.php
── TransferService.php
├── lang/ # i18n translation files
│ ├── en/{app.php, feedback.php, enums.php}
│ └── vi/{app.php, feedback.php, enums.php}
├── resources/views/filament/resources/feedback/
│ ├── similar-cases.blade.php
│ └── attachment-links.blade.php # Modal listing attachments with signed download URLs
│ └── attachment-links.blade.php
├── webappUI/aftersales_crm_core/ # Design tokens & system
│ └── DESIGN.md
├── database/
│ ├── migrations/
│ └── seeders/AfterSalesSeeder.php # includes departments, logs, attachments
├── tests/
│ ├── Feature/
│ ├── ClosingPermissionTest.php # 4 tests: staff forbid, no-evidence, with-evidence, cross-dept
└── TransferFlowTest.php # 2 tests: successful + missing reason
│ └── Pest.php
── storage/app/private/feedback-attachments/ # Private disk upload directory
├── composer.json
├── PROGRESS.md
└── AGENTS.md
│ ├── migrations/ # 25 migrations
│ └── seeders/{AfterSalesSeeder,PermissionSeeder}.php
├── tests/Feature/
│ ├── ClosingPermissionTest.php
└── TransferFlowTest.php
├── luutru/ # Archive các file đã lỗi thời
├── UI_DESIGN_BRIEF.md # Thiết kế UI chi tiết
── TASKS_ROADMAP.md
```
## Database Schema
### departments (NEW)
### activity_logs (NEW)
| Column | Type | Notes |
|--------|------|-------|
| id | bigint PK | |
| user_id | fk -> users nullable | Who performed action |
| action | string | import, export, transfer, close, create, update, delete |
| description | text | Human-readable description |
| subject_type | string nullable | Related model class |
| subject_id | bigint nullable | Related model ID |
| metadata | json nullable | Extra data |
| created_at | timestamp | |
### departments
| Column | Type | Notes |
|--------|------|-------|
| id | bigint PK | |
@@ -147,7 +200,7 @@ minicrm/
| manager_id | fk -> users nullable | Department head |
| created_at, updated_at | timestamp | |
### ticket_transfer_logs (NEW)
### ticket_transfer_logs
| Column | Type | Notes |
|--------|------|-------|
| id | bigint PK | |
@@ -164,10 +217,11 @@ minicrm/
| id | bigint PK | |
| customer_id | fk -> customers | cascadeOnDelete |
| customer_product_id | fk -> customer_product nullable | null = general feedback |
| contract_id | fk -> contracts nullable | **(NEW)** Snapshot contract |
| feedback_channel_id | fk -> feedback_channels | |
| assigned_to | fk -> users nullable | Current handler |
| current_department_id | fk -> departments nullable | **(NEW)** Current department |
| is_escalated | boolean default false | **(NEW)** |
| current_department_id | fk -> departments nullable | Current department |
| is_escalated | boolean default false | |
| title | string | |
| content | text | |
| status | string | pending, processing, resolved, closed |
@@ -177,20 +231,20 @@ minicrm/
| Column | Type | Notes |
|--------|------|-------|
| id | bigint PK | |
| uuid | string nullable unique | **(NEW)** |
| uuid | string nullable unique | |
| feedback_id | fk -> feedback | |
| feedback_interaction_id | fk -> feedback_interactions nullable | |
| user_id | fk -> users | |
| name | string | |
| path | string | |
| disk | string default 'local' | **(NEW)** |
| collection | string default 'general' | **(NEW)** proof_of_resolution, customer_evidence, general |
| disk | string default 'local' | |
| collection | string default 'general' | proof_of_resolution, customer_evidence, general |
| mime_type | string nullable | |
| size | bigint nullable | |
| created_at, updated_at | timestamp | |
### Other tables
feedback_interactions, feedback_tags, feedback_feedback_tag, products, customers, customer_product, feedback_channels, users (Spatie permission tables: roles, permissions, model_has_roles, etc.)
feedback_interactions, feedback_tags, feedback_feedback_tag, products, customers, customer_product, feedback_channels, users, contracts, handovers, product_services, roles, permissions, model_has_roles (Spatie), notifications, sessions, cache
## Workflow
@@ -205,14 +259,24 @@ feedback_interactions, feedback_tags, feedback_feedback_tag, products, customers
## Key Features
### Transfer Department (NEW - SOP compliant)
- Action on EditFeedback page: TransferDepartment
### Dual Panel System (NEW)
- **Admin Panel** (`/admin`): Đầy đủ modules, User/Role management
- **Support Panel** (`/support`): Rút gọn, tập trung Feedback. Dùng cho đội support không cần quản lý hệ thống
### ActivityLog — Audit Trail (NEW)
- Tự động ghi log các hành động: import, export, transfer, close, create, update, delete
- `ActivityLogger::log(action, description, subject, metadata, userId)`
- Xem tại `/admin/activity-logs` hoặc `/support/activity-logs`
- Admin-only access (ActivityLogPolicy)
### Transfer Department (SOP compliant)
- Action trên EditFeedback: TransferDepartment
- Modal: select target department + reason (required) + optional attachments
- Calls TransferService: creates TicketTransferLog, updates current_department_id, resets handler to dept manager
- Sends TicketTransferred notification to target department manager
### Close Ticket (NEW - SOP compliant)
- Action on EditFeedback page: CloseTicket
### Close Ticket (SOP compliant)
- Action trên EditFeedback: CloseTicket
- Visible only to admin/manager, only when status != 'closed'
- Requires confirmation
- Staff (403) if tries to close
@@ -224,14 +288,14 @@ feedback_interactions, feedback_tags, feedback_feedback_tag, products, customers
- Manager/Admin: all options including "closed"
- When "closed" selected: calls ClosingService which validates evidence
### File Management (Updated - SOP compliant)
- Files stored on private `local` disk (storage/app/private/feedback-attachments/)
### File Management (SOP compliant)
- Files stored on `public` disk (`storage/app/public/feedback-attachments/`)
- Collection system: `proof_of_resolution`, `customer_evidence`, `general`
- FileService validates: jpg, png, pdf, mp4, mov, max 20MB
- Temporary signed URLs for private file access
- FileService::hasCollection() checks existence of required evidence
### Dashboard Widgets (NEW)
### Dashboard Widgets
- ResolvedTicketsWidget: table of resolved tickets awaiting closure (manager: filtered to own department)
- AvgProcessingTimeWidget: 4 stats (resolved count, avg time, pending count, escalated count)
- HandlerPerformanceWidget: bar chart of avg processing time per handler
@@ -303,19 +367,35 @@ public function getHeading(): string | Htmlable | null
## Navigation Structure
### Admin Panel (`/admin`)
```
Dashboard
Dashboard (AccountWidget + 3 custom widgets)
├── Customer Care / Chăm sóc khách hàng (group)
│ └── Feedbacks / Phản ánh (chat-bubble-left-right, sort=1)
└── Management / Quản lý (group)
├── Products / Sản phẩm (building-storefront, sort=1)
├── Customers / Khách hàng (user-group, sort=2)
├── Channels / Kênh phản ánh (inbox-stack, sort=3)
├── Contracts / Hợp đồng (document-text, sort=4)
├── Tags / Thẻ (tag, sort=default)
├── Activity Logs (clock, sort=7) — admin only
├── Users / Người dùng (users, sort=5) — admin only
└── Roles / Vai trò (shield-check, sort=6) — admin only
```
### Support Panel (`/support`)
```
Dashboard (3 custom widgets)
├── Customer Care / Chăm sóc khách hàng (group)
│ └── Feedbacks
└── Management / Quản lý (group)
├── Products
├── Customers
├── Channels
├── Tags
└── Activity Logs
```
Dashboard widgets: ResolvedTicketsWidget, AvgProcessingTimeWidget, HandlerPerformanceWidget (admin/manager only)
## RBAC (Role-Based Access Control) - Spatie
@@ -400,6 +480,9 @@ use Filament\Schemas\Schema;
```php
use Illuminate\Support\Facades\App;
$service = App::make(FileService::class);
// ActivityLogger (static)
\App\Services\ActivityLogger::log('transfer', '...', $feedback, ['dept' => 'CSKH']);
```
### Spatie role check
@@ -432,6 +515,7 @@ $user->assignRole('manager');
19. **FileUpload in Actions**: When handling file uploads in Action callbacks (e.g., transfer attachments), file paths are strings (not UploadedFile). Create records directly instead of using FileService::upload().
20. **Tailwind CSS in Filament**: Custom blade views render inside Filament layout which does NOT include full Tailwind CSS build. Must add needed utilities to `public/css/filament-custom.css` with `!important`.
21. **SVG icon sizing**: Use inline `width`/`height` attributes on SVG icons (e.g., `<svg width="14" height="14">`) instead of Tailwind classes (`w-3.5 h-3.5`) — prevents Filament CSS from overriding sizes.
22. **Dual Panel**: Support panel at `/support` is separate from Admin panel at `/admin`. Both share the same models/services/policies/database.
## File Upload Architecture
@@ -501,3 +585,4 @@ protected function afterSave(): void
// For SVG icons, use inline attributes:
<svg width="14" height="14" class="text-blue-600">...</svg>
// NOT: <svg class="w-3.5 h-3.5 text-blue-600">...</svg>
```