Phase 10 — Support Ticket System:
- tickets.py router: SLA status (on_track/at_risk/breached/responded), email
notifications on create+reply via background threads, school_name in list,
priority filter, bulk-close endpoint
- tasks/tickets.py: escalate_stale Celery task (48h→high, 72h no reply→urgent)
- worker.py: escalate_stale scheduled every hour
- templates/email/ticket_notification.html: HTML ticket notification email
- TicketsPage.vue: status tabs, SLA badge, priority badge, school name column,
checkbox bulk-close, pagination
- TicketDetailPage.vue: inline priority/status/assignee selectors, SLA timer,
internal note lock icon, closed-ticket guard
Phase 11 — Monthly Report Generation:
- models/report.py: MonthlyReport + SchoolMonthlyStats ORM models
- tasks/reports.py: send_monthly_reports enhanced with SMS stats, attendance
data, invoice summary, stores MonthlyReport record per school per month
Phase 12 — On-Prem Monthly Report Pull:
- tasks/reports.py: pull_monthly_stats task — httpx GET to each school's
hub_base_url, upserts SchoolMonthlyStats; runs 1st at 5am
- worker.py: pull_monthly_stats scheduled 1st at 5am
Phase 13 — Feature Flags + Suspension:
- models/school.py: hub_base_url, feature_overrides (JSON), onboarding_completed_at
- routers/schools.py: PUT /{id}/feature-overrides endpoint
- routers/sync.py: _tier_features() merges school.feature_overrides into poll config
Phase 14 — Onboarding Wizard + Welcome Email:
- tasks/onboarding.py: send_welcome_email Celery task with license key
- routers/schools.py: auto-trigger welcome email on POST /schools,
POST /{id}/activate (status→active + onboarding_completed_at),
POST /{id}/resend-welcome
Phase 15 — UX Polish + Ops Tools:
- routers/search.py: GET /api/search?q= (schools + invoices + tickets, 5 each)
- routers/audit.py: GET /api/audit-logs (paginated, filterable)
- AppLayout.vue: global search bar with debounced dropdown, result navigation
- AuditLogsPage.vue: new page with filter + pagination
- AppSidebar.vue: Audit Logs nav item added
- router/index.ts: /audit-logs route
- api.ts: globalSearch, getAuditLogs, activateSchool, resendWelcomeEmail,
updateFeatureOverrides, bulkCloseTickets
Deployment:
- docker-compose.yml: x-backend-env anchor (DRY), PDF_DIR env var,
seed service (one-shot python seed.py on first boot)
- migrations/003_phases11_15.py: monthly_reports, school_monthly_stats tables
+ schools hub_base_url/feature_overrides/onboarding_completed_at columns
73 lines
2.2 KiB
Python
73 lines
2.2 KiB
Python
"""Celery worker + beat schedule for TapTrack Hub."""
|
|
import os
|
|
from celery import Celery
|
|
from celery.schedules import crontab
|
|
|
|
REDIS_URL = os.getenv("REDIS_URL", "redis://redis:6379/0")
|
|
|
|
celery_app = Celery(
|
|
"taptrack_hub",
|
|
broker=REDIS_URL,
|
|
backend=REDIS_URL,
|
|
include=[
|
|
"app.tasks.sms",
|
|
"app.tasks.billing",
|
|
"app.tasks.reports",
|
|
"app.tasks.license",
|
|
"app.tasks.tickets",
|
|
"app.tasks.onboarding",
|
|
],
|
|
)
|
|
|
|
celery_app.conf.update(
|
|
task_serializer="json",
|
|
accept_content=["json"],
|
|
result_serializer="json",
|
|
timezone="Asia/Manila",
|
|
enable_utc=True,
|
|
beat_schedule={
|
|
# Process pending SMS jobs every 30 seconds (push path via Semaphore)
|
|
"process-sms-queue": {
|
|
"task": "sms.process_queue",
|
|
"schedule": 30.0,
|
|
},
|
|
# Reclaim processing jobs where on-prem went offline (every 5 minutes)
|
|
"reclaim-stale-sms-jobs": {
|
|
"task": "sms.reclaim_stale_jobs",
|
|
"schedule": 300.0,
|
|
},
|
|
# Check license expiry every day at 8am
|
|
"check-license-expiry": {
|
|
"task": "license.check_expiry",
|
|
"schedule": crontab(hour=8, minute=0),
|
|
},
|
|
# Generate monthly invoices on the 1st at 6am
|
|
"generate-monthly-invoices": {
|
|
"task": "billing.generate_monthly_invoices",
|
|
"schedule": crontab(day_of_month=1, hour=6, minute=0),
|
|
},
|
|
# Pull on-prem stats on the 1st at 5am
|
|
"pull-monthly-stats": {
|
|
"task": "reports.pull_monthly_stats",
|
|
"schedule": crontab(day_of_month=1, hour=5, minute=0),
|
|
},
|
|
# Send monthly reports on the 1st at 7am
|
|
"send-monthly-reports": {
|
|
"task": "reports.send_monthly_reports",
|
|
"schedule": crontab(day_of_month=1, hour=7, minute=0),
|
|
},
|
|
# Check for overdue invoices daily at 9am
|
|
"check-overdue-invoices": {
|
|
"task": "billing.check_overdue",
|
|
"schedule": crontab(hour=9, minute=0),
|
|
},
|
|
# Escalate stale tickets every hour
|
|
"escalate-stale-tickets": {
|
|
"task": "tickets.escalate_stale",
|
|
"schedule": crontab(minute=0),
|
|
},
|
|
},
|
|
)
|
|
|
|
app = celery_app
|