[ __DIR__ . '/../App/pages', __DIR__ . '/pages', ], 'cache_dir' => __DIR__ . '/../public/cache', 'debug' => true, // Site name used as the default page title, og:site_name, and the // footer copyright line in novaconium/pages/_layout/layout.twig. 'site_name' => 'Novaconium Website', // Extra project-specific values exposed to every Twig template as // globals, e.g. 'twig_globals' => ['company_name' => 'Acme Ltd.'] makes // {{ company_name }} available everywhere. Only keys listed here reach // Twig — the rest of this config (API secrets, DB paths) never does. A // key that collides with a framework global (site_name, matomo_url, // matomo_site_id, admin_auth_enabled, content_index_enabled, is_404) // is ignored; set those through their own config keys instead. See // /admin/docs/config. 'twig_globals' => [], // Matomo analytics. Leave both empty (the default) to disable tracking // entirely — the layout emits no tracking script at all in that case. // Set both via App/config.php to enable, e.g.: // 'matomo_url' => 'https://matomo.example.com/', // 'matomo_site_id' => '1', 'matomo_url' => '', 'matomo_site_id' => '', // Gates every /admin/* route (clear-cache, docs, users, and any future // admin page) behind a session login against the `users` table on // Lib\Db's default connection — see /admin/docs/admin-auth. The first // user created is the admin; users after that are 'registered', each // with an optional group, and see whatever content sidecars grant via // Lib\Access (see /admin/docs/access-control) — /admin/* itself 404s // for them. Off by default because it depends on SQLite (same // reasoning as content_index_enabled below): when false, /admin/* is // wide open, /admin/login, /admin/logout, and /admin/users 404, // Access::require() allows everything, and nothing ever touches // Lib\Db because of this feature. After enabling it via // App/config.php, create the first user at /admin/users (open access // until at least one user exists) or with: // php novaconium/bin/create-admin-user.php 'admin_auth_enabled' => false, // Lib\Db (see /admin/docs/database) — named, simultaneously-usable // connections, keyed by name; 'default' is the only one required. A // sidecar can use more than one at once, e.g. Db::query(...) (default) // alongside Db::query(..., 'legacy'). Supported drivers: 'sqlite', // 'mysql'. The default connection's path deliberately lives outside // both public/ (must never be web-accessible) and novaconium/ (gets // wholly replaced on a framework update — see // /admin/docs/getting-started's "Updating the framework" section) — a // top-level data/ directory, project-owned like App/, is the only safe // place for it. migrations_dir is optional per connection (omit it to // never run migrations against that connection, e.g. a read-only // legacy database) and accepts either one path or an ordered list of // roots — the default connection lists novaconium/migrations/ (framework // -shipped schema, e.g. the content index — see /admin/docs/content-index) // before App/migrations/ (project migrations), so framework migrations // always apply first. NOTE: unlike every other key here, App/config.php // merges into db_connections one level deeper than a normal shallow // override — see the comment on Lib\Db::config() — so adding a second // connection there doesn't require repeating 'default'. 'db_connections' => [ 'default' => [ 'driver' => 'sqlite', 'path' => __DIR__ . '/../data/novaconium.sqlite', 'migrations_dir' => [ __DIR__ . '/migrations', __DIR__ . '/../App/migrations', ], ], ], // Routes an admin can preview before the public can see them (see // /admin/docs/drafts) — a list of Route::$dir-format paths, no leading // slash, e.g. 'blog/upcoming-post'. Not authenticated as admin (per // AdminAuth::isAuthenticated()) → 404, same as a route that doesn't // exist at all, so a draft's existence isn't revealed to anyone // poking at the URL. Authenticated → renders normally, and — critically // — is never written to the static HTML cache regardless of whether // the page has a sidecar (see Renderer::render()'s $isDraft param), // since a world-readable cached copy would otherwise permanently leak // the draft the first time an admin previewed it. 'draft_routes' => [], // Content index (see /admin/docs/content-index) — backs /sitemap.xml, // /search, and blog tag browsing. Off by default: all three depend on // SQLite (Lib\Db), a real dependency plenty of sites built on this // framework won't want at all, the same reasoning that keeps Matomo // and admin auth off by default above. When false, all three routes // 404 exactly as if they didn't exist, and nothing ever touches // Lib\Db because of this feature — no data/novaconium.sqlite gets // created just because the code exists. content_index_auto only // matters once enabled: true (the default) reindexes lazily, // on-demand, the first time a stale index is actually needed (never on // a normal page view); false disables that and leaves indexing // entirely to `php novaconium/bin/index-content.php`, e.g. from a // deploy step. 'content_index_enabled' => false, 'content_index_auto' => true, // Media manager (/admin/media — see /admin/docs/media-manager): an // upload/browse/delete UI for files under public/uploads/, covered by // the existing /admin/* auth gate the moment the page exists, so // there's no separate *_enabled flag here (unlike admin_auth_enabled/ // content_index_enabled above, it has no SQLite dependency to gate). // media_upload_extensions is an allowlist, matched case-insensitively // against the uploaded filename's extension; media_upload_max_bytes // caps a single file's size (checked against both $_FILES' reported // size and PHP's own upload_max_filesize/post_max_size ini limits, // see /admin/docs/media-manager). 'svg' is deliberately NOT in this // default list: files under public/uploads/ are served directly from // this origin, and an SVG can carry inline