← all writing

Next.jsReactunfinished2 min

The note app I stopped building, and why that was right

SyneSama is an unfinished Next.js note-taking app whose entire database is a Map in module scope. It taught me the difference between a UI that looks done and a product that is.

SyneSama is not shipped, not deployed, and not going to be. It's a Next.js note-taking app I built in 2024 that has a working sidebar, a working editor, working note cards, responsive layout, and no database whatsoever.

I'm writing it up because the failure is more useful than most of my successes, and because pretending an unfinished project doesn't exist is how you avoid learning from it.

Where it stops

Here is the entire persistence layer:

// This is a placeholder for your database logic
let notes = new Map();
let nextId = 1;

export async function POST(request: Request) {
  const { content } = await request.json();
  const id = String(nextId++);
  notes.set(id, { id, content });
  return NextResponse.json({ id, message: 'Note created successfully' });
}

A Map in module scope. Even the comment admits it.

This does not work, in a specific way worth understanding. The route handler runs in a serverless function. Module scope lives as long as that instance does, which might be one request or a few dozen. Two users get two different instances and two different sets of notes. A cold start silently drops everything.

And it looks like it works, which is the trap. In dev, with one process and one user, notes save and load and everything feels finished. POST even returns 'Note created successfully'. The failure only appears under exactly the conditions you don't have while building.

The shape of the mistake

I built the app in the order that felt productive: layout, then sidebar, then NoteCard, then NoteEditor, then routes for creating and viewing. Every one of those steps produced something visible. Every one felt like progress.

The database was going to be next, and "next" never came, because by then the app looked finished. All the reward had already been collected. What remained was the part with no visual payoff and all of the actual difficulty — schema, migrations, auth, ownership, conflict handling.

The uncomfortable version: I'd built the easy 80% and mistaken it for 80% done.

What I do differently now

The riskiest part goes first. In Manthan, billing and Keycloak SSO went in early — both unglamorous, both invisible in a screenshot, both capable of invalidating the design if left late. Doing them first meant the UI got built against real constraints instead of imaginary ones.

"Placeholder" is a decision, not a note. A comment saying this is a placeholder for your database logic is a promise to yourself with no deadline attached. Either the boring version is real — SQLite, a file, anything with a lifetime longer than the process — or the feature doesn't exist yet. A Map pretending to be a database is worse than an endpoint returning 501, because 501 is honest.

Not finishing is a legitimate outcome. I didn't stop because it got hard. I stopped because partway through I understood I was building a worse Obsidian, and I already used Obsidian. The right move was to stop — and the thing I actually wanted turned out to be memqi, which reads the vault I was already writing in instead of asking me to move.

Killing this one is what made that one possible. The repo stays up as a marker of where the line was.

← all writing
~/mohith.tech/blog 2 min read © 2026 Mohith Sarma K L K