Our product
atHeartbeat
A free public microblogging site with feeds, media, polls and threaded comments, open to anyone and carrying no advertising.
atHeartbeat is a social timeline: short posts with images, video and polls, threaded comments, follows, reposts, bookmarks and live notifications, with every feed readable without an account. There is no advertising, no paid tier and no monetisation code in it at all. It is also the product we point at when someone asks whether a read-heavy consumer app can run on serverless infrastructure.
What it does
- Home, explore, trending, hashtag, profile and bookmark feeds, all readable signed out
- Posts with images, video, polls and location tagging
- Likes, bookmarks, threaded comments, follows and quote reposts
- Mention autocomplete that generates notifications
- Realtime presence and notification delivery over WebSockets
- Email and password sign-up plus six OAuth providers
- Image uploads with automatic variants, client-side compression and a storage fallback
- Optional AI moderation of post and comment text at creation
- Content reporting, verified badge requests and an admin moderation dashboard
- Data export, account deletion, consent records and a cookie banner
Most people describe a social timeline as one product. It bills like a dozen and it fails like a dozen: a feed that loads slowly, an image that never finishes uploading, a reply that lands four minutes after the person has closed the tab. atHeartbeat is our attempt at the whole shape, built and deployed rather than sketched. Public feeds, images, video, polls, threaded comments, reposts, bookmarks and live notifications, readable without an account, with no advertising anywhere in it and nothing for sale.
Why it exists
There are two answers and only one of them is about the product.
The product answer is the plain one. People post short updates and other people read them. Home, explore, trending, hashtag, profile and bookmark feeds are all readable signed out, which was settled before anything was built. A social site that demands an account before it will show you a single post can only grow through people who already tolerated that, and there are not many of those.
The second answer is that consumer social is the least forgiving application shape we could have picked, so we picked it on purpose. Reads outnumber writes by a wide margin. Fan-out depends on who happens to follow whom, so no two writes cost the same. Media is large, slow and expensive to touch. People expect a notification while they are still looking at the screen and they notice when it is late. Building one end to end taught us more about where our usual platform stops being simple than any amount of reading would have. Its counterpart is Starterflare, a comparable ambition built on a conventional server stack, and having both means we can answer a hosting question with two codebases rather than a preference.
How it works
A Next.js front end talks to one worker running Hono, and the storage underneath is split by what each part of the application genuinely needs.
| Concern | Where it lives | Why there |
|---|---|---|
| Posts, follows, comments, polls | SQLite at the edge, across fifteen migrations | relational, small rows, read constantly |
| Sessions and hot feed data | key-value store with expiry | wants to be near the request, does not need to be durable |
| Images and video | image service with automatic variants, object storage behind it | large, immutable, read far more often than written |
| Presence and notification push | two Durable Objects holding WebSockets | genuinely stateful, unlike everything else |
| Verification and reset email | a queue consumer inside the same worker | slow, must retry, must not block a sign-up |
| Request metrics | analytics engine | written on every request, never read in one |
The split matters more than the product names in the middle column. Every request in this application can be answered by any instance anywhere, with one exception: who is online right now, and which open sockets need to hear about this reply. That exception is the reason two Durable Objects exist and the reason nothing else does. Presence and notifications share a single connection per person rather than opening one each, because anything billed by duration should be multiplexed or dropped.
Media works from the other direction. Pictures are compressed in the browser before upload, routed to a service that produces variants automatically, and loaded progressively on display. If that service is not configured, the same endpoint writes to object storage and the app carries on with one fewer optimisation. Registration accepts an email address and a password hashed with PBKDF2, or any of six OAuth providers, all six of which are live on the sign-up page.
The decision that shaped it
Two decisions, and both are about what happens when something is absent.
The first is that the public surface stays public and stays identical for everybody. Explore, trending and hashtag feeds compute one result that serves every visitor, so the cost of the most-read part of the site tends towards a constant no matter how many people arrive. The home timeline is unique per person and therefore scales with signed-in actives rather than with traffic. That boundary is close to impossible to retrofit. Personalise a public page even slightly, with a well-meant strip of posts you might like, and the cheapest surface in the product becomes the dearest one. We worked the whole bill through this way in which parts of a timeline actually cost money, where the two heaviest line items turn out to be things nobody would list if you asked them to describe a social network.
What that costs: no tailored discovery for a signed-out visitor, so a stranger's first screen is whatever is popular rather than whatever suits them, and every scraper on the internet reads the same open pages for free.
The second decision is failing open. Post and comment text can be checked by a model as it is created, and if that binding is missing the check is skipped and the content publishes. Image handling degrades to plain storage on the same principle. The storage fallback is uncontroversial. The moderation one is not, and it is defensible only at this size, where a missed check produces a visible post that somebody can report. At the scale the README daydreams about it would be an incident. It is written down here so that whoever reverses it later knows they are reversing a decision rather than fixing an oversight.
Where it stands today
Deployed, healthy and unused. The live API reports database, storage, cache and analytics all up, and the explore feed returns five seeded demo posts from five demo accounts, one of which welcomes you to the site. We have never marketed it, so nobody should read this entry as a claim about traction. The same shortcut, taken for the same reasons, turns up in Jonosakti, and the argument about what seeding a live database really costs is in launching an empty community site without faking it.
Several things here are less finished than they look.
Search is SQL LIKE matching across posts, users and hashtags. An embedding is written to a vector index whenever a post is created and nothing anywhere reads it, so every write pays towards a semantic search feature that does not exist. Removing that write is a one-line change we have not yet made.
Interface translation is not wired up. The README advertises fifteen languages; there are four message files, for English, Spanish, French and Japanese, and the localisation library, though installed, is not imported anywhere in the front end. Per-item translation is real, with a language field on posts and users and a translations table behind it. Automatic translation is not: that endpoint returns the original text with the target language stuck on the front and a note in the code saying to integrate a real service.
The repository's own audit, written in December 2025, scores test coverage four out of ten and flags a missing admin authentication middleware as a high risk item, while the README in the same repository calls the project production ready with more than 150 tests. Believe the audit. Sharding across four further databases is configured and switched off, which makes it a lever rather than a scaling feature. The image, video and link preview endpoints all depend on API tokens held as secrets, and we have not verified from the outside that they are configured in production. The last commit is from December 2025 and there is no about page, no features page and no pricing page, because there is nothing to sell.
What this says about how we work
Three habits show up in this codebase more clearly than they would in a client project, because nobody was paying us to tidy the description afterwards.
Anything that depends on an external credential should degrade rather than stop. The day a token is missing is already a bad day, and a product that loses one optimisation is in a different category from a product that returns errors. That principle is worth an argument at the start of a job, because it costs a fallback path in almost every integration.
Half-finished features are not free, and the ones on the write path are the expensive kind precisely because they are invisible. A vector index nobody queries is the tidy example. The untidy examples in most businesses are a webhook that fires into a dead endpoint and a nightly export nobody has opened since March.
And a lever that is switched off should be described as switched off. When we scope work, what we quote and how we price it follows the same rule: we would rather leave the ranking engine out of a first release and say why than bill for one before there is anything worth ranking.
What we wrote about building it
More of the same kind
- ObjectifyA hosted backend that gives developers a typed database, authentication, file storage and AI inference behind one REST API.
- DMARC EngineEmail authentication for companies that need DMARC enforced on their domain without blocking their own mail.
- ConsonasA CRM for organisations of roughly two to two hundred people who want customer tracking without an administrator to run it.
Want something like this?
Tell us the shape of the problem and we will tell you honestly whether we are the right people for it.
Start a conversation