Solo Dev · Laravel 11 · DMS Enterprise
Kế hoạch triển khai
Construction PM
Hướng dẫn từng bước dành cho solo dev lần đầu dùng Laravel — từ cài đặt môi trường đến hệ thống DMS hoàn chỉnh với Dual-Storage S3 + SharePoint, PDF/BIM Viewer và Approval Workflow.
Solo Dev — PHP thuần background
Laravel 11 + Vue 3 + Inertia.js
AWS S3 Primary + SharePoint Backup
PDF.js + IFC.js + Fabric.js
Target: 1000 users
68
Tổng nhiệm vụ
0
Đã hoàn thành
4
Phase chính
0%
Tiến độ
Ma trận công nghệ
| Module | Công nghệ / Thư viện | Lý do chọn |
|---|---|---|
| Backend | Laravel 11 PHP 8.4 | Storage facade, Queue, Policy — đủ mạnh cho dual-storage |
| Frontend SPA | Vue.js 3 Inertia.js | SPA mượt như Claude UI — không cần REST API riêng |
| Primary Storage | AWS S3 | Presigned URL, versioning, Intelligent-Tiering |
| Backup Storage | Microsoft Graph API SharePoint | Tận dụng M365 đang có sẵn — 0 chi phí thêm |
| Queue / Async | Laravel Queue Redis Horizon | Upload SharePoint async — không block user |
| PDF Viewer | PDF.js | Open source, render PDF trên browser, hỗ trợ annotation layer |
| BIM/IFC Viewer | ThatOpen (IFC.js) | Render file .ifc 3D trực tiếp trên browser, WebGL |
| Annotation | Fabric.js | Canvas 2D — vẽ hình, text, stamp; lưu tọa độ vào DB |
| PDF Flatten | pdf-lib | Ghi annotation vào PDF gốc khi approve — tạo file v_approved.pdf |
| Chunk Upload | Uppy.js | Bắt buộc cho file .rvt/.ifc 30–100MB — tránh PHP timeout |
| RBAC | spatie/laravel-permission | Role + Permission per folder/project — cài package, không tự viết |
| Audit Log | spatie/laravel-activitylog | Ghi log tự động mọi action — không thể xóa |
| Auth | Laravel Breeze hoặc Sanctum | Auth có sẵn + remember me + password reset |
| AWS SES hoặc Mailpit (dev) | SES $1/10K emails; Mailpit để test local | |
| Server | Docker Nginx VPS $24–40/tháng | Docker local = production parity; VPS DigitalOcean/Vultr |
Timeline tổng thể — Solo dev
Tuần 1–3
3 tuần
Phase 0 — Cài đặt & Học Laravel
Docker, Laravel 11, cấu trúc thư mục, Eloquent, Queue — học song song với cài đặt. Laracasts "Laravel From Scratch" (miễn phí). Mục tiêu: hiểu MVC + migration + seeder.
Tuần 4–7
4 tuần
Phase 1 — Nền tảng Backend
DB schema, RBAC, Dual-Storage (S3 + SharePoint), Queue jobs, Audit log, Versioning logic.
Tuần 8–14
7 tuần
Phase 2 — DMS Core (trái tim app)
File explorer, Upload với Uppy.js, Versioning UI, PDF.js viewer, IFC.js BIM viewer, Fabric.js annotation layer.
Tuần 15–19
5 tuần
Phase 3 — Approval Workflow
Approval flow builder, email notification, PDF flatten với pdf-lib, approval log & history.
Tuần 20–24
5 tuần
Phase 4 — Polish, Settings, Security
Settings, Help, Performance tuning, Security audit, Deploy production, UAT với client thực.
💡 Chiến lược solo dev
Không cố code hết mọi thứ cùng lúc. Phase 2 (DMS) là phần nặng nhất — ưu tiên file explorer + upload hoạt động trước, viewer + annotation làm sau. Dùng Claude để giải quyết từng vấn đề cụ thể thay vì hỏi tổng quát.Phase 0 · Tuần 1–3
🛠 Cài đặt môi trường từ đầu
Mục tiêu: Có môi trường dev chạy được Laravel 11 trên Docker, kết nối được MySQL, Redis, S3. Đây là bước solo dev mất nhiều thời gian nhất nếu lần đầu — hãy kiên nhẫn.
Bước 0.1 — Cài đặt theo thứ tự
📦 Yêu cầu máy tính (Windows/Mac/Linux)
Cài Docker Desktop
Download tại docker.com/products/docker-desktop — chọn phiên bản theo OS. Sau khi cài xong, mở terminal gõ
docker --version để xác nhận.Cài PHP 8.4 + Composer (để chạy lệnh artisan)
Windows: dùng XAMPP hoặc Laragon (khuyến nghị cho Windows). Mac:
brew install php@8.4 composer. Sau đó: composer --version để xác nhận.Cài Node.js 20 LTS + npm
Tải tại nodejs.org — chọn LTS. Cần để build Vue.js 3 + Inertia. Xác nhận:
node --version và npm --version.Tạo dự án Laravel 11 mới
Mở terminal tại thư mục làm việc:
Sau đó:
composer create-project laravel/laravel construction-pmSau đó:
cd construction-pmCài Laravel Sail (Docker wrapper chính thức của Laravel)
composer require laravel/sail --devSau đó:
php artisan sail:install → chọn mysql, redis, mailpitKhởi động:
./vendor/bin/sail up -d🐳 docker-compose.yml — Cấu hình đầy đủ
docker-compose.yml Laravel Sail extended
services: laravel.test: # App Laravel chính build: context: ./vendor/laravel/sail/runtimes/8.4 ports: ["80:80", "443:443"] environment: WWWUSER: 1000 volumes: ['.:${SAIL_APPLICATION_VOLUME}'] depends_on: [mysql, redis, mailpit] networks: [sail] mysql: image: mysql/mysql-server:8.0 environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' volumes: ['sail-mysql:/var/lib/mysql'] ports: ["3306:3306"] networks: [sail] redis: image: redis:alpine ports: ["6379:6379"] networks: [sail] mailpit: # Bắt email khi dev — không gửi thật image: axllent/mailpit ports: ["8025:8025", "1025:1025"] networks: [sail] networks: sail: {driver: bridge} volumes: sail-mysql: {driver: local}
⚙️ .env — Cấu hình môi trường
.env copy từ .env.example rồi sửa
# App APP_NAME="Construction PM" APP_URL=http://localhost # Database DB_CONNECTION=mysql DB_HOST=mysql # tên service trong docker-compose DB_PORT=3306 DB_DATABASE=construction_pm DB_USERNAME=sail DB_PASSWORD=password # Redis REDIS_HOST=redis REDIS_PORT=6379 # Queue — dùng Redis thay vì sync QUEUE_CONNECTION=redis # AWS S3 — Primary Storage AWS_ACCESS_KEY_ID=your_key AWS_SECRET_ACCESS_KEY=your_secret AWS_DEFAULT_REGION=ap-southeast-1 # Singapore AWS_BUCKET=construction-pm-files AWS_URL= # để trống — dùng Presigned URL # Microsoft Graph API — SharePoint Backup MICROSOFT_TENANT_ID=your_tenant_id MICROSOFT_CLIENT_ID=your_client_id MICROSOFT_CLIENT_SECRET=your_secret SHAREPOINT_SITE_ID=your_site_id SHAREPOINT_DRIVE_ID=your_drive_id # Mail (dev dùng mailpit, prod dùng SES) MAIL_MAILER=smtp MAIL_HOST=mailpit MAIL_PORT=1025
Bước 0.2 — Cài packages cần thiết ngay từ đầu
terminal chạy trong thư mục dự án
# 1. Frontend stack (Vue 3 + Inertia) ./vendor/bin/sail composer require inertiajs/inertia-laravel npm install @inertiajs/vue3 vue@3 # 2. RBAC — phân quyền ./vendor/bin/sail composer require spatie/laravel-permission # 3. Audit log ./vendor/bin/sail composer require spatie/laravel-activitylog # 4. AWS S3 ./vendor/bin/sail composer require league/flysystem-aws-s3-v3 # 5. Microsoft Graph API ./vendor/bin/sail composer require microsoft/microsoft-graph # 6. Excel import/export ./vendor/bin/sail composer require maatwebsite/excel # 7. PDF generation (approval stamp) ./vendor/bin/sail composer require barryvdh/laravel-dompdf # 8. Queue dashboard ./vendor/bin/sail composer require laravel/horizon # 9. Publish configs ./vendor/bin/sail artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" ./vendor/bin/sail artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider" ./vendor/bin/sail artisan migrate # Tạo bảng permissions, jobs, etc. # 10. Frontend deps npm install fabric uppy @uppy/core @uppy/dashboard @uppy/aws-s3-multipart npm install pdfjs-dist @thatopen/components npm run dev # Vite hot reload
💡 Khi gặp lỗi cài đặt
Prompt cho Claude: "Tôi chạy lệnh [paste lệnh] trong Laravel Sail và gặp lỗi [paste error]. Đây là file .env của tôi [paste]. Hãy giải thích lỗi và fix từng bước."Phase 1 · Tuần 4–7
🏗 Nền tảng & Hạ tầng Backend
Mục tiêu: Khung xương vững chắc — DB schema đầy đủ, RBAC hoạt động, dual-storage kết nối được S3 và SharePoint, Queue worker chạy background.
Cấu trúc thư mục — Service Pattern
app/ Service Pattern — tách business logic khỏi Controller
app/ ├── Http/Controllers/ │ ├── FileController.php # Upload, download, delete │ ├── FolderController.php # CRUD folder │ ├── ApprovalController.php # Submit, approve, reject │ └── AnnotationController.php # Save/load annotations ├── Services/ │ ├── StorageManager.php # Điều phối S3 + SharePoint │ ├── Drivers/ │ │ ├── S3Driver.php # Upload, Presigned URL, delete │ │ └── SharePointDriver.php # Graph API: upload, create folder │ ├── VersioningService.php # Logic v1 → v2 → v3 │ └── ApprovalService.php # Workflow state machine ├── Jobs/ │ ├── SharePointUploadJob.php # Async backup lên SharePoint │ ├── FlattenPdfJob.php # Flatten annotations → PDF mới │ └── SendApprovalEmailJob.php # Gửi email notification ├── Models/ │ ├── Organization.php │ ├── Project.php │ ├── Folder.php │ ├── File.php │ ├── FileVersion.php │ ├── Annotation.php │ ├── Submission.php │ └── ApprovalStep.php └── Policies/ ├── FolderPolicy.php # Ai được xem/sửa folder nào └── FilePolicy.php # Ai được download/delete file
Database Schema — Thiết kế đầy đủ
Migration: organizations — Tổ chức tham gia dự án
2h
Migration: users — Thành viên (thuộc organization)
2h
Migration: projects — Dự án xây dựng
1h
Migration: folders — Cây thư mục đệ quy
2h
Migration: files — File metadata (không lưu nội dung)
2h
Migration: file_versions — Lịch sử phiên bản file
1h
Migration: annotations — Ghi chú trên file
1h
Migration: submissions + approval_steps — Quy trình phê duyệt
2h
Seeder: Dữ liệu mẫu đầy đủ cho dev và demo
3h
RBAC — Phân quyền theo Folder/Project
🔐 Thiết kế Role & Permission
database/seeders/RolePermissionSeeder.php
// Roles hệ thống $roles = [ 'super_admin', // Admin tổng — toàn quyền 'org_admin', // Admin tổ chức — quản lý member của org mình 'project_manager', // Quản lý dự án — approve, quản lý folder 'member', // Thành viên — upload, download theo quyền folder 'viewer', // Chỉ xem — không upload, không download (chỉ preview) ]; // Permissions — kết hợp với FolderPolicy để check per-folder $permissions = [ // File permissions 'file.upload', 'file.download', 'file.delete', 'file.view', 'file.annotate', 'file.version.view', // Folder permissions 'folder.create', 'folder.rename', 'folder.delete', // Approval permissions 'approval.submit', 'approval.review', 'approval.approve', // Admin permissions 'user.manage', 'org.manage', 'project.manage', 'permission.manage', 'setting.manage', ];
Seeder: Tạo Roles và Permissions với spatie/laravel-permission
3h
FolderPolicy — kiểm tra quyền per-folder (quan trọng nhất)
4h
Migration: folder_permissions — ACL per folder
3h
Permission Matrix UI — trang admin quản lý quyền
6h
Dual-Storage — StorageManager Service
⚡ StorageManager — điều phối S3 (sync) + SharePoint (async)
app/Services/StorageManager.php
class StorageManager { public function store(UploadedFile $file, $folder, $metadata): FileModel { // 1. Generate UUID key — không dùng tên file gốc $uuid = Str::uuid(); $s3Key = "projects/{$folder->project_id}/{$folder->path}/{$uuid}.{$ext}"; // 2. Upload S3 — SYNCHRONOUS (user chờ kết quả này) Storage::disk('s3')->put($s3Key, fopen($file, 'r'), 'private'); // 3. Lưu metadata vào DB $fileRecord = FileModel::create([ 'folder_id' => $folder->id, 's3_key' => $s3Key, 'original_name' => $file->getClientOriginalName(), 'size_bytes' => $file->getSize(), 'current_version' => 1, ]); // 4. Dispatch job SharePoint — ASYNCHRONOUS (user không chờ) SharePointUploadJob::dispatch($fileRecord->id, $s3Key) ->onQueue('sharepoint') ->delay(now()->addSeconds(5)); return $fileRecord; } public function temporaryUrl(FileModel $file, $minutes = 15): string { // LUÔN dùng temporaryUrl — không bao giờ expose S3 URL trực tiếp return Storage::disk('s3') ->temporaryUrl($file->s3_key, now()->addMinutes($minutes)); } }
S3Driver — upload, delete, temporaryUrl, copy (versioning)
4h
SharePointDriver — OAuth2 token cache + upload nhỏ + chunked upload >4MB
8h
SharePointUploadJob — retry 3 lần, alert admin khi failed
3h
Laravel Horizon — cài và cấu hình queue dashboard
2h
S3 Presigned URL endpoint — GET /files/{id}/view
2h
Audit Log & Version Control
Cấu hình spatie/activitylog — log tự động mọi Model event
2h
VersioningService — logic v1 → v2 khi upload file trùng tên
4h
File Version History UI — xem và download các phiên bản cũ
4h
Phase 2 · Tuần 8–14
📁 DMS Core — Trái tim ứng dụng
Mục tiêu: File explorer hoạt động hoàn chỉnh — upload, versioning, view PDF/IFC, ghi annotation. Đây là phần phức tạp nhất về frontend (Vue 3 + Inertia).
2.1 — Tổ chức & Thành viên
CRUD Organizations — Admin quản lý công ty
6h
CRUD Users / Project Members — Org Admin quản lý team
8h
Assign thành viên vào Project với role cụ thể
4h
Trang Profile cá nhân — đổi info, đổi password, xem activity
4h
2.2 — File Explorer DMS (Quan trọng nhất)
🖥 Layout 3 panel — tham khảo Autodesk Docs
resources/js/Pages/DMS/Explorer.vue
<!-- Layout chính DMS --> <template> <div class="dms-layout"> <!-- Panel trái: Folder Tree --> <aside class="folder-tree"> <FolderTree :folders="projectFolders" :active-id="activeFolderId" @select="onFolderSelect" @context-menu="showContextMenu" <!-- right-click --> /> </aside> <!-- Panel giữa: File list --> <main class="file-panel"> <Breadcrumb :path="currentPath" /> <FileToolbar @upload="openUploader" @view-toggle="toggleView" /> <FileGrid v-if="viewMode==='grid'" :files="files" @click="openFile" /> <FileTable v-else :files="files" @click="openFile" /> </main> <!-- Panel phải: File Viewer + Sidebar --> <FileViewer v-if="selectedFile" :file="selectedFile" :presigned-url="presignedUrl" /> </div> </template>
FolderTree component — recursive, collapsible, drag-and-drop
10h
FileTable + FileGrid view — toggle, sort, filter
8h
Search toàn cục trong project — tìm file/folder
5h
Deep-link URL — bookmark folder cụ thể
3h
2.3 — Upload Engine với Uppy.js (Bắt buộc cho file lớn)
🚨 Tại sao bắt buộc phải dùng Uppy.js?
File .rvt/.ifc có thể nặng 30–100MB. PHP upload thông thường giới hạn bởi upload_max_filesize và request_timeout. Uppy.js chia file thành chunks 5–10MB, upload từng phần lên S3 Multipart — tránh hoàn toàn vấn đề timeout và có thể resume nếu mất kết nối.📤 Uppy S3 Multipart Upload Flow
User kéo file vào DMS
→
Uppy.js (browser)
→
POST /api/s3/multipart/create
→
Laravel tạo UploadId trên S3
Uppy chia file thành chunks 10MB
→
Upload mỗi chunk thẳng lên S3
→
S3 nhận đủ chunks
Uppy gọi POST /api/s3/multipart/complete
→
Laravel complete multipart + lưu DB
→
Dispatch SharePointUploadJob
Backend: S3 Multipart API endpoints (4 endpoints)
6h
Frontend: UppyUploader component — drag drop UI với progress
8h
VersioningService — detect file trùng tên → auto-version
5h
SharePoint sync status indicator — badge trên mỗi file
3h
2.4 — PDF Viewer + BIM/IFC Viewer
PdfViewer component — PDF.js với Presigned URL
10h
IfcViewer component — ThatOpen IFC.js render 3D model
14h
FileViewer sidebar — Info, Versions, Annotations, Approval tabs
8h
Metadata viewer cho .rvt và .dwg (không render full model)
3h
2.5 — Annotation Layer — Ghi chú trên file
✏️ Kiến trúc Annotation — Không chỉnh sửa file gốc
Annotation được lưu dưới dạng JSON canvas state của Fabric.js trong DB (cột
fabric_json). File gốc trên S3 không bị thay đổi. Chỉ khi người dùng ấn "Flatten & Save" (hoặc khi approval hoàn tất), hệ thống mới gọi pdf-lib ở backend để ghi annotation vào PDF và tạo file mới (tăng version).Fabric.js canvas overlay — layer vẽ trên PDF pages
12h
Save/Load annotation — API endpoint lưu JSON vào DB
5h
Comment pin — ghim comment vào tọa độ cụ thể trên file
8h
Annotation permission — chỉ ai có quyền annotate mới được vẽ
3h
Phase 3 · Tuần 15–19
✅ Approval Workflow
Mục tiêu: Tự động hóa quy trình phê duyệt — từ submit, notify qua email, đến flatten PDF và lưu approval log đầy đủ.
3.1 — Approval Flow Builder
ApprovalFlowBuilder component — chọn approver và thứ tự
10h
Submit Submission — POST /api/submissions với file + flow
5h
ApprovalService — state machine: pending → in_review → approved/rejected
8h
Approval Dashboard — pending/approved/rejected submissions
8h
Approve/Reject UI trong FileViewer sidebar
6h
Approval templates — lưu flow tái sử dụng
4h
3.2 — Notification System
Email template — Approval Request (HTML email đẹp)
4h
Email templates — Approved / Rejected / Reminder
3h
In-app Notification center — bell icon topbar
8h
3.3 — PDF Flatten & Approval Stamp
📄 FlattenPdfJob — pdf-lib ghi annotation vào PDF
app/Jobs/FlattenPdfJob.php + Node.js microservice hoặc dùng pdf-lib trực tiếp
// Khi approval hoàn tất → dispatch job này class FlattenPdfJob implements ShouldQueue { public function handle(): void { // 1. Download PDF gốc từ S3 về temp $pdfBytes = Storage::disk('s3')->get($this->file->s3_key); // 2. Gọi Node.js microservice để flatten với pdf-lib // (pdf-lib là JS lib — gọi qua HTTP hoặc exec node script) $response = Http::post('http://pdf-service:3001/flatten', [ 'pdfBase64' => base64_encode($pdfBytes), 'annotations' => $this->annotations, // fabric_json array 'approvalStamp' => [ 'text' => "APPROVED", 'approver' => $this->approver->name, 'date' => now()->format('d/m/Y H:i'), ], ]); // 3. Upload PDF mới lên S3 → tạo version mới $newS3Key = str_replace('.pdf', '_v'.$newVersion.'.pdf', $this->file->s3_key); Storage::disk('s3')->put($newS3Key, base64_decode($response['pdfBase64'])); // 4. Mark annotations as flattened, file version mới Annotation::whereFileId($this->file->id)->update(['is_flattened' => true]); // dispatch SharePointUploadJob cho bản approved mới } }
📌 Về pdf-lib và Node.js
pdf-lib là thư viện JavaScript — chạy tốt nhất trong Node.js. Bạn cần tạo một microservice nhỏ (Express.js ~50 dòng) trong Docker container riêng để nhận request từ Laravel và flatten PDF. Claude có thể viết toàn bộ microservice này cho bạn trong 1 prompt.Node.js PDF microservice — Express + pdf-lib (Docker container)
6h
FlattenPdfJob — kết nối PHP → Node microservice
4h
Approval stamp design — watermark "APPROVED" chuyên nghiệp
3h
Approval history log — timeline đầy đủ mọi action
5h
Phase 4 · Tuần 20–24
⚙️ Settings, Security & Production
Mục tiêu: Hoàn thiện app — settings đầy đủ, security audit, deploy production, test với người dùng thực.
4.1 — Settings & Help
Settings — General: tên app, logo, timezone, ngôn ngữ
4h
Settings — Email/SMTP: cấu hình server email
4h
Settings — File: giới hạn dung lượng, loại file cho phép
3h
Help — trang hướng dẫn nội tuyến
4h
4.2 — Performance, Security & Deploy
Database indexing — index các cột query nhiều
4h
Security: Rate limiting, brute force protection
4h
S3 lifecycle rule — tự động archive file cũ
2h
Deploy production — VPS + SSL + CI/CD đơn giản
8h
Laravel Telescope — debug tool cho production
2h
Lưu ý sống còn
⚠️ Không được bỏ qua
🚨 1. Pháp lý — Không bao giờ xóa file_versions
Thêm
protected $guarded = ['*'] và override method delete() trong model FileVersion để throw Exception. Chỉ Super Admin mới được "archive" (soft delete với flag), không xóa vật lý. Trên S3: không enable Object Delete trên file_versions/ prefix.🚨 2. Bảo mật S3 — Không bao giờ expose URL trực tiếp
Tất cả S3 key phải là UUID — không đoán được. Bucket đặt Private hoàn toàn — Block all public access. Mọi truy cập đi qua
Storage::temporaryUrl() với TTL 15 phút. Không bao giờ lưu presigned URL vào DB.⚡ 3. File lớn — Bắt buộc dùng Uppy.js Multipart
PHP upload timeout mặc định 30s — file .rvt 50MB sẽ fail 100%. Uppy.js multipart bypass hoàn toàn PHP cho việc upload — file đi thẳng browser → S3 theo từng chunk 10MB. Laravel chỉ nhận thông báo khi complete.
⚡ 4. SharePoint Rate Limit — Graph API giới hạn 10,000 req/10 phút
Khi nhiều user upload cùng lúc, SharePoint jobs có thể bị throttle. Giải pháp: dùng exponential backoff trong Job retry, cache OAuth token (không request token mới mỗi lần), và monitor qua Horizon để detect bottleneck sớm.
Hướng dẫn
🤖 Cách dùng Claude hiệu quả nhất
✅ Prompt hiệu quả — càng cụ thể càng tốt
Khi gặp lỗi:
"Tôi đang dùng Laravel 11 + Sail. Chạy lệnh [paste lệnh] gặp lỗi [paste toàn bộ error]. File liên quan: [paste code file]. Đây là .env: [paste]. Hãy giải thích nguyên nhân và fix từng dòng."
Khi cần code mới:
"Tôi cần viết class SharePointDriver.php trong Laravel 11 để: (1) lấy OAuth2 token từ Azure với client_credentials, (2) upload file nhỏ <4MB bằng PUT request, (3) upload file lớn bằng createUploadSession + chunk 10MB. Credentials lấy từ env MICROSOFT_*. Trả về sharepoint_file_id khi thành công."
Khi review code:
"Đây là FolderPolicy.php của tôi [paste]. Hãy kiểm tra: (1) có bị SQL injection không, (2) có case nào bị bypass permission không, (3) có thể tối ưu N+1 query không."
"Tôi đang dùng Laravel 11 + Sail. Chạy lệnh [paste lệnh] gặp lỗi [paste toàn bộ error]. File liên quan: [paste code file]. Đây là .env: [paste]. Hãy giải thích nguyên nhân và fix từng dòng."
Khi cần code mới:
"Tôi cần viết class SharePointDriver.php trong Laravel 11 để: (1) lấy OAuth2 token từ Azure với client_credentials, (2) upload file nhỏ <4MB bằng PUT request, (3) upload file lớn bằng createUploadSession + chunk 10MB. Credentials lấy từ env MICROSOFT_*. Trả về sharepoint_file_id khi thành công."
Khi review code:
"Đây là FolderPolicy.php của tôi [paste]. Hãy kiểm tra: (1) có bị SQL injection không, (2) có case nào bị bypass permission không, (3) có thể tối ưu N+1 query không."
📚 Tài nguyên học Laravel cho PHP dev (thứ tự ưu tiên)
1. Laracasts.com — "Laravel From Scratch" series (miễn phí) — xem song song với code
2. laravel.com/docs — Documentation chính thức — search khi cần feature cụ thể
3. spatie.be/docs — Docs của Spatie packages (Permission, ActivityLog)
4. Claude — Debug lỗi, explain concept, review code, generate boilerplate
5. Laravel Daily (YouTube) — Video ngắn về từng tính năng thực tế
2. laravel.com/docs — Documentation chính thức — search khi cần feature cụ thể
3. spatie.be/docs — Docs của Spatie packages (Permission, ActivityLog)
4. Claude — Debug lỗi, explain concept, review code, generate boilerplate
5. Laravel Daily (YouTube) — Video ngắn về từng tính năng thực tế