
The problem
A blogging platform is easy to demo dishonestly. Fixtures give you an empty feed, no comment threads and nothing to search, so every feature looks like it works and none of them are under any load.
Decisions
Real content, in the native schema
A background sync pulls articles and comments from dev.to’s public API into the same Post and Comment models that natively authored posts use: sixteen tags, twenty articles each, capped at three hundred per cycle with a 300ms gap between calls so the importer stays a good citizen of an API it does not pay for. The feed, tag search and threaded discussion therefore run against real articles with real comment threads under them, and there is no second code path to keep in step.
Markdown from the first keystroke
Live preview, syntax-highlighted code blocks, drafts and tag input, with read time computed from the post rather than entered by the author. A figure an author types is accurate once, and wrong from the next edit onward.
Someone else’s markdown is not markdown
Real dev.to posts arrive full of Liquid tags (embeds, calls to action, inline tables of contents) which any standard renderer prints as literal `{% … %}` noise. Stripping them would take the content with them, so the importer unwraps them: a tag whose argument is a URL becomes a real link, anything else collapses to its inner content, and the pass repeats until the text stops changing, because the tags nest. The argument pattern matches lazily up to `%}` instead of excluding `%` outright, because dev.to’s own CTA tags carry percent-encoded URLs and the stricter pattern truncates them at the first `%3A`. Importing real content means inheriting the shape it was written in.
Roles are enforced twice, deliberately
Reader, author and admin each get their own dashboard, guarded by client-side routes and by server middleware that enforces the same rule. Hiding a button is never the only thing standing between a role and an action.
The hard part
A public demo admin that cannot wreck the demo
The login page offers one-click demo accounts for all three roles, which means handing a stranger an admin session on a live deployment. The demo admin can open every tab of the admin dashboard (stats, users, posts), because a dashboard with the interesting screens removed does not demonstrate anything.
Every mutating action is refused server-side. The account carries an `isDemo` flag, and the privilege check everywhere is “admin role AND not isDemo”, never the role alone, so suspending or promoting a user, deleting or flagging a post, or deleting someone else’s comment is rejected with a 403 regardless of what the interface allowed. Real admin accounts never match the flag and are untouched by it.
The flag lives on the user, not on the session, and that is what makes it hold: a demo admin cannot escape it by signing in again, and nothing has to remember to pass a context through.
The distinction that matters is where the rule lives. The UI is not the control. The same request issued from curl fails the same way.