Shorten URL

Frontend
Backend
DevOps
Shorten URL

Tech stack

Laravel
MySQL
Docker
CI/CD
AWS

Project breakdown

Shorten URL - Modular Laravel Monolith

Client workspace · Group-based RBAC · Redirect expiry and click tracking

Role: Solo developer. I designed the modular architecture, validation rules, and deployment flow.

Laravel 10 · PHP 8.1 · MySQL 8 · Blade · AdminLTE 3 · Docker Compose · Nginx · spatie/laravel-permission · nwidart/laravel-modules

View Source Code

This project separates one Laravel application into three clear surfaces: public redirects, admin back office, and a client-facing workspace. The goal was not CRUD alone, but putting business rules such as RBAC, per-user uniqueness, and redirect expiry into the correct layers.


System Architecture

I chose a modular monolith because the domains are tightly coupled. Shared auth context, one runtime, and one database made more sense than splitting the application into multiple services at this scale.


Problem: A useful URL shortener needs more than a create form. Users want filtering, custom aliases, tags, archived states, detail views, and batch-like management without bouncing through multiple screens.

Solution: Build a dedicated client workspace while reusing the same domain logic as the admin surface.

Implementation highlights:

  • Client routes live under a dedicated namespace to keep boundaries clear
  • Create, update, archive, delete, and tag management delegate to the same controllers and repositories used elsewhere
  • Validation rules encode global and per-user uniqueness constraints
  • Repository methods hydrate tag relationships so edit forms can be prefixed correctly

Result: Users get a focused workspace while the business rules remain centralized instead of drifting between admin and client implementations.


RBAC by Group and Permission Matrix

Problem: The admin surface spans many resources and actions, and hard-coded roles on the user record are too rigid once groups and permission editing enter the picture.

Solution: Map business groups to roles, seed permission matrices by module/action, and let the admin surface edit those permissions safely.

Implementation highlights:

  • Seeder-driven permission generation by module and action
  • Each business group owns a role mapping
  • User updates sync group membership and the assigned role together
  • Route middleware blocks regular users from the admin namespace before controller logic runs
  • Permission forms load and sync the full matrix through Spatie permissions

Result: The authorization model scales with the product instead of remaining a fragile collection of if-statements.


Public Redirect with Expiry and Click Tracking

Problem: A redirect endpoint that only looks up a record and forwards the request misses business meaning. Expired links, missing links, and click tracking all need explicit behavior.

Solution: Treat public redirect as a first-class access flow with HTTP semantics and state mutation.

Implementation highlights:

  • Catch-all route reserved for short codes only
  • Access controller performs the lookup and decides between 404 and 410
  • Successful access increments clicks and extends expiry where the product requires it
  • Redirect logic stays small, but the surrounding validation and state rules remain explicit

Result: Redirects become observable business behavior rather than anonymous helper logic.


CI/CD & Deploy

  • Docker Compose for both local and production variants
  • Separate deployment files for production and CI-driven delivery
  • HTTPS-aware configuration and explicit routing boundaries so catch-all redirects stay safe

Key screens

Client Link Workspace

Client-facing workspace for creating links, editing aliases, managing tags, and reviewing link state.

Admin Dashboard

Admin surface for system overview, user/group administration, and permission-driven management tasks.