
Zapnin
Plans leave the group chat.
Selected work
Zapnin is a chat-first social planning app. Drop a plan in the group, everyone answers In, Maybe or Out, and a resolution engine untangles the “I'll go if you go” loops until the plan is actually on. Around the plan sits its own chat, a guest list, shared expenses that settle up over UPI, and an archive of the ones that happened.
Visit ZapninBuilt by Pivot & Anchor, a design and engineering studio.Zapnin is the most fun thing we've built, and the one that fought back hardest. It is a chat-first social planning app for the oldest problem in any group chat: the plan that never happens.
You know the failure. Someone says “we should hang out,” three people say “maybe,” one says “I'm down if everyone else is,” and the thread dies. Zapnin replaces the maybe. Everyone answers In, Maybe or Out. Conditions stay private. A resolution engine works out who is waiting on whom, breaks the loops, and the moment it tips, the plan is on.
How it works

01 — The first decision
Twelve vibes, and no form
A plan starts with what kind of thing it is, not with a date. One tap sets the artwork and the invite wording, and decides whether the plan even needs a place at all. Everything after this screen is optional.
02 — Enough to answer
A plan you can reply to
Photo, title, who is coming and when all sit on one card, and the time can be left as let everyone decide. The invite goes out with enough context that nobody has to ask the host what the plan actually is.
03 — The part that stalls
Pick a day, or deliberately don't
Some plans have a date. Most do not, and that is where group chats go to die. The host can leave the time open on purpose, and the app collects real availability instead of four people saying they are flexible.
04 — The other part that stalls
A place, online, or undecided
Location gets the same treatment. Undecided is a state the plan is allowed to hold, so everyone can see what still needs input rather than guessing whether anyone has booked anything.
05 — Sent
Now it is a thing, not a message
The plan becomes an object with its own chat, its own guest list and its own answer state. It stops being the fourteenth message in a thread that scrolls away by Thursday.
What we built
Honest responses
In, Maybe or Out. Maybe is the wedge: an answer that keeps the plan alive instead of stalling it, and a private condition underneath it that nobody else ever sees.
The resolution engine
A graph that maps conditions, detects circular dependencies, and resolves chains automatically from confirmed anchors outward.
Live status
Every response propagates to every device in real time, so the plan's state is always honest and shared.
Split the bill
In-chat expenses, simplified-debt settlement to the fewest transfers, and circles that remember your groups.
Privacy by default
Show the status, not the story. Conditions stay private; only the outcome is shared.
Zapnin looks like a chat app. Underneath, it is a coordination engine.
The mobile app is React Native on Expo SDK 54, one TypeScript codebase across iOS and Android, on the New Architecture. State is local-first: Zustand stores hydrated from encrypted on-device storage, updated optimistically, with a query cache as a warm fallback. A socket layer keeps it honest. Every plan and every chat is a live room, and responses reach every invitee the instant they happen.
The resolution lives on the server, never the client. The client renders state; it does not compute it. A “depends on Priya” can resolve from any device without races. The engine builds a dependency graph per plan, detects cycles, anchors on the hard confirmations, and propagates outward until the plan finalizes. That is the piece everything else hangs off.
The backend is Node and Express on PostgreSQL with Drizzle, twenty-three tables modelling plans, invitees, conditions, chat, bills, and circles. Socket.IO runs behind a Redis adapter so it scales across instances. Background work runs on BullMQ: nudges to non-responders, day-of reminders, deadline checks, auto-completion, and a settlement cascade across circles.
It runs on Railway, with Postgres, Redis, and a multi-stage Docker build that migrates on deploy. There is a web layer too: a marketing site plus invite links that let someone RSVP and vote on the venue from a browser before they ever install, and a private operations dashboard for the team.
The hard parts
The resolution engine
Graph-based dependency propagation with cycle detection and anchor-based confirmation. The maybe-loop, solved in code.
Real time at scale
Socket.IO behind a Redis adapter, every plan and chat a live room, state broadcast cleanly across instances.
Notifications that respect you
Escalation-based push batching with atomic Redis operations. A busy chat sends one digest, not forty pings, and a mention always breaks through.
Money math, instant
Simplified-debt settlement and a layered, stampede-proof cache so balances across every plan stay instant.
Honest offline
Optimistic UI with rollback, a message queue for dead zones, and a reachability check tuned for real-world networks.
Zapnin pairs a loud display face with a calm body. Righteous carries the headlines, round and confident, the way the product talks. Plus Jakarta Sans does the reading, neutral and modern.
- RighteousDisplay & headings
- Plus Jakarta SansBody & UI
Electric azure leads, the current colour of the brand and every primary action. Then a pair you read without thinking: emerald means In, red means Out. Amber warns, and true black carries the dark mode.
- AzurePrimary. The current brand and every key action.#3D6BFF
- Azure deepAccessible text and solid controls on light surfaces.#2C53E0
- EmeraldSuccess, and the colour of “In”.#10B981
- RedErrors, and the colour of “Out”.#EF4444
- AmberWarnings and pending states.#F59E0B
- InkTrue-black dark-mode background.#0A0A0A
- PaperLight-mode background; dark-mode text.#FAFAFA



