A responsive RTL Persian single-page Rasta live report website with a full admin panel.
- Public page (
/): Live campaign dashboard with KPIs, billboards, posters (version timeline), videos, analytics charts, and user submissions - Admin panel (
/admin): CRUD for all content, publish/unpublish, form validation (Zod + React Hook Form), confirmation dialogs - Mock data fallback: Works without Supabase configuration
- Auto refresh: Public page refreshes every 30 seconds
- RTL Persian UI with Vazirmatn font
- Next.js 15 (App Router)
- TypeScript
- Tailwind CSS v4
- shadcn/ui-style components
- Recharts
- Supabase (optional)
- Zod + React Hook Form
npm install
npm run devOpen http://localhost:3000 for the public report.
- URL:
/admin/login - Credentials come from
ADMIN_EMAIL/ADMIN_PASSWORD(or the admin account stored in the database). - Set a strong
AUTH_SECRET(16+ random characters). In production the app will not start with a missing or weak secret.
- In Coolify, create a PostgreSQL database service.
- Copy the internal connection string (example):
postgres://user:pass@postgres:5432/dashboard
From your machine or Coolify terminal (with DATABASE_URL set):
npm run db:migrateOr run database/schema.sql manually in PostgreSQL.
- Add a new Application in Coolify → connect GitHub repo
Dashboard-info. - Build pack: Dockerfile (auto-detected).
- Port: 3000
- Health check path:
/api/health
| Variable | Required | Example |
|---|---|---|
DATABASE_URL |
Yes | postgres://... |
ADMIN_EMAIL |
Yes | admin@example.com |
ADMIN_PASSWORD |
Yes | strong password |
AUTH_SECRET |
Yes | random 32+ chars |
CRON_SECRET |
Yes (for daily auto-refresh / backups) | random 32+ chars |
BACKUP_DIR |
No | /app/data/backups |
NODE_ENV |
Yes | production |
The app refreshes Eitaa views and site/press link metadata via:
GET|POST /api/cron/refresh-link-metrics
- In Coolify, open the app → Scheduled Tasks (or Cron Jobs).
- Schedule: once per day, e.g.
0 3 * * *(03:00 server time). - Command:
curl -fsS -X POST "$APP_URL/api/cron/refresh-link-metrics" \
-H "Authorization: Bearer $CRON_SECRET"Replace $APP_URL with your public app URL (or internal service URL) and ensure CRON_SECRET is set in the app environment.
What it updates:
- Eitaa posts: views (and empty title/description/cover)
- Aparat videos: views, likes, comments (and empty title/description/cover)
- Site publications + magazine/newspaper with a link: Open Graph title/description/cover when empty
Campaign backups are stored on the server under BACKUP_DIR (default /app/data/backups) and can be downloaded from the admin dashboard (خروجی و پشتیبانگیری).
GET|POST /api/cron/create-backups
- In Coolify, open the app → Scheduled Tasks.
- Schedule for noon Iran time. If the scheduler uses UTC:
30 8 * * *(12:00 Asia/Tehran). If the job TZ isAsia/Tehran:0 12 * * *. - Command:
curl -fsS -X POST "$APP_URL/api/cron/create-backups" \
-H "Authorization: Bearer $CRON_SECRET"Also set a persistent volume for BACKUP_DIR (Compose already mounts backups_data). Older ZIPs are pruned per campaign (BACKUP_RETENTION_COUNT, default 14).
Admins can also click ساخت پشتیبان (ذخیره روی سایت) any time, then دانلود آخرین پشتیبان.
Create a .env next to docker-compose.yml with strong POSTGRES_PASSWORD, ADMIN_EMAIL, ADMIN_PASSWORD, and AUTH_SECRET, then:
docker compose up --buildOpen http://localhost:3030 — login with ADMIN_EMAIL / ADMIN_PASSWORD.
Copy .env.example to .env.local:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
NEXT_PUBLIC_USE_MOCK_DATA=falseSet NEXT_PUBLIC_USE_MOCK_DATA=true to force mock data even when Supabase is configured.
- Create a Supabase project
- Run
supabase/schema.sqlin the SQL Editor - Create a storage bucket
campaign-mediafor uploads (optional) - Create an admin user via Supabase Auth
- Add env variables to
.env.local
app/
page.tsx # Public campaign report
api/campaign/route.ts # JSON API for client refresh
admin/
login/page.tsx # Admin login
(panel)/ # Protected admin pages
components/
public/ # Public page sections
admin/ # Admin CRUD components
ui/ # shadcn-style UI
charts/ # Recharts wrappers
media/ # Lightbox, video modal, timeline
lib/
types.ts # TypeScript interfaces
mock-data.ts # Mock data + in-memory store
data-access/ # Data fetching layer
supabase/ # Supabase clients
actions/ # Server actions
npm run dev # Development server
npm run build # Production build
npm run start # Production server
npm run lint # ESLint- خلاصه کمپین — Campaign overview & KPIs
- بیلبوردها — Billboards with filters
- پوسترها — Posters with version timeline
- ویدیوها — Videos with version timeline
- آمار بازدید سایت — Analytics charts
- مشارکت کاربران — Approved submissions
- Dashboard overview
- Campaign settings
- Billboards CRUD
- Posters (categories, items, versions)
- Videos (categories, items, versions)
- Analytics metrics
- Submissions (approve/reject)
MIT