#
Scheduled Reports
Scheduled reports allow organizations to automatically receive CSV exports of shared analytics links via Email and Telegram at custom intervals.
#
Overview
flowchart TB
subgraph Producer["notifications-worker"]
CRON[Cron: Every 5 min]
API[API: CRUD schedules]
SRC[scheduledReportsCron]
end
subgraph Queue["Cloudflare Queue"]
NQ[NOTIFICATIONS_QUEUE]
end
subgraph Consumer["notifications-consumer"]
SRS[sharedReportService]
CSV[Generate CSV]
EMAIL[Loops API]
TG[Telegram API]
end
subgraph DB[(Supabase)]
SCHED[shared_report_schedules]
RECIPIENTS[shared_report_schedule_recipients]
HISTORY[shared_report_notifications]
LINKS[shared_links]
VIDEOS[videos_with_statistics_fast]
end
CRON --> SRC
SRC -->|Find due| SCHED
SRC -->|Enqueue| NQ
API --> SCHED
NQ --> SRS
SRS -->|Get filters| LINKS
SRS -->|Query| VIDEOS
SRS --> CSV
CSV --> EMAIL
CSV --> TG
EMAIL --> HISTORY
TG --> HISTORY
#
How It Works
#
1. Schedule Creation
Users create schedules via API with:
shared_link_id- Which shared analytics view to exportcadence-daily,weekly, ormonthlyscheduled_time- Time in HH:MM format (stored as UTC)timezone- IANA timezone (e.g.,Europe/Moscow)send_email/send_telegram- Delivery channelsrecipients- Optional per-schedule recipients
#
2. Cron Check (Every 5 Minutes)
scheduledReportsCron queries for due schedules:
SELECT * FROM shared_report_schedules
WHERE enabled = true
AND next_run_at <= NOW()
#
3. Job Enqueue
For each due schedule:
- Get recipients (schedule-specific or fallback to org-wide)
- Enqueue
shared_reportjob toNOTIFICATIONS_QUEUE - Update
next_run_atusing cron expression
#
4. Consumer Processing
sharedReportService in consumer:
- Fetches latest filters from
shared_links - Queries
videos_with_statistics_fastwith filters - Paginates through all matching videos (1000 per page)
- Generates CSV with columns:
title, video_url, platform, status, campaign_tag, channel_username, published_at, created_at, views, likes, comments, reposts - Sends via Email (Loops) and/or Telegram (sendDocument)
- Logs delivery to
shared_report_notifications
#
Database Schema
erDiagram
shared_report_schedules ||--o{ shared_report_schedule_recipients : has
shared_report_schedules ||--o{ shared_report_notifications : generates
shared_links ||--o| shared_report_schedules : "scheduled by"
users ||--o{ shared_report_schedule_recipients : receives
shared_report_schedules {
uuid id PK
uuid organization_id FK
uuid shared_link_id FK
uuid created_by FK
string cron_expression
string timezone
string scheduled_time
boolean send_email
boolean send_telegram
boolean enabled
timestamp next_run_at
timestamp last_run_at
string last_run_status
timestamp created_at
timestamp updated_at
}
shared_report_schedule_recipients {
uuid id PK
uuid schedule_id FK
string channel "email or telegram"
uuid user_id FK
bigint telegram_chat_id
}
shared_report_notifications {
uuid id PK
uuid schedule_id FK
string channel
uuid recipient_user_id
bigint telegram_chat_id
string status "sent or failed"
jsonb payload
timestamp created_at
}
#
Recipients Resolution
1. Check schedule-specific recipients (shared_report_schedule_recipients)
↓ if none found
2. Fallback to organization-wide recipients
- organization_notification_email_recipients
- organization_notification_telegram_recipients
#
Cron Expression Generation
Custom cron_expression can be provided instead of cadence.
#
CSV Format
title,video_url,platform,status,campaign_tag,channel_username,published_at,created_at,views,likes,comments,reposts
"Video Title","https://...","tiktok","active","Campaign A","@creator","2024-01-01","2024-01-01",10000,500,100,50
Filename format: {slug}-{YYYY-MM-DD}.csv