ACTIVE FILES ADDED / MODIFIED public/index.php Path: /home/zyvio/public_html/portal/public/index.php Added tenant resolution logic before Symfony Kernel instantiation. Reads CENTRAL_DATABASE_URL and uses TenantResolver to find a tenant by host/subdomain. When a tenant is found and active, builds tenant DSN and injects DATABASE_URL into environment: putenv("DATABASE_URL=..."); $_ENV['DATABASE_URL'] = ...; $_SERVER['DATABASE_URL'] = ... Overrides session save path to var/sessions/{env} to avoid permission issues. Keeps Symfony boot intact so Doctrine and services use the injected tenant DB. Error reporting / debugging lines added for development. src/MultiTenant/TenantResolver.php Path: src/MultiTenant/TenantResolver.php New class that connects to the CENTRAL_DATABASE_URL and looks up tenants by host/subdomain. Returns tenant metadata including: id, name, subdomain, status, db_host, db_port, db_name, db_user, db_pass. Central single point of truth for tenant discovery. .env.local Path: project root (.env.local) Added/required variable: CENTRAL_DATABASE_URL=mysql://zyvio_Master:@127.0.0.1:3306/zyvio_Main public/admin/ (standalone Tenant Admin panel) Path: public/admin/index.php (and optional includes under public/admin/includes/) A self-contained PHP script (outside Symfony) that connects to zyvio_Main using zyvio_Master. Functionality: • List tenants (reads tenants table) • Create tenant (inserts name, subdomain, plan, status and populates db_host, db_port, db_name, db_user, db_pass) • Edit tenant (updates name, subdomain, plan, status) All PDO operations wrapped in try/catch with error messages. Meant to be served directly (URL below); keep it behind auth in production. public/.htaccess (recommended tweak) Path: public/.htaccess Optional rewrite rule tweak to ensure directories are served directly (so public/admin/ is not rewritten to Symfony): RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [QSA,L] TENANTS TABLE (CENTRAL) Table: tenants (in database zyvio_Main) Columns used/expected: id (PK, int) name (varchar) subdomain (varchar, unique) ← resolver matches host to this plan (varchar) status (varchar) ← e.g. active, suspended db_host (varchar) db_port (int) db_name (varchar) db_user (varchar) db_pass (varchar) ← stored currently in plaintext (see security) created_at (timestamp) (optional) How it’s used: The TenantResolver queries this table to obtain DB connection parameters for the incoming request’s host/subdomain. The admin panel reads/writes this table to create, list, and update tenant records. Suggested SQL (example) to create the table: CREATE TABLE tenants ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, subdomain VARCHAR(255) NOT NULL UNIQUE, plan VARCHAR(50) NOT NULL DEFAULT 'basic', status VARCHAR(50) NOT NULL DEFAULT 'active', db_host VARCHAR(255) NOT NULL, db_port INT NOT NULL DEFAULT 3306, db_name VARCHAR(255) NOT NULL, db_user VARCHAR(255) NOT NULL, db_pass VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; HOW A REQUEST FLOWS (STEP-BY-STEP) Request arrives at https://.zyvio.app/ and hits public/index.php. public/index.php reads CENTRAL_DATABASE_URL and uses TenantResolver to find a tenant row by host/subdomain. If tenant found and status == 'active', a tenant DSN is constructed and set into environment (DATABASE_URL). Symfony Kernel boots and Doctrine connects to the tenant database (the injected DATABASE_URL). If no tenant is found, the app falls back to configured behavior (404 or main site). STANDALONE ADMIN PANEL URL Place files under public/admin/ and visit: Recommended: https://zyvio.app/portal/public/admin/ If you put index.php directly under portal/admin: https://zyvio.app/portal/admin/index.php Note: Ensure public/.htaccess allows serving directories (see htaccess tweak above), or put the files into the exact webroot path the server serves. COMMANDS & DEV NOTES Clear Symfony cache after environment changes: php bin/console cache:clear --env=dev php bin/console cache:clear --env=prod Quick resolver test (example): resolveFromHost('next.zyvio.app')); If public/admin shows Symfony 404 or Twig error: verify that public/.htaccess doesn’t rewrite directories to Symfony's index.php (see htaccess tweak).