# Phase 3 — Advanced Features Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Build sharing, subscriptions, notifications, profile settings, onboarding wizard, summary metrics with charts, and task report PDF download. **Architecture:** A shared foundation layer (hooks, settings hub, notification bell) is built first, then 5 domain agents run concurrently on independent feature areas. Each agent produces pages and components that compile independently. **Tech Stack:** Next.js 16 (App Router), TanStack Query v5, React Hook Form + Zod 4, shadcn/ui + Radix, Tailwind CSS 4, Recharts (new), Zustand, Lucide icons. --- ## Execution Strategy: 7 Tasks, 5 Run in Parallel ``` Task 1: Shared Foundation (sequential — all features depend on this) ↓ Task 2: Sharing (residence + contractor) ─┐ Task 3: Profile Settings ─┤ Task 4: Notifications + Subscription ─┤ ← 5 parallel agents Task 5: Onboarding Wizard ─┤ Task 6: Dashboard + Task Reports ─┘ ↓ Task 7: Integration + Verification (sequential — cross-feature wiring) ``` **Verification gate:** Each task ends with `npm run build`. No task is complete until it compiles clean. --- ## Task 1: Shared Foundation **Files:** - Create: `src/lib/hooks/use-notifications.ts` - Create: `src/lib/hooks/use-subscription.ts` - Create: `src/components/notifications/notification-bell.tsx` - Create: `src/app/app/settings/layout.tsx` - Modify: `src/app/app/settings/page.tsx` (overwrite stub → settings hub) - Modify: `src/components/layout/top-bar.tsx` (add notification bell) - Modify: `src/lib/hooks/index.ts` (add new hook exports) ### Step 1: Install Recharts ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web npm install recharts ``` ### Step 2: Create notification hooks ```typescript // src/lib/hooks/use-notifications.ts "use client"; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import * as notificationsApi from '@/lib/api/notifications'; import type { UpdatePreferencesRequest } from '@/lib/api/notifications'; export function useNotifications(limit?: number) { return useQuery({ queryKey: ['notifications', limit], queryFn: () => notificationsApi.listNotifications(limit), }); } export function useUnreadCount() { return useQuery({ queryKey: ['notifications', 'unread-count'], queryFn: () => notificationsApi.getUnreadCount(), refetchInterval: 60_000, // Poll every minute }); } export function useNotificationPreferences() { return useQuery({ queryKey: ['notifications', 'preferences'], queryFn: () => notificationsApi.getPreferences(), }); } export function useUpdatePreferences() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: UpdatePreferencesRequest) => notificationsApi.updatePreferences(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications', 'preferences'] }); }, }); } export function useMarkAsRead() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: number) => notificationsApi.markAsRead(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); queryClient.invalidateQueries({ queryKey: ['notifications', 'unread-count'] }); }, }); } export function useMarkAllAsRead() { const queryClient = useQueryClient(); return useMutation({ mutationFn: () => notificationsApi.markAllAsRead(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); queryClient.invalidateQueries({ queryKey: ['notifications', 'unread-count'] }); }, }); } ``` ### Step 3: Create subscription hooks ```typescript // src/lib/hooks/use-subscription.ts "use client"; import { useQuery } from '@tanstack/react-query'; import * as subscriptionApi from '@/lib/api/subscription'; export function useSubscriptionStatus() { return useQuery({ queryKey: ['subscription', 'status'], queryFn: () => subscriptionApi.getSubscriptionStatus(), }); } export function useFeatureBenefits() { return useQuery({ queryKey: ['subscription', 'features'], queryFn: () => subscriptionApi.getFeatureBenefits(), staleTime: Infinity, }); } export function useUpgradeTriggers() { return useQuery({ queryKey: ['subscription', 'upgrade-triggers'], queryFn: () => subscriptionApi.getAllUpgradeTriggers(), staleTime: Infinity, }); } ``` ### Step 4: Create NotificationBell component ```tsx // src/components/notifications/notification-bell.tsx "use client"; import { useState } from "react"; import { Bell } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Badge } from "@/components/ui/badge"; import { useNotifications, useUnreadCount, useMarkAsRead, useMarkAllAsRead } from "@/lib/hooks/use-notifications"; export function NotificationBell() { const { data: unreadData } = useUnreadCount(); const { data: notifData } = useNotifications(10); const markAsRead = useMarkAsRead(); const markAllAsRead = useMarkAllAsRead(); const unreadCount = unreadData?.unread_count ?? 0; return (

