Workspace App β€” Implementation Plan & Work Breakdown

Document Type: Living Implementation Plan
Context: Solo developer, hobby-to-business trajectory, AI-assisted with full code review
Based on: Production-Grade Architecture Handover (May 2026)


Reading This Document

Tasks are grouped into phases. Each phase is a shippable milestone β€” by the end of it, something real and working exists that you can use, demo, or build on top of. Phases are sequenced to minimize re-work and to teach progressively harder concepts.

Complexity tags:
🟒 Beginner-friendly β€” follow-the-docs territory
🟑 Intermediate β€” requires understanding the β€œwhy”
πŸ”΄ Advanced β€” architectural weight-bearing, get it right first time

Learning tags:
πŸ“¦ Monorepo / toolchain
πŸ” Auth / Security
πŸ—„οΈ Database / Drizzle
🧩 Next.js patterns
🎨 UI / Mantine
✍️ Editor / Tiptap
πŸ€– AI / Embeddings
πŸ“± Mobile / PWA
πŸ–₯️ CLI / API
πŸ’³ Billing / SaaS


Phase 0 β€” Foundation & Tooling βœ… COMPLETE

Milestone: A working monorepo that builds, lints, and runs locally. The skeleton that every future phase lives inside.
Learning payoff: Turborepo, pnpm workspaces, TypeScript strict mode, project conventions.
Completed: May 2026

# Task Complexity Learning Status
0.1 Initialize pnpm monorepo with pnpm init and workspace config 🟒 πŸ“¦ βœ…
0.2 Set up Turborepo with turbo.json β€” define build, dev, lint, typecheck pipelines 🟒 πŸ“¦ βœ…
0.3 Create apps/web as a Next.js 16 App Router project with TypeScript strict 🟒 🧩 πŸ“¦ βœ…
0.4 Create apps/cli as a bare TypeScript package (empty for now, will be wired up later) 🟒 πŸ“¦ βœ…
0.5 Create packages/core β€” empty package with correct package.json and tsconfig 🟒 πŸ“¦ βœ…
0.6 Create packages/ui β€” empty package, will house shared Mantine components 🟒 πŸ“¦ βœ…
0.7 Create packages/features-registry β€” empty, will house ALL_FEATURES manifest 🟒 πŸ“¦ βœ…
0.8 Configure shared tsconfig.base.json at root; extend it in all packages 🟑 πŸ“¦ βœ…
0.9 Add ESLint + Prettier with boundary enforcement; wire into Turborepo lint pipeline 🟑 πŸ“¦ βœ…
0.10 Add .env.example template and document all required environment variables (see Β§20.1) 🟒 Β  βœ…
0.11 Set up Vercel project, link repo, configure environment variables in dashboard 🟒 Β  βœ…
0.12 Confirm turbo dev starts apps/web correctly from the monorepo root 🟒 πŸ“¦ βœ…
0.13 Add a root README.md documenting how to run, build, and add packages 🟒 Β  βœ…

