
Tech stack
Chi tiết dự án
Shorten URL — Modular Laravel Monolith
Workspace cho client · RBAC theo group · Redirect có expiry và click tracking
Vai trò: Solo developer. Tôi thiết kế kiến trúc theo module, viết validation rule và triển khai luồng deploy.
Laravel 10 · PHP 8.1 · MySQL 8 · Blade · AdminLTE 3 · Docker Compose · Nginx · spatie/laravel-permission · nwidart/laravel-modules
Project này tách một ứng dụng Laravel thành 3 bề mặt rõ ràng: public redirect, admin back office và workspace cho client. Trọng tâm không chỉ là CRUD mà là đặt rule nghiệp vụ đúng chỗ: phân quyền, uniqueness theo user và trạng thái hết hạn của link.
Kiến trúc Hệ thống
Chọn modular monolith vì nhiều domain liên kết chặt (user, group, permission, tag, url, redirect). Một Laravel app giúp build nhanh, trace request end-to-end, phù hợp quy mô hơn so với tách microservice. Chia module theo boundary business: code dễ đọc hơn app phẳng, vẫn shared runtime, shared DB và shared auth context.
Workspace quản lý short link end-to-end
Vấn đề: User có nhiều short link cần xem trạng thái, filter theo tag/thời gian, biết link custom back-half, bulk ẩn/khôi phục, edit không nhảy nhiều page. Viết riêng logic client dễ lặp với admin; gộp hết về admin thì UX end-user nặng và sai context.
Giải pháp: Client workspace riêng tại /trang-ca-nhan/links, reuse domain flow của Url, Tag và User module để business rule nhất quán.
Cách thực hiện:
- Route client namespace
/trang-ca-nhan— boundary rõ với admin, tránh catch-all redirect nuốt route ClientController@links: filter tags, custom link flag, khoảng thời gian, trạng thái archived — đúng nhu cầu quản lý thực tế- Create, update, hide, active, delete delegate sang UrlController/TagController/UserController qua container — một persistence path duy nhất
UrlRequest:back_halfunique toàn cục;titlevàlong_urlunique theouser_id— rule encode trong FormRequest- UrlRepository, TagRepository quản lý pivot
url_tag; detail fetchtags+other_tagsđể modal edit prefill đúng
Kết quả: Workspace gom toàn bộ flow short link (tạo, sửa, xoá, tag, filter, detail, bulk archive). Client flow bám chung rule với admin/domain — giảm drift nghiệp vụ.
RBAC theo group và permission matrix
Vấn đề: Admin có nhiều resource (group, user, tag, url), mỗi loại nhiều action (view, show, create, edit, delete); group còn permission riêng. Role cứng trực tiếp cho user khó mở rộng khi quản lý theo nhóm. Regular user phải chặn khỏi admin ngay từ route, không chờ tới lúc query mới fail.
Giải pháp: Map business group sang role trong hệ thống permission, seed permission theo module/action; admin phân quyền từ UI.
Cách thực hiện:
GroupDatabaseSeeder: bảngmodulesmetadata, role mặc định (super_administrator, administrator, user), permission theo module + action (xử lý edge caseview usersvsview user)- Mỗi group lưu
role_id; tạo group mới → GroupController tạo role slug → gắn role vào group - UserController create/update: lookup group → lấy role →
assignRole/syncRoles— user-role không lệch group membership - Route: middleware
check.role:userredirect regular user khỏi/quan-tri-vien; controller/view dùngcheckPermission()theo action - Permission form: load module + permission hiện tại của group → sync qua Spatie
syncPermissions()— permission change là admin operation
Kết quả: Authz model linh hoạt cho admin + client surface. Mapping rõ giữa business group, route guard, permission matrix và UI visibility. Thêm resource mới: thêm module + permission seed + controller checks.
Public redirect có expiry và click tracking
Vấn đề: Redirect đơn giản lookup → redirect không phân biệt link không tồn tại vs link hết hạn, không ghi nhận trạng thái sử dụng.
Giải pháp: Route catch-all /{backHalf} (regex alphanumeric), AccessController lookup theo back_half; HTTP semantics rõ (404 vs 410), tăng clicks và gia hạn expired_at khi dùng.
Cách thực hiện:
- Route
/{backHalf}dành URL space cho short code; admin/client qua prefix rõ, auth qua.html - AccessController lookup theo
back_half— flow public-facing - 404 nếu link không tồn tại, 410 nếu expired — dễ debug và monitor
- Tăng
clickstrước redirect; dờiexpired_atthêm 30 ngày phản ánh sử dụng gần đây Redirect::to($trueUrl)— flow ngắn, dễ trace
Kết quả: Redirect là request flow có state và error semantics, không chỉ helper function. Uniqueness: back_half global; title, long_url, tag title scoped theo user — encode trong FormRequest.
CI/CD & Deploy
- Stack: php-fpm + nginx + mysql qua Docker Compose;
docker/vàdeployment/docker/tách local vs production - Production:
docker-compose.prod.yml+.env.production, healthcheck container,URL::forceScheme('https')staging/production - Boundary: Admin/client prefix rõ để catch-all an toàn; deploy path là phần system design, không phải bước phụ sau khi code xong
Các màn hình chính
Workspace quản lý link
Khu vực phía client để tạo link, sửa alias, gắn tag và theo dõi trạng thái của từng short link.
Dashboard quản trị viên
Bề mặt quản trị cho tổng quan hệ thống, quản lý user/group và các tác vụ phụ thuộc quyền hạn.