crons

JQ Daily Drops Cron Setup

This document explains how to set up the daily cron job that automatically generates personalized encouragement drops from JQ for users who have enabled check-ins.

Overview

The JQ Daily Drops system:

  • Automatically generates 1 personalized drop per day for users with read_notes_enabled: true and check_in_enabled: true
  • Uses the user's latest note analysis to create personalized messages
  • Appears in the user's stream as an encouragement drop
  • Prevents duplicate drops on the same day

User Settings

Users can enable this feature in the JQ chatbot settings:

  1. Open the JQ chatbot
  2. Go to Settings
  3. Enable "Let JQ Read Your Notes" (read_notes_enabled)
  4. Enable "Daily Check-ins" (check_in_enabled)

Both settings must be enabled for JQ to generate daily drops.

Endpoint

POST /api/encouragement-drops/cron/generate-daily-drops

This endpoint is protected by a secret token and should be called by your cron service.

Headers:

  • x-cron-secret: Secret token (uses DROPS_CRON_SECRET, WORKOUT_WINDOW_CRON_SECRET, or CHAT_CRON_SECRET)

Response:

{
  "success": true,
  "message": "Generated 15 daily drops",
  "results": {
    "total": 20,
    "generated": 15,
    "skipped": 3,
    "failed": 2,
    "errors": ["User abc123: Failed to generate drop content"]
  }
}

Environment Variables

The endpoint uses one of these environment variables (in order of preference):

  • DROPS_CRON_SECRET
  • WORKOUT_WINDOW_CRON_SECRET
  • CHAT_CRON_SECRET

Add to your backend .env file:

DROPS_CRON_SECRET=your-secret-token-here

Cron Service Setup

Daily at 9 AM UTC (or your preferred time):

  • Gives users time to complete their morning journaling
  • Ensures drops appear during active hours
  • Avoids late-night notifications

Vercel Cron

If using Vercel, add to vercel.json:

{
  "crons": [
    {
      "path": "/api/encouragement-drops/cron/generate-daily-drops",
      "schedule": "0 9 * * *"
    }
  ]
}

Railway Cron

If using Railway, you can:

  1. Use Railway's cron job feature
  2. Set up an external cron service

External Cron Service

You can use services like:

Configure them to make a POST request to:

https://your-backend-url.com/api/encouragement-drops/cron/generate-daily-drops

With header:

x-cron-secret: your-secret-token-here

How It Works

  1. Find Eligible Users: Queries all users with both read_notes_enabled: true and check_in_enabled: true
  2. Check for Existing Drop: Skips users who already received a JQ drop today
  3. Get Note Analysis: Fetches the user's latest note analysis (from note_analyses table)
  4. Generate Drop: Uses OpenAI to create a personalized message based on:
    • Recent journaling summary
    • Mood trends
    • Key topics
    • Patterns noticed
    • Recommendations
    • Insights (gratitude, challenges, goals, achievements)
  5. Send Drop: Creates a system drop (bypasses normal drop limits) from JQ to the user
  6. Track Usage: Records token usage for cost tracking

Drop Content

Drops are personalized based on:

  • Mood trends: References how the user has been feeling
  • Topics: Mentions what they've been writing about
  • Patterns: Acknowledges behavioral patterns noticed
  • Challenges: Offers support for difficulties mentioned
  • Achievements: Celebrates progress and wins
  • Goals: Encourages continued progress toward goals

Example drops:

  • "I noticed you've been writing about work stress lately. Remember to take breaks and breathe. You've got this! 💪"
  • "Your gratitude entries have been really inspiring. Keep focusing on the positive - it's making a difference! ✨"
  • "I see you're working toward your fitness goals. Every small step counts. Keep going! 🎯"

System User Setup

JQ drops are sent from a special system user ID: e06ebb7d-c31b-4b95-8677-3e5ac2d78be5

Important: You need to create this system user in Supabase before the cron job will work:

Step 1: Create System User in Supabase Auth

  1. Go to Supabase Dashboard → Authentication → Users
  2. Click "Add User" → "Create new user"
  3. Set:
    • Email: jq@hivejournal.com
    • Password: Generate a secure random password (you won't need it)
    • User ID: e06ebb7d-c31b-4b95-8677-3e5ac2d78be5 (must match exactly)
  4. Click "Create user"

Note: The system user has already been created with ID e06ebb7d-c31b-4b95-8677-3e5ac2d78be5. If you need to recreate it, use this exact ID.

Step 2: Run Migration

The migration 042_allow_jq_system_drops.sql will:

  • Create a profile entry for JQ
  • Document the system user ID

Run the migration:

# If using Supabase CLI
supabase migration up

# Or apply via Supabase Dashboard → SQL Editor

Step 3: Verify

After setup, JQ drops will:

  • Display "JQ" as the sender name
  • Bypass normal drop limits
  • Be easily identifiable as system-generated
  • Have no impact on user drop allowances

Testing

You can test the cron endpoint manually:

curl -X POST https://your-backend-url.com/api/encouragement-drops/cron/generate-daily-drops \
  -H "x-cron-secret: your-secret-token-here" \
  -H "Content-Type: application/json"

Monitoring

Monitor the cron job to ensure:

  • Drops are generated daily
  • No errors occur during processing
  • All eligible users receive drops

Check your backend logs for:

  • [JQ Daily Drops] Starting generation for X users
  • [JQ Daily Drops] Generated drop for user...
  • [JQ Daily Drops] Completed: X generated, Y skipped, Z failed
  • Any error messages

Performance Considerations

  • Processes users in batches of 5 to avoid overwhelming the API
  • 1-second delay between batches to avoid rate limits
  • Only users with both settings enabled are processed
  • Skips users who already received a drop today
  • Falls back to generic message if analysis unavailable

Database Schema

Drops are stored in the drops_sent table:

  • sender_id: System user ID (00000000-0000-0000-0000-000000000000)
  • recipient_id: User who receives the drop
  • drop_type: Always 'encouragement'
  • content: Personalized message from JQ
  • date_sent: Date the drop was sent

Troubleshooting

No Drops Generated

Check:

  1. Users have both read_notes_enabled: true AND check_in_enabled: true
  2. Users have note analyses available (run note analysis cron first)
  3. Users haven't already received a drop today
  4. OpenAI API key is set correctly

Generic Drops Only

If all drops are generic:

  • Users may not have note analyses yet
  • Run the note analysis cron first: /api/chat/cron/analyze-notes
  • Check that users have recent journal entries

Drops Not Appearing in Stream

Check:

  1. Drops are being created in drops_sent table
  2. Stream is fetching from /api/encouragement-drops/received
  3. Drops have read_at: null to appear as unread
  • Note Analysis: Requires note analysis to be run first (/api/chat/cron/analyze-notes)
  • Stream Display: Drops appear in stream when fetched from /api/encouragement-drops/received
  • Token Tracking: All AI-generated drops track token usage for cost monitoring

Recommended Setup:

  1. Run note analysis cron at 2 AM UTC: /api/chat/cron/analyze-notes
  2. Run daily drops cron at 9 AM UTC: /api/encouragement-drops/cron/generate-daily-drops

This ensures users have fresh analysis before drops are generated.

JQ DAILY DROPS CRON — Docs | HiveJournal