Files
novaconium/App/pages/blog/novaconium-features/index.twig
T
code c0455241ea Slim down README: features to a blog post, docs pointer, ASCII banner
Features section becomes a "Novaconium Features" blog post
(App/pages/blog/novaconium-features/), demonstrating the framework's own
content model rather than living as a long bullet list in README.md.
Getting started is trimmed to the minimum needed to run the site and
reach /admin/docs, which is now the single canonical source for every
topic (Docker, deploying, project layout, etc.) instead of being
mirrored into README.md. Third-party section kept as-is. AGENTS.md's
documentation-duplication rule updated to describe this new split so
future changes don't re-bloat the README. Also adds an ASCII art banner
above the title.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 07:44:51 +00:00

52 lines
7.3 KiB
Twig

{% extends layout %}
{% import '_layout/icons.twig' as icons %}
{% block title %}Novaconium Features{% endblock %}
{% block description %}A tour of what ships with novaconium out of the box: routing, sidecars, caching, admin auth, access control, media manager, database, search, RSS, and more.{% endblock %}
{% block robots %}index, follow{% endblock %}
{% block tags %}features, meta{% endblock %}
{% block canonical %}{{ request_path|default('/') }}{% endblock %}
{% block og_type %}article{% endblock %}
{% block og_title %}{{ block('title') }}{% endblock %}
{% block og_description %}{{ block('description') }}{% endblock %}
{% block og_url %}{{ block('canonical') }}{% endblock %}
{% block twitter_card %}summary{% endblock %}
{% block twitter_title %}{{ block('title') }}{% endblock %}
{% block twitter_description %}{{ block('description') }}{% endblock %}
{% block blog_content %}
<h1>Novaconium Features</h1>
<p>A tour of what ships with novaconium out of the box. Every topic below has a full writeup at <a class="icon-link" href="/admin/docs">{{ icons.book() }}/admin/docs</a> on any running instance — this post is the overview.</p>
<ul>
<li><strong>File-based routing</strong> — a directory under <code>App/pages/</code> <em>is</em> a route (Hugo-style page bundles). No route table to maintain.</li>
<li><strong><code>[param]</code> segments</strong> — a directory literally named <code>[param]</code> (e.g. <code>App/pages/products/[id]/</code>) captures any single URL segment into <code>$params['param']</code> for clean URLs, no query strings.</li>
<li><strong>Optional PHP "sidecars"</strong> — drop an <code>index.php</code> next to any <code>index.twig</code> to supply Twig context data, or return a <code>Response</code> (redirect/JSON/XML/HTML) to short-circuit templating entirely.</li>
<li><strong>Static caching, zero config</strong> — sidecar-less pages render once and are written to <code>public/cache/</code>; <code>.htaccess</code> serves the cached file directly on every later hit, skipping PHP and Twig entirely.</li>
<li><strong>Override-by-path</strong> — <code>App/</code> (your project) is checked before <code>novaconium/</code> (the framework defaults) for every page, layout, <code>Lib\</code> class, and even the Sass color palette (<code>App/sass/_colors.sass</code>). Drop a file at the same relative path to override it; nothing needs duplicating to get a working site.</li>
<li><strong>Layout inheritance</strong> — <code>_layout/layout.twig</code> directories are resolved by walking upward from the matched page, so you can override the layout for a whole subtree.</li>
<li><strong>SEO boilerplate out of the box</strong> — the default layout ships meta description, canonical link, robots, Open Graph, and Twitter Card tags, all overridable per-page via Twig blocks.</li>
<li><strong>Built-in Matomo analytics</strong> — set <code>matomo_url</code> and <code>matomo_site_id</code> in <code>App/config.php</code> to enable tracking site-wide, including automatic 404 tracking. Off by default.</li>
<li><strong>Admin authentication</strong> — gate every <code>/admin/*</code> route behind a session login with multi-user management: a SQLite-backed <code>users</code> table, <code>/admin/login</code>/<code>/admin/logout</code>, and an <code>/admin/users</code> page to create, disable, delete, group, promote/demote, and change the email or password of accounts (plus a <code>novaconium/bin/create-admin-user.php</code> CLI for the first user or deploy scripts). Two roles: the first user created is the admin; everyone after is a registered user with an optional group. Enabled with a single <code>admin_auth_enabled</code> flag in <code>App/config.php</code>; off by default.</li>
<li><strong>Access control</strong> — assign a page (or a section, one line per page) to a user or group from its sidecar: <code>Access::require('group:members')</code> returns <code>null</code> or a ready-made <code>Response</code> (login redirect with a return path, or a 404 for the wrong account). Public is the default — a sidecar that never calls it is untouched, and static (sidecar-less, cached) pages are always public by construction.</li>
<li><strong>Draft pages</strong> — list a route under <code>draft_routes</code> in <code>App/config.php</code> to make it visible only to an authenticated admin; anyone else gets a plain 404, not a login prompt.</li>
<li><strong>Media manager</strong> — <code>/admin/media</code>, an upload/browse/delete UI for files under <code>public/uploads/</code>, covered by the existing <code>/admin/*</code> auth gate with no separate flag needed. Extension allowlist and max upload size are configurable.</li>
<li><strong>Dark/light theme toggle</strong> — a nav button flips a <code>data-theme</code> attribute (persisted to <code>localStorage</code>) that swaps every color via CSS custom properties.</li>
<li><strong>Self-hosted spam prevention &amp; form validation</strong> — <code>Lib\SpamGuard</code> (honeypot + submission-timing check, no external CAPTCHA), <code>Lib\FormValidator</code>, and <code>Lib\Validate</code>, demonstrated on the contact form.</li>
<li><strong>Form security by default</strong> — <code>Lib\Input</code> (cleaning accessor for <code>$_POST</code>/<code>$_GET</code>) and <code>Lib\Csrf</code> (standalone session-token CSRF protection), wired into the contact form and every admin form.</li>
<li><strong>SQLite/MySQL database, zero setup</strong> — <code>Lib\Db</code>, a thin PDO wrapper (no ORM) supporting multiple named connections open at once, each with its own plain-SQL migration convention, applied automatically on first use or via <code>php novaconium/bin/migrate.php</code>.</li>
<li><strong>Sessions with flash data</strong> — <code>Lib\Session</code>, a thin wrapper around native PHP sessions with CodeIgniter-style flash values for post/redirect/GET flows.</li>
<li><strong>Content index: sitemap, search, tags</strong> — <code>/sitemap.xml</code>, full-text <code>/search</code> (SQLite FTS5), and blog tag browsing all share one crawler. Off by default; reindexes lazily on demand or via <code>php novaconium/bin/index-content.php</code>.</li>
<li><strong>Blog RSS feed</strong> — <code>/blog/feed</code>, built from the same hand-written post list <code>App/pages/blog/index.php</code> itself renders from, so it works with no database at all.</li>
<li><strong>Syntax-highlighted code blocks</strong> — vendored <a href="https://highlightjs.org/">highlight.js</a> colors PHP/Bash/HTML code blocks site-wide, auto-detected with no per-block markup.</li>
<li><strong>No build step, no Composer</strong> — clone it, point Apache (or <code>php -S</code>) at <code>public/</code>, and it runs. Twig is vendored as source.</li>
</ul>
<p>Full details on every one of these live at <a class="icon-link" href="/admin/docs">{{ icons.book() }}/admin/docs</a>, rendered live from this same running instance — routing, sidecars, libraries, database, session, content index, XML sitemap, RSS feeds, layouts, static caching, SEO, Matomo, admin authentication, access control, draft pages, media manager, styling, project layout, and third-party notices.</p>
{% endblock %}