{"slug": "title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc", "title": "Title: How I Built ZenPlan: A Premium AI Habit Tracker with Next.js, Vercel OIDC, and Amazon DynamoDB", "summary": "A developer built ZenPlan, a premium AI habit tracker using Next.js 16, Vercel OIDC, and Amazon DynamoDB for the Hack the Zero Stack with Vercel v0 and AWS Databases Hackathon. The app features a glassmorphic UI, an AI coach, and analytics, with engineering challenges including edge caching and single-table DynamoDB design. The developer resolved caching issues by forcing dynamic routing and adding cache-control headers, and optimized performance with a single DynamoDB table structure.", "body_md": "I built this for the Hack the Zero Stack with Vercel v0 and AWS Databases Hackathon.\n\nHere's the thing—building a habit tracker sounds easy until you actually start building it. Check off a box, increment a counter, save it. Done, right? Wrong. If you want it to feel premium, look polished, and actually work without lag or weird edge-caching bugs, it gets complicated fast.\n\nSo I decided to build ZenPlan—a dark, glassmorphic habit tracker and routine planner that actually feels like a real app. I deployed it serverless on Vercel, hooked it up to Amazon DynamoDB, and ran into some genuinely interesting engineering problems. Let me walk you through how I built it.\n\nWhat's ZenPlan Actually Do?\n\nI didn't want just another boring checklist. The whole point was to make it feel alive and interactive.\n\nWhen you check off a habit, it triggers this CSS particle animation that actually feels good. I also built an AI Coach you can chat with—like, actually useful. If the coach suggests something (morning meditation, whatever), it renders an \"Add to Dashboard\" button right in the chat and writes it straight to your database. No copy-paste, no manual entry.\n\nOn top of that, there's an analytics section showing your streaks, a checkout modal where you can simulate upgrading to Pro, and even an interactive architecture diagram showing how data actually flows through the system in real-time.\n\nFor the tech stack, I went with Next.js 16 (App Router), Tailwind CSS, and Framer Motion on the frontend, backed by Amazon DynamoDB.\n\nThe Security Thing: Vercel OIDC + AWS IAM\n\nTechnical Deep Dive 2: Tackling Edge Caching & State Persistence\n\nDuring deployment on Vercel, I noticed that upgrading or cancelling a subscription plan would occasionally show outdated badges on the navbar due to Edge caching. I'd click upgrade, Vercel would execute it successfully, but the UI badge wouldn't update until a hard browser refresh.\n\nTo fix this, we forced dynamic routing on the API and injected explicit Cache-Control header directives into src/app/api/profile/route.ts: import { NextResponse } from 'next/server';\n\nimport { db, isDynamoConfigured } from '@/lib/db';\n\nexport const dynamic = 'force-dynamic';\n\nexport async function GET() {\n\ntry {\n\nconst profile = await db.getProfile();\n\nreturn NextResponse.json({\n\n...profile,\n\ndbMode: isDynamoConfigured ? 'Amazon DynamoDB' : 'Local File Simulator',\n\n}, {\n\nheaders: {\n\n'Cache-Control': 'no-store, max-age=0, must-revalidate',\n\n},\n\n});\n\n} catch (error) {\n\nconsole.error('API GET profile error:', error);\n\nreturn NextResponse.json({ error: 'Failed to fetch profile' }, { status: 500 });\n\n}\n\n} Alongside this server-side configuration, client-side fetches were updated with cache-busting search parameters: const response = await fetch(`/api/profile?t=${Date.now()}`\n\n, {\n\ncache: 'no-store'\n\n}); This double-layered solution ensures state modifications (e.g., ticking off a habit or upgrading a subscription) reflect instantly without reloading or facing stale client mismatches.\n\nTechnical Deep Dive 3: Single-Table DynamoDB Mode\n\nFor maximum performance and cost optimization, we structured profiles and habits in a single DynamoDB table. When DYNAMODB_TABLE_NAME is configured, the application appends partition keys (PK) and sort keys (SK):\n\nProfile Key: PK: PROFILE#default-user | SK: PROFILE\n\nHabit Key: PK: HABIT# | SK: HABIT\n\nDoing index scans on these partition and sort keys allowed us to fetch all dashboard dependencies in index scans, resulting in blazing fast loads.\n\nWhat I Learned\n\nOIDC is the Future: Passwordless integrations make serverless deploys safer and easier to maintain.\n\nEdge Cache Busting: When compiling React Server Components and Edge Route handlers, you must be extremely explicit about cache control header policies to keep client views synchronized. Links\n\nLive Demo: [https://zenplan-six.vercel.app](https://zenplan-six.vercel.app)\n\nGitHub Repository: [https://github.com/divinefavour1234567/zenplan](https://github.com/divinefavour1234567/zenplan)\n\nThank you to Vercel and AWS for hosting this amazing Hackathon! If you liked ZenPlan, please drop a star on the repo!", "url": "https://wpnews.pro/news/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc", "canonical_source": "https://dev.to/divinefavour1234567/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-nextjs-vercel-oidc-and-amazon-314l", "published_at": "2026-06-20 16:32:29+00:00", "updated_at": "2026-06-20 17:06:57.302078+00:00", "lang": "en", "topics": ["developer-tools", "ai-products", "artificial-intelligence", "ai-infrastructure"], "entities": ["ZenPlan", "Next.js", "Vercel", "Amazon DynamoDB", "Vercel OIDC", "AWS IAM", "Framer Motion", "Tailwind CSS"], "alternates": {"html": "https://wpnews.pro/news/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc", "markdown": "https://wpnews.pro/news/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc.md", "text": "https://wpnews.pro/news/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc.txt", "jsonld": "https://wpnews.pro/news/title-how-i-built-zenplan-a-premium-ai-habit-tracker-with-next-js-vercel-oidc.jsonld"}}