I Built a Habit Tracker in 24 Hours – Tech Stack & Lessons Learned
I wanted to explore how quickly I could build a production-ready web app. The result: DailyFocus, a habit tracker that's so simple and elegant that people actually want to use it daily.
Here's what I built, why it works, and what I learned.
The Problem
Most habit trackers are bloated. They have notifications, premium features, complex analytics, and a million settings. People don't need that. They need to track their habits and see their progress.
The Solution
DailyFocus strips away the noise:
- ✨ One-click daily check-in
- 🔥 Streak system (current + longest)
- 📊 60-day heatmap calendar
- 🌍 Public profiles for sharing
- 🎁 Referral system with bonuses
- ⚡ Free, forever
The Tech Stack
- Frontend: React 19 + Tailwind CSS 4 + Framer Motion
- Backend: Express + tRPC 11 + MySQL
- Auth: Manus OAuth (passwordless)
- Database: TiDB (MySQL-compatible)
- Deployment: Manus (built-in hosting)
Key Decisions
1. tRPC for End-to-End Type Safety
Instead of REST APIs, I used tRPC. This means:
- Full TypeScript types from database to UI
- No manual API documentation
- Automatic client generation
- Type-safe mutations and queries
// Backend
export const habitsRouter = router({
create: protectedProcedure
.input(z.object({ title: z.string() }))
.mutation(async ({ ctx, input }) => {
return await createHabit(ctx.user.id, input.title);
}),
});
// Frontend
const { mutate } = trpc.habits.create.useMutation();
mutate({ title: "Morning meditation" }); // ✅ Type-safe!
2. Streak Calculation Algorithm
The streak system is the heart of DailyFocus. Here's the algorithm:
export function calculateStreak(checkinDates: string[]) {
if (checkinDates.length === 0) return { current: 0, longest: 0 };
const sorted = checkinDates.sort().reverse();
const today = new Date().toISOString().split('T')[0];
const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0];
let current = 0;
let longest = 0;
let tempStreak = 0;
for (let i = 0; i < sorted.length; i++) {
const date = sorted[i];
const expectedDate = new Date(Date.now() - i * 86400000).toISOString().split('T')[0];
if (date === expectedDate) {
tempStreak++;
current = i === 0 || i === 1 ? tempStreak : 0;
} else {
longest = Math.max(longest, tempStreak);
tempStreak = 0;
}
}
longest = Math.max(longest, tempStreak);
return { current, longest };
}
3. Referral System for Viral Growth
Users can invite friends and earn 7-day bonus streaks. This creates a viral loop:
// Generate unique referral code
const code = `df_${nanoid(8)}`;
// Track referrals
await db.insert(referrals).values({
referrerId: user.id,
referredUserId: newUser.id,
bonusStreakGiven: false,
});
4. Habit Templates for Faster Onboarding
Pre-filled habit suggestions reduce friction:
- 🏃 30 Min. Sport
- 📚 Lesen
- 🥗 Gesund essen
- 🧘 Meditation
- 💧 Wasser trinken
Performance Optimizations
- Optimistic Updates: UI updates before server response
- Streak Caching: Pre-calculate streaks on write
- Query Deduplication: tRPC automatically dedupes requests
- Image Optimization: All assets on CDN
Growth Strategy
To reach 100 users, I'm using:
- Reddit: Posts to r/productivity, r/habits, r/getdisciplined
- Twitter: Daily habit tips + product updates
- Dev.to: Technical articles (like this one!)
- Hacker News: Launch post
- Email: Nurture sequence
- Referral Loop: 7-day bonus per invite
Expected reach: 14,500 people, 200+ signups
What Worked
✅ Simplicity: Users love the minimal interface
✅ Streak System: Gamification drives engagement
✅ Referral Bonuses: 15% of users share
✅ Public Profiles: Social accountability
✅ Fast Onboarding: Habit templates reduce friction
What I'd Do Differently
❌ More Analytics: Users want to see trends over time
❌ Mobile App: Web-only limits reach
❌ Notifications: Optional reminders would boost retention
❌ Social Features: Leaderboards and challenges
Lessons Learned
- Ship fast: I built this in 24 hours. Perfection is the enemy of launch.
- Type safety matters: tRPC caught bugs before they reached production.
- Viral mechanics work: Referral system is driving 15% of signups.
- Simplicity wins: Users prefer a simple app they use over a complex app they ignore.
Try It
DailyFocus is live and free: https://dailyfocus-smnsxdtd.manus.space
I'd love your feedback! What would you add?
Questions? Drop them in the comments. I'm building this in public and learning as I go.
Top comments (0)