I built Spotin because I was tired of showing up to “highly rated” workspaces only to find zero outlets, dead WiFi, or a room full of people on calls. Static reviews never told me what it was actually like right now. I wanted something closer to Waze for desks: live signals from people who are there, filtered by how I like to work (quiet, power outlets, decent upload speed). I did the whole thing solo, so I chose tools that let one person ship fast without drowning in boilerplate. Next.js 15 and React 19 handled most of the heavy lifting. Server Components plus the new Actions pattern made the check-in form and concierge chat feel simple instead of wiring separate API routes for every mutation. Partial Prerendering kept the place listings fast while still showing fresh data. Tailwind v4’s build speed was noticeable during the many small UI tweaks; the CSS-first setup also removed the usual config fights.
The data side was the real puzzle. DynamoDB forced me to design access patterns before I wrote much code. I went with a single table plus a few global secondary indexes so I could query by location, pull recent check-ins for the crowd score, and run the personalization logic without scanning the whole table. The Fresh Work Score uses a simple time decay since last check-in. I calculate it on read and let DynamoDB Streams push updates when someone checks in, so the “freshness” number actually moves. The hardest parts were the personalization retrieval and making the AI recommendations explain themselves.
I had to shape the user profile data so the query could actually rank places by noise tolerance, outlet priority, and WiFi needs, then feed that context into the chat without the model hallucinating reasons. Getting the decay and live check-in numbers to feel trustworthy took more iteration than I expected. I also spent too much time early on trying to pre-compute everything; in the end a mix of on-read calculation and stream-driven updates worked better.
What I learned: modeling real-world signals in NoSQL is mostly about the queries you need to support, not the data you want to store. React 19’s Actions made form-heavy flows (check-ins, feedback) feel native instead of bolted on. And users care more about “three people checked in here in the last hour and it’s quiet” than any star rating. Shipping solo meant I cut scope aggressively core recommendation loop and chat first, admin analytics and nicer mobile views later. The project is still rough in places, but the core loop (see live signals → get a recommendation that explains why) already feels useful.
Built With
- amazon-dynamodb-(single-table-design
- better-auth-(email/password
- email-password
- google-oauth
- gsis
- next.js-15-(app-router
- partial-prerendering)
- react-19-(actions
- role-based
- server-components
- server-components)
- sessions
- streams-for-real-time-signals)
- tailwind-css-v4-(oxide-engine-+-css-first-config)
- useoptimistic
Log in or sign up for Devpost to join the conversation.