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 guard — UPDATE ... WHERE status = 'approved' מונע publish כפול או מקדים
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)
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)
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
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 + WhatsApp — buildSummaryLine() כמקור יחיד לספירת ערים/אזורים; תיקון דקדוקי "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 הפוך (>= במקום <=)
אנשי קשר — חברו חברים ומשפחה עם קוד בן 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 עתידי
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, ותמיכה בערוצים לצד קבוצות
עמוד נחיתה — שלוש דרכים — עמוד הנחיתה מציג כעת שלוש אפשרויות: 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
+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 Splitting — React.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
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
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 ללא עדכון ידני
דף נחיתה — סטטיסטיקות מ-README — landing/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:00 — getCurrentMapStyle() נקרא פעמים נפרדות ב-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 לגבולות ערים בולטים יותר
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, דחיית ערך לא-מספרי
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
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 לכתובת URL — siteUrl.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()) במקום אדום קבוע
Recharts Hebrew RTL — HebrewYAxisTick עם 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) ומציג נכון בכל הטרמינלים
תיקון BiDi בטרמינל — מחרוזות עבריות המשולבות עם מספרים (כגון "פורט 3000", "כל 2 שניות") נעטפות ב-Unicode RLE embedding (\u202B...\u202C) ומוצגות כעת בסדר הנכון בכל הטרמינלים
לינקים לחיצים — 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
ניווט אזורים stateless — zoneHandler.ts מקודד כעת את ה-context המלא (superRegionIdx:zoneIdx:page) ישירות ב-callback_data של כל כפתור (zp:, ct:, ca:, cr:); הכפתורים עובדים לאחר restart הבוט ללא state בצד שרת; ZoneState Map הוסר לחלוטין
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