Phase 0 Exit Criteria: βœ… All met.

  • pnpm turbo build completes without errors or warnings
  • pnpm turbo dev starts apps/web at localhost:3000
  • pnpm turbo lint and pnpm turbo typecheck pass across all 5 packages
  • Dependency boundary enforcement active β€” packages/* β†’ apps/* blocked by ESLint
  • Deployed to Vercel at https://sidekick-six-bay.vercel.app

Implementation notes:

  • Next.js 16 was current at time of implementation (plan said 15 β€” updated in place)
  • pnpm 11.0.8 via Corepack (plan said pnpm@8 β€” Corepack handles version enforcement)
  • apps/web/eslint.config.mjs generated by scaffolder was removed β€” root eslint.config.js handles all packages
  • apps/web/pnpm-lock.yaml generated by scaffolder was removed β€” root lockfile manages the workspace
  • packages/features-registry not packages/feature-registry β€” corrected after initial scaffold
  • turbo.json build.env array added to prevent stale Vercel cache when env vars change
  • Repo made public intentionally β€” see architecture handover Β§21

Phase 1 β€” Supabase & Auth Shell βœ… COMPLETE

Milestone: A real login screen that works. Protected routes. A profile in the database. The security skeleton everything else hangs on.
Learning payoff: Supabase auth, cookie sessions, Next.js middleware, server vs browser client separation.
Completed: May 2026

# Task Complexity Learning Status
1.1 Create Supabase project; enable email/password auth 🟒 πŸ” βœ…
1.2 Install Supabase client packages in packages/core 🟒 πŸ” βœ…
1.3 Implement createBrowserClient() helper in packages/core/supabase/browser.ts 🟑 πŸ” βœ…
1.4 Implement createServerClient() helper in packages/core/supabase/server.ts 🟑 πŸ” βœ…
1.5 Implement admin/service-role client in packages/core/supabase/admin.ts β€” server only πŸ”΄ πŸ” βœ…
1.6 Write profiles table schema in packages/core using Drizzle; add id, email, createdAt 🟑 πŸ—„οΈ βœ…
1.7 Set up drizzle.config.ts in packages/core; configure migrations folder 🟑 πŸ—„οΈ βœ…
1.8 Add a root pnpm db:migrate script that discovers and runs all package migrations in order πŸ”΄ πŸ—„οΈ πŸ“¦ βœ…
1.9 Enable RLS on profiles; add the canonical user-owns-rows policy πŸ”΄ πŸ” πŸ—„οΈ βœ…
1.10 Implement withRLS(userId, fn) helper in packages/core/db/rls.ts πŸ”΄ πŸ” πŸ—„οΈ βœ…
1.11 Implement Next.js proxy in apps/web β€” session refresh, redirect unauthenticated users, exclude /api/* πŸ”΄ 🧩 πŸ” βœ…
1.12 Build login page UI with Mantine form components 🟒 🎨 βœ…
1.13 Build sign-up page UI with email/password 🟒 🎨 βœ…
1.14 Add Mantine provider, Notifications, and PostCSS config (see Β§20.4) 🟑 🎨 βœ…
1.15 Implement post-login redirect to /dashboard 🟒 🧩 βœ…
1.16 Build a minimal dashboard shell layout (sidebar navigation placeholder, header) 🟒 🧩 🎨 βœ…
1.17 Implement sign-out functionality 🟒 πŸ” βœ…
1.18 Verify session persists across page reloads; verify redirect works for unauthenticated users 🟒 Β  βœ…

Phase 1 Exit Criteria: βœ… All met.

  • You can sign up, log in, and see a dashboard
  • Unauthenticated access to /dashboard redirects to login
  • RLS is enabled on profiles

Implementation notes:

  • Next.js 16 renamed middleware β†’ proxy. File: middleware.ts β†’ proxy.ts. Export: export function middleware β†’ export function proxy. The config export is unchanged. This affects how session refresh and route protection work at the edge.
  • Profile creation via Postgres trigger, not API route. Trigger on_auth_user_created on auth.users calls create_profile_for_new_user(). The function must reference public.profiles (fully qualified) because triggers run in the auth schema context. This approach handles all auth providers (email, OAuth, magic link) without per-provider app-level code, and cannot fail silently after auth succeeds.
  • CSS modules only. No inline styles. No Mantine style props. packages/eslint-plugin-sidekick with a no-mantine-style-props rule enforces this. Mantine behavioral props (withBorder, shadow, navbar=) are allowed; pure style props (h, px, fw, c, mt, size, color, justify, gap) are banned.
  • 4 Supabase clients. A fourth client, createProxyClient(request, response), was added for the Edge runtime. It reads cookies from the incoming request/response directly and never imports next/headers (which is Node.js-only). Used exclusively in proxy.ts.
  • packages/copy added. Centralized string copy shared across all apps. Never hardcode user-visible strings in source files β€” import from packages/copy instead.
  • useNavigation hook added. Always calls router.push() + router.refresh() together. Prevents forgetting the refresh step after auth actions that change server-rendered state.
  • export const dynamic = 'force-dynamic' required. Must be set on all route groups that touch Supabase (e.g. (app)/layout.tsx, (auth)/layout.tsx). Prevents Next.js from pre-rendering server-rendered auth-dependent routes at build time.
  • dotenv-cli pattern for env loading. .env.local lives at the repo root only. All scripts that need env vars prefix with dotenv -e ../../.env.local --. Node.js --env-file flag is blocked as a security measure by Node.js itself.
  • GraphQL + Relay deferred to post-MVP. REST is sufficient for MVP. Relay + App Router friction is unresolved upstream. withApiGuard maps cleanly to REST. Can add GraphQL later without a full rewrite.
  • API versioning (/api/v1/) deferred to post-MVP. Current routes are at /api/. Versioning adds URL complexity for no current benefit β€” MVP has one client and breaking changes can be coordinated directly.
  • DATABASE_DIRECT_URL (port 5432) for migrations only; DATABASE_URL (port 6543) for runtime. DATABASE_DIRECT_URL is NOT needed in Vercel β€” migrations run locally, never on Vercel.
  • Supabase renamed keys in 2025. NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY replaces the old NEXT_PUBLIC_SUPABASE_ANON_KEY. SUPABASE_SECRET_KEY replaces the old SUPABASE_SERVICE_ROLE_KEY.

Phase 2 β€” Core Infrastructure (API Guard, Feature System)

Milestone: The architectural backbone is live. withApiGuard is implemented and tested. The feature registry exists. You could add any feature safely from here.
Learning payoff: Middleware patterns, centralized auth, feature flags, the β€œwhy” behind the architecture.

# Task Complexity Learning
2.1 Implement resolveApiCaller(req) in packages/core/api/auth.ts β€” handles both cookie sessions and Bearer API keys πŸ”΄ πŸ” 🧩
2.2 Implement withApiGuard(handler, opts) in packages/core/api/guard.ts (see Β§10.2 canonical implementation) πŸ”΄ πŸ” 🧩
2.3 Wire withRLS inside withApiGuard πŸ”΄ πŸ” πŸ—„οΈ
2.4 Add basic request logging inside withApiGuard (method, path, userId, latency) 🟑 🧩
2.5 Add auth failure logging inside withApiGuard 🟑 🧩
2.6 Define FeatureManifest type in packages/features-registry 🟑 πŸ“¦
2.7 Implement ALL_FEATURES array in packages/features-registry/index.ts β€” start with an empty array 🟑 πŸ“¦
2.8 Create user_feature_entitlements table in packages/core with userId, featureSlug, RLS policy πŸ”΄ πŸ—„οΈ πŸ”
2.9 Implement getEnabledFeatures(userId) in packages/core β€” reads from entitlements table 🟑 πŸ—„οΈ
2.10 Write a seed script to enable all features for your own user account during development 🟒 πŸ—„οΈ
2.11 Create a test API route /api/health using withApiGuard to verify the full guard chain works 🟑 🧩 πŸ”
2.12 Verify 401 is returned when unauthenticated; 403 when a feature is disabled 🟒  

Phase 2 Exit Criteria: withApiGuard is implemented and the /api/health route correctly returns 401/403 in the right conditions. The feature system can enable/disable features per user.


Phase 3 β€” First Feature: Notes (End-to-End Vertical)

Milestone: A fully working Notes feature β€” create, read, update, soft-delete. This is your β€œproof of architecture” feature. Every future feature follows this exact same pattern.
Learning payoff: The complete feature loop: schema β†’ migration β†’ API β†’ repository β†’ UI. This is the template you’ll reuse for every other feature.

# Task Complexity Learning
3.1 Create packages/feature-notes with its own package.json, tsconfig, and Drizzle config 🟑 πŸ“¦ πŸ—„οΈ
3.2 Define notes table schema in packages/feature-notes/schema.ts β€” include id (client UUID), userId, title, content, createdAt, updatedAt, deletedAt, embeddingStatus πŸ”΄ πŸ—„οΈ
3.3 Run migration; verify table appears in Supabase dashboard 🟒 πŸ—„οΈ
3.4 Enable RLS on notes; add canonical user-owns-rows policy πŸ”΄ πŸ” πŸ—„οΈ
3.5 Register notes feature in packages/features-registry/ALL_FEATURES 🟒 πŸ“¦
3.6 Implement NotesRepository in packages/feature-notes/repository.ts β€” list(), getById(), create(), update(), softDelete() πŸ”΄ πŸ—„οΈ
3.7 Implement GET /api/notes route using withApiGuard + feature guard + notes:read scope πŸ”΄ 🧩 πŸ”
3.8 Implement POST /api/notes route β€” accept client-generated UUID πŸ”΄ 🧩 πŸ”
3.9 Implement GET /api/notes/[id] route 🟑 🧩
3.10 Implement PATCH /api/notes/[id] route 🟑 🧩
3.11 Implement DELETE /api/notes/[id] route β€” soft delete only, set deletedAt 🟑 🧩 πŸ—„οΈ
3.12 Build Notes list page at /notes β€” server component fetching notes via repository 🟑 🧩 🎨
3.13 Build Note detail/edit page at /notes/[id] 🟑 🧩 🎨
3.14 Build β€œNew Note” flow with client-generated UUID 🟑 🧩 🎨
3.15 Wire up soft-delete in the UI with confirmation 🟒 🎨
3.16 Enable the notes feature for your own user account via seed script 🟒  
3.17 Manually test the full CRUD loop via both UI and direct API calls (use curl or Postman) 🟒  

Phase 3 Exit Criteria: Notes can be created, edited, listed, and soft-deleted through the UI. The API layer enforces auth and feature entitlement. All queries filter where(isNull(notes.deletedAt)).


Phase 4 β€” Rich Text Editor (Writing Feature)

Milestone: A proper writing experience with Tiptap. Notes and Writing share the editor component. This is where the app starts feeling real.
Learning payoff: Tiptap configuration, rich text as JSON storage, markdown export, editor extensions.

# Task Complexity Learning
4.1 Install Tiptap dependencies in packages/ui 🟒 ✍️
4.2 Build a <RichTextEditor> component in packages/ui using @mantine/tiptap 🟑 ✍️ 🎨
4.3 Configure extensions: Bold, Italic, Heading, BulletList, OrderedList, Code, Link, Image 🟑 ✍️
4.4 Implement JSON storage β€” editor outputs editor.getJSON() for storage πŸ”΄ ✍️
4.5 Implement markdown export β€” editor.storage.markdown.getMarkdown() for embedding pipeline πŸ”΄ ✍️
4.6 Make editor mobile-friendly (touch targets, mobile toolbar) 🟑 ✍️ πŸ“±
4.7 Swap plain textarea in Notes editor for <RichTextEditor> 🟒  
4.8 Create packages/feature-writing with its own schema 🟑 πŸ“¦ πŸ—„οΈ
4.9 Define documents table β€” similar shape to notes but with type (essay, journal, draft) 🟑 πŸ—„οΈ
4.10 Implement full API routes for Writing feature (same pattern as Notes) 🟑 🧩
4.11 Register writing feature in feature registry 🟒  
4.12 Build Writing section in the app shell (/writing) 🟑 🧩 🎨

Phase 4 Exit Criteria: The rich text editor is shared, reusable, stores JSON, exports markdown. Notes and Writing both use it.


Phase 5 β€” Content Features (Bookmarks, Recipes, Budget)

Milestone: The app is a multi-feature productivity tool. Three more features built using the established pattern.
Learning payoff: Repetition builds fluency. Schema design for varied content types. Simpler after Notes.

Each sub-feature follows the same pattern: schema β†’ migration β†’ RLS β†’ feature registry β†’ API routes β†’ repository β†’ UI pages.

5A β€” Bookmarks

# Task Complexity
5A.1 Create packages/feature-bookmarks; define bookmarks schema (url, title, description, tags, favicon) 🟑
5A.2 Migration, RLS, feature registry entry 🟑
5A.3 API routes: list, create, update, soft-delete 🟑
5A.4 Implement BookmarksRepository 🟑
5A.5 UI: Bookmarks list with search/filter by tag 🟑
5A.6 UI: Add bookmark form (URL, auto-fetch title/description via server action) 🟑

5B β€” Recipes

# Task Complexity
5B.1 Create packages/feature-recipes; define recipes schema (title, ingredients, steps, tags, servings) 🟑
5B.2 Migration, RLS, feature registry entry 🟑
5B.3 API routes: list, create, update, soft-delete 🟑
5B.4 Implement RecipesRepository 🟑
5B.5 UI: Recipe list with search 🟑
5B.6 UI: Recipe detail with structured ingredients and steps 🟑

5C β€” Budget

# Task Complexity
5C.1 Create packages/feature-budget; define transactions schema (amount, category, date, notes) 🟑
5C.2 Migration, RLS, feature registry entry 🟑
5C.3 API routes: list (with date range filter), create, update, soft-delete 🟑
5C.4 Implement BudgetRepository 🟑
5C.5 UI: Transaction list with monthly grouping 🟑
5C.6 UI: Simple spending summary by category 🟑

Phase 5 Exit Criteria: All three content features are live, follow the same architectural patterns, and are protected by the feature entitlement system.


Phase 6 β€” AI Layer (Embeddings + RAG + Chat)

Milestone: Your content is semantically searchable. An AI chat interface can answer questions about your notes, bookmarks, and recipes. This is where the app becomes genuinely powerful.
Learning payoff: pgvector, HNSW indexes, semantic chunking, the Vercel AI SDK, streaming responses, RAG pipeline design.

# Task Complexity Learning
6.1 Enable pgvector extension in Supabase 🟒 πŸ€–
6.2 Add embedding vector column to notes, documents, bookmarks, recipes tables 🟑 πŸ€– πŸ—„οΈ
6.3 Create HNSW indexes on each embedding column πŸ”΄ πŸ€– πŸ—„οΈ
6.4 Implement generateEmbedding(text) in packages/core/ai/embed.ts using OpenAI text-embedding-3-small 🟑 πŸ€–
6.5 Implement semantic chunking strategy β€” split tiptap JSON β†’ markdown β†’ chunks with overlap πŸ”΄ πŸ€– ✍️
6.6 Implement async background embedding job with retry (2 retries, exponential backoff) using waitUntil() πŸ”΄ πŸ€– 🧩
6.7 Wire embedding generation into Notes create/update API routes β€” non-blocking, sets embeddingStatus πŸ”΄ πŸ€– πŸ”
6.8 Implement match_content() PostgreSQL function for vector similarity search πŸ”΄ πŸ€– πŸ—„οΈ
6.9 Create packages/feature-ai-chat with its own schema (chat_sessions, chat_messages) 🟑 πŸ“¦ πŸ—„οΈ
6.10 Migration, RLS, feature registry entry for AI Chat 🟑  
6.11 Implement POST /api/ai/chat streaming route using Vercel AI SDK + Anthropic Claude πŸ”΄ πŸ€– 🧩
6.12 Implement RAG context retrieval in the chat handler β€” retrieve top-k relevant chunks before calling LLM πŸ”΄ πŸ€–
6.13 Build AI Chat UI in packages/feature-ai-chat β€” streaming message display, input, loading states 🟑 🎨 🧩
6.14 Add /chat page to app shell 🟒  
6.15 Implement embeddingStatus monitoring β€” a simple admin view showing failed embeddings 🟑 πŸ€–
6.16 Add retry trigger API endpoint for failed embeddings 🟑 πŸ€–

Phase 6 Exit Criteria: You can type a question in the chat, it retrieves relevant chunks from your notes/recipes/bookmarks, and streams a contextual answer from Claude. Failed embeddings are visible and retriable.


Phase 7 β€” PWA & iOS Shell

Milestone: The app is installable on your iPhone. It works as a PWA in the browser and as a side-loaded Capacitor app.
Learning payoff: Service workers, PWA manifest, Capacitor, mobile UX constraints.

# Task Complexity Learning
7.1 Install and configure Serwist for service worker support in apps/web 🟑 πŸ“±
7.2 Create manifest.json β€” app name, icons, display mode, theme color 🟒 πŸ“±
7.3 Configure offline asset caching strategy in the service worker 🟑 πŸ“±
7.4 Test PWA install flow in Chrome DevTools and on iPhone via Safari 🟒 πŸ“±
7.5 Audit mobile UI β€” touch targets, viewport, safe areas, keyboard behavior 🟑 πŸ“± 🎨
7.6 Initialize Capacitor in apps/web 🟑 πŸ“±
7.7 Configure Capacitor to point at the hosted Vercel Next.js URL 🟑 πŸ“±
7.8 Build and side-load the iOS app onto your iPhone using Xcode 🟑 πŸ“±
7.9 Test core flows (login, notes, chat) on device 🟒  
7.10 Handle iOS safe area insets in the layout 🟑 πŸ“±

Phase 7 Exit Criteria: App is installable as a PWA from Safari, side-loadable as an iOS app via Capacitor. Core features work on-device.


Phase 8 β€” API Keys & CLI

Milestone: You can use your own app from the terminal. API keys are manageable from the UI. The CLI is a real working tool.
Learning payoff: CLI tooling (commander.js or similar), API key security patterns, Bearer auth flows, streaming in a terminal context.

# Task Complexity Learning
8.1 Create api_keys table in packages/core (see Β§8.3 canonical schema) 🟑 πŸ—„οΈ πŸ”
8.2 Migration + RLS for api_keys 🟑 πŸ—„οΈ πŸ”
8.3 Implement API key generation β€” secure random bytes β†’ raw key returned once β†’ SHA-256 hash stored πŸ”΄ πŸ”
8.4 Wire Bearer API key lookup into resolveApiCaller() in packages/core πŸ”΄ πŸ”
8.5 Implement POST /api/api-keys β€” create key, return raw key once πŸ”΄ πŸ” 🧩
8.6 Implement GET /api/api-keys β€” list keys (no raw key values, show label/scopes/last-used) 🟑 🧩
8.7 Implement DELETE /api/api-keys/[id] β€” revoke key by setting revokedAt 🟑 🧩
8.8 Update withApiGuard to track lastUsedAt on successful API key auth 🟑 πŸ”
8.9 Build API key management UI β€” list keys, create key (show raw key once), revoke 🟑 🎨
8.10 Build apps/cli as a Node.js CLI tool β€” authenticate with API key from env/config file 🟑 πŸ–₯️
8.11 Implement cli notes list command 🟑 πŸ–₯️
8.12 Implement cli notes create command (from stdin or file) 🟑 πŸ–₯️
8.13 Implement cli chat command with streaming output to terminal πŸ”΄ πŸ–₯️ πŸ€–
8.14 Document CLI usage in README 🟒  

Phase 8 Exit Criteria: You can generate an API key in the UI, set it as an env var, and run cli notes list and cli chat from your terminal.


Phase 9 β€” Observability & Hardening

Milestone: The app is reliable enough for friends and family. You have visibility into what’s failing. Error handling is consistent.
Learning payoff: Structured logging, error boundaries, rate limiting, the operational side of running a web service.

# Task Complexity Learning
9.1 Add structured request logging to withApiGuard β€” method, path, userId, latency, status 🟑 🧩
9.2 Add auth failure logging β€” track 401/403 patterns 🟑 πŸ”
9.3 Add failed embedding logging with enough context to retry 🟑 πŸ€–
9.4 Add Next.js error boundaries to all main UI sections 🟑 🧩
9.5 Add global API error response normalization β€” consistent { error, code } shape 🟑 🧩
9.6 Review and audit all API routes β€” confirm every route uses withApiGuard 🟒 πŸ”
9.7 Audit all queries β€” confirm where(isNull(table.deletedAt)) on syncable tables 🟒 πŸ—„οΈ
9.8 Add basic rate limiting on auth routes and AI chat endpoint 🟑 πŸ”
9.9 Run a manual penetration test of your own app β€” try to access another user’s data πŸ”΄ πŸ”
9.10 Add input validation (zod) on all API route handlers 🟑 🧩

Phase 9 Exit Criteria: Logs are structured and useful. All routes are guarded. No RLS gaps. Input validation is consistent across the API.


Phase 10 β€” Dogfooding (Friends & Family Access)

Milestone: You can invite others to use the app. They have their own isolated data. You have a basic way to manage who has access.
Learning payoff: Multi-user ops, invite flows, feature management for different users.

# Task Complexity Learning
10.1 Build an invite flow β€” generate invite link that pre-approves sign-up πŸ”΄ πŸ” 🧩
10.2 Build a simple admin page (your user only) to list users and manage feature entitlements 🟑 🎨 πŸ”
10.3 Add isAdmin flag to profiles table; gate admin pages behind it 🟑 πŸ”
10.4 Enable specific features for invited users from the admin panel 🟑  
10.5 Test full sign-up and feature access flow from a fresh incognito session 🟒  
10.6 Collect feedback from dogfood users; create a prioritized bug list 🟒  

Phase 10 Exit Criteria: You can invite someone, they can sign up, they have access only to the features you enabled for them, and their data is fully isolated from yours.


Phase 11 β€” Billing & SaaS Readiness (Optional Path)

Milestone: The app can charge for access. Feature entitlement is tied to subscription tier. The foundation for a real business offering.
Learning payoff: Stripe integration, webhook handling, subscription state management, SaaS architecture patterns.

# Task Complexity Learning
11.1 Create Stripe account; configure products and price tiers 🟒 πŸ’³
11.2 Add subscriptions table β€” userId, stripeCustomerId, stripePriceId, status, currentPeriodEnd 🟑 πŸ—„οΈ πŸ’³
11.3 Implement Stripe checkout session creation in POST /api/billing/checkout 🟑 πŸ’³ 🧩
11.4 Implement Stripe webhook handler β€” sync subscription state into subscriptions table πŸ”΄ πŸ’³ πŸ”
11.5 Update getEnabledFeatures() to resolve features from subscription tier as well as manual entitlements πŸ”΄ πŸ’³ πŸ—„οΈ
11.6 Build billing settings page β€” current plan, upgrade CTA, portal link 🟑 🎨 πŸ’³
11.7 Implement Stripe customer portal redirect for managing subscriptions 🟑 πŸ’³
11.8 Add a landing page or marketing page explaining features per tier 🟒 🎨
11.9 End-to-end test: sign up β†’ subscribe β†’ gain feature access β†’ cancel β†’ lose access 🟑 Β 

Phase 11 Exit Criteria: A new user who subscribes to a paid plan automatically gains access to paid features. A cancelled user loses access at period end.


Phase 12 β€” Bots, Workflows & Agents (Future)

Milestone: The app can execute automations on your behalf. External agents can interact with your data via the public API.
Learning payoff: Agent interoperability, webhook-driven automation, workflow design patterns.

# Task Complexity Learning
12.1 Design a workflows schema β€” trigger type, actions, enabled flag πŸ”΄ πŸ—„οΈ
12.2 Implement a simple recurring workflow β€” e.g., weekly digest of bookmarks emailed to self 🟑 🧩
12.3 Add webhook ingest endpoint β€” external services can push events to the app πŸ”΄ πŸ” 🧩
12.4 Document the public API surface for agents β€” OpenAPI spec or equivalent 🟑 πŸ–₯️
12.5 Evaluate Inngest for durable workflows if complexity warrants it 🟑  
12.6 Add agent-friendly scoped API keys for automation use cases 🟑 πŸ”

If you’re new to some of the tech in this stack, here’s the minimum viable reading before each phase:

Before Phase Read / Watch
Phase 0 Turborepo docs getting started; pnpm workspaces
Phase 1 Supabase Auth docs; Next.js App Router docs (routing, middleware, server components)
Phase 2 Next.js Route Handlers; how middleware chains work
Phase 3 Drizzle ORM quickstart; PostgreSQL RLS basics
Phase 4 Tiptap getting started; @mantine/tiptap docs
Phase 6 pgvector README; Vercel AI SDK docs; Anthropic API docs
Phase 7 Serwist docs; Capacitor iOS quickstart
Phase 8 Node.js CLI patterns (commander.js); API key security best practices
Phase 11 Stripe docs: Checkout, webhooks, customer portal

Architectural Invariants to Review After Every Phase

Before moving to the next phase, verify:

  • Every new API route uses withApiGuard()
  • No packages/* imports from apps/*
  • Every new user-owned table has RLS enabled with the canonical policy
  • Every new table with user content uses withRLS() via the guard, not inline
  • All mutations go through the repository layer
  • Syncable tables include createdAt, updatedAt, deletedAt
  • Soft deletes only β€” no hard deletes on user data
  • All queries on syncable tables filter where(isNull(table.deletedAt))
  • Content tables in the embedding pipeline have embeddingStatus

Rough Effort Estimates (Solo, AI-assisted, Learning pace)

Phase Estimated Sessions Notes
Phase 0 2–3 sessions Mostly config, fast with AI help
Phase 1 3–5 sessions Auth has depth; worth going slow
Phase 2 2–4 sessions Conceptually dense; revisit often
Phase 3 4–6 sessions The learning payoff is highest here
Phase 4 2–4 sessions Tiptap is well-documented
Phase 5 4–8 sessions Repetition; gets faster each sub-feature
Phase 6 6–10 sessions Most technically complex phase
Phase 7 2–4 sessions Mostly config and testing
Phase 8 3–5 sessions CLI is fun; API key crypto needs care
Phase 9 2–3 sessions Audit work; methodical
Phase 10 2–3 sessions Satisfying milestone
Phase 11 4–6 sessions Stripe webhooks need careful testing
Phase 12 Open-ended Exploratory; do when ready

Sessions are loosely defined as focused 2–3 hour working blocks. Estimates assume you’re reviewing every line and asking questions β€” that’s the point.


Back to top

Sidekick internal documentation — not for public distribution.