Vai al contenuto
Spedizione in 24/48h in tutta Italia
Vai al contenuto
Navigazione documentazione

Questa pagina non è ancora disponibile nella lingua scelta. È mostrata la versione EN.

Tenant JSON field disposition

Tenant JSON identifies a tenant, locates its database, and carries deployment policy needed before tenant settings can be read. The configured database is not the source for its own locator. TenantConfigInventory classifies raw JSON paths; unknown paths fail the audit. The runtime TenantConfigRepository resolves environment placeholders, follows aliases and normalizes absent module_config to an empty array. Its optional disk cache stores only that resolved JSON configuration and invalidates on source digest, mtime or referenced environment changes. A DB-backed effective tenant snapshot must remain separate from both raw JSON and its cache.

This matrix was checked against canonical raw files on 2026-09-14: seven canonical configurations and one alias, with 54 distinct normalized leaf paths after safe omissions and zero unclassified paths. Numeric list positions are normalized to .*; an empty array or object contributes its parent path. Counts refer to the repository snapshot, not a live tenant database. No hostname, credential value or tenant-specific choice is recorded here.

Raw path(s) Owner and consumers Precedence and absence behavior Disposition
id Tenant resolver, context and bootstrap Required raw identity before DB access. Retain.
alias_of, redirect_to_canonical TenantConfigRepository host resolution Alias files are followed before canonical config is loaded; missing redirect means no forced canonical redirect. Retain only in alias files; audit aliases separately.
database.driver, database.provider, database.url, database.path, database.host, database.port, database.dbname, database.user, database.password, database.charset, database.sslmode Tenant DB connection factory and settings bootstrap JSON or allowed environment placeholder determines the connection; no DB fallback can locate its own DB. Driver/path are present in every canonical file; other fields are connection-shape dependent. Retain locator/topology and pre-DB credentials. Do not expose through backoffice.
boot_profile TenantContext, ModuleBootstrapper, container and route caches Missing or invalid value falls back to full. Retain when selecting a non-default deployment footprint; an omitted default follows code.
modules.* Module catalog, active module resolver, migration/install paths Deployment allowlist is read before container/module states; DB module states govern requested activation within it. Retain. The two full development tenant inventories remain complete.
fixtures.enabled, fixtures.enabled.* TenantContext and fixture runner Missing or empty selection enables no optional fixture pack. Retain nonempty install-time choices; empty selection can be omitted after install-flow equivalence.
features.require_change_verification Security definitions for account verification Missing value means verification required. Retain explicit deployment safety policy, particularly intentional development exceptions.
compilation.* TenantContext, config/container/route cache factories Absent compilation object disables compilation; optional subflags default within an enabled object. No canonical leaf currently uses it. Retain as deployment-only when intentionally enabled.
theme.front, theme.admin Early module compatibility and theme wrapper selection, render profile, email; coordinated DB theme selection is the target owner Legacy JSON pair supplies migration fallback only while the aggregate row is absent. A valid DB aggregate wins; malformed present DB data is an error. Removed from all seven configured JSON files after five rendering-tenant DB readbacks and two lite default-pair equivalence checks. The lite tenants exclude theme wrappers and have no theme aggregate.
theme.overrides, theme.overrides.* Legacy route resolver and theme-wrapper synchronization interpret values differently Empty object and absent key both yield no overrides. No canonical nonempty object was found. Five empty objects removed. Preserve any external nonempty override pending separate contract review; no editor in this change.
i18n.default_locale Locale middleware and HTTP, email/import/search consumers JSON is a legacy fallback only if the core DB setting is absent; chosen locale must belong to supported locales. Removed from all seven configured JSON files after DB readback.
i18n.documentation_locale Documentation module fallback catalog JSON is a legacy fallback only if the module-owned DB setting is absent; installed catalogs constrain values. Removed from five Documentation-enabled tenant JSON files after DB readback. The two lite tenants exclude Documentation and had exact en compatibility defaults, so those redundant fields were omitted without DB rows.
i18n.supported_locales.* RequestPrivacy, SideDetectionMiddleware, locale middleware and localized content owners Read before routing; missing consumers have differing code fallbacks, so omission is not equivalent. Retain as deployment policy; changing it requires a separate privacy/routing contract.
search.engine, search.sql.table, search.modern.provider, search.modern.enabled, search.modern.endpoint, search.modern.index, search.modern.index_per_tenant, search.fallback.enabled Search adapter selection, indexes and failover Deployment topology and provider-specific defaults; absent modern settings do not imply a safe switch to another provider. Retain technical topology. Review redundant fields only against every search consumer in a separate tranche.
module_config.redis.host, module_config.redis.port, module_config.redis.db, module_config.redis.password Shared Redis connection Process/worker transport connection; AiModuleConfig can fall back to this Redis object. Retain topology/credential fields.
module_config.queue.name, module_config.queue.driver, module_config.queue.max_attempts, module_config.queue.redis.host, module_config.queue.redis.port, module_config.queue.redis.db, module_config.queue.redis.password, module_config.queue.redis.prefix, module_config.queue.worker.slot, module_config.queue.worker.sleep, module_config.queue.worker.max_idle, module_config.queue.worker.max_jobs, module_config.queue.worker.reclaim_after, module_config.queue.worker.reclaim_interval, module_config.queue.worker.reserve_timeout Queue transport, topology registry and worker CLI Transport/worker topology is resolved at startup; several values have code defaults but an explicit deployment pin can be intentional. Retain until a separately measured worker/topology default audit establishes omission intent. No general backoffice editor.
module_config.ai.advanced.queue, module_config.ai.advanced.worker_heartbeat_max_age_seconds, module_config.ai.advanced.python.binary, module_config.ai.advanced.python.script, module_config.ai.advanced.python.working_directory, module_config.ai.advanced.python.timeout_seconds AI worker/process settings Worker executable paths and limits apply at process startup. Retain deployment/process policy.
module_config.ai.redis, module_config.ai.redis.host, module_config.ai.redis.port AiModuleConfig transport selection An absent AI Redis object falls back to shared module_config.redis; an explicitly empty AI object selects AI's bounded host/port defaults instead. Retain explicit empty objects until the transport fallback semantics are reviewed.
module_config.ai.history_limit, module_config.ai.chat.max_prompt_length, module_config.ai.upload.max_file_size_mb, module_config.ai.upload.max_extracted_characters, module_config.ai.rate_limit.reply_per_minute, module_config.ai.rate_limit.document_upload_per_minute, module_config.page.max_revisions AiModuleConfig, AiFeatureSettings, Page revision service All 35 previously present scalar values were exactly equal to the corresponding code fallbacks. Missing keys use those fallbacks in the same consumers. Omitted from five canonical files. This intentionally follows bounded code defaults on future releases; reintroduce an explicit policy pin when a deployment must hold a particular ceiling. AI history count is prompt context, not stored-history retention; Page pruning can delete revisions.
empty top-level module_config TenantConfigRepository normalization Missing and empty object both resolve to module_config: []. Two empty objects removed.

