Files
minicrm/PROGRESS.md
phuongtc efa97b6c71
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled
them log, chinh upload
2026-05-09 11:00:59 +00:00

203 lines
10 KiB
Markdown

# AfterSales CRM - Tiến độ
## Trạng thái: Hoàn thành SOP + 6/7 AI Instructions (85%)
Đã test: Tất cả routes HTTP 200, Pest 8/8 tests (21 assertions) pass ✓
Tham chiếu: `SOP_des.md` — Bản đặc tả hệ thống After-Sale CRM
**Data import:** `php artisan app:import-cskh ai_instructions/CSKH.xlsx` — 3658 rows imported successfully
## Công nghệ
- Laravel 13.6.0 + Filament 5.6.1 + SQLite
- PHP 8.3
- Spatie laravel-permission (RBAC)
- Pest PHP (testing)
## Tài khoản test
| Role | Email | Password |
|------|-------|----------|
| admin | admin@minicrm.local | password |
| manager | manager@minicrm.local | password |
| staff | staff@minicrm.local | password |
---
## ĐÃ HOÀN THÀNH
### Giai đoạn 1: Mở rộng CSDL
- [x] Bảng `departments` (id, name, manager_id → users)
- [x] Bổ sung `feedback`: current_department_id, is_escalated
- [x] Bảng `ticket_transfer_logs` (feedback_id, from/to department, sender, reason)
- [x] Nâng cấp `feedback_attachments`: uuid, disk, collection
- [x] Cài Spatie laravel-permission
### Giai đoạn 2: Services & Logic
- [x] `FileService`: upload, validation (jpg/png/pdf/mp4/mov ≤20MB), collection query, temporary URL
- [x] `TransferService`: transfer department + reason required + notification
- [x] `ClosingService`: role-gated close + proof_of_resolution check
- [x] Policies cập nhật dùng Spatie `hasRole()`
- [x] Custom Rule `RequireProofOfResolution`
### Giai đoạn 3: Notifications
- [x] `TicketTransferred` (Database + Mail)
- [x] `TicketClosed` (Database + Mail)
### Giai đoạn 4: Filament UI
- [x] `TransferDepartment` Action trên Edit Feedback (modal: department + reason + attachment)
- [x] `CloseTicket` Action (visible: admin/manager, status ≠ closed, requires confirmation)
- [x] InteractionsRelationManager: role-aware status options (staff: no "closed"), department field
- [x] FeedbackForm: current_department_id, is_escalated, attachment_collection
### Giai đoạn 5: Dashboard Widgets
- [x] `ResolvedTicketsWidget`: bảng ticket resolved chờ đóng (manager lọc theo phòng quản lý)
- [x] `AvgProcessingTimeWidget`: 4 stats (resolved count, avg time, pending, escalated)
### Giai đoạn 6: Testing
- [x] Pest cài đặt + 6 test scenarios
- [x] `ClosingPermissionTest`: 4 tests (staff 403, no evidence 422, with evidence OK, cross-department 403)
- [x] `TransferFlowTest`: 2 tests (success + missing reason)
### Giai đoạn 7: Seeder
- [x] 4 departments (CSKH, Kỹ thuật, Kế toán, Pháp lý)
- [x] 1 ticket_transfer_log mẫu
- [x] 3 feedback_attachments (2 proof_of_resolution, 1 customer_evidence)
### Giai đoạn 8: Polish
- [x] AGENTS.md cập nhật đầy đủ
### Bug Fix
- [x] Dashboard widget lọc Manager dùng `Department::where('manager_id')` thay vì `auth()->id()`
- [x] Migration default disk `private``local`
- [x] File upload trong Interaction/Create/Edit dùng lưu thẳng FeedbackAttachment, không tạo UploadedFile giả
### PM (Improvements)
- [x] FeedbackTable: thêm cột Department, Escalated icon, Department filter
- [x] EditFeedback: validation `proof_of_resolution` khi đổi status sang `closed` từ form
### PASS 3 — Hoàn thiện SOP
- [x] `HandlerPerformanceWidget`: biểu đồ bar chart thời gian xử lý trung bình theo từng nhân viên
- [x] Department_Head: Manager chỉ đóng được ticket phòng mình quản lý (kèm test)
- [x] Temporary URL tích hợp vào UI: nút "View Attachments" trong Interaction History với download link
- [x] Cho phép upload attachment trong status_change interaction
- [x] Docker sẵn sàng production: Dockerfile, docker-compose, entrypoint
- [x] Migration `notifications` table
### AI Instructions — Phase A: Module Hợp đồng (Contract)
- [x] Migration `contracts`: product_id, customer_id, type (sale/lease/bcc), dates, status, signed_status
- [x] Enum `ContractType` (SALE/LEASE/BCC) + `ContractStatus` (ACTIVE/EXPIRED/LIQUIDATED)
- [x] Model `Contract`: relationships product(), customer(), feedbacks()
- [x] Filament Resource `Contracts` (CRUD) + `ContractPolicy`
- [x] RelationManager `ContractsRelationManager` trên ProductResource
- [x] Model `Product` thêm `contracts()` HasMany
- [x] Seeder: 5 contracts mẫu
### AI Instructions — Phase B: Snapshot Hợp đồng
- [x] Migration thêm `contract_id` FK nullable vào `feedback`
- [x] Model `Feedback`: thêm `contract_id` fillable + `contract()` BelongsTo
- [x] FeedbackForm: auto-select active contract khi chọn sản phẩm, cho phép chọn lại thủ công
- [x] FeedbackTable: cột "Contract" hiển thị loại HĐ dạng badge
- [x] Seeder: gán contract_id cho 5 feedback mẫu
### AI Instructions — Phase C: Module Bàn giao (Handover)
- [x] Migration `handovers`: product_id, customer_id, handover_date, status, remark
- [x] Enum `HandoverStatus` (NOT_READY/READY/SCHEDULED/HANDED_OVER)
- [x] Model `Handover`: relationships product(), customer()
- [x] RelationManager `HandoversRelationManager` trên ProductResource
- [x] Model `Product` thêm `handovers()` HasMany
- [x] Seeder: 5 handovers mẫu
### AI Instructions — Phase D: Module Dịch vụ (ProductService)
- [x] Migration `product_services`: product_id, service_type, status, actual_collection_date, remark
- [x] Enum `ServiceType` (MANAGEMENT_FEE/GRATITUDE/SELF_BUSINESS)
- [x] Model `ProductService`: relationship product()
- [x] RelationManager `ProductServicesRelationManager` trên ProductResource
- [x] Model `Product` thêm `productServices()` HasMany
- [x] Seeder: 5 services mẫu
### AI Instructions — Phase E: Enhancement ProductResource
- [x] ProductResource có 3 tabs: Contracts + Handovers + Services
### AI Instructions — Phase G: Data Import Pipeline
- [x] Cài `spatie/simple-excel` (Lazy Collection, chống OOM)
- [x] Command `app:import-cskh {file_path} --dry-run` với ProgressBar
- [x] Pipeline: Product/Customer firstOrCreate → customer_product pivot → Contract → Handover → Service → Feedback + Interactions
- [x] Xử lý DateTimeImmutable object từ Excel, skip meta rows
- [x] Đã test thành công với CSKH.xlsx: 3658 rows → 3299 products, 2089 customers, 2637 contracts, 2077 handovers, 159 services, 71 feedbacks, 226 interactions
### Còn lại (Optional)
- [ ] Auto-suggest chuyển phòng ban dựa trên loại hợp đồng (Ticket BCC → gợi ý Pháp lý)
### Granular Permissions + Export Backup + User/Role Management
- [x] PermissionSeeder: 29 permissions (view/create/update/delete per module + close-ticket, transfer-department, export-data)
- [x] Role → Permission mapping: admin (all), manager (no delete/export), staff (view + limited write)
- [x] Policies updated to use `hasPermissionTo()` instead of `hasRole()`
- [x] Widgets/Filament updated to use permission-based checks
- [x] ExportBackup command: `app:export-backup` (JSON, per-table, chunk 500, manifest.json)
- [x] UserResource: admin can create/edit/delete users + assign roles
- [x] RoleResource: admin can create/edit/delete roles + assign permissions
- [x] UserPolicy + RolePolicy (admin-only)
- [x] Tests updated: 8 tests, 21 assertions pass
### Internationalization (i18n) — Vietnamese + English
- [x] Config: `APP_LOCALE=vi`, `APP_FALLBACK_LOCALE=en` in `.env`
- [x] Created `lang/en/` and `lang/vi/` with 3 files each: `app.php`, `feedback.php`, `enums.php`
- [x] ~120 translation keys covering: navigation, labels, status, widgets, services, notifications, enums
- [x] All Resources: override `getPluralLabel()` + `getNavigationGroup()` with `__()` calls
- [x] All Form fields: explicit `->label(__('key'))` on TextInput, Select, Textarea, etc.
- [x] All Table columns: explicit `->label(__('key'))` on TextColumn, IconColumn
- [x] All RelationManagers: `$title` property uses translation key
- [x] All Widgets: `getHeading()`/`getDescription()` methods return translated strings
- [x] Enums: `ContractType`, `ContractStatus`, `HandoverStatus`, `ServiceType` use `__()` in `label()`
- [x] Services/Notifications: all user-facing strings use translation keys
- [x] Blade views: all hardcoded strings replaced with `__()` calls
- [x] Filament vendor translations (57 Vietnamese files) auto-activated for UI chrome
- [x] Tests: 8/8 pass (21 assertions)
### UI Polish & Bug Fixes
- [x] File upload: Fixed disk('local') → disk('public') across all components
- [x] File upload: Added exists() check before getting metadata
- [x] File upload: Fixed dehydrated(false) issue - use property to store paths
- [x] Tailwind CSS: Added ~200 utility classes to filament-custom.css
- [x] SVG icons: Use inline width/height attributes instead of Tailwind classes
- [x] GlobalSearch: Customized for all 6 Resources with multi-field search
- [x] RelationManager titles: Override getTitle() for proper translation
- [x] Enum refactoring: Added color() method, static options(), developer comments
- [x] Documentation: Created docs/I18N_GUIDE.md and docs/ENUM_GUIDE.md
---
## Database Schema (final — 23 migrations)
```
products customers customer_product (pivot)
feedback_channels feedback feedback_interactions
feedback_attachments feedback_tags feedback_feedback_tag (pivot)
users departments ticket_transfer_logs
permissions roles model_has_roles (spatie)
notifications sessions cache
contracts handovers product_services
```
## Data Import
```bash
# Dry-run (phân tích trước, an toàn)
php artisan app:import-cskh ai_instructions/CSKH.xlsx --dry-run
# Import thật
php artisan app:import-cskh ai_instructions/CSKH.xlsx
```
## Local Dev
```bash
cd /home/phuongtc/vibecode/minicrm
php artisan migrate:fresh --seed
php artisan serve
# Mở http://localhost:8000/admin
php artisan test # 8 tests (21 assertions)
```
## Hướng dẫn cho AI Agent khác
- `CODEBASE_SNAPSHOT.md` — Toàn bộ cấu trúc codebase (đọc thay vì scan code)
- `TASKS_ROADMAP.md` — Roadmap: đã làm, đang làm, sẽ làm
- `AGENTS.md` — Hướng dẫn chạy, workflow, RBAC, gotchas
- `docs/I18N_GUIDE.md` — Hướng dẫn đa ngôn ngữ chi tiết
- `docs/ENUM_GUIDE.md` — Hướng dẫn thêm Enum mới