Shorten URL - Hệ thống rút gọn liên kết

Frontend
Backend
DevOps
Shorten URL - Hệ thống rút gọn liên kết

Tech stack

Laravel
MySQL
Docker
CI/CD
AWS

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

Xem Source Code

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.


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_half unique toàn cục; titlelong_url unique theo user_id — rule encode trong FormRequest
  • UrlRepository, TagRepository quản lý pivot url_tag; detail fetch tags + 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ảng modules metadata, role mặc định (super_administrator, administrator, user), permission theo module + action (xử lý edge case view users vs view 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:user redirect regular user khỏi /quan-tri-vien; controller/view dùng checkPermission() 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 clicks trước redirect; dời expired_at thê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/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.