Single DAG, single 30-min schedule instead of 5-min or two separate
DAGs. run_sync() itself decides whether to do real work: always during
business hours (default 07:00-17:00 WIB), otherwise only once per
EDOXID_OFF_HOURS_INTERVAL_MINUTES (default 120) tracked via a
last_full_sync timestamp in the sqlite state. Off-hours skips return
immediately without touching DB/Calendar/Gmail at all.
Requesting a narrower scope explicitly (scopes=[...]) during refresh
was rejected by Google as invalid_scope in the Airflow container's
google-auth version, even though it worked locally with a newer one.
Drop scopes= entirely — the refresh_token already carries the full
granted scope (calendar + gmail.send), no need to request a subset.
apache/airflow:2.7.1 base image ships Python 3.8, which doesn't have
zoneinfo (3.9+) and can't evaluate `X | Y` / list[X] type hints at
runtime (3.10+). Add `from __future__ import annotations` everywhere
and swap zoneinfo -> pytz (already a dependency in this repo).
Sync jadwal sidang eDOXID ke Google Calendar "Jadwal Sidang" tiap 5 menit
(read-only ke doxid2022), plus reminder email H-1/1-jam via Gmail API
karena reminder Calendar bawaan tidak ikut ke kalender pribadi attendee.