Laravel app tách riêng từ V3 — giờ bỏ hay giữ? Chi tiết quyết định per-domain, per-asset. Lúc trước tách vì HRM; V4 drop HRM → merge Laravel nhưng giữ SPA.
Hiểu lý do gốc để quyết định đúng cho V4.
2 hành động riêng biệt cho 2 phần của backend-admin.
Laravel 12 + React SPA bundled
PHP merge + SPA standalone
Per-domain quyết định: DROP hoàn toàn (HRM) hay MERGE vào unified backend V4.
| V3 Domain | % backend-admin | Action | V4 Destination | Ghi chú |
|---|---|---|---|---|
| Hrm | ~60% | DROP | — | 35 models, internal HR không phải V4 focus. Biggest removal. |
| Campaign | ~8% | MERGE | backend/app/Domain/Recruitment | Recruitment campaigns submodule |
| Crm | ~10% | SPLIT | M3 + M4 + M8 (tách theo function) | Lead flows: Recruitment, Worker, Supplier |
| Finance (staff view) | ~8% | MERGE | backend/app/Domain/Payroll + Reconciliation | Admin approval views |
| RecruitmentSupport | ~5% | MERGE | backend/app/Domain/Supplier | Recruiter tools |
| Trust | ~4% | MERGE | backend/app/Domain/Reconciliation + Trust Layer | Disputes + reputation |
| Attendance (admin) | ~3% | MERGE | backend/app/Domain/Attendance | Staff oversight routes |
| Infrastructure + Shared | ~2% | MERGE | backend/app/Domain/Platform + IAM | User sync → Integration Hub |
Extract thành admin-spa/ standalone Vite app. Giữ 75% code, adapt routing + auth.
Tables, modals, forms, buttons, charts, inputs, dialogs...
Sidebar, Header, Breadcrumb, TopBar, Footer
useDebounce, useLocalStorage, useClickOutside...
Zod validation schemas + React Hook Form patterns
Theme, color palette, responsive wrappers
40+ extensions configured
Drag-drop workflow patterns
Optimized pipeline + Tailwind v4
| Page Group | Count | Action | Notes |
|---|---|---|---|
| HRM pages | ~60 | DROP | Biggest removal — không có V4 equivalent |
| Finance admin | ~40 | ADAPT | Payroll approval + reconciliation views |
| Attendance admin | ~25 | ADAPT | Staff oversight pages |
| Campaign | ~20 | ADAPT | Move to V4 M3 campaigns |
| CRM | ~30 | ADAPT | Employer + worker management |
| Trust | ~15 | ADAPT | Disputes + reputation |
| RecruitmentSupport | ~15 | KEEP | Move to V4 M8 as-is |
| Infrastructure | ~10 | ADAPT | Tenant config, settings |
| Dashboard | ~20 | REWRITE | Per-tenant analytics (hardest) |
| Shared layouts | ~22 | KEEP | Profile, settings common |
Thêm tenant context vào store shape:
// V3 auth store { user, token, isAuthenticated } // V4 auth store { user, tenant, currentRole, token, isAuthenticated, switchTenant(slug) }
Update API base URL + inject tenant header:
// V3 axios.get('/admin/api/workers') // V4 axios.get('/v4/admin/workers', { headers: { 'X-Tenant-Slug': slug } })
// V3 React Router v7 (single-tenant) <Route path="/admin/hrm/employees" element={<Employees />} /> <Route path="/admin/campaigns" element={<Campaigns />} /> // V4 React Router v7 (multi-tenant) <Route path="/t/:tenantSlug/admin/campaigns" element={<Campaigns />} /> <Route path="/t/:tenantSlug/admin/workers" element={<Workers />} /> <Route path="/system/tenants" element={<TenantManager />} /> // super admin
Không dùng Turborepo/pnpm workspaces. Mỗi app có git + deployment riêng.
| Dimension | ✅ Pros (Git độc lập) | ⚠ Cons |
|---|---|---|
| Simplicity | Không cần học Turborepo/Nx. Git flow quen thuộc. | — |
| Ownership | Rõ ràng per-team. PR focus 1 repo. | — |
| Deployment | Decoupled. Deploy 1 app không ảnh hưởng app khác. | — |
| Shared code | — | Phải copy (vd: TypeScript types) hoặc npm private package |
| Atomic refactor cross-app | — | Khó hơn — cần PRs nhiều repos đồng bộ |
| Build cache | — | Không shared cache (mỗi app build độc lập) |
| Migration | Từng app migrate dần, rollback dễ | — |
Từ V3 backend-admin → V4 unified backend + standalone admin-spa.
| Step | Action | Output |
|---|---|---|
| 1 | Init new git repo admin-spa/ | Clean history |
| 2 | Copy backend-admin/resources/js/src/ → admin-spa/src/ | Source code |
| 3 | Copy backend-admin/package.json + vite config + tsconfig | Build pipeline |
| 4 | Remove Laravel integration (laravel-vite-plugin) | Pure Vite standalone |
| 5 | Update API base URL env vars | Points to unified backend |
| 6 | Setup nginx/CDN deployment cho admin.xanhvina.com.vn | Infrastructure ready |
| 7 | Verify build + dev server work | Green build |
| Step | Action | Output |
|---|---|---|
| 1 | Delete HRM domain code + migrations | Clean slate |
| 2 | Port Campaign → backend/app/Domain/Recruitment | Merged domain |
| 3 | Port CRM (split into Recruitment/Worker/Supplier) | 3 targets |
| 4 | Port Finance (admin views) → Payroll + Reconciliation | Merged |
| 5 | Port RecruitmentSupport → Supplier | Merged M8 |
| 6 | Port Trust → Reconciliation + Trust Layer | Merged M10 + cross-cutting |
| 7 | Port Attendance admin views | Merged M5 |
| 8 | Delete PublicApiClient + UserSyncObserver | Cleanup |
| 9 | Port tests (non-HRM) | Coverage maintained |
| 10 | Delete backend-admin/ repo entirely | Archive + sunset |
| Step | Action | Output |
|---|---|---|
| 1 | Remove HRM pages (~60) | Cleanup |
| 2 | Update router: add /t/:tenantSlug prefix | Tenant routing |
| 3 | Update Zustand auth store với tenant context | Multi-tenant aware |
| 4 | Update 164 SWR hooks: new API URL + X-Tenant-Slug header | API integration |
| 5 | Adapt Finance/Attendance/Campaign/CRM/Trust pages | ~130 pages adapted |
| 6 | Rewrite Dashboard pages (per-tenant analytics) | ~20 pages rewritten |
| 7 | Add TenantSwitcher component (super admin) | Multi-tenant UX |
| 8 | E2E tests với 2+ tenants | Isolation verified |
So sánh trước/sau khi merge backend-admin.
| Dimension | V3 (2 Laravel apps) | V4 (Unified) | Change |
|---|---|---|---|
| Laravel apps | 2 (backend + backend-admin) | 1 unified | -50% |
| Databases | 2 MySQL | 1 PostgreSQL | -50% |
| Cross-DB queries | ⚠ Attendance proxy reads work_records | ✅ None | Eliminated |
| Auth systems | 2 (staff Sanctum + worker/employer Sanctum) | 1 (unified JWT with scoped roles) | -50% |
| PublicApiClient proxy | 20+ methods | ❌ Removed | Deleted |
| UserSyncObserver | Required (admin→public DB) | ❌ Removed | Deleted |
| Staff permissions | config file (hardcoded 358 perms) | DB table (dynamic per tenant) | Improved |
| Migration files | 71 split across 2 DBs | 92 unified | +21 (V4 expanded) |
| Deployment pipelines | 2 separate (backend + admin) | 1 backend + 1 admin-spa | Cleaner separation |
| Frontend codebases | backend-admin SPA embedded | admin-spa standalone | Decoupled |
backend-admin Laravel project: DROP · backend-admin SPA: KEEP as admin-spa standalone
Laravel PHP → 30% merge vào unified backend · SPA React → 75% reuse extract thành standalone Vite app · Design system value preserved 95% · Deploy admin.xanhvina.com.vn không đổi.