Notifications

{unreadCount > 0 && ( )}
{(!notifData || notifData.results.length === 0) ? (
No notifications
) : ( notifData.results.map((n) => ( { if (!n.is_read) markAsRead.mutate(n.id); }}>

{n.title}

{n.body}

{new Date(n.created_at).toLocaleDateString()}

)) )}
); } ``` ### Step 5: Modify TopBar to include notification bell In `src/components/layout/top-bar.tsx`, add `` before the profile dropdown. Import from `@/components/notifications/notification-bell`. Add a `
` wrapper around the bell and avatar dropdown. ### Step 6: Create settings layout with sidebar navigation ```tsx // src/app/app/settings/layout.tsx "use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { cn } from "@/lib/utils"; import { User, Bell, CreditCard } from "lucide-react"; const settingsNav = [ { label: "Profile", href: "/app/settings/profile", icon: User }, { label: "Notifications", href: "/app/settings/notifications", icon: Bell }, { label: "Subscription", href: "/app/settings/subscription", icon: CreditCard }, ]; export default function SettingsLayout({ children }: { children: React.ReactNode }) { const pathname = usePathname(); return (

Settings

{children}
); } ``` ### Step 7: Overwrite settings page stub → redirect to profile ```tsx // src/app/app/settings/page.tsx import { redirect } from "next/navigation"; export default function SettingsPage() { redirect("/app/settings/profile"); } ``` ### Step 8: Update hooks barrel export Add to `src/lib/hooks/index.ts`: ```typescript export * from './use-notifications'; export * from './use-subscription'; ``` ### Step 9: Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Step 10: Commit ```bash git add -A && git commit -m "feat: add Phase 3 foundation — notification hooks, subscription hooks, settings layout, notification bell" ``` --- ## Task 2: Sharing (Residence + Contractor) **Depends on:** Task 1 **Files:** - Create: `src/app/app/residences/[id]/share/page.tsx` - Create: `src/app/app/residences/join/page.tsx` - Create: `src/components/sharing/share-code-display.tsx` - Create: `src/components/sharing/user-management.tsx` - Create: `src/components/sharing/honeydue-file-handler.tsx` - Create: `src/lib/hooks/use-sharing.ts` - Modify: `src/app/app/residences/[id]/page.tsx` (add Share button) - Modify: `src/app/app/contractors/[id]/page.tsx` (add Share/Export button) - Modify: `src/app/app/contractors/page.tsx` (add Import button) ### Residence Sharing Components **share-code-display.tsx** — Displays share code with copy button and expiry countdown: - If no active code: "Generate Share Code" button → calls `POST /residences/:id/generate-share-code/` - If active code: displays code in large monospace text, copy-to-clipboard button, expiry timer - Uses existing `residencesApi.generateShareCode()` and `residencesApi.getShareCode()` **user-management.tsx** — Lists residence users with remove action: - Uses `residencesApi.getResidenceUsers(id)` to fetch user list - Each user row: name, email, role badge (Owner/Member) - Owner can click "Remove" → ConfirmDialog → `residencesApi.removeResidenceUser(residenceId, userId)` ### .honeydue File Handler **honeydue-file-handler.tsx** — Reusable component for both residence and contractor sharing: - **Export mode**: Takes data object, generates JSON `{ type: "residence"|"contractor", ... }`, triggers browser download as `.honeydue` file - **Import mode**: FileUpload drop zone accepting `.honeydue` files, reads JSON, validates type, calls callback with parsed data - Uses `URL.createObjectURL` + anchor click for download - Uses `FileReader.readAsText` for import ### Pages **Residence Share page** (`/app/residences/[id]/share`): - ShareCodeDisplay for generating/displaying share codes - .honeydue export button → downloads file with share code embedded - UserManagement table - Only accessible to residence owner **Residence Join page** (`/app/residences/join`): - Text input for manual code entry - .honeydue file import drop zone - On submit: calls `residencesApi.joinWithCode()` → redirect to residence detail ### Contractor Sharing On contractor detail page, add "Share" button → generates .honeydue file with contractor data for download. On contractor list page, add "Import" button → opens import dialog → reads .honeydue file → creates contractor via API. ### Query hooks ```typescript // src/lib/hooks/use-sharing.ts "use client"; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import * as residencesApi from '@/lib/api/residences'; export function useShareCode(residenceId: number) { return useQuery({ queryKey: ['residences', residenceId, 'share-code'], queryFn: () => residencesApi.getShareCode(residenceId), enabled: !!residenceId, }); } export function useGenerateShareCode(residenceId: number) { const queryClient = useQueryClient(); return useMutation({ mutationFn: () => residencesApi.generateShareCode(residenceId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['residences', residenceId, 'share-code'] }); }, }); } export function useResidenceUsers(residenceId: number) { return useQuery({ queryKey: ['residences', residenceId, 'users'], queryFn: () => residencesApi.getResidenceUsers(residenceId), enabled: !!residenceId, }); } export function useRemoveResidenceUser(residenceId: number) { const queryClient = useQueryClient(); return useMutation({ mutationFn: (userId: number) => residencesApi.removeResidenceUser(residenceId, userId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['residences', residenceId, 'users'] }); }, }); } export function useJoinResidence() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (code: string) => residencesApi.joinWithCode({ code }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['residences'] }); }, }); } ``` ### Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Commit ```bash git add -A && git commit -m "feat: add residence sharing (share code, join, user management) and contractor .honeydue export/import" ``` --- ## Task 3: Profile Settings **Depends on:** Task 1 **Files:** - Create: `src/app/app/settings/profile/page.tsx` - Create: `src/components/settings/profile-form.tsx` - Create: `src/components/settings/change-password-form.tsx` - Create: `src/components/settings/delete-account-section.tsx` - Create: `src/components/settings/theme-picker.tsx` - Modify: `src/lib/api/auth.ts` (add changePassword and deleteAccount functions if missing) ### API additions needed in auth.ts Check if these exist, add if missing: ```typescript export async function changePassword(data: { current_password: string; new_password: string }): Promise { const res = await fetch('/api/proxy/auth/change-password/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Timezone': timezone() }, body: JSON.stringify(data), }); return handleResponse(res); } export async function deleteAccount(): Promise { const res = await fetch('/api/proxy/auth/delete-account/', { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-Timezone': timezone() }, }); return handleResponse(res); } ``` ### Components **profile-form.tsx** — Edit first name, last name, email: - Zod schema: first_name (required), last_name (required), email (required, valid email) - Pre-fills from current user (from auth store) - On submit: calls `authApi.updateProfile()` → updates auth store user - Success toast / inline success message **change-password-form.tsx** — Change password: - Zod schema: current_password (required, min 8), new_password (required, min 8), confirm_password (must match new_password) - On submit: calls `authApi.changePassword()` → clear form on success **delete-account-section.tsx** — Danger zone: - Red bordered card with warning text - "Delete Account" button → ConfirmDialog with "Type DELETE to confirm" pattern - On confirm: calls `authApi.deleteAccount()` → logout → redirect to login **theme-picker.tsx** — Visual theme selector: - Grid of 11 theme swatches (colored circles/squares from theme-config) - Click to select → applies theme via `useTheme()` hook from existing theme store - Dark/light toggle using existing theme store - Read theme config from `src/lib/themes/theme-config.ts` ### Profile page ```tsx // src/app/app/settings/profile/page.tsx "use client"; // 4 sections stacked vertically: // 1. ProfileForm (personal info) // 2. ChangePasswordForm // 3. ThemePicker // 4. DeleteAccountSection (danger zone at bottom) ``` ### Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Commit ```bash git add -A && git commit -m "feat: add profile settings — edit info, change password, theme picker, delete account" ``` --- ## Task 4: Notifications + Subscription **Depends on:** Task 1 **Files:** - Create: `src/app/app/settings/notifications/page.tsx` - Create: `src/app/app/settings/subscription/page.tsx` - Create: `src/components/settings/notification-preferences.tsx` - Create: `src/components/settings/subscription-status.tsx` - Create: `src/components/settings/feature-comparison.tsx` - Create: `src/components/shared/upgrade-prompt.tsx` ### Notification Preferences **notification-preferences.tsx** — Toggle switches per notification type: - Uses `useNotificationPreferences()` to load current state - Each preference row: label, description, toggle switch (shadcn Switch component — install via shadcn if not present) - On toggle: calls `useUpdatePreferences()` with changed field - Preference types: Task Reminders, Task Completions, Residence Updates, Share Notifications, Marketing **Notifications page** (`/app/settings/notifications`): - NotificationPreferences component - Section header "Notification Preferences" - Each toggle saves immediately (optimistic update) ### Subscription **subscription-status.tsx** — Current plan display: - Uses `useSubscriptionStatus()` to load tier, limits, usage - Shows current tier name (Free/Premium) - Progress bars for usage: residences (X/max), tasks per residence (X/max), contractors (X/max), documents (X/max) - If free tier: show upgrade CTA section **feature-comparison.tsx** — Free vs Premium comparison: - Uses `useFeatureBenefits()` to load feature list - Two-column comparison table: Free vs Premium - Check/cross icons per feature - "Upgrade on App Store" button linking to App Store **upgrade-prompt.tsx** — Reusable upgrade prompt dialog: - Shown when user hits a tier limit (e.g., max residences reached) - Takes `feature` prop (what they're trying to do) - Shows limit info + upgrade CTA - Uses shadcn Dialog - Can be imported by any domain page that needs feature gating **Subscription page** (`/app/settings/subscription`): - SubscriptionStatus card at top - FeatureComparison below - If premium: show expiry date, management info ### Install Switch component ```bash npx shadcn@latest add switch ``` ### Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Commit ```bash git add -A && git commit -m "feat: add notification preferences and subscription status with feature comparison" ``` --- ## Task 5: Onboarding Wizard **Depends on:** Task 1 **Files:** - Create: `src/app/onboarding/page.tsx` - Create: `src/app/onboarding/layout.tsx` - Create: `src/components/onboarding/welcome-step.tsx` - Create: `src/components/onboarding/choose-path-step.tsx` - Create: `src/components/onboarding/create-residence-step.tsx` - Create: `src/components/onboarding/first-task-step.tsx` - Create: `src/components/onboarding/join-residence-step.tsx` - Create: `src/components/onboarding/complete-step.tsx` - Create: `src/stores/onboarding.ts` ### Onboarding Zustand Store ```typescript // src/stores/onboarding.ts import { create } from "zustand"; interface OnboardingState { currentStep: number; path: "create" | "join" | null; residenceId: number | null; isComplete: boolean; nextStep: () => void; prevStep: () => void; setPath: (path: "create" | "join") => void; setResidenceId: (id: number) => void; complete: () => void; reset: () => void; } export const useOnboardingStore = create()((set) => ({ currentStep: 0, path: null, residenceId: null, isComplete: false, nextStep: () => set((s) => ({ currentStep: s.currentStep + 1 })), prevStep: () => set((s) => ({ currentStep: Math.max(0, s.currentStep - 1) })), setPath: (path) => set({ path, currentStep: 2 }), setResidenceId: (id) => set({ residenceId: id }), complete: () => set({ isComplete: true }), reset: () => set({ currentStep: 0, path: null, residenceId: null, isComplete: false }), })); ``` ### Onboarding Layout - Clean, centered layout (no sidebar or app shell) - Progress indicator (step dots or progress bar) - honeyDue logo at top ### Steps **Step 0: Welcome** — "Welcome to honeyDue!" message, illustration, "Get Started" button **Step 1: Choose Path** — Two cards: "Create a new residence" (House icon) and "Join an existing residence" (Users icon). Clicking sets path and advances. **Path A — Create:** - **Step 2a: Create Residence** — Simplified ResidenceForm (name, address, type only). On submit: creates residence via `useCreateResidence()`, stores ID, advances. - **Step 3a: First Task (optional)** — "Add your first task?" Quick task form (title + due date only) or "Skip" button. On submit: creates task, advances. On skip: advances. - **Step 4a: Complete** — "You're all set!" Redirect to `/app/residences/${id}` **Path B — Join:** - **Step 2b: Join Residence** — Code input (6-char) or .honeydue file import. On submit: joins via API, advances. - **Step 3b: Complete** — "Welcome to the residence!" Redirect to residence detail. ### Onboarding trigger After login/register, check if user has 0 residences → redirect to `/onboarding`. This is done via middleware or the auth store's login flow. For now, just mark `localStorage.setItem('onboarding_complete', 'true')` after completion, and check in the app layout. ### Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Commit ```bash git add -A && git commit -m "feat: add onboarding wizard with create/join paths" ``` --- ## Task 6: Enhanced Dashboard + Task Reports **Depends on:** Task 1 **Files:** - Modify: `src/app/app/page.tsx` (enhance existing dashboard) - Create: `src/components/dashboard/task-completion-chart.tsx` - Create: `src/components/dashboard/recent-activity.tsx` - Create: `src/components/dashboard/stats-cards.tsx` - Modify: `src/app/app/residences/[id]/page.tsx` (add "Download Report" button) ### Enhanced Dashboard Replace the current simple dashboard with the spec's design: **stats-cards.tsx** — Top row of stat cards: - 4 cards: Overdue (red), Due Today (orange), Active (blue), Completed (green) - Data from `useTasks()` kanban response `total_summary` field - Each card: count, label, colored icon **task-completion-chart.tsx** — Area chart using Recharts: - Uses task completion data (from completions API or derived from kanban data) - Shows last 30 days of completions as an area chart - `` + `` + `` from recharts - Styled with theme colors via CSS variables - If no completion data available, show "No completion data yet" empty state **recent-activity.tsx** — Recent activity feed: - Uses `useNotifications(5)` to show last 5 notifications as activity items - Each item: icon, title, time ago (relative) - "View all" link to settings/notifications - If no notifications: "No recent activity" ### Dashboard page structure ```tsx // src/app/app/page.tsx (enhanced) // 1. Welcome message with user name (from auth store) // 2. StatsCards (4-column grid) // 3. TaskCompletionChart (full width card) // 4. RecentActivity (list) ``` ### Task Report PDF On residence detail page (`src/app/app/residences/[id]/page.tsx`), add a "Download Report" button: - Calls `residencesApi.generateTasksReport(residenceId)` - The API generates a PDF and emails it (existing behavior) - Show success message "Report sent to your email" - Alternative: if API returns a PDF URL, trigger browser download ### Verify build ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Commit ```bash git add -A && git commit -m "feat: add enhanced dashboard with charts and task report PDF download" ``` --- ## Task 7: Integration + Verification **Depends on:** Tasks 2-6 ### Step 1: Full build verification ```bash cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build ``` ### Step 2: Route verification Confirm all new routes compile: - `/app/settings/profile` - `/app/settings/notifications` - `/app/settings/subscription` - `/app/residences/[id]/share` - `/app/residences/join` - `/onboarding` ### Step 3: Cross-feature integration checks - TopBar notification bell renders and shows unread count - Settings hub sidebar navigates between profile/notifications/subscription - Residence detail has Share and Download Report buttons - Contractor detail has Share button, list has Import button - Dashboard shows stats, chart, and recent activity ### Step 4: Commit ```bash git add -A && git commit -m "feat: complete Phase 3 — advanced features integration verified" ``` --- ## Deliverables Checklist At the end of Phase 3, verify: - [ ] **Residence sharing**: generate share code, copy, join with code, manage users (list/remove) - [ ] **Contractor sharing**: .honeydue file export from detail, import on list page - [ ] **.honeydue files**: download as JSON, import via drag-and-drop - [ ] **Subscription**: status display with usage bars, feature comparison table, upgrade CTA - [ ] **Feature gating**: upgrade prompt dialog available for tier limit enforcement - [ ] **Notification preferences**: toggle switches per notification type, saves immediately - [ ] **In-app notifications**: bell icon in TopBar with unread count badge, dropdown with recent notifications - [ ] **Profile**: edit name/email form, change password form, delete account with confirmation - [ ] **Theme picker**: 11 theme swatches + dark/light toggle in profile settings - [ ] **Onboarding**: multi-step wizard with create/join paths, stores completion state - [ ] **Dashboard**: enhanced with stats cards, completion trend chart (Recharts), recent activity feed - [ ] **Task reports**: "Download Report" button on residence detail, triggers PDF generation - [ ] **Settings hub**: sidebar navigation between profile, notifications, subscription - [ ] **Build passes**: `npm run build` exits 0