# Statistics Feature Specification ## Overview Add a comprehensive statistics dashboard to track journaling habits and provide insights. All analytics are computed locally from user data - no external services required. --- ## 1. Streak Tracking ### Feature Description Track consecutive days of journaling activity to motivate users to maintain their habit. ### Metrics to Track - **Current Streak**: Consecutive days with at least one event - **Longest Streak**: All-time record of consecutive days - **Streak Start Date**: When current streak began - **Days Until Milestone**: Days until 7/14/30/60/90 day milestones - **Streak Risk**: Days with no events that would break streak ### Visualization Approaches - Flame icon with day count (πŸ”₯ 12 days) - Progress bar to next milestone - Calendar mini-view showing streak days - Warning indicator when streak at risk ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ πŸ”₯ 12 Day Streak πŸ† 45 days β”‚ β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 4 days to 16 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Current streak calculation const events = await prisma.event.findMany({ where: { userId }, select: { date: true }, orderBy: { date: 'desc' } }); // Group by date, find consecutive days ``` ### Implementation Complexity - **Backend**: Medium - requires date range queries with grouping - **Frontend**: Low - simple counter display - **Priority**: HIGH - strong motivation driver --- ## 2. Word Count Statistics ### Feature Description Track total words written in events and journal entries over time. ### Metrics to Track - **Total Words**: All-time word count - **Daily Average**: Average words per day (active days) - **Today/This Week/This Month**: Rolling word counts - **Longest Entry**: Day with most words - **Word Count Distribution**: Histogram by day - **Writing Sessions**: Days with 100+/500+/1000+ words ### Visualization Approaches - Line chart showing word count over time (30/90/365 days) - Comparison bar chart: this week vs last week - Mini sparkline showing recent trend - Percentile badges (e.g., "Top 10% writers") ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ πŸ“ 12,450 words total β”‚ β”‚ Avg: 156/day β€’ This week: 1,234 β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β–‚β–ƒβ–…β–‡β–…β–ƒβ–‚β–„β–…β–‡β–ˆβ–„β–ƒβ–‚β–…β–‡ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Word count aggregation await prisma.$queryRaw` SELECT date, SUM(LENGTH(content) - LENGTH(REPLACE(content, ' ', '')) + 1) as word_count FROM Event WHERE userId = ${userId} GROUP BY date `; ``` ### Implementation Complexity - **Backend**: Low - simple aggregation queries - **Frontend**: Low - chart library needed - **Priority**: MEDIUM --- ## 3. Entry Frequency Heatmap ### Feature Description GitHub-style contribution heatmap showing activity intensity by day. ### Metrics to Track - Days with events (boolean per day) - Event count per day (intensity levels) - Active weeks/months count - Most productive day of week - Most productive month ### Visualization Approaches - GitHub-style grid (52 weeks Γ— 7 days) - Color scale: empty β†’ light β†’ dark (slate-800 to purple-600) - Tooltip on hover showing date + count - Day-of-week labels on left - Month labels on top ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Activity Heatmap β”‚ β”‚ Jan Feb Mar Apr May Jun β”‚ β”‚ Mon β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚ β”‚ Tue β–‘β–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚ β”‚ Wed β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚ β”‚ Thu β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚ β”‚ Fri β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚ β”‚ β”‚ β”‚ Less β–‘β–’β–“β–ˆ More β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Heatmap data await prisma.event.groupBy({ by: ['date'], where: { userId }, _count: { id } }); ``` ### Implementation Complexity - **Backend**: Low - groupBy query - **Frontend**: Medium - requires heatmap component (use react-heatmap-grid or custom SVG) - **Priority**: HIGH - visual engagement --- ## 4. Event Type Distribution ### Feature Description Breakdown of events by type (text, photo, voice, health, etc.). ### Metrics to Track - Count per event type - Percentage distribution - Type trends over time (increasing/decreasing) - Media attachments count ### Visualization Approaches - Donut/pie chart with legend - Horizontal bar chart (easier to read) - Stacked area chart over time - Type badges with counts ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Event Types β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ text β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 45% β”‚ β”‚ β”‚ photo β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ 28% β”‚ β”‚ β”‚ voice β”‚ β–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘ 15% β”‚ β”‚ β”‚ health β”‚ β–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘ 8% β”‚ β”‚ β”‚ event β”‚ β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ 4% β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Type distribution await prisma.event.groupBy({ by: ['type'], where: { userId }, _count: { id } }); ``` ### Implementation Complexity - **Backend**: Low - simple groupBy - **Frontend**: Low - chart library - **Priority**: MEDIUM - nice-to-have insight --- ## 5. Time-of-Day Patterns ### Feature Description Analyze when users typically log events (morning person vs night owl). ### Metrics to Track - Events by hour of day (0-23) - Events by time block (Morning 5-11, Afternoon 12-17, Evening 18-22, Night 23-4) - Most active hour - Average time of first event - Average time of last event ### Visualization Approaches - 24-hour radial/bar chart - Time block pie chart - Timeline showing first-last event range - "Your prime time" indicator ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Writing Time Patterns β”‚ β”‚ β–”β–”β–”β–”β–”β–”β–” β”‚ β”‚ β–”β–” β–”β–”β–” β”‚ β”‚ β–”β–” ● β–”β–” β”‚ β”‚ β–” β–”β–” β–” β”‚ β”‚ Morning Afternoon Evening β”‚ β”‚ (6-12) (12-6) (6-12) β”‚ β”‚ β”‚ β”‚ β˜€οΈ Peak: 9:00 AM β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Hour extraction from createdAt await prisma.$queryRaw` SELECT strftime('%H', createdAt) as hour, COUNT(*) as count FROM Event WHERE userId = ${userId} GROUP BY hour `; ``` ### Implementation Complexity - **Backend**: Low - SQL date functions - **Frontend**: Medium - radial chart - **Priority**: LOW - interesting but not core --- ## 6. Monthly/Yearly Summaries ### Feature Description Aggregate statistics for specific time periods with comparison to previous periods. ### Metrics to Track - Monthly: events, journals, words, active days - Yearly: same metrics - Month-over-month change (%) - Year-over-year change (%) - Best month ever - Days with 100% journal generation ### Visualization Approaches - Monthly bar chart comparison - Year-in-review cards - Progress ring showing yearly goals - "This time last year" comparison ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 2024 Year in Review β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ 342 β”‚ β”‚ 45 β”‚ β”‚ 15,600 β”‚ β”‚ β”‚ β”‚Events β”‚ β”‚ Journalsβ”‚ β”‚ Words β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Best month: November (52 events) β”‚ β”‚ +12% vs 2023 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Monthly aggregation await prisma.event.groupBy({ by: ['date'], where: { userId, date: { gte: '2024-01-01', lte: '2024-12-31' } }, _count: { id } }); ``` ### Implementation Complexity - **Backend**: Low - grouped queries with date filters - **Frontend**: Low-Medium - cards and charts - **Priority**: MEDIUM --- ## 7. Progress & Motivation Features ### Feature Description Gamification elements to encourage consistent journaling. ### Metrics & Features - **Achievement Badges**: - "First Entry" (1 event) - "Week Warrior" (7 day streak) - "Month Master" (30 day streak) - "Century" (100 events) - "Word Smith" (10,000 words) - "Photojournalist" (50 photos) - "Consistent" (journal every day for a month) - **Goals**: Set daily/weekly targets - **Streak Protection**: 1 "freeze" per month to preserve streak - **Weekly Report**: Auto-generated summary every Sunday - **Milestone Celebrations**: Confetti at 7/14/30/60/90 days ### Visualization Approaches - Badge grid (earned + locked) - Progress rings for goals - Streak flame animation - Weekly summary card ### Dashboard Layout ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Achievements β”‚ β”‚ β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”‚ β”‚ β”‚πŸ”₯7 β”‚ β”‚πŸŒŸ30β”‚ β”‚πŸ“1Kβ”‚ β”‚πŸ“Έ10β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”‚ β”‚ β”‚πŸ”’ β”‚ β”‚πŸ”’ β”‚ β”‚πŸ”’ β”‚ (locked) β”‚ β”‚ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Daily Goal: 5 events β”‚ β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 3/5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Database Queries ```typescript // Achievement checks - multiple queries const eventCount = await prisma.event.count({ where: { userId } }); const streak = await calculateStreak(userId); ``` ### Implementation Complexity - **Backend**: Medium - multiple queries, achievement logic - **Frontend**: Medium - badge components, progress rings - **Priority**: MEDIUM - strong engagement driver --- ## 8. Privacy-Preserving Analytics ### Feature Description Ensure all statistics computation keeps data on-device. ### Approach - **All aggregations in SQLite**: Use Prisma raw queries on server - **No external analytics services**: No GA, Mixpanel, etc. - **Opt-in sharing**: Optional anonymous stats (streak length, event count) for community features - **Local-first**: Dashboard computes from local API responses - **Data export**: Users can export all their data ### Implementation ```typescript // All stats computed server-side via API // Frontend receives aggregated numbers, not raw data GET /api/v1/stats/streak GET /api/v1/stats/words GET /api/v1/stats/heatmap ``` ### Privacy Considerations - No tracking cookies - No cross-user analytics - API key = user identity (no additional tracking) - Full data deletion on user request --- ## API Changes ### New Endpoints ```typescript // Statistics aggregation GET /api/v1/stats/streak β†’ { currentStreak, longestStreak, streakStart } GET /api/v1/stats/words β†’ { total, dailyAvg, thisWeek, thisMonth, trend } GET /api/v1/stats/heatmap β†’ [{ date, count }] GET /api/v1/stats/types β†’ [{ type, count, percentage }] GET /api/v1/stats/time-of-day β†’ [{ hour, count }] GET /api/v1/stats/summary β†’ { monthly: [], yearly: [] } GET /api/v1/stats/achievements β†’ { earned: [], available: [], progress: {} } GET /api/v1/stats/month/:year β†’ { events, journals, words, activeDays } ``` ### Response Types ```typescript interface StreakStats { currentStreak: number; longestStreak: number; streakStartDate: string; daysToMilestone: number; } interface WordStats { total: number; dailyAverage: number; thisWeek: number; thisMonth: number; trend: 'up' | 'down' | 'stable'; longestEntry: { date: string; count: number }; } interface HeatmapData { date: string; count: number; level: 0 | 1 | 2 | 3 | 4; } interface Achievement { id: string; name: string; description: string; icon: string; earned: boolean; earnedAt?: string; progress?: number; target: number; } ``` --- ## Database Schema Additions ### Optional: Cached Stats Table For expensive queries, cache results: ```prisma model UserStats { userId String @id currentStreak Int @default(0) longestStreak Int @default(0) totalWords Int @default(0) totalEvents Int @default(0) lastUpdated DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) } ``` **Update Strategy**: Recalculate on event create/delete or daily cron. --- ## Frontend Implementation ### New Page: /stats ```tsx // /frontend/src/pages/Stats.tsx import { useState, useEffect } from 'react'; import { api } from '../lib/api'; export default function Stats() { const [streak, setStreak] = useState(null); const [words, setWords] = useState(null); const [heatmap, setHeatmap] = useState([]); // ... } ``` ### Chart Library Recommendation - **Recharts**: Good for line/bar charts (used with React commonly) - **react-heatmap-grid**: For activity heatmap - **react-circular-progressbar**: For goal progress rings - Build custom SVG for simple visualizations --- ## Implementation Roadmap ### Phase 1: Core Stats (Week 1) 1. API endpoints for streak, word count, heatmap 2. Basic stats page with counters 3. Heatmap visualization ### Phase 2: Visualizations (Week 2) 1. Word count trend chart 2. Event type distribution chart 3. Time-of-day analysis ### Phase 3: Gamification (Week 3) 1. Achievement system 2. Daily goals 3. Streak UI improvements ### Phase 4: Summaries (Week 4) 1. Monthly/yearly summaries 2. "This time last year" comparison 3. Weekly report --- ## Priority Recommendations | Feature | Priority | Impact | Effort | |---------|----------|--------|--------| | Streak Tracking | HIGH | High | Low | | Heatmap | HIGH | High | Medium | | Word Count | MEDIUM | Medium | Low | | Event Types | MEDIUM | Low | Low | | Time Patterns | LOW | Low | Medium | | Monthly/Yearly | MEDIUM | Medium | Low | | Achievements | MEDIUM | High | Medium | | Goals | MEDIUM | Medium | Low | --- ## Summary Statistics feature transforms DearDiary from a passive journal into an active self-improvement tool. Key priorities: 1. **Streak tracking** - strongest motivation driver 2. **Heatmap** - visual engagement, GitHub-style 3. **Achievements** - gamification layer 4. **Word count** - progress visualization All data stays local - no privacy concerns. Implementation can be phased with clear value at each step.