יומן שינויים

היסטוריית גרסאות מלאה. 0.5.3 הוא הנוכחי. פורמט: Keep a Changelog + SemVer.

v0.5.3 — 2026-04-16

✨ תכונות חדשות

  • Community Pulse — סקר "מה שלומך?" אוטומטי אחרי אזעקה בעיר המגורים; 3 אפשרויות (✅ בסדר / 😰 מפחד/ת / 🤝 עוזר/ת לאחרים); תוצאות מרוכזות כשמגיעים ל-threshold מוגדר; opt-in; cooldown מוגדר (ברירת מחדל 6 שעות) (PR #219)
  • סיפורי מקלט — שיתוף חוויה קצרה מהמקלט (עד 200 תווים); flow אישור בדשבורד (lock → publish); פרסום בערוץ נושא ייעודי (TELEGRAM_TOPIC_ID_STORIES); INSERT OR IGNORE מגן מפני כפילויות (PR #220)
  • שיתוף מיומנויות/skills להצהרת מיומנויות מרשימה מוגדרת מראש (30 מיומנויות + קטגוריות); /need [מיומנות] לחיפוש אנשי קשר מתאימים לסיוע בשעת חירום; skill_catalog table + repository (PR #221, #228)
  • בדיקת שכנים — X דקות לאחר אזעקה בעיר מגורים → DM אוטומטי "בדקת את שכניך?" עם 3 כפתורי מענה (בדקתי / לא יכולתי / הבנתי); injectable scheduleFn/sendFn/cancelScheduleFn לבדיקות; kill-switch ב-dashboard (PR #222)
  • מחיקת/העברת קבוצה — מנהל קבוצה יכול למחוק אותה עם confirmation, או להעביר בעלות לחבר אחר; audit log בטבלה ייעודית (group_transfer_log) (PR #231)
  • Community Config Dashboard — עמוד /community בדשבורד עם 5 הגדרות hot-configurable: cooldown סקרים, מגבלת תווים לסיפורים, threshold תוצאות, השהיית בדיקת שכנים, מתג הפעלה כלל-מערכתי (PR #227)

🐛 תיקוני באגים

  • CHECK (length(body) <= 200) הוסר מ-DB — ה-constraint גרם ל-crash מובטח כשה-dashboard default הוא 500; app layer אחראי לבדיקה
  • insertResponse מחזירה boolean — מאפשר לזהות duplicate response ב-communityPulseHandler ולהציג "כבר ענית על הסקר הזה"
  • shelterStoriesHandler — pending state נמחק רק בהצלחה — שגיאת שרת לא "תתקע" את המשתמש בלולאת תגובה; pendingShares.delete ב-success path + catch block, לא ב-finally
  • publishStory עם status guardUPDATE ... WHERE status = 'approved' מונע publish כפול או מקדים
  • Empty catch blocksneighborCheckHandler, skillsHandler — כל catch מוסיף log('error/warn', ...) + reply למשתמש

🧪 בדיקות

  • alertWindowTracker — 5 tests ל-setWindowCloseCallback: lazy expiry, no-double-fire, copy semantics, clearAllCloseTimers independence
  • neighborCheckHandler — 5 callback tests: checked/unable/dismissed confirmations, already-responded guard, expiry message (injected :memory: DB via setNeighborCheckHandlerDb)
  • communityPulseHandler — 6 callback tests: first-response תודה, duplicate guard, multi-user, missing from, agg threshold
  • alertHandler — 4 tests ל-scheduleNeighborCheck dep: fresh send, dmCities filter on edit, empty dmCities guard, optional dep
  • סה"כ: 1,789 tests (1,418 main suite + 371 dashboard)

🔧 תחזוקה

  • cancelNeighborCheckTimers מחובר ל-shutdown() ב-index.ts — graceful shutdown מלא
  • TS2571 fix: (calls[0].arguments[0] as Alert).cities ב-alertHandler.test.ts
  • alertWindowTracker silent catch הוחלף ב-log('warn', ...) עם context

v0.5.2 — 2026-04-13

✨ תכונות חדשות

  • הגדרות חברתיות — /settings — 5 מתגי הפעלה/כיבוי לתכונות חברתיות: שאלת "הכל בסדר" אחרי אזעקה, באנר תזכורת, מספר אנשי קשר בהתראה, התראות קבוצתיות, כפתור שליחה מהירה (PR #236)
  • כפתור "הכל בסדר — לכולם" — כפתור חד-לחיצתי בתפריט הראשי ששולח עדכון "הכל בסדר" לכל אנשי הקשר עם הרשאת סטטוס ביטחוני; מסך אישור לפני שליחה; TTL מותאם של 6 שעות (PR #237)
  • באנר תזכורת ב-/start — הצגת אזהרה בראש התפריט כשיש שאלת בטיחות שלא נענתה; כולל שם עיר מהאזעקה וכפתורי פעולה מהירה (PR #238)
  • מספר אנשי קשר בהתראת DM — שורת "👥 X אנשי קשר שלך נמצאים באזור" מתווספת להתראות כשיש אנשי קשר מאושרים באזור המותקף (PR #239)
  • טאב בדיקת שלומות בדשבורד — עמוד /safety-check חדש עם 6 כרטיסי KPI (שאלות, אחוז תגובה, זמן תגובה ממוצע, פילוח תשובות), גרף מגמה 7 ימים, וטבלת שאלות אחרונות עם מיסוך פרטיות (PR #240)
  • ניהול טקסטים חברתיים בדשבורד — עריכה חמה של כל טקסטי התכונות החברתיות (באנר, כפתור, אישור, שידור, שורת אנשי קשר) עם תצוגה מקדימה; מתגי ברירת מחדל למשתמשים חדשים; סף זמן לבאנר תזכורת; פונקציות getString/getNumber/getBool חדשות ב-configResolver (PR #241)

v0.5.1 — 2026-04-12

✨ תכונות חדשות

  • קבוצות חוסן — /group — קבוצות משפחה/חברים/עבודה לתיאום ביטחוני: /group create <שם> יוצר קבוצה עם קוד הזמנה, /group join <קוד> מצטרף, /group leave עוזב, /group list מציג קבוצות (PR #230)
  • מסך סטטוס קבוצתי — /group status — תצוגה חיה של סטטוס הביטחוני של כל חברי הקבוצה (✅/⚠️/🔇/❓); בחירת קבוצה inline; כפתור רענון; מחיצת קבוצה בודדת — אוטומטית (PR #232)
  • התראות קבוצה — עדכון אוטומטי לכל חברי הקבוצה כשמישהו מעדכן סטטוס; dismissed לא מעדכן; notify_group=0 מאפשר opt-out פר-חבר; dedup בין קבוצות חופפות (PR #233)
  • ניהול קבוצות בדשבורד — עמוד "קבוצות חוסן" חדש: KPI cards (סה"כ / ממוצע חברים / גדולה ביותר), טבלה עם drill-down ל-drawer חברים, מחיקת קבוצה עם rate-limit 5/דקה (PR #234)
  • hot-config לקבוצותgroups_max_per_user (ברירת מחדל 5) ו-groups_max_members (ברירת מחדל 20) ניתנים לשינוי מהדשבורד ללא restart; שמירה על minimum=1 למניעת נעילת הפיצ'ר (PR #234)

⚡ שיפורי ביצועים

  • N+1 ב-GET /api/groups נפתרlistAllGroupsWithStats מבצע LEFT JOIN ל-users בשאילתה אחת במקום N קריאות getUser() פר-קבוצה (PR #234)
  • CI: חיסכון ~50% דקות Actionspull_request trigger מוגבל ל-opened/reopened בלבד; synchronize (push לענף PR) מכוסה ע"י ה-push trigger הקיים (PR #235)

🐛 תיקוני באגים

  • groups_max_per_user=0 לא עוצר יצירת קבוצותvalidatePositiveInt (n≥1) בגבול ה-PATCH + resolveIntConfig(..., { minimum: 1 }) ב-runtime; קוד שגוי "0" ב-DB נופל ל-fallback עם warn-log (PR #234)

🧪 בדיקות

  • groupHandler — 1,150 שורות: /group create|join|leave|list|status, callback_data guard (64 bytes), collision retry, auth invariants (owner-only invite, non-member block), hot-config override
  • groupRepository — 320 שורות: CRUD, member count, stats helpers, InviteCodeCollisionError
  • groupNotificationService — 222 שורות: ok/help/dismissed, opt-out, cross-group dedup, XSS escaping, fallback display name
  • dashboard/routes/groups — 201 שורות: GET list/stats/detail, DELETE + rate-limit, input validation, CASCADE
  • settings.test.ts — 6 tests חדשים ל-groups_max_per_user/groups_max_members validation
  • סה"כ: 1,615 tests (מ-1,086 ב-v0.5.0)

🔧 תחזוקה

  • schema.ts — 2 טבלאות חדשות: groups + group_members (CASCADE FKs, CHECK constraint על role, 3 indexes)
  • botSetup.tsregisterGroupHandler נוסף; setMyCommands — 15 פקודות (נוספה /group)
  • configResolver.ts — הוספת groups_max_per_user, groups_max_members, groups_invite_code_ttl_hours ל-ALLOWED_CONFIG_KEYS
  • dashboard/router.ts/api/groups route חדש

v0.5.0 — 2026-04-07

✨ תכונות חדשות

  • Safety Status — "האם אתה בסדר?" — שאלת סטטוס אוטומטית כשמגיעה התראה לעיר המגורים; 3 כפתורים (✅ בסדר / ⚠️ צריך עזרה / 🔇 התעלם); dedup חכם לפי fingerprint — INSERT OR IGNORE מונע כפל (PR #186–#189)
  • פקודת /status — צפייה ועדכון ידני של סטטוס ביטחוני עם מד-זמן עד לפקיעה; תצוגת סטטוס אנשי קשר מורשים; ניווט safety:contacts / safety:back (PR #197–#199)
  • עדכון אנשי קשר אוטומטי — שיתוף סטטוס אוטומטי עם אנשי קשר בעלי הרשאת safety_status=true; דרך dmQueue עם backoff 429; התעלמות אינה מעדכנת קשרים (PR #200–#201)
  • ניהול סודות מוצפן — AES-256-GCM envelope encryption (DEK/KEK via PBKDF2); ניהול API keys מלוח הבקרה ללא env vars; עמוד Configuration חדש עם SecretCard ו-RestartBanner; migration אוטומטי מ-.env בהפעלה (PR #153, #160, #161)
  • תבניות גוף הודעה — עורך תבניות עם {{ערים}} {{כותרת}} {{זמן}} {{אמוגי}} {{מספר_ערים}}; live preview בסגנון Telegram; tab "עורך תבנית" חדש בדאשבורד (PR #156)
  • ניהול תצורה מאוחדconfigResolver.ts עם שרשרת DB → env fallback; SECRET_KEYS (5) + RESTART_REQUIRED_KEYS (6); DASHBOARD_SECRET בלבד נדרש לאתחול (PR #154, #155, #157, #158)
  • טקסטי DM ניתנים לשינוי — רלוונטיות ("באזורך", "באזור קרוב", "לא באזורך") ו-"נשמו" ניתנים לשינוי מלשונית "הודעות DM" בדאשבורד ללא restart (PR #159)

🐛 תיקוני באגים

  • יישור RTL — תווי \u200F נוספו לכותרות אזורים ב-buildZonedCityList, buildZoneOnlyList ו-formatAlertMessage — מונע הצגה הפוכה של בטלגרם (PR #151)
  • "נשמו" לפי עיר בית — הודעת "נשמו" נשלחת רק למי שעיר המגורים (home_city) הייתה בהתראה המקורית — לא לכל מנויי האזור (PR #152)
  • "נשמו" + שעות שקט — שעות שקט ו-snooze מופעלים גם על הודעת "נשמו" (לא עוקפים אותם) (PR #152)
  • "נשמו" דרך DmQueue — הגנה מ-Telegram 429 בעת התראות רחבות-היקף; מקביליות 10 + backoff (PR #152)

⚠️ שינויים שוברים

  • DASHBOARD_SECRET הוא משתנה הסביבה היחיד הנדרש לאתחול לאחר migration. TELEGRAM_BOT_TOKEN, MAPBOX_ACCESS_TOKEN ושאר הסודות מנוהלים דרך לוח הבקרה (PR #155, #161)
  • callback_data של safety prompts כולל prompt ID מפורש: safety:ok:42 — לא חיפוש "ה-prompt האחרון" (מונע עמביגואיזציה בין שתי התראות מקבילות) (PR #191, #195)

🧪 בדיקות

  • Safety Status — 75 tests חדשים: safetyStatusRepository (15), safetyPromptRepository (27), safetyPromptService (12), safetyStatusHandler (14), safetyAutoReset (7)
  • 3 integration tests מקצה לקצה: happy path (prompt → ok → contact notified → dedup), dismiss (no notify), fingerprint dedup
  • userRepository — 3 tests חדשים ל-getUsersWithHomeCity; alertHandler — 28 tests כולל dispatchSafetyPrompts optional dep
  • סה"כ: 1,086 tests (מ-1,008 ב-v0.4.5)

🔧 תחזוקה

  • src/CLAUDE.md + src/db/CLAUDE.md + .claude/rules/structure.md + README.md — עודכנו עם פרטי Safety Status feature
  • botSetup.tsregisterSafetyStatusHandler נרשם לפני registerMenuHandler (PR #196)
  • setMyCommands — 14 פקודות (נוספו /status, /today, /legend, /connect, /contacts, /privacy)

v0.4.5 — 2026-04-05

✨ תכונות חדשות

  • all-clear — שליחת הודעת "שקט חזר" אחרי אזעקה; תמיכה ב-DM, ערוץ, או שניהם (all_clear_mode); זיהוי מובנה של newsFlash רשמי "האירוע הסתיימה"; ניהול מלא מלוח הבקרה כולל בחירת נושא ייעודי (all_clear_topic_id)
  • density indicator — אינדיקטור צפיפות יומי בהתראות חיות: רגיל / גבוה / חריג על בסיס ממוצע 90 ימים; מחושב לפי timezone ישראל
  • פקודת /today — ציר זמן יומי מלא של ההתרעות עם density summary לכל קטגוריה
  • dashboard sidebar — sidebar RTL מתקפל עם היררכיית ניווט עברית
  • dashboard settings trust — badges להבחנת הגדרות ENV vs DB בממשק הניהול
  • page headers — כותרות אחידות לכל 10 עמודי dashboard

🐛 תיקוני באגים

  • density log level — הודעות "message not modified" תויגו כ-warn במקום info; זהו מצב הצלחה
  • allClearService renderTemplate — שגיאה באחד האזורים כבתה את כל שאר האזורים; עכשיו עטוף ב-try-catch עם continue
  • getDailyAverageAlerts timezone — חישוב ממוצע אזעקות יומי השתמש ב-UTC במקום timezone ישראל (Asia/Jerusalem)
  • all_clear_mode validation — PATCH /api/settings עכשיו מאמת שהערך הוא אחד מ-dm / channel / both

🧪 בדיקות

  • allClearService — test suite מלא עם injectable deps
  • allClearIntegration — integration tests מקצה לקצה לפיצ'ר all-clear
  • density→editAlert — test חסר לpath של editAlert (density מועבר כ-arg 5)

v0.4.4 — 2026-04-04

✨ תכונות חדשות

  • חזותיות אזורים חכמה — 33 צבעים ייחודיים לאזורים במפות Mapbox; ספריית zoneColors.ts עם runtime assertion שמגן מפני אי-התאמה
  • אינדיקטור רלוונטיותgetRelevanceIndicator() מציין בכותרת ערוץ אם ההתרעה נוגעת לאזורים שנבחרו
  • סרגל ספירה לאחור ב-DMrenderCountdownBar() מייצר סרגל ויזואלי (🟥🟥🟥🟥🟥 עד 🔵⬜⬜⬜⬜) בהודעות DM
  • allClearTracker — מעקב all-clear per-zone: הודעת "הסתיימה ההתרעה" עם חלון שקט למניעת הצפה; injectable deps; timers מנוקים בעת SIGTERM/SIGINT
  • פקודת /today — סיכום יומי של כל ההתרעות עם פירוט לפי קטגוריות (alertsToday handler)
  • פקודת /legend — פלטת צבעי האזורים לפי 6 סופר-אזורים (legendHandler)
  • Forum topics support — GramJS listener תומך בנושאים (threads) בקבוצות forum; סינון לפי sourceTopicId
  • פורמט משותף Telegram + WhatsAppbuildSummaryLine() כמקור יחיד לספירת ערים/אזורים; תיקון דקדוקי "1 עיר" לעומת "N ערים"

🐛 תיקוני באגים

  • alertSerial — timezone ישראל — מספרי אינדקס התרעות מחושבים לפי Asia/Jerusalem (UTC+2/+3); האינדקס מתאפס בחצות המקומית ולא בחצות UTC
  • Empty chat list on fresh GramJS session — fallback ל-client.getEntity() ו-retry עם השהיה של 2 שניות בעת 0 תוצאות
  • GetForumTopics not paginated — pagination loop לקבוצות עם יותר מ-100 נושאים

🗑️ הוסר

  • Docker Hub / GHCR פרסום ציבורי — הוסרה אוטומציית פרסום Docker image ל-GHCR ו-Docker Hub; הדרך המומלצת להתקנה היא npx @haoref-boti/pikud-haoref-bot. ה-Dockerfile נשמר לבנייה מקומית.
  • alertLayout.ts — הוסר עקב circular import; הלוגיקה הועברה ל-telegramBot.ts

🧪 בדיקות

  • +199 בדיקות חדשות — כיסוי מלא לחזותיות אזורים, accessibility, allClearTracker, todayHandler, legendHandler, zoneColors, crossChannelFormat, summaryLine

v0.4.3 — 2026-04-03

✨ תכונות חדשות

  • Telegram Listener — האזנה לקבוצות/ערוצים Telegram דרך GramJS MTProto (חשבון משתמש), סינון לפי מילות מפתח, והעברה לנושאים בערוץ ו-WhatsApp; ניהול מלא מלוח הבקרה עם auth flow (טלפון → OTP → 2FA)
  • הגדרות פרטיות — פקודה חדשה /privacy לניהול מדיניות פרטיות ברירת המחדל לחיבורים חדשים
  • שליטה per-contact — ניתן לשנות בנפרד אילו שדות (סטטוס ביטחוני, עיר בית, זמן עדכון) כל איש קשר יכול לראות
  • תבנית ברירת מחדל — הגדרות הפרטיות שנבחרו מוחלות אוטומטית על כל חיבור חדש
  • שיפור UX חיבור חברים — זרימה אינטראקטיבית לא-טכנית עם תפריט, קוד בתיבה tappable, ובחירת הרשאות מפורשת לפני שליחת בקשה
  • סיכום הרשאות בעת אישור — כשחבר מאשר בקשת חיבור, הם רואים בדיוק אילו שדות שותפו (עיר בית, זמן עדכון אחרון)
  • ניסוח משופר — כל הודעות שגיאה וחיבור כתובות בעברית יומיומית, לא טכנית

🐛 תיקוני באגים

  • Telegram Listener — pagination — לולאת refreshKnownChats עצרה אחרי 100 צ'אטים ראשונים בגלל תנאי break הפוך (>= במקום <=)
  • Telegram Listener — סיווג supergroup — קבוצות-ערוץ (megagroup) אוחסנו בטעות כ-group במקום supergroup
  • Telegram Listener — race conditionstartPhoneAuth() יכול היה לרוץ במקביל ל-initialize() וליצור שתי TelegramClient instances
  • Telegram Listener — env validation — אפליקציה עלתה ללא TELEGRAM_API_ID/TELEGRAM_API_HASH ונכשלה מאוחר יותר בלי הודעת שגיאה ברורה
  • Telegram Listener — chatId null — שימוש ב-! non-null assertion על TELEGRAM_CHAT_ID גרם לקריסה כש-env var לא הוגדר
  • Privacy — update_timecreateContactWithPermissions נקרא ללא update_time, כך שתמיד ברירת המחדל הייתה true ללא קשר להגדרות /privacy
  • Privacy — error handling — חריגות לא-נתפסות ב-updatePermissions() ו-editMessageText() גרמו לקריסת callback handlers

🧪 בדיקות

  • כיסוי הרשאות פרטיות — טסטים מלאים ל-/privacy, pv:toggle, cx:perm, cp:toggle ו-getPrivacyDefaults
  • rendering test לבדיקת הרשאות — בדיקה שעיר הבית מוצגת/מוסתרת בהתאם להרשאת home_city
  • +8 בדיקות connectHandler — כיסוי של תפריט ה-connect, קולבקי toggle הרשאות, ו-cx:confirm/cx:cancel
  • +81 בדיקות Telegram Listener — repository, service, ו-dashboard routes; injectable deps לבידוד מ-GramJS

v0.4.2 — 2026-04-03

✨ תכונות חדשות

  • אנשי קשר — חברו חברים ומשפחה עם קוד בן 6 ספרות, אשרו בקשות, ונהלו רשימת קשרים
  • הגנה מפני שימוש לרעה — המערכת מגבילה בקשות חריגות ומנקה בקשות ישנות באופן אוטומטי
  • קוד חיבור בפרופיל — הקוד האישי שלכם מופיע גם בעמוד הפרופיל
  • אנשי קשר בלוח הבקרה — מנהלים רואים קודי חיבור, מספר קשרים, ורשימת אנשי קשר לכל מנוי

🧪 בדיקות

  • +11 בדיקות — כיסוי מלא למערכת אנשי הקשר, לוח הבקרה, וניקוי אוטומטי

✨ תכונות חדשות

  • פרופיל מנויים בדשבורד — עמוד מנויים מציג כעת שם תצוגה, עיר מגורים, וסטטוס onboarding; חיפוש לפי שם ועיר; עריכת שם ועיר מהדשבורד; ייצוא CSV כולל שדות פרופיל

🧪 בדיקות

  • +8 בדיקות dashboard/subscribers — חיפוש לפי שם ועיר, עדכון display_name/home_city, CSV עם שדות פרופיל

v0.4.1 — 2026-04-02

✨ תכונות חדשות

  • Onboarding wizard ב-/start — משתמש חדש נכנס לתהליך הגדרה מונחה: שם תצוגה → עיר מגורים → אישור. מצב נשמר ב-SQLite (onboarding_step) ושורד ריסטארט; אפשרות דילוג בכל שלב
  • הרשמה אוטומטית לעיר מגורים — בסיום ה-onboarding, המשתמש נרשם אוטומטית להתראות על עיר המגורים שבחר
  • פקודת /profile — צפייה ועריכה של שם תצוגה, עיר מגורים ושפה במקום אחד; כפתורי עריכה inline עם ולידציית קלט
  • בחירת שפה — תמיכה ב-locale (כרגע עברית בלבד); מוכן ל-i18n עתידי
  • הרחבת טבלת users — 6 עמודות חדשות: display_name, home_city, locale, onboarding_completed, connection_code, onboarding_step; מיגרציה בטוחה עם addColumnIfMissing
  • WhatsApp — טקסט מיידי + מפה מושהית — בתוך חלון העדכון, הודעת טקסט נשלחת מיידית ונערכת בזמן אמת (msg.edit); תמונת המפה נשלחת פעם אחת אחרי debounce (ברירת מחדל: 15 שניות)
  • הגדרת עיכוב מפה בדשבורדwhatsapp_map_debounce_seconds — ניתן לשנות מהדשבורד ללא הפעלה מחדש

🐛 תיקוני באגים

  • תמונת מפה בהתרעות מרובות ערים (#101) — בטלגרם: תמונת המפה נשלחת תמיד כשהיא זמינה; ב-WhatsApp: נשלחת הודעה חדשה עם מפה מעודכנת כשיש שינוי בערים

🧪 בדיקות

  • +48 בדיקות Onboarding + Profile — 21 בדיקות userRepository (מיגרציה, פרופיל, onboarding, connection code), 16 בדיקות onboardingHandler (מעברי שלבים, דילוג, ולידציה), 11 בדיקות profileHandler (סיכום, עריכה, ברירות מחדל)
  • +15 בדיקות WhatsApp — 8 debounce, 7 buildSendPayload + edit-with-image

🔧 תחזוקה

  • src/bot/onboardingHandler.ts — handler חדש ל-wizard onboarding
  • src/bot/profileHandler.ts — handler חדש לפקודת /profile
  • הרחבת userRepository.tsgetProfile, updateProfile, completeOnboarding, isOnboardingCompleted, setOnboardingStep, setConnectionCode, findUserByConnectionCode

v0.4.0 — 2026-03-31

✨ תכונות חדשות

  • WhatsApp Broadcast לקבוצות — קבוצות WhatsApp יכולות לקבל התראות פיקוד העורף עם מפות, edit-window dedup, ו-channel store fallback
  • קטגוריה 6 — WhatsApp Forward — קבוצות WhatsApp יכולות להירשם לקבלת הודעות מועברות מ-WhatsApp Listener (נושא שישי בדשבורד)
  • שידור Listener לקבוצות WA — הודעות מתאימות מ-WhatsApp Listener מועברות גם לקבוצות WhatsApp מנויות (בנוסף לטלגרם)
  • דשבורד WhatsApp — שדרוג משמעותי — עמודי WhatsApp ו-WhatsApp Listeners עם סלקטורים חיפושיים, תיקון קטגוריות, fallback ל-topics, ותמיכה בערוצים לצד קבוצות
  • WhatsApp ChannelsgetChannels() חדש לסריקת ערוצי WhatsApp; tab filter ב-SourceSelector; disconnect + reconnect משופרים
  • עמוד נחיתה — שלוש דרכים — עמוד הנחיתה מציג כעת שלוש אפשרויות: Telegram, WhatsApp, ו-Self-host — עם כרטיסי מידע שנוצרים אוטומטית מה-README
  • עמוד נחיתה — WHATSAPP_INVITE_LINK — תמיכה במשתנה סביבה חדש להצגת קישור הזמנה ל-WhatsApp בדף הנחיתה
  • Wizard: פרופיל הגדרות — שלושה פרופילים (מינימלי / מומלץ ⭐ / מלא) שמכסים את כל 27 משתני הסביבה עם ברירות מחדל חכמות; מחליף את ה-flow הישן של required + optional
  • Wizard: שכפול משופרgit clone --depth 1 מהיר יותר, שינוי remote ל-upstream לעדכונים, הצעת Fork אוטומטית דרך gh CLI
  • Wizard: --profile flag--profile=minimal|recommended|full ו---full כקיצור ל---profile=full

🐛 תיקוני באגים

  • שעון uptime בדשבורד — תוקן תצוגת "0d 0h" קבועה; כעת מציג דקות עבור uptime קצר (3m, 1h 22m)
  • WhatsApp disconnect/reconnect — שיפור יציבות חיבור WhatsApp עם disconnect handler ו-reconnect endpoint

🧪 בדיקות

  • +19 בדיקות wizard — 13 בדיקות profile חדשות, 6 בדיקות deployment חדשות (remote setup, spawnQuiet, fork flow)
  • +12 בדיקות WhatsApp — כיסוי חדש ל-whatsappBroadcaster, whatsappService, dashboard routes
  • 167 בדיקות wizard | סה"כ ~700 בדיקות

🔧 תחזוקה

  • wizard: מחיקת optional.ts ו-required.ts — הוחלפו במערכת profiles מאוחדת (profile.ts)
  • WHATSAPP_INVITE_LINK — נוסף ל-ENV_TEMPLATE של ה-wizard
  • landing/build.js — תמיכה בסקשן "דרכים להשתמש" שנוצר אוטומטית מה-README
  • עדכון .gitignore — הוספת Claude configuration ו-package-lock.json

v0.3.3 — 2026-03-31

✨ תכונות חדשות

  • מערכת ניהול תבניות (Messages) — עורך מקובץ לפי קטגוריה (5 סקשנים) עם Emoji picker ויזואלי, טולטיפים בעברית, סטטוס בר, ואיפוס לפי קטגוריה
  • Simulation Engine + Telegram Preview — בחירת ערים (autocomplete, עד 50), תצוגה מקדימה חיה בתוך phone-frame mockup, character count bar, ו-test-fire לשליחת הודעת בדיקה אמיתית לטלגרם
  • Versioning + Rollback — כל עריכת תבנית יוצרת snapshot (עד 10 לסוג), פאנל היסטוריה עם diff ו-rollback בלחיצה
  • Historical Replay — בחירת התראה היסטורית ורינדור מחדש עם התבנית הנוכחית/override
  • Import/Export תבניות — ייצוא כ-JSON וייבוא עם אימות all-or-nothing
  • ניהול Topic IDs מהדשבורד — ניתוב נושאי פורום (כולל WhatsApp) ישירות מלוח הבקרה עם hot-reload מיידי ללא restart
  • Code SplittingReact.lazy + Suspense לכל 10 דפים + Vite manualChunks לvendor chunks; הchunk הגדול ביותר ירד מ-945KB ל-364KB
  • ErrorBoundary — עמוד שגיאה בעברית עם כפתור "טען מחדש" כשchunk נכשל בטעינה
  • QR Code בטרמינל — קוד QR של WhatsApp מוצג ישירות בטרמינל בהפעלה הראשונה
  • Wizard: קובץ .env מלאwriteFullEnvFile יוצר .env עם כל 22 משתני הסביבה ב-9 סקשנים עם הערות בעברית
  • שדות חדשים בהגדרותtelegram_invite_link, mapbox_image_cache_size, whatsapp_enabled + מידע מערכת (גרסה, גודל DB)
  • דשבורד: Operations — כפתור "בדוק את כל הקטגוריות" (5 הודעות לnoshim המתאימים) + טקסט הסבר לכל סקשן
  • דשבורד: Landing — הסבר מהו דף הנחיתה, סטטוס אתר עם LiveDot, קישור GitHub Actions
  • דשבורד: WhatsApp Listeners — 4 תת-קומפוננטות (ListenersBanner, KeywordHelp, RuleCard, SourceSelector)

🐛 תיקוני באגים

  • wizard: קריסת npm install בנתיב עבריresolveTargetPath() ברירת מחדל ל-~/pikud-haoref-bot (ASCII-safe) במקום CWD שעלול לכלול עברית/רווחים
  • wizard: .env זבל ב-CWD — קובץ .env זמני נמחק אחרי node-mode setup; כרטיס סיום מציג את הנתיב הסופי
  • wizard: escaping ל-.envquoteIfNeeded תומך ב-#, $, ", \ עם round-trip נכון
  • Sidebar RTL — מחוון פעיל ל-border-right, כיוון hover תוקן
  • Overview RTL — anchor ציר Y, שמות ערים בעברית, tooltip מסודר
  • Alerts — תרשים עוגה שנחתך הוחלף בפאנל מספרי (AlertCategoryStats)
  • test-alert-all — מכסה כעת את כל 5 הקטגוריות עם topic routing
  • test-fire truncation — הודעות ארוכות נחתכות ל-4096 תווים לפני שליחה

⚡ שיפורי ביצועים

  • Code splitting — כל דף נטען רק בגישה ראשונה; vendor chunks מופרדים לcaching עצמאי

🔧 תחזוקה

  • alertCategories.ts — חילוץ ALERT_TYPE_CATEGORY ו-CATEGORY_ENV_VAR לקובץ משותף; מבטל כפילות בין topicRouter.ts ל-routingCache.ts
  • --test-concurrency=1 — מונע race condition ב-Node.js v25 בtest runner של wizard

🧪 בדיקות

  • 28 tests חדשים לendpoints של Messages (cities, export, import, replay, test-fire, history, rollback)
  • 9 tests ל-messageTemplateHistoryRepository
  • 11 tests ל-routingCache
  • 4 tests לquoting חדש ב-wizard env
  • 672 tests — 0 regressions

v0.3.2 — 2026-03-30

✨ תכונות חדשות

  • פורמט הודעות חדש — תוכן/הוראות ההתראה מופיע לפני רשימת הערים בכל סוגי ההודעות (ערוץ, DM, WhatsApp), כך שהוא גלוי בהתראת ה-push ולא קבור אחרי מאות ערים; כותרת ערוץ עברה לשתי שורות (🔴 סוג\n⏰ שעה · N ערים); כותרות אזור שינו מ-📍 ל-; label מיותר תוכן ההודעה: הוסר מ-newsFlash
  • שדרוג סגנון מפה — יום: light-v11mapbox/streets-v12 (כבישים, נקודות ציון, תוויות בעברית/ערבית); לילה: dark-v11mapbox/navigation-night-v1 (ניגודיות גבוהה, קריאות משופרת בלילה)
  • Padding אדפטיבי — מחליף את padding=40 הקשיח: 80px ל-1–3 ערים, 50px ל-4–15, 30px ל-16+ — התראות קטנות מקבלות יותר הקשר גיאוגרפי; גדולות לא מבזבזות viewport
  • ערובת min-span לסמני pin (Strategy 0) — ערים ללא נתוני polygon שלחו עד כה pin markers עם zoom-in קרוב מדי; כעת buildMarkersWithPaddingUrl מוסיף bbox בלתי-נראה ל-URL שמבטיח ~50 ק"מ הקשר (כמו expandGeoJSONBounds בנתיב הפוליגונים)
  • Strategy 2.5 — איחוד פוליגונים חופפים — בהתראות עם 50+ ערים (כמו כל מרכז הארץ), גם aggressive simplification לא הספיקה כדי לשמור על URL מתחת ל-8,000 תווים, והמפה נפלה ל-pin markers; שלב חדש _buildUnionedPolygonsUrl משתמש ב-@turf/union כדי למזג את כל הפוליגונים לכמה "כתמים" מאוחדים (100 פוליגוני גוש דן → 2–4 צורות), מקצר את ה-URL פי 10–20× ומאפשר הצגת אזורים ממולאים גם בהתראות גדולות; ערים לא-סמוכות (צפון + דרום ביחד) הופכות ל-MultiPolygon ומוצגות כבלובים נפרדים
  • GitHub Sponsors.github/FUNDING.yml חדש; מאפשר כפתור "Sponsor" בעמוד הריפו; badge ❤️ Sponsor נוסף לשורת הbadges ב-README וסקשן תמיכה ייעודי
  • דף נחיתה — סקשן "מה חדש?"landing/build.js מחלץ אוטומטית את 5 השינויים האחרונים מ-CHANGELOG.md ומזריק אותם לדף הנחיתה; מתעדכן בכל build ללא עדכון ידני
  • דף נחיתה — כפתור Sponsor — כפתור "❤️ תמוך בפרויקט" בפוטר דף הנחיתה מקשר ל-GitHub Sponsors
  • דף נחיתה — סטטיסטיקות מ-READMElanding/build.js מחלץ נתוני מפתח (ערים, אזורים, קטגוריות) מטבלת ## 📊 עובדות ב-README; עדכון README מספיק לעדכן גם את דף הנחיתה
  • ROADMAP.md — מסמך מפת דרכים חדש: כללי ניהול גרסאות (SemVer, שני מסלולי תיוג, checklist), מיילסטונים שהושלמו v0.1–v0.3, placeholder לגרסאות עתידיות

🐛 תיקוני באגים

  • WhatsApp→Telegram: חיתוך caption מדיה ל-1,024 תווים — הודעות וואטסאפ עם תמונה/קובץ שגוף ההודעה שלהן ארוך מ-~960 תווים גרמו לשגיאת API (message caption is too long). whatsappListenerService.ts מיישם כעת truncateToCaptionLimit() על ה-caption לפני sendPhoto/sendDocument
  • Race condition בגבול 06:00/18:00getCurrentMapStyle() נקרא פעמים נפרדות ב-buildCacheKey() וב-buildMapboxUrl(); התרעה שהגיעה בדיוק בגבול יכלה להישמר בקאש עם key של יום אבל עם תמונת לילה (או להיפך); כעת הסגנון מחושב פעם אחת בתחילת generateMapImage() ומועבר לכל ה-builders

🧪 בדיקות

  • +4 בדיקות _buildUnionedPolygonsUrl — null ל-FeatureCollection ריקה, URL עם geojson( (לא pin markers) לעיר בודדת, URL בתוך 8,000 תווים ל-15 ערי גוש דן חופפות, URL קצר מ-naive full-polygon encoding

🔧 תחזוקה

  • קבוע MAP_DIMENSIONS — מחליף את המחרוזת הכפולה '800x500@2x' ב-buildMapboxUrl ו-_buildMarkersUrl
  • שיפור ויזואלי של פוליגוניםfill-opacity 0.4 → 0.5, stroke-width 3 → 4 לגבולות ערים בולטים יותר
  • תלות @turf/union — נוספה לצד @turf/bbox, @turf/simplify, @turf/helpers; guard ל-single-feature (union דורשת ≥ 2 גאומטריות)
  • README — badge גרסה, Sponsors badge, סקשן ## 📊 עובדות, עדכון טבלת sync של דף הנחיתה
  • landing/template/index.html — סקשן "מה חדש?", כפתור Sponsor בפוטר, data-target לאזורים/קטגוריות/ערים עובר מ-hardcode לplaceholders
  • landing/template/style.css — styles ל-.whats-new, .changelog-list, .sponsor-btn

v0.3.1 — 2026-03-30

✨ תכונות חדשות

  • TELEGRAM_TOPIC_ID_WHATSAPP — env var חדש; topic טלגרם ברירת-מחדל להעברות WhatsApp-to-Telegram; כאשר ל-listener אין telegramTopicId ספציפי, ההודעות מנותבות לתפריט זה במקום ל-chat הראשי; per-listener telegramTopicId ממשיך לגבור (opt-in override); ערכים לא-מספריים ו-ID=1 נדחים כמו ב-topicRouter
  • Wizard — RTL rendering תקין — שילוב bidi-js להמרת עברית לסדר visual לפני הדפסה; עובד בכל הטרמינלים כולל VS Code (שמתעלם מ-\u202B); toVisualRtl() חדש ב-wizard/src/ui/rtl.ts
  • Wizard — overhaul ויזואלי ו-UX — banner gradient (כחול טלגרם → ענבר) ב-boxen round; progress bar עם / blocks לפני כל שלב; section cards ב-boxen לפני כל קבוצת prompts; skip warnings: boxen warning card עם רשימת consequences מדויקת; PROXY_URL מקבל אזהרה קריטית אדומה כברירת-מחדל; completion card עם סיכום ✓/→ --update + פקודת deploy

🧪 בדיקות

  • +5 בדיקות whatsappListenerService — fallback topic נוצל, fallback מדולג כשלא מוגדר, listener-specific topic גובר על env var, דחיית ID=1, דחיית ערך לא-מספרי
  • +5 בדיקות RTL (wizard/__tests__/rtl.test.ts) — toVisualRtl, containsHebrew, hebrew-before-chalk ordering

v0.3.0 — 2026-03-30

✨ תכונות חדשות

  • האזנה לקבוצות/ערוצים WhatsApp — כלל האזנה לכל קבוצה/ערוץ: keywords, topic טלגרם, is_active
  • סינון לפי מילות מפתח — ריק = כל הודעה; עם keywords = רק התאמות; media-only נדחות בשקט
  • העברה אוטומטית לטלגרם — כולל thread/topic; fallback ל-TELEGRAM_CHAT_ID; גוף > 3900 תווים נקצץ
  • ניהול כללים בדשבורד — דף "WA Listeners": רשימה, הוספה, עריכה, מחיקה, keyword chip input
  • guard msgFromMe — מניעת לופ; הבוט לא מעביר את ההודעות שלעצמו חזרה לטלגרם
  • TELEGRAM_FORWARD_GROUP_ID — env var חדש לניתוב העברות; fallback ל-TELEGRAM_CHAT_ID
  • חותמת זמן יציבהalert.receivedAt מוחתם בזמן הסקר; הודעות ערוכות לא מציגות שעה משתנה; timezone: Asia/Jerusalem
  • קריאות ערים משופרת — כותרת הודעה מציגה · N ערים כולל; כותרת אזור מציגה (N) לכל אזור
  • מיון ערים אלפבתי — ערים ממוינות לפי localeCompare('he') בתוך כל אזור
  • 📍 ערים נוספות — ערים ללא נתוני polygon מקבלות כותרת מפורשת במקום להידבק לאזור הקודם
  • pin markers fallback — כאשר buildGeoJSON מחזיר תוצאות ריקות (עיר ב-cities.json אך ללא polygon), generateMapImage מנסה pin markers לפני החזרת null
  • שרשרת עריכה מדורגתeditAlert מנסה editMessageMedia → editMessageCaption → editMessageText במקום לכשול על השגיאה הראשונה; רק isMessageGoneError מייצר הודעה חדשה

🔒 אבטחה

  • Rate limiting מקיףcreateRateLimitMiddleware factory חדש (src/dashboard/rateLimiter.ts), zero new dependencies; מגבלות per-IP: broadcast 2/min, test-alert 10/min, delete-window 5/min, deploy 3/hr, backup 5/hr, CSV export 10/hr, subscriber mutations 10/min
  • Brute-force protection פרסיסטנטי — מונה ניסיונות כניסה עבר מ-Map בזיכרון לטבלת login_attempts ב-SQLite; שורד restart; header Retry-After נכלל בתשובת 429
  • Bot callback cooldown — 1.5s per-user למנוי/הסרת ערים (ct/ca/cr), search toggle (st), settings (rm/quiet:toggle/snooze) — מונע ספאם callback

⚡ שיפורי ביצועים

  • cityLookup O(1)Array.find() הוחלף ב-Map objects: byNormalizedName, byId, byZone — בנויות פעם אחת בטעינה; pre-sort לרשימות אזורים; FIFO cache (200 ערכים) ל-searchCities()
  • N+1 fix — dmDispatcherisMuted(chat_id) per-subscriber הוחלף ב-JOIN אחד עם u.muted_until ב-getUsersForCities; 1 query במקום 1+N
  • TTL Stats Cache/health 15s, /overview 60s, /alerts/by-category 5min, /alerts/top-cities 5min (ה-json_each + GROUP BY query הוא היקר ביותר)
  • In-memory Subscription CachecityToSubscribers + subscriberData Maps נטענות ב-startup; write functions שומרות sync עם cache; guard cacheInitialized מונע דליפת state בין test suites
  • In-memory Mapbox Usage Cache — מונה module-level; DB write לעמידות בלבד; initUsageCache() נקרא ב-startup

🐛 תיקוני באגים

  • Queue log spam — אזהרת queue-depth הועברה מ-drain() (N+1 per task) ל-enqueueAll() — מופיעה פעם אחת לבאץ׳ בלבד
  • paused field מיותרgetStats() החזיר paused ו-rateLimited לאותו ערך; הוסר paused; rateLimited הוא השם הקנוני
  • Dead _format parambuildDmText(alert, _format) לא השתמש בפרמטר השני; הוסר מהסיגנטורה ומה-call site; NotificationFormat import נוקה
  • retry_after=0 guardsetTimeout delay מוגן עם Math.max(1, retryAfter * 1000) למניעת delay אפסי על ערכים תיאורטיים של 0
  • validateChatId() extracted — לוגיקת ולידציה chatId הוצאה מה-closure לפונקציה מיוצאת; גם תוקן comment מטעה (ה-float path תופס ".5", לא "123.0")

🧪 בדיקות

  • 391 בדיקות (+62 מ-0.2.3):
  • +12 dmQueue / dmDispatcher — validateChatId (5), quiet hours via injectable now (1), mixed mute/active subscribers (2), getStats (2), empty enqueueAll (1), error paths (1)
  • +11 rateLimiter (6) + userCooldown (5)
  • +2 auth.test.ts — persistence after restart (login_attempts SQLite)
  • WhatsApp: whatsappService (30+), whatsappListenerService (20+), whatsappBroadcaster (15+), whatsappFormatter (15+), whatsappGroupRepository (10+), whatsappListenerRepository (10+)
  • subscriptionRepository — cache init, add/remove sync, evict (20+)
  • mapboxUsageRepository — cache seed, limit check, month rollover (10+)
  • cityLookup — O(1) lookup, search cache (5+)
  • statsCache — hit/miss/expiry (5+)
  • mapService — pin markers fallback, receivedAt timestamp, edit chain (10+)
  • telegramBot — city counts, alphabetical sort, noZone header (15+)

🔧 תחזוקה

  • src/dashboard/rateLimiter.ts — factory חדש לrate limiting (reusable, per-IP)
  • src/bot/userCooldown.ts — per-user callback cooldown Map
  • src/dashboard/statsCache.ts — TTL cache גנרי לendpoints יקרים
  • src/db/whatsappGroupRepository.ts + src/db/whatsappListenerRepository.ts — CRUD לטבלאות חדשות
  • src/dashboard/routes/whatsapp.ts + src/dashboard/routes/whatsappListeners.ts — 7 endpoints חדשים
  • src/whatsapp/ — 4 קבצים חדשים: whatsappService, whatsappListenerService, whatsappBroadcaster, whatsappFormatter
  • dashboard-ui/src/pages/ — שני דפים חדשים: WhatsApp.tsx, WhatsAppListeners.tsx
  • src/db/schema.ts — טבלאות חדשות: login_attempts, whatsapp_groups, whatsapp_listeners
  • Startup orderinitSubscriptionCache() + initUsageCache() נוספו לרצף האתחול ב-index.ts לפני initializeCache()

⚠️ שינויים שוברים

  • WHATSAPP_ENABLED=true נדרש להפעלת הלקוח; ללא הגדרה — כל קוד ה-WhatsApp מושבת (callback נשמר אך event לא מופעל)
  • login_attempts — טבלת SQLite חדשה; migration אוטומטי ב-initSchema()

v0.2.3 — 2026-03-29

🔒 אבטחה

  • timingSafeEqual להשוואת סיסמה — מניעת timing-attack על endpoint הכניסה דרך node:crypto
  • Session token — הכניסה מייצרת randomUUID() ושומרת אותו ב-cookie; הסיסמה עצמה לעולם לא יוצאת מהשרת
  • Session persistence — טוקני סשן שמורים ב-SQLite עם TTL של 7 ימים ומתמידים לאחר restart
  • Logout מיידיDELETE FROM sessions מבטל את הטוקן באופן מיידי; אין המתנה לפקיעה
  • trust proxy: 1 — Express קורא את ה-IP הנכון מ-X-Forwarded-For (hop אחד — nginx) במקום IP פנימי של ה-proxy
  • Rate limiting — 10 ניסיונות / 15 דקות לכל IP — לאחר 10 כשלונות, IP נחסם עם 429 Too Many Requests + header Retry-After
  • Reset מונה לאחר כניסה מוצלחת — מונה הניסיונות הכושלים מתאפס כשמזינים סיסמה נכונה
  • ולידציה של סיסמה ריקה400 Bad Request על סיסמה ריקה / חסרה במקום השוואה מיותרת

🐛 תיקוני באגים

  • תמיכה ב-HTTPS אותיות גדולות — regex /^https?:\/\//i (עם i flag); קודם HTTPS://example.com נדחה בטעות
  • Trim לכתובת URLsiteUrl.trim() מנקה רווחים מוביל/נגרר לפני הולידציה
  • כפילות DMs בעריכת הודעה — במסלול העריכה, המנויים מקבלים רק את הערים החדשות (dmCities) ולא את כל הרשימה המאוחדת
  • Phantom test — בדיקת message:text handler תוקנה עם assertion מפורש שמוודא שאין reply כשלא במצב חיפוש

🧪 בדיקות

  • auth.test.ts — בדיקות חדשות: cookie flags (httpOnly, sameSite: strict), סיסמה ריקה (400), שדה סיסמה חסר (400), שני סשנים במקביל (logout של אחד לא מבטל את השני), header Retry-After על 429, rate limit per-IP עצמאי
  • landing.test.ts — בדיקות חדשות: siteUrl עם רווחים (trim), פרוטוקול HTTPS:// (i flag)

🔧 תחזוקה

  • src/services/dmDispatcher.ts — הוסר import מיותר של formatAlertMessage שלא היה בשימוש
  • src/alertHandler.ts — הוסף הסבר ל-notifySubscribers({ ...alert, cities: dmCities }) המבהיר את ההבדל בין alert ל-finalAlert

v0.2.2 — 2026-03-29

✨ תכונות חדשות

  • KPI trend indicators — "התראות היום" ו-"התראות 7 ימים" מציגים ▲/▼ עם delta מול אתמול / שבוע קודם
  • Skeleton loading — גרפים מציגים בזמן טעינה ראשונית במקום לקפוץ ל-EmptyState
  • אגדת גרף עם תוויות עבריות לפי קטגוריה בגרף הפילוח השבועי
  • Empty state — הבחנה בין "אין תוצאות עבור הסינון הנוכחי" (כשסינון פעיל) לבין "אין התראות לתקופה זו" (כשהתקופה ריקה)
  • עמוד תבניותתבניות בתפריט הצד מאפשר לערוך לכל סוג התראה: אמוג׳י, כותרת עברית, וקידומת הוראות
  • שינויים מיידיים — אין צורך ב-restart; הבוט טוען את הקאש מחדש אחרי כל שמירה
  • איפוס לברירת מחדל — כפתור Reset מחזיר כל שורה לברירת המחדל שבקוד
  • סגנון יום/לילהlight-v11 בשעות 06:00–18:00 ו-dark-v11 ב-18:00–06:00 (שעון ישראל, כולל DST)
  • הקשר גיאוגרפי לעיר בודדתexpandGeoJSONBounds() מוסיף padding שקוף כשהאזור הפגוע < ~50 ק"מ
  • Padding על כל URL?padding=40 מונע גזירת polygons בקצות התמונה
  • מרקרים צבעוניים לפי סוג — צבע הסיכה נגזר מסוג ההתראה (getAlertColor()) במקום אדום קבוע
  • Polygon מודגשfill-opacity 0.3 → 0.4, stroke-width 2 → 3

🐛 תיקוני באגים

  • Recharts Hebrew RTLHebrewYAxisTick עם direction="rtl" על SVG ; ללא זאת שמות ערים עבריים הוצגו הפוך
  • alertsYesterday query — תוקן מחלון rolling של 24 שעות ל-גבולות חצות קלנדריות (date('now','-1 day') עד date('now')); הבחנה עקבית עם alertsToday
  • פילטר קטגוריה שבור?type=drills לא התאים לעולם (DB שומר missilesDrill, earthQuakeDrill וכו׳); הוחלף ב-?category=drills שנגזר מ-ALERT_TYPE_CATEGORY
  • קאש תמונות עמיד לאתחול — הוספת טבלת mapbox_image_cache ב-SQLite; initializeCache() טוען תמונות שמורות ב-startup; מונה הדשבורד עקבי עם חיוב Mapbox
  • toVisualRtl() במקום wrapRtl()\u202B (RLE embedding) לא נתמך ב-VS Code terminal; toVisualRtl() ממיר לסדר ויזואלי דרך bidi-js (Unicode TR#9) ומציג נכון בכל הטרמינלים

🧪 בדיקות

  • 142 בדיקות חדשות: mapboxCacheRepository (13), templateCache (16), dashboard routes /messages (17), mapServicegetCurrentMapStyle (5) + expandGeoJSONBounds (3) + colored markers (2), ועדכון assertions ל-toVisualRtl() ב-logger.test.ts

🔧 תחזוקה

  • src/config/alertTypeDefaults.ts — חילוץ ALERT_TYPE_HE / ALERT_TYPE_EMOJI / DEFAULT_INSTRUCTIONS_PREFIX מ-telegramBot.ts לקובץ ייעודי
  • src/config/templateCache.ts — קאש in-memory עם Object.freeze() + reload אטומי
  • src/db/mapboxCacheRepository.ts — repository pattern לטבלת mapbox_image_cache
  • src/db/messageTemplateRepository.ts — repository pattern לטבלת message_templates

v0.2.1 — 2026-03-29

✨ תכונות חדשות

  • תיקון BiDi בטרמינל — מחרוזות עבריות המשולבות עם מספרים (כגון "פורט 3000", "כל 2 שניות") נעטפות ב-Unicode RLE embedding (\u202B...\u202C) ומוצגות כעת בסדר הנכון בכל הטרמינלים
  • startup box מעוגל — פינות ╭╮╰╯, רוחב דינמי לפי רוחב הטרמינל
  • לינקים לחיצים — Health Server ו-Dashboard מציגים OSC 8 hyperlinks (VS Code terminal, iTerm2)
  • tag badges — תגי לוג צבעוניים עם רקע לכל מקור (Poller, AlertHandler, DM וכו')
  • section divider — קו הפרדה עם תאריך בין ה-startup box לשורות הלוג
  • מונה התראות היום — startup box מציג כמה התראות נשלחו היום (מה-DB)

🐛 תיקוני באגים

  • יצירת data/ אוטומטיתschema.ts יוצר את תיקיית data/ אם אינה קיימת לפני פתיחת ה-DB; מונע SQLITE_CANTOPEN בהתקנות רעננות שבהן התיקייה מוסרת ע"י gitignore
  • ניווט אזורים statelesszoneHandler.ts מקודד כעת את ה-context המלא (superRegionIdx:zoneIdx:page) ישירות ב-callback_data של כל כפתור (zp:, ct:, ca:, cr:); הכפתורים עובדים לאחר restart הבוט ללא state בצד שרת; ZoneState Map הוסר לחלוטין
  • settingsHandler.ts — 13 קריאות console.error הוחלפו ב-log() מ-logger.ts
  • dmDispatcher.ts — פרמטר enqueueAll להזרקה בבדיקות (ברירת מחדל: dmQueue) — מאפשר בדיקות יחידה ללא module mocking
  • Recharts — נוסף orientation="right" ל- ב-Overview ו-Alerts; הציר מופיע כעת בצד הנכון בממשק RTL
  • Sidebar — תוקן ל-border-l-2 (הקצה הפנימי מול אזור התוכן) במקום border-r-2
  • Pagination — חצי ניווט הוחלפו (RTL-correct)
  • Framer Motion — כיוון x entry animation תוקן לערכים חיוביים לכניסה מימין (RTL-correct)

🧪 בדיקות

  • 13 בדיקות חדשות ל-notifySubscribers() — אינטגרציה עם DB אמיתי + enqueueAll מוזרק
  • 5 בדיקות לפילטר snooze / muted_until ב-dmDispatcher
  • 2 בדיקות לפילטר quiet hours בשליחה לתור

🔧 תחזוקה

  • src/loggerUtils.ts — קובץ helpers חדש (wrapRtl, osc8Link, boxWidth, hr, containsHebrew)
  • src/db/alertHistoryRepository.ts — הוספת countAlertsToday()
  • CI: --test-concurrency=1 — בדיקות core רצות סדרתית כדי למנוע race conditions בין mapboxUsageRepository.test.ts ו-mapService.test.ts שחולקים DB על הדיסק
  • CI: wizard-check — בדיקת קיום wizard/package-lock.json הועברה מ-job-level if לשלב ייעודי (hashFiles() זמין רק ב-step context, לא ב-job context)
  • .worktrees/ נוסף ל-.gitignore

v0.2.0 — 2026-03-29

✨ תכונות חדשות

  • חבילה קלה: wizard/ נפרד עם 2 תלויות בלבד (@clack/prompts + chalk) — במקום ~180 חבילות עם native addons
  • חוויה עשירה: ממשק @clack עם צבעים, select menus, progress badges, spinners
  • ולידציה חיה: בדיקת פורמט token / chat-id / mapbox / URL בכל שדה בזמן ההקלדה
  • Update mode (--update): זיהוי .env קיים, multiselect של שדות לעדכון, merge אימות
  • Verify mode (--verify): בדיקת תקינות TELEGRAM_BOT_TOKEN + MAPBOX_ACCESS_TOKEN מול API
  • RTL בטרמינל: עברית ו-LTR על שורות נפרדות, visibleWidth Unicode-aware לחישוב padding
  • Glassmorphism design system: CSS tokens ב-:root {}--color-glass, --color-border-glass, --color-glow-*
  • כל 7 הדפים עוצבו מחדש עם framer-motion animations + RTL תקין (Overview, Alerts, Subscribers, Operations, Settings, LandingPage, Login)
  • Component library (dashboard-ui/src/components/ui/): GlassCard, AnimatedCounter, LiveDot, PageTransition
  • RTL fixes: chevron sidebar (right/left מתהפכים נכון), slide direction (x הוא כיוון פיזי, לא לוגי), text alignment
  • StatusStrip: isLoading state — מונע false-positive ״מחובר״ לפני שהבדיקה הראשונה חזרה
  • GlowVariant type: exported ומשותף — exhaustiveness נאכף ב-compile time ב-KpiCard
  • Mutation patterns: onMutate + onSettled תוקנו בכל פעולה destructive (delete, patch, deploy)
  • src/logger.ts חדש: log(level, tag, msg) עם chalk v4 — levels: info/success/warn/error
  • logStartupHeader(version, services[]): טבלת סטטוס בעת הפעלה — Health Server, Alert Poller, Dashboard, DB
  • logAlert(type, cities, action): תיבת ⚡ מעוצבת לכל שליחה/עריכה עם סוג + רשימת ערים
  • כל console.log/warn/error בקוד הפרודקשן הוחלפו ב-log() מובנה
  • עיצוב SaaS מודרני עם hero section, feature grid, CTA
  • RTL מלא, Heebo font, Telegram blue theme, dark mode
  • Error handling, accessibility, ו-CSS structure תוקנו

⚠️ שינויים שוברים

  • root/package.json קיבל "private": true — הבוט עצמו לא מפורסם יותר ל-npm
  • bin/setup.js הוסר — הוחלף ב-wizard/src/
  • שם חבילת wizard נשמר: @haoref-boti/pikud-haoref-bot

🧪 בדיקות

  • 76 בדיקות ל-wizard/ (TDD)
  • test(logger): suite מלאה ל-log, logStartupHeader, logAlert
  • test(alertHandler): stdout מדוכא בבדיקות — פלט CI נקי יותר

🔧 תחזוקה

  • publish-npm job הוחלף ב-publish-wizard — trigger: wizard-v* tags (עצמאי מ-v*)
  • CI עודכן ל-4 jobs מקבילים: test, dashboard-build, docker-build, wizard-check
  • wizard-check מותנה: hashFiles('wizard/package-lock.json') != '' — מדלג כשאין wizard/
  • תיקון: DB_PATH=:memory: הועבר לבלוק env: — YAML compact mapping תקין
  • תיקון: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 נוסף לכל ה-jobs

v0.1.6 — 2026-03-29

✨ תכונות חדשות

  • npx @haoref-boti/pikud-haoref-bot — wizard אינטראקטיבי להגדרת הבוט
  • שואל על TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, MAPBOX_ACCESS_TOKEN (חובה)
  • תמיכה בדגלים: --token, --chat-id, --mapbox, --dashboard, --proxy, --invite-link, --full, --output
  • בחירת אופן הרצה: Docker (מומלץ) או Node.js
  • החבילה מפורסמת ב-npm: @haoref-boti/pikud-haoref-bot

🔧 תחזוקה

  • publish-npm job נוסף ל-release.yml — פרסום אוטומטי ל-npm בכל tag גרסה
  • bin/setup.js נוסף לפרויקט (plain JS, ללא תלויות)
  • package.json: נוספו שדות bin, files, publishConfig
  • דף הנחיתה עודכן: כפתור "הרץ instance משלך" מציג npx @haoref-boti/pikud-haoref-bot
  • גריד "שתי דרכים" אוזן לגובה שווה בין שני הכרטיסים

v0.1.5 — 2026-03-28

✨ תכונות חדשות

  • שרת Express חדש על פורט DASHBOARD_PORT (ברירת מחדל: 4000) — מופעל רק כאשר DASHBOARD_SECRET מוגדר
  • אימות מאובטח עם עוגיית httpOnly, timingSafeEqual למניעת timing attacks
  • API routes: /api/stats, /api/subscribers, /api/operations, /api/settings, /api/landing
  • React SPA (Vite + Tailwind v4 RTL) עם 7 דפים: Overview, Alerts, Subscribers, Operations, Settings, LandingPage, Login
  • Command Palette (⌘K), sidebar RTL, status strip עם polling חי
  • ייצוא מנויים כ-CSV, ניהול תור שליחה DM, ניהול alert window
  • שידור ידני של התראה, endpoint ל-deploy של landing page דרך GitHub Actions
  • ניהול הגדרות key-value בטבלת settings ב-SQLite
  • זמן מקלט (⏱ X שנ׳) מוצג בהודעות DM קצרות — כמינימום הזמן בין ערי המנוי
  • דחיית התראות (snooze) — המשתמש יכול להשתיק DMs לפרק זמן מוגדר
  • עמוד /mycities מציג כעת תוויות אזור לכל עיר
  • /start בצ'אטי קבוצה מחזיר תשובה (במקום להתעלם)
  • /start בתפריט הראשי מציג את ההתראה האחרונה
  • /history מציג שעה מוחלטת לצד הזמן היחסי (לפני X שעות)
  • פוליגונים חדים יותר לערים
  • צבע פוליגון לפי סוג ההתראה (אדום לביטחוני, כתום לטבעי, צהוב לסביבתי וכו׳)
  • הזרקת סקריפט Google Analytics 4 דרך GA4_MEASUREMENT_ID env var
  • ב-template — מוחלף בזמן בניה

⚠️ שינויים שוברים

  • משתנה סביבה חדש DASHBOARD_SECRET נדרש להפעלת הדשבורד (ללא הגדרה — לא נטען)
  • משתנה סביבה חדש DASHBOARD_PORT (ברירת מחדל: 4000)
  • עמודת muted_until TEXT נוספה לטבלת users — migration אוטומטי בהפעלה

🔧 תחזוקה

  • initSchema(database) מופרד מ-initDb() לבדיקות עם DB בזיכרון
  • addColumnIfMissing() helper מאחד את הלוגיקה של ALTER TABLE migrations
  • DB_PATH=:memory: ב-npm test לבדיקות בזיכרון ללא קובץ
  • build:dashboard ו-dev:dashboard נוספו ל-package.json
  • Docker ו-CI מבנים את ה-dashboard-ui כחלק מהבנייה הכוללת

v0.1.4 — 2026-03-28

✨ תכונות חדשות

  • טבלת alert_history ב-SQLite — כל התראה שנשלחת נשמרת עם type, ערים, instructions ו-fired_at
  • ניקוי אוטומטי של רשומות ישנות מ-7 ימים בכל הפעלה
  • alertHistoryRepositoryinsertAlert, getRecentAlerts(hours), getAlertsForCity, getAlertsForCities
  • סיכום 24 שעות אחרונות לפי קטגוריה (🔴 ביטחוני, 🌍 טבע, ☢️ סביבתי, 🔵 תרגילים, 📢 כללי)
  • ספירה אישית: כמה מהתראות נגעו לאזורים שהמשתמש רשום אליהם
  • /history — 10 התראות אחרונות לערים שהמשתמש רשום אליהן
  • /history [עיר] — 10 התראות אחרונות לעיר ספציפית
  • fallback לכלל-ארצי כשאין מנויים, עם טיפ להצטרפות
  • זמן יחסי בעברית: "עכשיו" / "לפני X דקות" / "לפני X שעות" / "לפני X ימים"
  • כל מנוי מקבל רק ערים שרשום אליהן (matchedCities) — לא את כל ערי ההתראה
  • buildDmText — helper לבניית הודעה לפי פורמט + type
  • shouldSkipForQuietHours — מסנן DMs מסוג drills ו-general בשעות הלילה
  • התראות קריטיות (missiles, earthquake, hazmat) תמיד עוברות
  • לחצן toggle בתפריט /settings: 🔕 שעות שקט: כבוי / פעיל ✓
  • GET /health — מחזיר JSON: uptime, lastAlertAt, lastPollAt, alertsToday
  • פורט מוגדר דרך HEALTH_PORT (ברירת מחדל: 3000)
  • updateLastAlertAt() נקרא אוטומטית בכל התראה חדשה
  • טבלת alert_window ב-SQLite — מצב חלון ההתראות הפעיל נשמר על הדיסק
  • loadActiveMessages() בהפעלה — משחזר מצב מ-DB, מונע הודעות כפולות בערוץ לאחר restart
  • upsertWindow, deleteWindow, loadAllWindows, clearAllWindows ב-alertWindowRepository
  • DmQueue — תור שליחה עם מגבלת מקביליות מוגדרת (ברירת מחדל: 10)
  • backoff אוטומטי לשגיאות 429: מחזיר לראש התור ומשהה לפי retry_after
  • ניהול משתמשים חסומים: מסיר אוטומטית ממסד הנתונים
  • notifySubscribers הפכה ל-sync — השליחה אסינכרונית בתור

🔧 תחזוקה

  • ALERT_TYPE_CATEGORY ו-AlertCategory מיוצאים מ-topicRouter.ts לשימוש ב-statsHandler ו-dmDispatcher
  • User interface מכיל quiet_hours_enabled: number
  • getUsersForCities מחזיר matchedCities[] + quiet_hours_enabled לכל מנוי

v0.1.3 — 2026-03-27

✨ תכונות חדשות

  • דף נחיתה עברי RTL ב-landing/ עם עיצוב dark tactical theme (Heebo + Telegram blue)
  • Hero עם לוגו, אינדיקטור live ירוק, ושני CTAs: "הצטרף לערוץ" + "הרץ instance משלך"
  • גריד פיצ'רים — מסונכרן אוטומטית מטבלת ## ✨ תכונות ב-README.md
  • תצוגה מקדימה של 5 צילומי מסך עם scroll-snap אופקי
  • Footer עם גרסה ותאריך בנייה שמוזרקים אוטומטית מ-package.json
  • דף חי: https://yonatan2021.github.io/pikud-haoref-bot-landing/
  • deploy-landing.yml — בכל push ל-main: מריץ node landing/build.js, דוחף landing/dist/ לריפו pikud-haoref-bot-landing
  • SSH deploy key (LANDING_DEPLOY_KEY) מאפשר דחיפה מ-CI ללא אישור ידני

⚡ שיפורי ביצועים

  • לוגו: קימפוס 674KB → 18KB (37×) דרך sips; גרסה מקוצרת שמורה ב-landing/template/logo.jpg
  • צילומי מסך: קימפוס 340KB → 29-31KB (11×) לכל תמונה; גרסאות מקוצרות ב-landing/template/screenshots/

🔧 תחזוקה

  • landing/dist/ מכוסה ע"י כלל dist/ הקיים ב-.gitignore

v0.1.2 — 2026-03-27

✨ תכונות חדשות

  • buildNewsFlashDmMessage() — הודעות DM ל-newsFlash מציגות שמות אזורים במקום ערים (📢 הודעה מיוחדת | גליל עליון, קריות)
  • alert.instructions מוצג בשורה נפרדת כשקיים
  • שימוש ב-Set לדדופ אזורים ב-buildNewsFlashDmMessage
  • buildZonedCityList() — מקבץ ערי התראה לפי אזור עם כותרת 📍 Zone לכל אזור
  • ערים ללא match ב-cities.json נצמדות כרשימה שטוחה בסוף
  • סדר אזורים לפי סדר הופעה ראשון במערך הערים של ההתראה
  • שלב חדש: פישוט פוליגונים אגרסיבי (tolerance 0.01) לפני מעבר ל-bounding box
  • שלב חדש: pin markers קומפקטיים (~30 תווים לעיר) כ-fallback לפני bounding box
  • truncateToCaptionLimit() — חיתוך caption ב-1,024 תווים בגבול section אחרון שלם למניעת שבירת HTML
  • normalizeCityName() — trim, כיווץ רווחים כפולים, ואיחוד כל גרסאות המקף (-, , ) ל-" - " עם רווח עקבי

⚡ שיפורי ביצועים

  • Docker layer cache: הסרת .version מ-package.json לפני npm ci — מייצב את שכבת ה-cache ומונע invalidation על bump גרסה בלבד

🐛 תיקוני באגים

  • TypeScript strict: תיקון cast של mock.fn דרך unknown כדי לעמוד בבדיקת overlap קפדנית של TypeScript

🔧 תחזוקה

  • הוספת לוגו הפרויקט ל-README

v0.1.1 — 2026-03-27

✨ תכונות חדשות

  • חילוץ לוגיקת עיבוד ההתראה מ-index.ts לקובץ ייעודי alertHandler.ts עם dependency injection מלא
  • כל התלויות (מפה, שליחה, עריכה, מעקב, DM) מוזרקות כפרמטרים — מאפשר בדיקות יחידה מלאות ללא side effects
  • alertHelpers.ts: עזרים isDrillAlert / shouldSkipMap מחולצים לקובץ נפרד לשימוש חוזר ובדיקות
  • התראות מאותו סוג שמגיעות בתוך חלון הזמן (ברירת מחדל: 120 שניות) עורכות את ההודעה הקיימת בטלגרם במקום לשלוח הודעה חדשה
  • ערים מתמזגות (union) להודעה המעודכנת עם מפה מעודכנת
  • fallback לשליחת הודעה חדשה אם העריכה נכשלת (למשל הודעה ישנה מדי)
  • שינוי גודל החלון דרך ALERT_UPDATE_WINDOW_SECONDS
  • מונה בקשות חודשי נשמר ב-SQLite (טבלת mapbox_usage, מפתח: YYYY-MM)
  • מגבלה חודשית קשיחה דרך MAPBOX_MONTHLY_LIMIT — fallback לטקסט בלבד כשמגיעים למגבלה
  • מטמון FIFO בזיכרון (ברירת מחדל: 20 ערכים) לפי fingerprint — cache hit לא צורך מכסה
  • המונה מתעדכן רק בעת תגובת API מוצלחת
  • newsFlash תמיד נשלח כטקסט בלבד (ללא מפה)
  • תרגילים נשלחים כטקסט בלבד כאשר MAPBOX_SKIP_DRILLS=true
  • Dockerfile רב-שלבי: builder עם Native addon ו-runner קל עם non-root user
  • CI (.github/workflows/ci.yml): type-check + בדיקות + אימות בנייה — פועל על כל push/PR
  • Release (.github/workflows/release.yml): בנייה ודחיפה ל-ghcr.io וגם ל-Docker Hub — פועל על push ל-main

🐛 תיקוני באגים

  • newsFlash ארצי: מניעת re-emission בעת התראות מקבילות — citylessFingerprints מנוהל בנפרד ולא נמחק על ידי לולאת הפקיעה הרגילה
  • noop callback: הוספת handler מפורש — ללא זה, כפתורי תצוגה (ספירת עמודים) הציגו ספינר טעינה בלתי-נגמר בטלגרם
  • DM notifications: התראות DM לא נשלחו כאשר עריכת ההודעה החזירה "message is not modified" — מטופל כ-no-op תקין, DM נשלח בכל מקרה
  • Mapbox counter isolation: הפרדת עדכון המונה מיצירת התמונה — מונע desync בין מונה SQLite לתמונה שנוצרה בעת כשל
  • Error handling: guard בהפעלה (missing env vars), לוג מלא של שגיאות, אזהרת מכסה Mapbox, shallow copy ב-tracker למניעת mutation

🧪 בדיקות

  • בדיקות guard לפרמטר windowMs (ערך אפס וערך סביבה לא חוקי)
  • בדיקות מלאות ל-alertWindowTracker
  • בדיקות ל-alertHandler ו-alertHelpers (כולל isDrillAlert, shouldSkipMap)
  • בדיקות ל-mapService: selectEditMethod, גודל מטמון מקסימלי, cache hit, מגבלה חודשית
  • closeDb() מיוצא לאיפוס ה-singleton בין קבצי בדיקות — מונע stale handle בעת ריצת כל הבדיקות יחד

🔧 תחזוקה

  • הרחבת .gitignore: קבצי WAL של SQLite, וריאנטים של .env, לוגים, כיסוי קוד, tsbuildinfo
  • Node.js 24: עדכון GitHub Actions runners ל-Node 24
  • לוגים באנגלית: תרגום כל הודעות ה-console log מעברית לאנגלית לאחידות

v0.1.0 — 2026-03-20

🎉 גרסה ראשונה פומבית

  • סקירת API של פיקוד העורף כל 2 שניות
  • מפות Mapbox עם פוליגוני ערים מדויקים + fallback לבounding box ולטקסט
  • ניתוב 5 קטגוריות נושאים בטלגרם: ביטחוני, טבע, סביבתי, תרגילים, כללי
  • DM אישי למנויים לפי ערים ואזורים (6 אזורי-על, 28 אזורים)
  • Deduplication חכם לפי fingerprint — פוקע כשהתרעה נעלמת, לא רק ב-all-clear
  • תפיסת newsFlash ארצי (ללא ערים) שהספרייה מדלגת עליו
  • תמיכה ב-Proxy לשימוש מחוץ לישראל
  • בוט גראמי לניהול מנויים: /start, /add, /zones, /mycities, /settings