Back to portfolio
Case Study · B2B Web App

Document Portal

A secure document management portal built for construction companies to share project files with clients, subcontractors, and consultants — with granular three-level access control, secure file delivery, queued email notifications, and per-deployment brand theming.

Screenshots / app walkthrough

The Challenge / why this exists

The Problem

  • Construction projects involve multiple parties — clients, subcontractors, consultants — each needing access to different documents
  • Sharing files via email or Dropbox offers no access control: anyone with a link can see everything
  • Generic cloud storage doesn't support role-based access at the folder or individual file level
  • No audit trail: companies can't know who viewed or downloaded which document, and when

The Solution

  • A dedicated portal where each user sees only the projects, folders, and files they're explicitly granted access to
  • Three-level access hierarchy: full project, specific folders, or individual files — with per-permission flags for view, download, and notifications
  • All files served through the controller — never exposed as public URLs — so access checks run on every request
  • Full audit log of every view and download event, with IP address and user agent

Tech Stack / what powers it

A clean Laravel 11 monolith with Blade + Alpine.js, deployed to standard shared PHP hosting on SiteGround. SQLite for development, MySQL for production. Each client gets their own installation and domain.

Backend

Laravel 11 PHP 8.4 Queued Jobs

Frontend

Tailwind CSS v4 Alpine.js Blade Templates

Database

SQLite (dev) MySQL (prod) Database Sessions

File Storage

Local (private) AWS S3 (optional) Controller-served

Hosting

SiteGround Per-client deploy Cron queue worker

Auth & Security

Session-based auth Role middleware Active user enforcement

Key Features / what it does

Three-Level Access Control

Grant access at the full project level, specific folders, or individual files. Each level has its own permission flags: can view, can download, notify on new upload. When saving, lower-level records are cleared automatically to keep access clean.

Secure File Delivery

Files are stored outside the public directory and never accessible via direct URL. Every view or download request goes through the controller, which checks access before serving the file. Switching to S3 requires only an env variable change.

Role System

Five roles: admin (full system access), staff (can upload, limited admin panel), subtrade, consultant, owner (access via access records only). Role middleware protects routes. Inactive users are kicked out on every request.

Folder Hierarchy

Projects have nested folder structures with parent/child relationships and sort order. Admins can create, rename, and delete folders. Users see only the folders they have access to.

Document Upload

Upload PDF, DOCX, XLSX, DWG, PNG, JPG files up to 51MB. Files are stored with a project-scoped path. On upload, a queued notification job emails all users with notify permissions for that project.

Email Notifications

When a document is uploaded, a queued job dispatches email notifications to all users with notify_on_new_document enabled at the project level. Queue runs via database driver — no Redis needed, cron-triggered on SiteGround.

Access Audit Log

Every view and download is logged with user, document, action, IP address, and user agent. Admins have a dedicated log viewer to track who accessed what and when.

Per-Client Brand Theming

Each client deployment has its own brand color set via APP_COLOR in .env. The color is injected as a CSS custom property at runtime — no asset rebuild required. Navigation, buttons, and badges all pick up the brand color automatically.

User Management

Admin CRUD for users with role assignment and active/inactive toggle. Deactivated users are immediately locked out on their next request via middleware. Last login time is tracked per user.

Multi-Tenant by Design

Each client gets a completely separate Laravel installation on their own domain or subdomain — no shared database, full data isolation. Setting up a new client means cloning the repo, configuring .env, and seeding their admin user.

Architecture / how it works

A classic Laravel monolith with Blade views and Alpine.js for interactivity. The AccessService centralizes all access decisions through static methods used across controllers and views.

Document Download Flow

User Request GET /documents/{id}/download
Auth Check Session + active user
AccessService Project / folder / file check
Access Log IP + UA recorded
File Response Served from storage

Upload & Notification Flow

Admin Upload POST /projects/{id}/documents
Store File storage/app/documents/
Dispatch Job NotifyNewDocument queued
Queue Worker Cron on SiteGround
Email Notifiable users

Like what you see?

I build production-ready B2B web apps — secure file management, role-based access, multi-tenant architecture, Laravel, deployed to real hosting. Let's talk about your project.