Technical Architecture
A complete overview of the technology stack, application structure, data flow, and system design decisions behind Deprixa Plus.
Full Technology Stack
Frontend Layer
| Library / Tool | Version | Purpose | Notes |
|---|---|---|---|
| React | 18.3 | Core UI library — component model, hooks, state management | Functional components throughout, no class components |
| Inertia.js | 1.2 | Client/server bridge — eliminates the need for a REST API for page renders | Pages are React components, data is passed as props from Laravel controllers |
| Tailwind CSS | 4.0 | Utility-first CSS framework | Used with the Vite plugin for JIT compilation |
| Vite | 5.4 | Frontend build tool and dev server with HMR | Replaces Laravel Mix. Configured in vite.config.js |
| shadcn/ui | — | Pre-built accessible UI components (dialogs, dropdowns, tables) | Components are copied into the codebase and customized |
| Lucide React | 0.400 | Icon library — 1,400+ consistent SVG icons | Tree-shakeable, used throughout the UI |
| React i18next | 14.x | Internationalization — EN and ES language support | Translation files in resources/js/i18n/ |
| Recharts | 2.12 | Chart library for dashboard analytics | Line charts, bar charts, pie/donut charts for KPI visualization |
| Ziggy | 2.3 | Exports Laravel named routes to JavaScript | Allows using route() helper in React components |
Backend Layer
| Library / Tool | Version | Purpose | Notes |
|---|---|---|---|
| Laravel | 12.x | PHP application framework — routing, ORM, queues, events, validation | Built on PHP 8.2+ with modern PHP features |
| Spatie Laravel Permission | 6.x | Role and permission management, stored in database | Roles: super-admin, admin, manager, dispatcher, courier, accountant, customer |
| Spatie Laravel Activity Log | 4.x | Automatic audit logging for all Eloquent model events | Logs causer (user), subject (model), description, and metadata as JSON |
| Laravel Sanctum | 4.x | API token authentication for the REST API | SPA authentication uses Sanctum's cookie-based session for Inertia |
| Laravel Socialite | 5.x | OAuth 2.0 social login library (installed, not active in this version) | Package is present but social login routes are not enabled in the basic version. |
| Barryvdh DomPDF | 3.x | PDF generation for invoices, shipment labels, and reports | Uses Blade views as PDF templates |
| maatwebsite/excel | 3.x | Excel and CSV export for reports | Leverages Laravel queues for large exports |
| intervention/image | 3.x | Image processing for logo uploads and resizing | Requires GD or Imagick PHP extension |
Infrastructure Layer
| Component | Default | Alternative | Purpose |
|---|---|---|---|
| Database | MySQL 8.0 | MariaDB 10.6+ | Primary relational data store for all application data |
| Cache | Redis | File driver | Query result caching, view cache, rate limiting counters |
| Session | Redis | File / Database | User session storage. Redis recommended for multi-server deployments |
| Queue | Redis | Database / Sync | Background job processing — emails, PDF generation, report exports |
| File Storage | Local disk | AWS S3 / S3-compatible | Logos, shipment labels, employee documents, report files |
Project Folder Structure
The project follows standard Laravel conventions with additional directories for services, React components, and localization files.
deprixa-plus/ ├── app/ │ ├── Console/ │ │ └── Commands/ │ │ └── CleanActivityLog.php # Prune old audit log entries │ ├── Http/ │ │ ├── Controllers/ │ │ │ ├── Auth/ # Login, register, password reset, 2FA │ │ │ ├── Api/ # API v1 controllers │ │ │ ├── Settings/ # All settings sub-controllers │ │ │ │ ├── BrandingController.php │ │ │ │ ├── CompanyController.php │ │ │ │ ├── LocaleController.php │ │ │ │ ├── NotificationsController.php │ │ │ │ ├── SecurityController.php │ │ │ │ └── UpdatesController.php │ │ │ ├── ShipmentController.php │ │ │ ├── ClientController.php │ │ │ ├── InvoiceController.php │ │ │ ├── ReportController.php │ │ │ └── DashboardController.php │ │ ├── Middleware/ │ │ │ ├── CheckPermission.php # Spatie permission gate middleware │ │ │ └── HandleInertiaRequests.php # Shares global Inertia props │ │ └── Requests/ # Form request validation classes │ ├── Models/ │ │ ├── User.php │ │ ├── Shipment.php │ │ ├── ShipmentStatus.php │ │ ├── Client.php │ │ ├── Invoice.php │ │ ├── InvoiceItem.php │ │ ├── Branch.php │ │ ├── ServiceType.php │ │ └── Setting.php # Key-value settings store │ └── Services/ │ ├── ShipmentService.php # Business logic for shipments │ ├── InvoiceService.php │ ├── NotificationService.php │ └── ReportService.php ├── config/ │ ├── app.php │ ├── auth.php │ ├── database.php │ ├── filesystems.php │ └── permission.php # Spatie permission config ├── database/ │ ├── migrations/ │ │ ├── 0001_01_01_000000_create_users_table.php │ │ ├── create_shipments_table.php │ │ ├── create_clients_table.php │ │ ├── create_invoices_table.php │ │ ├── create_branches_table.php │ │ ├── create_settings_table.php │ │ └── create_activity_log_table.php # From spatie/laravel-activitylog │ └── seeders/ │ ├── DatabaseSeeder.php │ ├── RoleSeeder.php # Creates all roles and permissions │ ├── UserSeeder.php # Default admin user │ ├── SettingSeeder.php # Default company settings │ └── ShipmentStatusSeeder.php ├── public/ │ ├── index.php │ ├── build/ # Compiled frontend assets (Vite output) │ └── storage -> ../storage/app/public # Symlink (php artisan storage:link) ├── resources/ │ ├── js/ │ │ ├── app.jsx # Inertia app entry point │ │ ├── bootstrap.js │ │ ├── Components/ │ │ │ ├── Layout/ # Sidebar, topbar, breadcrumb │ │ │ ├── UI/ # shadcn/ui adapted components │ │ │ ├── Shipment/ # Shipment-specific components │ │ │ └── Charts/ # Recharts wrappers │ │ ├── Layouts/ │ │ │ ├── AuthLayout.jsx # Login/register page wrapper │ │ │ └── AppLayout.jsx # Main authenticated app wrapper │ │ ├── Pages/ │ │ │ ├── Auth/ # Login, Register, ForgotPassword, 2FA │ │ │ ├── Dashboard/ # Dashboard.jsx with KPI cards + charts │ │ │ ├── Shipments/ # Index, Create, Show, Edit │ │ │ ├── Clients/ │ │ │ ├── Invoices/ │ │ │ ├── Reports/ │ │ │ └── Settings/ # All settings sub-pages │ │ └── i18n/ │ │ ├── en.json # English translations │ │ └── es.json # Spanish translations │ └── views/ │ ├── app.blade.php # Inertia root template │ └── pdf/ # PDF Blade templates (invoices, labels) ├── routes/ │ ├── web.php # All Inertia page routes (authenticated) │ ├── api.php # REST API v1 routes (Sanctum) │ └── console.php # Scheduled command definitions ├── storage/ │ ├── app/ │ │ └── public/ # User uploads (accessible via symlink) │ ├── framework/ │ │ ├── cache/ │ │ ├── sessions/ │ │ └── views/ # Compiled Blade view cache │ └── logs/ │ └── laravel.log ├── .env # Environment configuration (not in git) ├── artisan # Laravel CLI entry point ├── composer.json ├── package.json └── vite.config.js
System Architecture Diagram
This diagram shows how the major system components interact at runtime.
Request Data Flow
Inertia.js Page Request (Authenticated Users)
- Browser sends an HTTP GET to
https://app.yourdomain.com/shipments - Nginx routes to PHP-FPM socket
HandleInertiaRequestsmiddleware runs, shares global props (auth user, flash messages, permissions, settings) with the React pageShipmentController@indexqueries the database with Eloquent, applies permission scopes, paginates results- Controller returns
Inertia::render('Shipments/Index', ['shipments' => ...]) - For full page loads: Laravel returns a full HTML page with the React app bootstrapped inside the Blade template
- For Inertia SPA navigations: Laravel returns a JSON response with
X-Inertiaheader — React swaps the page component without a full reload
API Request Flow (External Integrations)
- Client sends POST to
/api/tokenswithemail,password,device_name - Laravel validates credentials, creates a Sanctum personal access token, returns it in the response
- Client includes
Authorization: Bearer {token}header on subsequent requests - Sanctum middleware authenticates the token, loads the user with their Spatie roles and permissions
- API controller processes the request and returns JSON
Background Job Flow (Notifications, Exports)
- User triggers an action (e.g., mark shipment delivered)
- Controller calls a Service class method
- Service dispatches a queued Job (e.g.,
SendDeliveryNotification::dispatch($shipment)) - Job is serialized and pushed to the Redis queue
- Queue worker (running as a Supervisord process) picks up the job and executes it asynchronously
- On failure, the job is retried up to 3 times with exponential backoff
Authentication Architecture
Deprixa Plus supports four authentication methods:
| Method | Used By | Implementation |
|---|---|---|
| Email + Password | All users — primary login method | Laravel built-in auth with session cookies. Rate-limited to prevent brute force. |
| TOTP 2FA | Any user who enables it; enforced for admins if configured | Time-based One-Time Password (RFC 6238). Compatible with Google Authenticator, Authy, 1Password. |
| API Bearer Token | External integrations, mobile apps | Laravel Sanctum personal access tokens. Created via POST /api/tokens. Revocable. |
Inertia SPA vs. REST API
The Inertia frontend uses Laravel's session-based authentication (cookies) — not Bearer tokens. Bearer tokens are only for external API consumers. This means the Inertia app benefits from CSRF protection and traditional Laravel session security automatically.
Permissions Architecture (Spatie)
Deprixa Plus uses Spatie Laravel Permission for all access control. Permissions are stored in the permissions table and assigned to roles. Roles are assigned to users. The permission cache is stored in Redis.
// In a controller: checking permissions
public function destroy(Shipment $shipment)
{
$this->authorize('delete-shipments');
// or: Gate::authorize('delete-shipments');
// or: abort_unless(auth()->user()->can('delete-shipments'), 403);
$shipment->delete();
}
// In middleware (routes/web.php)
Route::middleware(['auth', 'permission:manage-settings'])
->prefix('settings')
->group(function () {
Route::get('/', [SettingsController::class, 'index']);
// ...
});
// In React (Inertia shared props)
// HandleInertiaRequests.php shares:
// $permissions = auth()->user()->getAllPermissions()->pluck('name')
// Used in React as: page.props.auth.permissions.includes('delete-shipments')
Dynamic Settings Store
Application settings (company info, branding, locale, notification preferences) are stored in a settings table as key-value pairs. This allows runtime configuration without modifying code or environment files.
CREATE TABLE settings (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
key VARCHAR(255) NOT NULL UNIQUE,
value TEXT,
type ENUM('string','boolean','json','integer') DEFAULT 'string',
group VARCHAR(100) DEFAULT 'general',
created_at TIMESTAMP,
updated_at TIMESTAMP
);
Settings are read with a typed helper and cached in Redis:
// Get a setting value with a default
setting('company.name', 'My Company');
// Set a setting
setting(['company.name' => 'Deprixa Plus Corp']);
// Flush settings cache (called automatically on save)
Cache::forget('app_settings');
Multi-Tenant Architecture
Deprixa Plus uses a single-database, shared-schema multi-tenancy model:
- Every data table includes an
organization_idcolumn - The
CheckTenantmiddleware automatically scopes all queries to the authenticated user's organization - Models use the
BelongsToTenanttrait for automatic query scoping - Data isolation is enforced at the query level — users in Organization A can never see data from Organization B
- Each organization can have its own branding (logo, colors, fonts), locale (language, timezone, currency), notification settings, rate cards, and shipment status workflows
- The Customer Portal allows end-customers to register, create pre-alerts, and track shipments within their organization's scope
Role Hierarchy
Super Admin ──→ Full access to everything + organization management
│
Admin ──→ Full operational + settings access within their organization
│
Employee ──→ Daily operations (shipments, customers, pickups, warehouse, import) — no financial data, no settings
│
Driver ──→ Assigned shipments and pickups only — dedicated mobile-friendly dashboard
│
Customer ──→ Self-service portal (My Locker, Pre-Alerts, Tracking, Contacts)