rontimeExplore ☰
Systems, markets & everything between.
Search ↗The dispatch ↗

Building in Public · Sep 8, 2026 · 4 min read

Why rontime keeps its articles out of the database

A personal blog needs somewhere to put words, pictures and comments. Those do not have to be the same place.

Original AI-generated cover illustration.

The smallest useful split

Rontime is a personal publication about data, AI and the business of getting technology adopted. It also needs ordinary website features: photos, comments, an administrator login and a subscription form. Once those are on the list, a database is sensible. Putting every part of the site in it is optional.

The current split is straightforward. Article content lives in the repository. Next.js renders the public reading pages. Neon stores the records that change when someone uses the site: comments, subscribers, media metadata and blocked sources. Vercel Blob stores uploaded image files. This description is based on the checked-in implementation, not an assertion that every optional provider is configured in production.

A typo in an article should be fixable through an ordinary Git diff. A new comment should not require a site deployment. Those two requirements are enough to draw the first boundary.

Content and reader activity take different pathsContent and reader activity take different paths
Figure 1. The implemented service split. The public article body stays independent of the dynamic comments request.
Download Excalidraw source ↗Click diagram to enlarge
Text version

Editorial path · changes when the author publishes

  1. Git repository: Article text, diagram definitions and application code
  2. Next.js build: Generate public reading pages
  3. Vercel → reader: Serve the built article; no article query to Neon

Interaction path · changes when a reader submits

  1. Browser form: Comment or email subscription
  2. Server handler: Validate input and apply abuse checks
  3. Neon / Drizzle: Persist the allowed relational record

Uploaded photos follow a separate storage path: image bytes in Vercel Blob, metadata in Neon.

Git is a small CMS, with obvious disadvantages

Repository-backed content gives this site version history, a reviewable diff and a clear connection between a content change and a deployment. For one author, that is a reasonable starting point. It is less appealing if publishing means asking a non-technical editor to fix a TypeScript error.

There is an unfinished part worth being precise about. The architecture document describes MDX as the target authoring format. This first collection uses typed article records with sections, references and diagram definitions. It is not an MDX pipeline disguised by a nice page. Moving to MDX later should improve authoring without changing the public URLs or turning articles into database rows.

I would reconsider a browser-based CMS when editorial coordination becomes a real problem: several writers, scheduled publishing, image selection by an editor, or review permissions that do not fit Git. Until then, it would add another application to administer before solving a problem this publication actually has.

The public form is the part to distrust

An article is trusted content reviewed in the repository. A comment form accepts input from anybody. That is why comments cross a server boundary before reaching storage. The checked-in handler validates the payload, checks the request origin, applies a honeypot and rate limits, and inserts accepted comments with pending status. The public query returns approved comments only.

Commenter emails are encrypted before storage. The abuse controls use an IP-derived rotating HMAC rather than retaining raw visitor IP addresses. That still deserves careful handling; a pseudonymous identifier is not a reason to collect more data than the feature needs.

Administrator authentication uses GitHub through Auth.js, followed by an explicit login allow-list checked on the server. Completing OAuth is not enough on its own. Uploaded images go through an authenticated upload flow, while metadata stays in the relational database. The useful security question is which code enforces each boundary, not whether the architecture diagram includes a lock icon.

A submitted comment is not a published commentA submitted comment is not a published comment
Figure 2. The moderation boundary in the code. An accepted HTTP submission is an acknowledgement, not permission to display the comment.
Download Excalidraw source ↗Click diagram to enlarge
Text version

Intake

  1. Public submission: Untrusted name, email and body
  2. Server validation: Origin, payload, honeypot and rate checks
  3. Pending record: Stored privately for moderation

Publication · a separate decision

  1. Allow-listed admin: GitHub session + server-side authorization
  2. Moderation: Approve, reject or mark spam
  3. Public read: Only approved body, name and public metadata

A saved email is not a newsletter operation

The subscription route persists an encrypted address and supports unsubscribe tokens. That is real backend behavior. It does not, by itself, constitute an editorial newsletter workflow with an issue composer, a campaign schedule or a delivery report.

Resend welcome-email and notification code is feature-gated on provider configuration. Turnstile verification is also conditional on its keys. The application has basic abuse controls without it, but optional code should not be described as an active service merely because the integration file exists. I want that distinction visible in the project notes.

The same restraint applies to analytics. The site includes Vercel Web Analytics and a private handoff to its dashboard. Rich custom-event attribution is a separate, deferred decision. Traffic events do not need to be copied into the blog’s Postgres tables just because Postgres is available.

What would justify more machinery?

For now, I would spend the next unit of effort on reading quality and publishing useful work. The newly added sidebar, dark mode and diagrams are examples of changes a reader can notice immediately. A more sophisticated content platform would be harder to justify while there is still only one author.

The triggers for changing the architecture should be specific. Add editorial tooling when writing in Git becomes the bottleneck. Add a durable email workflow when delivery requirements outgrow feature-gated notifications. Expand analytics when there is a concrete question the existing reports cannot answer. Review provider limits and costs before committing to those changes rather than assuming any tier remains free indefinitely.

This is not a universal stack recommendation. It is the shape of this blog at this stage: static words, dynamic conversations, and enough separation that one can evolve without dragging the other along.

More in Building in PublicBrowse this topic ↗

04 / Reader discussion

Continue the conversation.

Add a thoughtful question or perspective. Every comment is reviewed before it appears publicly.

Loading discussion…

Leave a commentEmail addresses are encrypted and never shown publicly.