Changelog
A plain-English record of what changed, version by version. Breaking changes are always called out explicitly.
Direct Push to WordPress & Ghost, Contact Forms, Responsive Images, Cacheable Post Pages & a New Desk
- New — Push straight to WordPress or Ghost: Admin → Export can send your content to a running site through its API, as well as download a file. Posts already on the other site are left as they are by default, so a second run sends only what is missing. It runs in the background with a per-item progress page. The credential (a WordPress application password or a Ghost Admin API key) is held in memory only while the push runs and is never written to the database, a log or the audit trail. Comments and authors are not carried; the file export still has them.
- New — Contact forms: Admin → Forms builds forms, and a Form block places one on a page. Works without JavaScript. Spam gets the same checks as comments and is never stored. Submissions are listed, searchable and downloadable as CSV, can be emailed to you and sent to webhooks as
form.submitted, and are deleted after a retention period you set (365 days by default). - New — Responsive images: every JPEG, PNG and WebP upload also gets 480, 800 and 1200 px WebP copies, offered through
srcsetandsizes, so phones download a small copy. Existing images get copies from a background job. Upload images now carry their width and height and load lazily. - New — Pages can be written in Markdown, like posts, with the same self-hosted editor and preview. Switching an existing page keeps it looking exactly as before.
- New — Custom fields over the API, with the same validation as the editor, and
GET /api/v1/pages/{slug}for headless front ends. - New — Accessibility checks in the post and page editors (missing alt text, skipped headings, vague link text, tables without headers, very long paragraphs), plus an Accessibility view in Content Health. Advisory only; they never block a publish.
- New — Content calendar: Admin → Calendar shows the month’s published, scheduled and dated draft posts. Read-only.
- New — Right-to-left sites: Arabic, Hebrew, Persian, Urdu and other right-to-left sites now read right to left in every layout and preset. Left-to-right sites look exactly as before.
- New — Contact details for search and answer engines: a contact email, page and type in Settings add a
contactPointto the site’s structured data and the email tollms.txt. Optional page-view retention removes detailed view records after a period you choose; Analytics keeps every figure. - Changed — Post pages can be cached by a CDN, like the home page: an anonymous visit sets no cookie and is not marked
no-store, and commenting still works with and without JavaScript. - Changed — A new Desk: a grouped sidebar with badges, a command palette (Ctrl/Cmd+K), a dashboard with a “Needs attention” list, one set of components in both colour schemes, a precompiled stylesheet instead of the in-browser compiler, and editors that fit a phone. The Desk shows which version is running; public pages never do.
- Fixed — The Docker deployment now builds and starts on an empty database (
docker compose upruns a one-offdb-initservice), and a fresh clone of the repository builds again. Analytics and AI Crawlers load quickly on busy sites through a daily summary. Also fixes four layouts that scrolled sideways on phones, see-through header menus, the API’s write endpoints, and comments that could still be posted with comments switched off. - Security — Sign-up closes once a site has its first account (it used to stay open and gave new accounts the Author role, so review your Users if your site has been public). The API no longer returns commenters’ email or IP addresses, API writes follow the Desk’s permissions and are audited, the example
Jwt:Keyno longer works, and disabling or deleting a user ends their Desk session.
Backward-compatible — new tables and columns are applied on startup. If you run a single container with docker run against your own SQL Server, create the database and run DBScripts/init.sql first. Removed: POST /api/v1/comments and POST /api/v1/media.
Newsletter Sending, Markdown Authoring, Two-Factor Sign-In, WordPress & Ghost Export, Backup & Restore
- New — Newsletter sending: Admin → Newsletter writes an issue (subject, preview text, a Markdown introduction and up to six posts as cards), previews it, sends you a test, then sends it to every confirmed subscriber. Delivery runs in the background in batches through your own SMTP server (
Newsletter:BatchSizeper minute, default 50), with retries, a send log and Stop sending. Every copy carries the subscriber’s own unsubscribe link and RFC 8058 one-click unsubscribe headers. No tracking pixels, no rewritten links. Single-site installs only. - New — Markdown authoring: choose Write in Markdown on a new post or switch an existing one. The editor is self-hosted, with a toolbar, side-by-side view and a preview rendered by the server; CommonMark plus tables, task lists and footnotes. HTML is still rendered on every save, so feeds, search,
llms.txtand exports are unchanged. - New — Two-factor sign-in with an authenticator app and ten single-use recovery codes. Optional by default; an Admin can require it for chosen roles, and can reset it for someone who lost their phone.
- New — Export to WordPress and Ghost: Admin → Export downloads a WordPress WXR 1.2 file or a Ghost import ZIP, after a summary of what carries over for your actual content. Tested by real imports into WordPress and Ghost.
- New — Backup and restore: Admin → Backups makes one ZIP of the whole site (content, users, settings, theme, menus, comments, subscribers, revisions, the audit trail and every upload), stored outside the web root. Restore it into a fresh install from the first-run screen. Not available in cloud mode.
- New — Editorial review: authors without publish permission submit posts for review. Editors approve them or send them back with a note (In review, Needs changes), and readers never see either state.
- New — Navigation menus for the header and footer, rendered by every navbar and footer layout; signed, retried webhooks for publish, update, unpublish and comment events; custom fields for posts and pages, shown to readers and emitted as
additionalProperty; a gallery block with a self-hosted lightbox; and alt text and captions in the media library. - New — Cookie consent, on by default: a self-hosted banner with equal Accept and Reject buttons, and Google Analytics loads only after Accept. The built-in Analytics sets no cookies either way.
- New — Dates in your time zone and country’s format, from the IANA Time Zone Database and Unicode CLDR, on every public page and in the Desk.
- Changed — The home page can be cached by a CDN: it sets no cookie, and the newsletter form fetches its anti-forgery token only when a reader presses Subscribe.
- Fixed — Listing pages return 404 past the last page and 301 away from unknown query strings; most dates now follow the site’s time zone; structured-data times end in
Z; opening an unsubscribe link no longer unsubscribes on its own, so mail scanners cannot remove readers. - Security — Removed an unused autosave endpoint that another website could use to overwrite posts (draft auto-save never worked and is no longer claimed). The setup wizard closes once any user exists, a crafted save request can no longer publish without permission, and failed API sign-ins count toward the IP firewall.
Backward-compatible — new tables and columns are applied on startup. Set up SPF, DKIM and DMARC for your sending domain before sending newsletters. A backup contains password hashes and subscriber emails: store it like a password.
Docker Deployment, Crawler Identity Check & Honest Page-View Counting
- New — Docker deployment: a multi-stage, non-root, health-checked
Dockerfileand adocker-compose.yml(the app, SQL Server, and Caddy for automatic HTTPS) at the repository root. Copy.env.exampleto.envand rundocker compose up -d, or run a single container against your own SQL Server, configured entirely through environment variables. See the Docker guide. - New — Crawler identity check in AI Crawlers: visits claiming to be Googlebot, Bingbot, Applebot, GPTBot, OAI-SearchBot, ChatGPT-User, PerplexityBot or Perplexity-User are checked against the IP list or reverse-DNS name each operator publishes. An Identity check column shows verified, failed or unchecked, and impersonators are left out of the totals, the daily trend and the most-crawled pages.
- Changed — Page views are counted when the page reports back: a small self-hosted script sends a signed, path-bound token once the page loads, and only that beacon records a view. Scrapers and request floods are no longer counted, so Analytics now counts on the same basis as Google Analytics. No cookies are set and nothing is stored in the browser. Expect a step down in the trend after upgrading.
- Changed — “Most read” ignores crawlers, and page-view and crawler tracking is buffered and written in batches, so a traffic flood cannot become a flood of database writes.
- Fixed — Crawler errors are recorded once, under the URL that was requested, with its real status; Google fetchers with no “bot” token are no longer counted as readers; a fresh checkout no longer fails to build.
- Security — Reader IP hashes are now HMAC-SHA256 under a random per-install secret and are no longer reversible. Crawler impersonators lose the firewall’s crawler protection. Behind a proxy with Trust proxy headers enabled, tracking uses the real client address.
Backward-compatible — the new Verified column on crawler visits is applied on startup. Back up the new ip-hash.secret alongside your Data Protection keys. Rows written before the upgrade keep their old IP hashes until cleared; nothing in Inkwell reads that column, so clearing it loses no feature.
Search Console in the Desk, Revision History, Job Scheduler, Password Reset & Desk UX Overhaul
- New — Search Console, wired into the Desk: connect your own property with a service-account key (no platform-owned OAuth, no third party) and a nightly job pulls clicks, impressions, CTR and position. The editor gains a Search performance panel with 28-day deltas, the queries bringing traffic, and flags for striking distance (position 8–20), losing impressions, and page-one-with-few-clicks. The same flags appear as Content Health tiles and on the dashboard. The key is encrypted at rest and never logged or exported.
- New — Revision history for posts and pages: every save with changed content writes a revision tagged with why and by whom. Compare shows a line-level diff against the current version; Restore records the current state first, so a restore is itself undoable. Slug and publish state are never touched. Kept per item is configurable (default 25).
- New — Self-service password reset: a single-use, 30-minute link from the sign-in page. Only its hash is stored, the response is identical for known and unknown addresses, and requests are capped at three an hour.
- New — Comment-spam gate: public comments pass a honeypot, a signed form-timing token bound to the post, markup-link and link-only rejection, repeat detection and a per-address rate limit before anything is stored. No word list, no external service, fails open. Each discard is reported to the IP Firewall.
- New — A real job scheduler, no cron required: one in-process scheduler runs due work every minute (crawler-visit retention, expired token pruning, the Search Console sync, Open Graph card cleanup). Runs are claimed atomically against a ledger table, so two instances sharing a database never run the same job twice. Admin → Dashboard shows every job’s last run and result.
- New — The Desk rebuilt on five shared primitives: one styled dialog replaces sixteen native browser popups, every editor gets an unsaved-changes guard, every long action a busy indicator, every growing list search and paging, and the Desk and reader site a genuine dark colour scheme. Settings is now seven tabs. Bulk actions for posts and comments, with a typed guard above five items.
- New — Accessibility pass across the whole product: phone navigation below 768 px, real password fields with correct
autocomplete, inline announced errors, a skip-to-content link and visible focus rings on the public site,aria-currenton active nav items, and accessible names on every icon-only control. - Changed — CMS pages now appear in
llms.txtandllms-full.txtand carry their own meta title, description and canonical; a shared reading-time helper across all three post layouts; a “Needs attention on this server” dashboard panel for a shadowed static file or an unpersisted Data Protection key ring; generated invite passwords shown once and never emailed;robots.txtnow disallows/searchand/preview/; landing-page fonts are self-hosted. - Fixed — A typed schedule time is now read in your display time zone and converted to UTC on save, and every timestamp runs in UTC end to end, so a freshly published post no longer answers 200 at its URL while missing from the homepage, feed and sitemap. A source-scanning test fails the build on regression.
- Fixed — Revisions are tenant-scoped, comment-form tokens are bound to their post, the duplicate-comment check is scoped to the post’s owner, Search Console rows are pruned on disconnect, and roughly twenty further UI defects (mis-encoded dashes, a white-on-dark button, non-scrolling Import tables, a stolen 404 announcement, and more).
- Security — Media upload’s anti-forgery check is restored and upload failures no longer return a stack trace; an administrator can no longer disable their own account, and role changes require an explicit confirmed action.
Backward-compatible — a tenant who opens nothing new keeps working exactly as before, and every new table and index is applied on startup. One manual step if your host’s clock ever ran outside UTC: run the two dated UTC-conversion scripts once with the host’s historical offset. Set DataProtection:KeysPath to a folder that survives a redeploy, or comment-form tokens and preview links are invalidated on every app-pool recycle.
Structured-Data Linter, Answer-Engine Readiness, Link Audit & AI-Crawler Analytics
- New — Pre-publish structured-data linter: a post whose FAQ, Key Facts, How-To or roundup block would not validate is saved as a draft with the reason shown, instead of shipping broken schema. Advisory issues warn without blocking.
- New — Answer-engine readiness score: every post carries a 0–100 score with a per-signal breakdown in the editor sidebar and in Admin → Content Health. Advisory only — it never blocks a publish.
- New — Answer capsules: a short, quotable direct answer shown above the article body and emitted as schema.org
abstracton theBlogPosting. Visible copy, never hidden text. - New — Internal-link suggester and Link Audit: the editor proposes links in both directions as you write, and Admin → Link Audit scans every published post for dead ends, retired (410) targets and avoidable redirect hops.
- New — Redirects manager with a triaged 404 worklist: manage the rules v1.0.4 could only create, and act on the 404s that show evidence of being reader-facing with a one-click 301 or 410.
- New — AI-crawler analytics (Admin → AI Crawlers): which answer engines actually fetch your site, how often, and which pages they read. Recorded separately, so human analytics are untouched.
- New — Publisher identity for the knowledge graph: publisher type, legal name, founder, founding date and authority profiles feed
sameAsand the Identity section ofllms.txt. Every field optional; nothing inferred. - New — Import dry-run: preview exactly what a WordPress or Ghost import would create, rename, overwrite or skip before anything is written. Plus a
## Topicsindex inllms-full.txt. - Changed — The
| Site Nametitle suffix is appended only when the finished title still fits the search-result budget; category and tag links point straight at the canonical archive instead of a query URL that 301s. - Fixed — Unknown
/category/{slug}and/tag/{slug}URLs now return 404 instead of an empty soft-404 archive; empty taxonomies are no longer offered as filters; draft-only tag archives stay out of the sitemap; archive pagination no longer repeats the facet.
Backward-compatible — existing redirect rules, archives, filters and settings keep working. Note that publishing can now be refused when a structured-data block fails validation; existing published posts are not re-validated until next saved.
IP Firewall, WordPress & Ghost Importer, Series & Indexation Controls
- New — IP Firewall: failing requests are scored and hostile addresses block themselves automatically. Loopback, private ranges, signed-in staff, and search/AI crawlers are never blocked. Managed in Admin → Security.
- New — WordPress & Ghost importer: upload a WordPress WXR or Ghost JSON export, preview and select, then run a batched, resumable import with WebP image conversion and preserved permalink redirects. Undoable.
- New — Series & collections: group posts into an ordered sequence with a
/series/{slug}page, a "Part N of M" banner, andCollectionPage/ItemListschema. - New — Content Health dashboard: surfaces posts needing review, missing Key Facts/FAQ blocks, or truncating meta descriptions (Admin → Content Health).
- New — Indexation controls: 410 Gone retirement for redirects, filter-URL canonicalization (
/?tags=x301s to/tag/{slug}), and depth-gated tag archives kept out of the sitemap until indexable. - Fixed — HEAD requests no longer return 405; category and tag archives render full listing chrome; post pages no longer 500 without categories or tags.
Backward-compatible — no breaking changes; existing tenants keep their layout, theme, content, and settings.
Automatic WebP Conversion on Upload
- New — Raster images (JPEG, PNG, GIF) uploaded to the media library are re-encoded to WebP for smaller, faster-loading assets, with their dimensions captured in the same pass. SVG and images already in WebP pass through unchanged, and an image that cannot be decoded is stored as uploaded.
SEO/AEO Overhaul, Verdict Roundups, Catalog Layout, IndexNow & Error Monitor
- New — SEO/AEO overhaul: rich structured data (CollectionPage, author
Person, roundupItemList/Review), per-tenantllms.txtplus a newllms-full.txt, author E-E-A-T pages at/author/{slug}, image sitemap, and a sitelinks search box. - New — Verdict scored-roundup content system for “Top N Best… Software” buyer’s guides, with per-entry scores, pros/cons, and rich-result-safe schema.
- New — Catalog layout: a single-column boxed-card list with a category filter bar and numbered pagination.
- New — IndexNow instant indexing pings Bing, Yandex, Seznam, and Naver to re-crawl within minutes of publishing.
- New — Error Monitor: 4xx/5xx errors grouped by signature with occurrence counts, plus optional email alerts.
- Improved — Authoring: Key Facts and How-To step blocks, a live meta-description length helper, and smarter related-posts linking.
Backward-compatible — no breaking changes; existing tenants keep their layout, theme, and content.
Analytics, Audit Trail & Inkwell Theme System
- New — Analytics dashboard: page-view tracking, UTM attribution, geo-location, and traffic-source breakdown.
- New — Immutable, admin-only audit trail of every write action across the platform.
- New — Inkwell theme system: 10 colour presets with multiple layouts.
- New — A subscriber list with double opt-in and a member directory, plus redirect rules.
- Improved — SEO toolkit: OG image generation, FAQ schema, and structured data.
Initial Release
- New — ASP.NET Core MVC blog engine with Dapper data access and automatic SQL Server schema migration on startup.
- New — Cookie-based authentication with PBKDF2-SHA256 password hashing, and Admin, Editor and Author roles.
- New — Post creation, editing, scheduling and publishing, with categories and tags.
- New — Media library with secure upload and organized storage.
- New — Comments with moderation, and basic theme customization.
- New — Multi-tenant support in cloud mode.