Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4fdfcc7
feat(mcp): פתקים דביקים — צפייה, יצירה ועריכה דרך ה-MCP
claude Jul 20, 2026
fd6b706
feat(webapp): קיצור דרך לעריכת תיאור מתפריט ⋮ בעמוד הקובץ
claude Jul 20, 2026
e97bee5
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 20, 2026
9218b77
fix(webapp): תבנית חדשה מגיעה מיד אחרי deploy (ETag כולל גרסת deploy)
claude Jul 20, 2026
e745b7e
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 20, 2026
71e3264
feat(webapp): אייקון תיאור על קבצים באוסף + מודאל תצוגה
claude Jul 20, 2026
7ea470a
feat(webapp): הזזת אייקון תיאור בכרטיס אוסף + ארכיון לאוספים
claude Jul 20, 2026
26b25b6
Merge origin/main: יישור הענף מול main + פתרון קונפליקט collections.css
claude Jul 20, 2026
991b1ad
fix(webapp): המרת צבעים קשיחים לטוקני ערכה במודאל התיאור ובכפתור הארכיון
claude Jul 20, 2026
afa7b6d
Merge origin/main: יישור מול main אחרי squash של #3192 + פתרון קונפלי…
claude Jul 20, 2026
c7c49a3
fix(bot): תיקון מספר קבצים בהודעות ZIP + שלב בחירת שם ל-ZIP
claude Jul 24, 2026
bab0701
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 24, 2026
fd88aa0
fix(bot): הקשחת יצירת ZIP — ניקוי שמות (Zip-Slip), מגבלות איסוף, to_t…
claude Jul 24, 2026
85bcfa9
fix(bot): הקשחת ZIP סבב 2 — מגבלות לפני הורדה, מניעת שמות כפולים, תיק…
claude Jul 24, 2026
2f84c9f
fix(webapp): Config Inspector — הפרדת שירותים, סטטוס Set, וביטול מיסו…
claude Jul 26, 2026
552bcf4
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 26, 2026
78c0a04
fix(webapp): Config Inspector v2 — webserver כשירות נפרד, משתנים משות…
claude Jul 26, 2026
606a1c1
feat(bot): סוג קובץ חדש "סקיל" — אחסון נפרד מגיבויים
claude Jul 26, 2026
b4f4844
fix(bot,webapp): סבב review לסקילים — כשלי CI, אבטחה וביצועים
claude Jul 26, 2026
352247a
fix(bot): שמירת סקילים נכשלה — pymongo Database לא תומך ב-bool()
claude Jul 26, 2026
ace434f
Merge origin/main: יישור מול main אחרי squash של #3197 ו-#3198 (פתרון…
claude Jul 26, 2026
49ca0a2
fix(webapp): Config Inspector — שחזור רווחים, סינון בעמוד 2, ודיוק שי…
claude Jul 26, 2026
0ed5fd9
fix(bot): סבב review לסקילים — PII בלוגים, ניקוי pending, מכסות, ושאי…
claude Jul 26, 2026
fe906d5
feat(bot): נוסח חדש להודעת קליטת ZIP, "קבצי גיבוי" במקום "קבצי ZIP", …
claude Jul 26, 2026
9ef85c2
Merge origin/main: יישור אחרי squash של #3199 (main זהה לגרסת טרום-fe…
claude Jul 26, 2026
81cc87d
style(bot): איחוד אייקון הסקיל ל-🧩 בכל המופעים
claude Jul 26, 2026
4909cb3
fix(bot): סבב review על PR #3200 — wrapper לעריכות שגיאה ו-fallback מ…
claude Jul 26, 2026
03e6ea9
docs: עמוד תיעוד ל-Config Inspector + עדכון הנחיית Sphinx ב-CLAUDE.md
claude Jul 27, 2026
bca47c8
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 27, 2026
37224f4
fix(webapp): קישורי תפריט פנימיים במסמכי Markdown לא גללו לסעיף
claude Jul 30, 2026
552f4f5
Merge remote-tracking branch 'origin/claude/mcp-codekeeper-webapp-ldn…
claude Jul 30, 2026
e8b669b
fix(webapp): כותרות Setext בעוגני Markdown + ניתוק מצב מודולרי בתצוגה…
claude Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,16 @@ safe_rmrf() {
### כללים
- **אין להריץ** קוד בטופ-לבל בזמן build (importים חייבים להיות בטוחים)
- RTD נחשב נכשל על אזהרות (`fail_on_warning: true`) – שמור 0 warnings
- **כל עמוד חדש חייב להירשם ב-`docs/index.rst`** (ה-master document) בתוך `toctree` מתאים.
עמוד שלא רשום מייצר אזהרת `document isn't included in any toctree` – ומכיוון ש-RTD נכשל
על אזהרות, זה **מפיל את הבילד**. אם עמוד לא אמור להתפרסם – הוסף אותו ל-`exclude_patterns`
ב-`docs/conf.py` במקום להשאיר אותו "יתום"
- השתמש ב-`:noindex:` בעמודי סקירה חופפים: api, database, handlers, services, configuration

### הגדרות
- `autodoc_mock_imports`: cairosvg, aiohttp, textstat, langdetect, pytest, search_engine, code_processor, integrations
- `docs/examples.rst` מוחרג עד שהעמוד יתווסף ל-toctree (ואז הסר מה-exclude)
- `exclude_patterns` (ב-`docs/conf.py`) מרכז את העמודים שאינם ב-toctree בכוונה (למשל כפילויות
`.md`/`.rst`). לפני שמוסיפים החרגה – ודא שהעמוד באמת לא אמור להיות בתוכן העניינים

---

Expand Down
5 changes: 5 additions & 0 deletions docs/environment-variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
.. note::
בכל פעם שמוסיפים או משנים משתני סביבה בקוד/Infra **חייבים** לעדכן עמוד זה (רפרנס משתני הסביבה) וכן לציין זאת ב-PR. בכך אנו מבטיחים שהמידע הופך ל-Single Source of Truth גם למפתחים וגם לאנשי DevOps.

.. seealso::
:doc:`webapp/config-inspector` — כלי האדמין שמציג את המשתנים בזמן ריצה. שם מתועדים
גם הכללים להוספת משתנה: איך קובעים לאיזה שירות הוא שייך, איך נמנעים מסטטוס
``Modified`` שגוי, ומה צריך לתעד כשמשתנה משרת כמה שירותים.

טבלה מרכזית
------------

Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Code Keeper Bot - תיעוד API
webapp/caching
webapp/advanced-caching
webapp/cache-inspector
webapp/config-inspector
webapp/static-checklist
webapp/commands-catalog
webapp/code-execution
Expand Down
261 changes: 261 additions & 0 deletions docs/webapp/config-inspector.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
.. _webapp-config-inspector:

Config Inspector (סקירת משתני סביבה)
=====================================

מה זה Config Inspector?
------------------------

**Config Inspector** הוא כלי אדמין שמציג תמונת מצב של הקונפיגורציה: אילו משתני סביבה
מוגדרים, מה הערך הפעיל שלהם, מה ברירת המחדל בקוד, והאם הערך שונה מברירת המחדל.

הכלי נותן מענה לשאלות שקשה לענות עליהן מול Render Dashboard:

- האם המשתנה הזה בכלל מוגדר, או שאנחנו רצים על ברירת מחדל?
- מה ברירת המחדל שבקוד, ובמה הערך שברנדר שונה ממנה?
- לאיזה שירות שייך המשתנה, ואיפה צריך להגדיר אותו?
- אילו משתנים הכרחיים חסרים?

איך נכנסים?
-----------

**דרך ה-UI:** דף **Settings** ← קטגוריית **כלי אדמין** ← **Config Inspector**

**ישירות:**

.. code-block:: text

GET /admin/config-inspector

.. note::
הדף זמין **רק לאדמינים** (``@admin_required`` ב-``webapp/app.py``). ערך מוצג ממוסך
(``********``) **רק אם הוא מסווג כרגיש** — לפי שם המשתנה או לפי סימון מפורש
``sensitive=True``; כל שאר הערכים מוצגים כמות שהם. הסיווג מפורט ב-
:ref:`config-inspector-sensitive`, וחשוב לקרוא אותו לפני הוספת משתנה שהוא סוד.

.. _config-inspector-two-pages:

שני עמודים — ולמה
------------------

הדף מחולק לשני טאבים, וההפרדה ביניהם אינה קוסמטית אלא נובעת ממגבלה אמיתית.

.. _config-inspector-page1:

עמוד 1: שירות ה-Webapp (עם Status וערך פעיל)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

העמוד הראשון מציג **רק משתנים ששייכים (גם) לשירות ה-Webapp**, ורק הם מקבלים עמודות
``Status`` ו-``Active Value``.

**הסיבה:** ה-Config Inspector הוא קוד שרץ **בתוך תהליך ה-Webapp**. כשהוא קורא
``os.environ`` הוא רואה אך ורק את משתני הסביבה של אותו תהליך. הבוט, שרת ה-MCP וה-webserver
הם **שירותי Render נפרדים**, כל אחד עם ENV משלו — ותהליך ה-Webapp פשוט אינו יכול לראות
אותם.

לכן, אילו היינו מציגים ``Status`` למשתנה של הבוט, הוא היה מוצג כ-*Default* או *Missing*
גם כשהוא מוגדר מצוין בשירות הבוט. **מידע שגוי גרוע מהיעדר מידע** — ולכן העמוד הראשון
מסונן, והסינון נאכף בקוד:

.. code-block:: python

# services/config_inspector_service.py — get_config_overview
for definition in self.CONFIG_DEFINITIONS.values():
# עמוד ראשי: רק משתנים ששייכים (גם) לשירות ה-webapp
if "webapp" not in definition.services:
continue

בראש העמוד מוצגים כרטיסי סיכום (סה"כ / שונו מדיפולט / הוגדרו בסביבה / חסרים / ברירת מחדל),
שורת סינון (קטגוריה + סטטוס), פירוט לפי קטגוריות, וטבלת המשתנים המלאה. כפתור
**"העתק הכל"** מייצא את השורות המוצגות בפורמט ``KEY=VALUE`` (שורות ``.env``).

עמוד 2: שירותים אחרים — Bot / MCP / Webserver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

העמוד השני מציג את כל המשתנים שיש להם שירות **שאינו** webapp — כולל משתנים משותפים
שמופיעים גם בעמוד הראשון.

מה מוצג: ``Key`` / ``שירות`` / ``Default Value`` / ``תיאור``.

מה **לא** מוצג, ולמה: **אין כאן ``Status`` ואין ``Active Value``** — מאותה סיבה בדיוק
שתוארה למעלה. הערכים חיים בתהליכים אחרים ואינם נגישים מכאן. לערכים בפועל יש לבדוק
ב-Render Dashboard של השירות הרלוונטי.

- שורה של משתנה שמוגדר גם בוובאפ מסומנת בתגית **"גם Webapp"** — הערך שלה מופיע בעמוד הראשון.
- שורת הסינון בעמוד זה היא לפי **קטגוריה** ולפי **שירות** (ולא לפי סטטוס — אין כאן סטטוס).
- "העתק הכל" בעמוד זה מעתיק ``KEY=<ברירת מחדל>`` ומציין זאת מפורשות, כדי שלא ייווצר רושם
שאלו הערכים החיים.

.. _config-inspector-status:

ארבעת הסטטוסים — ואיך נמנעים מ-"Modified" שגוי
------------------------------------------------

.. list-table::
:header-rows: 1
:widths: 15 45 40

* - סטטוס
- מתי מתקבל
- משמעות
* - ``Default``
- אין ערך בסביבה ויש ברירת מחדל בקוד — או שהערך בסביבה **זהה** לברירת המחדל
- רצים על ברירת המחדל. אין מה לעשות
* - ``Set``
- יש ערך בסביבה ו**אין ברירת מחדל בקוד**
- המשתנה הוגדר (למשל ברנדר). זו **אינה** סטייה — אין דיפולט שממנו אפשר לסטות
* - ``Modified``
- יש ערך בסביבה, יש ברירת מחדל, והם **שונים**
- סטייה אמיתית מברירת המחדל — כאן צריך להסתכל
* - ``Missing``
- אין ערך בסביבה, אין ברירת מחדל, והמשתנה מסומן ``required=True``
- משתנה הכרחי חסר. מוצג גם כאזהרה בראש הדף

הלוגיקה ממומשת ב-``ConfigService.determine_status``.

.. warning::
**הכלל השורשי:** ה-``default`` שרשום ב-``ConfigDefinition`` חייב להיות **זהה תו-בתו**
לברירת המחדל האמיתית בקוד. אחרת מתקבל סטטוס ``Modified`` שקרי — משתנה שמוגדר נכון
ייראה כאילו מישהו שינה אותו, ואי אפשר יהיה לסמוך על העמודה הזו.

שתי הטעויות שמייצרות ``Modified`` שגוי:

**1. דיפולט משוער במקום זה שבקוד.** אם הקוד עושה ``os.getenv("X", "60")`` אבל בהגדרה
נרשם ``default="30"`` — משתנה שמוגדר ל-60 ברנדר יוצג כ-``Modified``, למרות שהוא זהה
לברירת המחדל בפועל.

**2. המצאת דיפולט למשתנה שאין לו דיפולט בקוד.** אם בקוד יש ``os.getenv("TOKEN")`` בלי
ערך שני, אין ברירת מחדל — וההגדרה צריכה להשאיר ``default`` ריק. אז הסטטוס יהיה ``Set``
(נכון), ולא ``Modified`` (מטעה).

**הבדיקה לפני הוספה** — לאתר את ברירת המחדל האמיתית ולהעתיק אותה כמות שהיא:

.. code-block:: bash

rg -n -w 'MY_VAR' -t py -g '!tests/**'

``-w`` מחפש את שם המשתנה כמילה שלמה, ולכן תופס גם ``os.getenv("MY_VAR")``, גם
``os.getenv('MY_VAR')`` וגם ``config.MY_VAR``, בלי להיתפס ל-``MY_VAR_OTHER``.

.. _config-inspector-services:

לאיזה שירות שייך המשתנה? — לבדוק, לא לנחש
--------------------------------------------

השדה ``services`` בהגדרה קובע באיזה עמוד המשתנה יופיע. שיוך שגוי מייצר רעש: משתנה
של הוובאפ בלבד שמסומן כשייך לכולם מופיע בעמוד 2 כאילו צריך להגדיר אותו בארבעה מקומות.

.. important::
**אל תסיקו את השיוך משם המשתנה.** שם שנשמע גלובלי (``PUSH_*``, ``UPTIME_*``,
``MAINTENANCE_*``) לא אומר שהמשתנה נצרך בכל השירותים. בסבב ניקוי אחד הוסרו 68 שיוכים
שגויים שנקבעו לפי תחושה.

**הנוהל (שלושה צעדים):**

1. **למצוא איפה המשתנה נצרך בפועל** — חיפוש אחד תופס גם ``os.getenv`` (בכל סוג גרשיים)
וגם גישה דרך אובייקט הקונפיג (``config.MY_VAR``):

.. code-block:: bash

rg -n -w 'MY_VAR' -t py -g '!tests/**'

2. **לזהות לאיזה שירות שייך הקובץ שנמצא** — לפי נקודות הכניסה:

.. list-table::
:header-rows: 1
:widths: 40 25 35

* - קובץ / תיקייה
- שירות
- נקודת כניסה
* - ``main.py``, ``handlers/``, ``*_handler.py``
- ``bot``
- ``main.py``
* - ``webapp/``
- ``webapp``
- ``webapp/app.py``
* - ``mcp_server/``
- ``mcp``
- ``mcp_server/app.py``
* - ``services/webserver.py``
- ``webserver``
- ``services/webserver.py``
* - ``scripts/``
- ``scripts``
- סקריפטים ידניים/CI

3. **קובץ משותף — לפי שרשרת ה-imports.** קובץ כמו ``database/``, ``services/`` או
``utils.py`` אינו שייך לשירות מסוים בפני עצמו: הוא שייך לשירות רק אם הוא **נטען**
בשרשרת ה-imports של אותה נקודת כניסה. משתנה שנצרך רק ב-``webapp/app.py`` **אינו**
שייך ל-bot/mcp/webserver, נקודה.

.. tip::
``PORT`` הוא חריג מוצדק: הוא לא בהכרח מופיע בקוד של השירות, אבל כל שירות web צריך
אותו בפקודת ההרצה. חריגים כאלה — לתעד בהערה ליד ההגדרה.

.. _config-inspector-multi-service:

משתנה שמשרת כמה שירותים — לתעד בכל המקומות
--------------------------------------------

משתנה יכול להיות מוגדר בכמה שירותי Render במקביל (למשל ``MONGODB_URL``). במקרה כזה
מתעדים אותו **בכל המקומות הרלוונטיים, כל אחד במקום שלו** — ולא בוחרים "בית" אחד:

1. **``services`` בהגדרה** — כל השירותים, לא רק העיקרי:

.. code-block:: python

"MONGODB_URL": ConfigDefinition(
key="MONGODB_URL",
services=("webapp", "bot", "mcp", "webserver"),
...
)

2. **``docs/environment-variables.rst``** — עמודת **"רכיב"** בטבלה המרכזית חייבת לשקף
את **אותה** רשימת שירותים. השורה הזו היא הרפרנס לאנשי DevOps.

3. **תיאור תואם בשני המקומות** — ה-``description`` שב-``ConfigDefinition`` (מה שמוצג
בטבלת ה-Config Inspector) וההסבר שב-``environment-variables.rst`` צריכים לומר את אותו
דבר. שני התיאורים נקראים זה לצד זה כשמדבגים תקלת קונפיגורציה, ותיאורים סותרים גרועים
מהיעדר תיאור.

.. _config-inspector-sensitive:

מיסוך ערכים רגישים
-------------------

ערך ממוסך (``********``) בשני מקרים:

- **לפי שם המשתנה** — ``SENSITIVE_PATTERNS`` (``TOKEN``, ``KEY``, ``PASSWORD``, ``SECRET``,
``URI``, ``CREDENTIALS``, ``AUTH``, ``PRIVATE``, ``CERT``, ``DSN``, ``CONNECTION_STRING``).
- **לפי סימון מפורש** — ``sensitive=True`` בהגדרה.

.. note::
``URL`` הוסר מהרשימה **בכוונה**: כתובת ציבורית (``WEBAPP_URL``, ``MCP_SERVER_URL``)
אינה סוד, ומיסוכה הפך את הדף לחסר תועלת. כתובת שמכילה credentials — למשל
``MONGODB_URL`` בפורמט ``scheme://user:pass@host`` — מסומנת ``sensitive=True``
מפורשות, ובנוסף קיים זיהוי אוטומטי של תבנית ה-credentials בתוך URL.

המסקנה המעשית: **משתנה חדש שהוא סוד ושמו אינו מכיל אחת מהמילים ברשימה — סמנו
``sensitive=True`` ידנית.**

צ'קליסט: הוספת משתנה סביבה חדש
--------------------------------

1. **לאתר את הצריכה בפועל** — ``grep`` על שם המשתנה (:ref:`config-inspector-services`).
2. **להעתיק את ברירת המחדל מהקוד תו-בתו** — ואם אין דיפולט, להשאיר ריק כדי לקבל ``Set``
ולא ``Modified`` (:ref:`config-inspector-status`).
3. **לקבוע ``services``** לפי הצריכה שנמצאה — כל השירותים שצורכים, ורק הם.
4. **``sensitive=True``** אם זה סוד ששמו לא נתפס אוטומטית (:ref:`config-inspector-sensitive`).
5. **לעדכן את ``docs/environment-variables.rst``** — שורה בטבלה המרכזית עם עמודת "רכיב"
תואמת ותיאור זהה. זו **חובה** לפי ההנחיה שבראש אותו עמוד.
6. **לוודא בדף** שהמשתנה מופיע בעמוד הנכון ושהסטטוס הגיוני (משתנה שלא נגעתם בו ברנדר
אמור להיות ``Default``, לא ``Modified``).

טסטים: ``tests/test_config_inspector_service.py``.

ראו גם
-------

- :doc:`../environment-variables` — הרפרנס המלא של משתני הסביבה
- :doc:`cache-inspector` — כלי אדמין מקביל ל-Redis
Loading
Loading