All Posts
ProductDecember 15, 2025

The GoalSlot Story: From Idea to Launch

How we built GoalSlot, a goal-tracking and time-blocking productivity app with calendar integration. Covers the SaaS product development process, architecture decisions, and real lessons from launching a goal tracking platform.

The Problem We Kept Running Into

Every productivity tool we tried solved one slice of the problem. Notion for notes. Google Calendar for scheduling. Toggl for time tracking. Linear for task management. None of them answered the question we actually cared about: am I spending time on the things that matter?

The gap wasn't in any single tool. It was in the space between them. Goals lived in one place, time lived in another, and the connection between "I want to ship feature X this quarter" and "here's when I'm actually working on it" was entirely manual.

We built GoalSlot to fix that disconnect. It's a goal-tracking, time-blocking productivity platform that connects your objectives directly to your calendar. Started as an internal tool. Turned into a SaaS product. The journey from idea to launch taught us more than we expected about building productivity software people actually stick with.

The Core Idea

Goals Q1: Ship v2 schedule Time Slots Mon 9-11am: v2 work track Progress Tracking 12hrs / 40hrs target

The insight was simple: time blocks are the atomic unit of productivity. If every block on your calendar is connected to a goal, and time tracking is built into the calendar itself, then progress measurement happens automatically. No extra apps, no manual logging.

Architecture Decisions

Stack

We went with a stack we trust for production:

  • Next.js for the frontend. SSR for fast loads, client-side interactivity for the calendar UI.
  • Node.js API layer for business logic.
  • PostgreSQL for structured data: goals, time slots, users, analytics.
  • WebSocket connections for real-time calendar sync across devices.

The Calendar Problem

Building a calendar UI that feels native is harder than it looks. We evaluated existing libraries (FullCalendar, react-big-calendar) and found they all made the same mistake: they treat events as display-only entities.

In GoalSlot, a time slot is an interactive object. You can:

  • Drag to resize (adjusting the time commitment)
  • Click to start/stop tracking
  • See goal progress roll up in real-time as you complete slots

We ended up building the calendar from scratch using a grid-based layout. More work upfront, but it gave us complete control over the interaction model.

MON TUE WED THU FRI 9am 11am 1pm 3pm Ship v2 API 2h tracked Design Review 1.5h tracked Ship v2 API Deep work 4h tracked User Research 2h tracked Sprint Review 1h planned This Week 9.5h of 20h goal Ship v2 6h Design 1.5h Research 2h

Data Model

The core schema is straightforward:

  • Goals have a title, a time target (hours per week/month/quarter), and a color
  • Slots belong to a goal, have a start/end time, and a tracked duration
  • Users have preferences, timezone, and connected calendar integrations

The key insight: slots can exist in two states, planned (on the calendar but not yet worked on) and tracked (timer was started and stopped). This distinction makes the analytics useful. You can see not just what you planned, but whether you actually followed through.

Technical Deep Dive: Real-Time Sync

One of the trickiest parts of building a calendar-based productivity app is making it feel instant across devices. When you drag a time slot on your laptop, your phone should reflect the change before you look down at it.

WebSocket Architecture

Every client opens a persistent WebSocket connection scoped to the user's workspace. When a user modifies a slot (creating, moving, resizing, or tracking), the change flows through three stages:

  1. Optimistic update. The local UI applies the change immediately, no round-trip wait.
  2. Server broadcast. The API validates the change, persists it, and pushes an event to all other connected clients in the workspace.
  3. Confirmation or rollback. The originating client receives either a confirmation (with the server-assigned timestamp) or a rejection, in which case the optimistic update is reverted.
Real-Time Sync: Sequence Flow Device A Server Device B 1. Optimistic Update (local) slot.move {id, start, end} Validate + Persist broadcast: slot.updated ack + server timestamp Apply update to local state ! Conflict Scenario move slot to 2pm move slot to 4pm Last-write-wins (ts) rollback + correct state

Conflict Resolution

The interesting edge case: what happens when two people (or two devices) edit the same slot at the same time?

We use a last-write-wins strategy with server-assigned timestamps. When two conflicting writes arrive, the server accepts the one with the later timestamp and sends a rollback event to the other client. The losing client's optimistic update gets reverted, and they see the slot snap to the winning state.

This works well for our use case because slot edits are infrequent enough that conflicts are rare, and when they happen, the visual correction is immediate. We considered CRDTs, but the added complexity wasn't worth it for a calendar where most operations are user-initiated and non-concurrent.

Optimistic Updates in Practice

The pattern that made the biggest UX difference: we apply changes to local state before the server responds. Dragging a slot feels instant because the UI doesn't wait for a network round-trip. If the server rejects the change (overlapping slot, permission issue), we animate the slot back to its original position with a subtle shake animation. Users almost never see this, but when they do, it feels like a natural "nope" rather than a broken experience.

What Worked