The classification is a boundary, not permission to mutate every classified field. Backoffice-editable settings use their declared owner, validation, ACL, audit and DB storage. A legacy JSON fallback is read-only during cutover. After the 2026-09-14 per-tenant readback and JSON cleanup, DB values are authoritative for theme and locale choices in five rendering tenants, and default locale in the two lite tenants; tenant identity, connection, module allowlist and early safety policy remain deployment-owned.

Cutover verification on 2026-09-14: seven SQLite databases and eight JSON files (including the alias) had private, integrity-checked backups; a restored copy was opened successfully. Readback confirmed five theme aggregates, seven core default locales and five Documentation locales before removing their JSON counterparts. Fresh CLI diagnostics and raw-key audits passed for all seven canonical tenants. An isolated restarted-process check rendered notification email in the new DB default locale. A paired 100-iteration disposable-SQLite bootstrap measurement found one connection and four SQL reads versus the prior one state read; median times were 1.079 ms and 0.871 ms, respectively. These local timings are indicative, not a deployment latency guarantee. PostgreSQL portability remains untested in this PHP environment because pdo_pgsql is unavailable.

To reproduce the raw path audit without printing configuration values:

php -r 'require "vendor/autoload.php"; $inventory = new K0smos\Tenant\TenantConfigInventory(); $paths = []; $unknown = []; $canonical = 0; $aliases = 0; foreach (glob("config/tenants/*.json") ?: [] as $file) { $raw = json_decode(file_get_contents($file), true, 512, JSON_THROW_ON_ERROR); if (isset($raw["alias_of"])) { $aliases++; continue; } $canonical++; foreach ($inventory->audit($raw) as $row) { $paths[$row["path"]] = true; if ($row["category"] === "unknown") $unknown[$row["path"]] = true; } } printf("canonical=%d aliases=%d paths=%d unknown=%d\n", $canonical, $aliases, count($paths), count($unknown));'

tenant:config:audit reads the running tenant's raw canonical JSON through findRawByHost(); it does not count synthetic DB overlay fields. The command above is the reproducible repository-wide inventory, including alias counts.