feat: subdomain routing por tenant — refac-xxx.nexusautoparts.com
- Nginx wildcard config: *.nexusautoparts.com routes to POS app with X-Tenant-Subdomain header - middleware_tenant.py: resolves subdomain -> tenant_id via nexus_master.tenants.subdomain - auth_bp: login and employee list endpoints accept tenant from subdomain, URL param, or body - login.html: auto-detects tenant from subdomain, shows business name, falls back to ?tenant=ID - tenant_manager: generates subdomain slug from business name on provision_tenant() - Migration v1.2: adds subdomain column + unique index to tenants table - setup-nginx.sh: one-command install script for the nginx config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nexus Autoparts — Iniciar Sesión</title>
|
||||
<link rel="stylesheet" href="/pos/static/css/tokens.css" />
|
||||
<link rel="manifest" href="/pos/static/pwa/manifest.json" />
|
||||
<meta name="theme-color" content="#F5A623" />
|
||||
<style>
|
||||
|
||||
/* =====================================================================
|
||||
@@ -1124,10 +1126,23 @@
|
||||
/* ------------------------------------------------------------------
|
||||
TRIGGER LOGIN (demo)
|
||||
------------------------------------------------------------------ */
|
||||
// Get tenant_id from URL or localStorage
|
||||
var tenantId = new URLSearchParams(window.location.search).get('tenant')
|
||||
// Tenant resolution: subdomain (server-side) > URL param > localStorage
|
||||
var _serverTenantId = {{ tenant_id | default('null') | tojson }};
|
||||
var _serverTenantName = {{ tenant_name | default('null') | tojson }};
|
||||
var _serverSubdomain = {{ tenant_subdomain | default('null') | tojson }};
|
||||
|
||||
var tenantId = _serverTenantId
|
||||
|| new URLSearchParams(window.location.search).get('tenant')
|
||||
|| localStorage.getItem('pos_tenant_id')
|
||||
|| '11'; // Default tenant — remove in production when multi-tenant selector exists
|
||||
|
||||
// Show business name from subdomain if available
|
||||
if (_serverTenantName) {
|
||||
var brandNameEl = document.querySelector('.brand-name');
|
||||
var brandSubEl = document.querySelector('.brand-sub');
|
||||
if (brandNameEl) brandNameEl.textContent = _serverTenantName;
|
||||
if (brandSubEl) brandSubEl.textContent = 'Punto de Venta';
|
||||
}
|
||||
// Device ID (persistent)
|
||||
var deviceId = localStorage.getItem('pos_device_id');
|
||||
if (!deviceId) {
|
||||
@@ -1277,10 +1292,14 @@
|
||||
------------------------------------------------------------------ */
|
||||
function loadEmployees() {
|
||||
if (!tenantId) {
|
||||
document.getElementById('usersGrid').innerHTML = '<div style="text-align:center;padding:var(--space-4);color:var(--color-error);">No se especificó tenant. Agrega ?tenant=ID a la URL.</div>';
|
||||
document.getElementById('usersGrid').innerHTML = '<div style="text-align:center;padding:var(--space-4);color:var(--color-error);">No se especificó tenant. Agrega ?tenant=ID a la URL o usa un subdominio.</div>';
|
||||
return;
|
||||
}
|
||||
fetch('/pos/api/auth/employees/' + tenantId)
|
||||
// If subdomain is set, the server already knows the tenant — use /employees endpoint
|
||||
var empUrl = _serverSubdomain
|
||||
? '/pos/api/auth/employees'
|
||||
: '/pos/api/auth/employees/' + tenantId;
|
||||
fetch(empUrl)
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
var grid = document.getElementById('usersGrid');
|
||||
@@ -1342,5 +1361,8 @@
|
||||
|
||||
</script>
|
||||
|
||||
<script src="/pos/static/js/sync-engine.js"></script>
|
||||
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user