Goal-to-calendar mapping was the feature that made everything click. Instead of separate goals and calendar views, GoalSlot treats them as one system. Every block on your calendar is connected to a goal. Progress rolls up automatically.

Time tracking that doesn't feel like time tracking. Click a slot, tracking starts. Finish, it stops. No separate timer window, no forgetting to log hours. The calendar is the tracker.

Weekly reviews. We added a simple weekly summary: hours planned vs. hours tracked per goal. It became the most-used feature. Most people don't need a complex analytics dashboard. They need one clear view of whether they're spending time on what matters.

What We'd Do Differently

We over-engineered permissions early. We built team collaboration features from day one: shared goals, workspace roles, team analytics. Our first users were individuals. We spent 3 weeks on a permission system that nobody used for months. Ship the simpler version first.

The onboarding was too long. V1 required setting up goals before showing the calendar. Users dropped off. Now the calendar is the first thing you see, and goals are introduced contextually. Time-to-value matters more than feature completeness.

We should have used an existing auth provider sooner. We built custom auth, then migrated to a managed provider 4 months later. That migration was a week of work that we could have avoided entirely.

Lessons for Founders Building SaaS Products

Building GoalSlot taught us a lot about shipping productivity software. Some of this applies to any SaaS product, but especially to products that need to earn a daily habit. (If you're looking for a team to help you build, we do exactly this kind of product development work.)

Choose the Right Level of Abstraction

The biggest architectural decision you'll make early on is how much to build versus how much to adopt. We built our calendar grid from scratch. Right call, since calendar interaction was our core differentiator. But we also built custom auth, and that was a waste.

The rule we landed on: build custom only where your product's unique value lives. Everything else (auth, payments, email, infrastructure), use the best existing solution and move on. Your users don't care that you rolled your own auth. They care that the thing they came for works well.

Validate Before You Build

We spent three weeks on team permissions before a single user asked for it. The fix was embarrassingly simple: we started shipping features only after hearing the same request from three separate users. Not three people on our team, three customers.

For productivity apps specifically, validation looks different than other categories. People will tell you they want features they'll never use. The signal that matters is retention, not feature requests. Are people coming back daily? If yes, build what they're doing more of. If no, more features won't fix it.

Metrics That Matter for Productivity Apps

Most SaaS metrics (MRR, churn, NPS) apply to productivity apps, but there are a few that matter more in this category:

  • Daily active usage rate. Productivity apps live or die on daily habits. Weekly usage isn't enough.
  • Time-to-value. How fast does a new user get their first "aha" moment? For GoalSlot, that's seeing a goal connected to a calendar block. We got this under 90 seconds.
  • Feature adoption depth. Are users engaging with the core loop (goal + slot + tracking) or just using surface features?
  • Planned vs. completed ratio. This is GoalSlot-specific, but the principle applies broadly: measure whether your tool helps people follow through, not just plan.

The Build vs. Buy Decision Matrix

Every feature decision maps to two axes: how core is it to your value proposition, and how well do existing solutions cover it? We found this framework useful.

Build vs. Buy Decision Matrix Core to Value Proposition Low High Existing Solutions Quality Low High BUY Use existing solutions. Ship faster. WRAP Adapt an existing solution with a custom layer. SKIP Defer or drop it. Not worth building yet. BUILD This is your moat. Build it from scratch. Auth Billing Notifs Calendar Grid Goal Engine Team Perms Cal Sync

For GoalSlot, the calendar grid and goal engine were firmly in "BUILD" territory. Auth and billing were clear "BUY" decisions. Calendar sync APIs (Google Calendar, Outlook) landed in "WRAP" since we use the official APIs but built a custom abstraction layer on top. Team permissions? "SKIP" until we actually needed it.

When to Use Existing Components vs. Building Custom

A more granular version of the same question comes up at the component level. Our rule of thumb:

  • Use existing for anything interaction-standard: modals, dropdowns, toasts, form inputs. Users have expectations here, and meeting them is more important than originality. We use Radix primitives for most of this.
  • Build custom for anything that's part of your product's core interaction. For us, that's the calendar grid, the goal sidebar, the slot editor. These components encode your product's opinion about how things should work.
  • Fork and modify when an existing component gets you 80% there. We started with an open-source color picker for goal colors, then modified it to support our palette system. Cheaper than building from zero, but still tailored.

Takeaways

  1. Ship the simplest version that's still useful. GoalSlot v1 had half the features we planned. Right call. We learned more from 10 real users than from 100 hours of planning.
  2. Measure time-to-value, not feature count. The fastest path to value was seeing a goal on the calendar. Everything else could wait.
  3. Use your own product. We use GoalSlot every day. That keeps us honest about what works versus what sounds good in a spec.

Try It

GoalSlot is live and we're actively building based on user feedback. If you're interested in how we approach product development for products like this, that's one of our core service areas at Leaf Compute. Join our Discord to see what's coming next.