How routing works
Tenants are identified by theirslug field. The routing strategy differs between environments.
In local development, the microsite uses a path-based fallback at
/t/{tenant:slug}. In production, you configure subdomain routing (e.g., {tenant}.yourdomain.com) via config/tenancy.php and Nginx. The path-based routes are always registered as a fallback for compatibility.Public tenant surfaces
| Route | Purpose |
|---|---|
/t/{tenant} | Public microsite (catalog, SEO, checkout) |
/t/{tenant}/book | Public booking and appointment page |
/appointments/{appointment}/manage | Signed URL portal for appointment self-management |
/registrar-negocio | Public business registration form |
The Tenant model
TheTenant model (app/Models/Tenant.php) is the central entity of the platform. It owns all business data and drives plan-gated capabilities.
Core attributes
What a Tenant owns
Catalog
Products, menu sections, modifier groups, product option groups, and gallery images.
Sales
Orders, order items, order events, payments, and subscription payments.
Bookings
Services, service providers, appointments, and opening hours.
Marketing
Coupons, campaigns, announcements, leads, and follower relationships.
Loyalty
Loyalty program configuration, rewards catalog, and ledger entries.
Analytics
Tenant visits, aggregated daily analytics, and interaction tracking.
Relationships defined on Tenant
Tenant isolation
Data isolation is enforced at two layers.BelongsToTenant trait
All tenant-owned models use theBelongsToTenant trait (app/Infrastructure/Persistence/Eloquent/Traits/BelongsToTenant.php). It automatically scopes every Eloquent query to the current authenticated tenant and sets tenant_id on creation.
Route-level middleware
API routes protected bytenant.ownership middleware verify the authenticated user’s tenant matches the requested resource before any controller logic executes.
Tenant creation flow
Public registration
A business owner visits
/registrar-negocio. The React/Inertia form is served by RegisterTenantController@create. The POST endpoint is rate-limited to 5 attempts per minute.Slug uniqueness check
The UI calls
GET /api/check-slug before submission to verify slug availability without full form submission.Atomic registration
RegisterTenantController@store creates the User and Tenant records in a single database transaction. The tenant starts on the semilla plan.Payment (optional)
For paid plans, the owner is redirected to
/registro/pago-pendiente/{payment} to monitor payment confirmation status.Plan system
Subscription statuses
| Status | Label | Can use PRO features |
|---|---|---|
active | Activo | Yes |
trial | Período de Prueba | Yes |
past_due | Vencido | No |
canceled | Cancelado | No |
Capability gating
Feature flags are evaluated at runtime through theCapabilityManagerInterface:
getPublicMenuStructure() method is an example of plan-gated data access — it returns null for non-pro tenants, triggering the fallback flat product list.
Media collections
TheTenant model registers three Spatie Medialibrary collections:
thumb (400×400) and optimized (800px WebP at 80% quality).
Activity logging
TheTenant model uses Spatie Activitylog. It logs changes to name, is_active, plan_type, and subscription_status under the negocios log name, with dirty-only tracking to suppress no-op updates.