API
Stack: Laravel 12, MySQL, Redis (queue + cache), Reverb (WebSockets), Stancl Tenancy, Sanctum, Spatie Laravel Permission.
The API is the hub: the admin panel, POS frontend, and storefront all talk to it, and it owns both the central database and every tenant’s database. See Architecture for the multitenancy model this is all built around.
Route surfaces
Section titled “Route surfaces”| File | Scope | Notes |
|---|---|---|
routes/api.php |
Central, no tenant header | Tenant resolution, Tuma callback, loads routes/admin.php |
routes/admin.php |
Central, admin-only | Everything the admin panel calls |
routes/tenant.php |
Tenant, requires X-Tenant-ID |
Everything the POS frontend calls; middleware api, InitializeTenancyByRequestData, CheckSubscriptionStatus |
Modules
Section titled “Modules”Business logic lives in modules/{ModuleName}/ rather than in one flat app/. See Modules for the per-module business-logic docs (in progress).
- Registered in
config/modules.php’senabledarray. App\Providers\ModulesServiceProvidermerges each module’s config, registers its service provider, loads its migrations, views, and lang files.- A module in
tenantRouteModules(currently: Inventory, StockTransfer, ReceiptSettings, Analytics, Tuma, Etims, CreditNotes) has its routes required directly fromroutes/tenant.phprather than auto-loaded. Everything else loads its ownModules/.../Routes/*with standardapimiddleware.
Full module list today: Accounting, Analytics, Approvals, CreditNotes, Ecommerce, Etims, HR, Integrations, Inventory, Jobs, Pdfs, Production, Promotions, Purchasing, ReceiptSettings, Repair, SaleCustomers, Sales, StockTransfer, Tax, Tuma.
Sanctum, token-based, shared shape across Admin and POS. Inside a tenant, authorization is Spatie Laravel Permission, seeded per tenant on creation.
Background jobs
Section titled “Background jobs”Queue workers you’ll typically need running locally, depending on what you’re touching:
php artisan queue:work --tries=3 --timeout=90 # defaultphp artisan queue:work central --queue=backups --tries=3 --timeout=90 # DB backups (central queue connection)php artisan queue:work redis --queue=inventory-import --tries=2 --timeout=200 # stock CSV import chunksphp artisan queue:work --queue=platform-migrations --tries=1 --timeout=3600 # platform architecture migration backfillsphp artisan reverb:start --debug # WebSocket serverDatabase backups
Section titled “Database backups”Central DB and every tenant DB back up to Cloudflare R2, scheduled at 07:00, 12:00, 14:00, 23:00 EAT. Backup jobs run on the central queue connection. Manual triggers live in Admin → Backups. Only super_admin can restore; central restores go only to a staging database. See docs/PRODUCTION_BACKUPS_AND_SCHEDULER.md in the API repo for production Supervisor/cron setup.
Before you touch the database
Section titled “Before you touch the database”Read Conventions → Database safety first. There’s a real incident behind that rule, not a hypothetical one.