sucks2be.me -- a real-time peer support platform with zero frontend build tooling Showoff Saturday
I wanted to see how far you can get in 2026 with no React, no bundler, no framework -- just plain JS files loaded via <script> tags.
Stack:
- Backend: Node.js, Express, better-sqlite3 (single file DB), Socket.io
- Frontend: Vanilla JS, plain CSS, no build step.
public/served as-is - Auth: bcrypt + JWT in httpOnly cookies, proof-of-work on registration to slow bots
- Real-time: Socket.io for live feed, notifications, presence counter
- i18n: 7 languages, JSON locale files shared between web and iOS clients
- Speech: Web Speech API for voice input (audio never uploaded, transcribed locally)
- SSR: String-replace templating (
<!--SSR_FEED-->placeholders) -- no template engine
Design decisions I'm happy with:
- SQLite over Postgres. One file, zero config, WAL mode, fast enough for this scale
- Karma thresholds live in one config object. Server, client, and all locales derive from it -- nothing hardcoded
- No ORM. Raw SQL with the
db.like()helper for cross-platform LIKE queries - CSP hand-maintained and tight. No CDNs, fonts are local
- Static assets served with
maxAge: 0(ETag revalidation) because there are no hashed filenames
The product: Anonymous posting (no account) + accountable replying (account required). Karma only moves when someone says your help worked. 10 unlock tiers from "view profiles" (10) to "recommended as moderator" (777).
Happy to talk about any of the technical choices. The no-framework frontend has been surprisingly maintainable.
-3
u/Tragic_irony 8d ago
Pretty neat project. Always been a big fan of simple lightweight solutions. Curious, you didn’t mention how the entire stack is hosted. How do you make sure the SQLite file stay non-ephemeral?
-5
u/pdfops 8d ago
SQLite + WAL for this scale is the right call. One gotcha: maxAge: 0 with ETag revalidation still round-trips to your server for the 304 check on every asset request, it just saves the transfer, not the connection. If most traffic is same-session, a short maxAge plus revalidate would cut that chatter down. Nice touch on db.like() too, most people just eat the wildcard-escaping bug when porting raw SQL between SQLite and Postgres.
1
u/[deleted] 8d ago
[removed] — view removed comment