Sometimes you need one password. Generate, copy, move on. In practice you land in a mini CRM of your secrets: subscriptions, syncs, a “happy safe forever” plan, autofill that wants one more permission.
I wanted it simple. That is how PassWave appeared: a generator with an optional vault. No card at the door. Project page here.
I first thought of a Telegram Mini App. Then a PWA won: install on phone and desktop, works offline, not tied to a messenger. The Telegram version stayed on the shelf. If someone asked, I would pull it out. Nobody asked in a way that justified a second contour.
Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4, Supabase, FSD. Idea to production in two weeks. FSD at that size looks theatrical. Without it the same two weeks grow a dump of hooks. Folders are cheaper than theatre.
What shipped
Encryption on the client. The server sees an opaque blob and does not need to know what is inside. Zero bytes of plaintext on the backend disk, at least that was the design. Passwords come from proper crypto, not alley Math.random. The passphrase is the user’s. Lose it, I cannot recover it. I also cannot read the contents.
Full offline: generation and a local vault without a network. Cross-device sync only if you ask, not “we already took everything, hope you do not mind”. Registration is optional. You can live local only and tell nobody you keep a box for passwords.
Several languages from day one, seven in the end. Presets, a mode that skips O/0 and I/l. Passphrases if you want to remember instead of copy. Batch generation when you tidy everything at once. A QR code so you do not mail the secret to yourself. Dark theme, of course.
No autofill, no extensions. The less code between a person and a password, the fewer places to fail. A browser extension is another tenant in the house that you have to feed with updates. I already failed to feed axios on time.
This was not a replacement for a manager with a thousand entries. A pocket multitool: generate, keep a few important items, leave. Enough for a freelancer who opens a new service every week. Not enough for a family vault of 400 accounts. I was not selling it to them.
Plans that never got used: a light import, more phrase dictionaries, an auto-lock on blur. Spring arrived before the dictionaries.
Supabase here is a courier: auth, blob storage, sync. Not a reader. I picked it so I would not write my own backend for a box a person may never turn on. Local mode should work even if the cloud dies tomorrow. The cloud, it turned out, can die for another reason.
April 2026
In spring 2026 the service was breached. The vector was an axios vulnerability that reached the backend. The attacker got the encrypted blobs stored on the server.
Without the passphrase the contents are useless. The fact that someone walked into the backend was already a failure. An architecture where “the server reads nothing” does not cancel a hole people walk through. I did not want to run a service I no longer trusted.
I shut everything down before it got worse.
Zero-knowledge does not excuse the backend. Dependencies are attack surface. Especially on a side project where you update when you remember. A pet project with live users is already a product. You cannot treat it like a toy.
No relaunch. If it ever comes back, only a shape with a tiny surface and a strict dependency pipeline. Not the same box with the same hole, freshly painted. Serverless, less long-lived backend, updates not “when I remember”. That is a note for later, not a date.
How I keep a backend under my own hands: Self-host Supabase.