דמו / פורטפוליו בעברית וב־RTL: בונה תוכנית אימון שבועית וממיר טקסט חופשי לכרטיסייה שאפשר להריץ במצב אימון. זה לא מוצר SaaS חי, אין מנויים ואין שרת בענן בדמו הציבורי.
למי נבנה: מאמנים אישיים עצמאיים בישראל שרוצים תוכנית מותאמת (מטרה, רמה, ציוד, ימים) בלי אקסל. זה גם כלי תרגול למתאמן בודד.
דמו חי על GitHub Pages · בנה אימון · ספריית הסרטונים · ספריית תרגילים · יומן ביצוע · הצעה למאמנים · דף אחד להדפסה · ניהול מאגר · טקסט לכרטיסייה · מצב אימון
הדמו סטטי. פענוח AI ב־backend/main.py רץ רק אם מרימים localhost:8001 עם מפתח; ב־Pages הוא לא פעיל.
- מנוע אימון מפרומט (
index.html+js/prompt-parser.js+js/session-builder.js): מטרה קצרה בעברית לצד שדות מפורשים לזמן, ציוד וכמות חניכים. פרסר מבוסס-כללים בדפדפן (בלי רשת ובלי מפתח) מחלץ גם נתונים שנכתבו בטקסט, בונה אימון מהמאגר ומחלק קבוצה לתחנות. אם אין מספיק סרטונים — נאמר במפורש ומוצע הקרוב ביותר. בלי הבטחות תוצאה. - קליטת אימון קיים (
js/ingest.js): מדביקים טקסט («3 סבבים: 40 שניות פלאנק…») — מפורק לתרגילים ומותאם לסרטון במאגר, כולל שגיאות כתיב («סמיכה»=«שמיכה»). תרגיל בלי סרטון נשאר טקסט ונכנס לרשימת «סרטונים שכדאי לצלם». פירוק סרטון ארוך הוא סימון ידני של התחלה/סוף — אין זיהוי ראייה אוטומטי. - מנתח אימון (
js/analyzer.js): תרגיל בודד (שרירים, דפוס תנועה, סוג עומס, קושי) ואימון שלם (פילוח נפח, איזון דחיפה-משיכה, זמן/עצימות, גירוי, דגלי איכות). - ליבה משותפת (
js/core.js+js/catalog.json+videos/drive-catalog.json): סכימתphases,esc, אחסון,wa.me, מנוע התוכנית, וקטלוג מאוחד עם שדהsource(מקומי / דרייב / יוטיוב / קישור). כשהקטלוג טעון המנוע מעדיף קליפים אמיתיים על מאגר גנרי. חיפוש, תגיות (ילדים / זוגות / ספורט), חלופות, ולינק לקליפ בודד (#CLIP.) — בלי שם קובץ בכתובת. בדיקות:node --test(בלי תלויות) על המנוע, הקטלוג, הפרסר, המנתח, הספרייה, קוד הסיום ל־wa.me, וסכימתphases. - ספריית סרטונים (
library.html): 70 רשומות הותאמו ל־68 קובצי OneDrive אמיתיים ונארזו כווידאו H.264 ציבורי דרך GitHub Releases. שבע רשומות שהיו בלי קובץ מנגנות מהטמעת יוטיוב (youtubeId, בלי הורדה). רשומה אחת (אתגר שתייה) נשארת בלי סרטון ולא נבחרת לאימון. סרטוני יוטיוב נוספים לקבוצות דלות יושבים ב־videos/youtube-catalog.jsonומצטרפים לספרייה ולבונה. בלי רשת או במקרה שגיאה מוצגים פרטי התרגיל במקום נגן שבור. שמות קבצים לא מוצגים. - ניהול מאגר (
manage.html): הדבקת קישור דרייב / מזהה / יוטיוב → הצעת שריר/ציוד/רמה → שמירה ב־localStorage וייצוא JSON. קישור חיצוני נשמר כקישור שנפתח בחוץ — לא חיבור למאמנים ולא חיפוש ביוטיוב. - בונה שבועי (
weekly.html): מטרה משנה סטים/חזרות/מנוחה (כוח 4×4–6 / 120 שנ׳, היפרטרופיה 3×8–12 / 60 שנ׳, סיבולת 3×12–15 / 45 שנ׳). ציוד כולל גומיות/קונוסים/כדור (מה שיש בספרייה), וקהל ילדים/ספורט. תרגיל עם קליפ מסומן; אפשר להחליף לחלופה מאותה ספרייה. התחל אימון פותח את מצב האימון עם אותה סכימתphases. אימונים שנשמרו מספריית התרגילים מופיעים בראש הדף; «הצג בתוכנית השבועית» (או כתובת#reel-plan) מציב כל אימון שמור כיום בתוכנית, עם אותם כפתורי התחלה, תצוגת מתאמן, שיתוף והדפסה. - ספריית תרגילים מרילים (
exercises.html+data/exercises.json+js/reel-library.js): איחוד רשימת הרילים והמיפוי — 79 רשומות. חיפוש וסינון לפי קבוצת שריר בעברית, כרטיס עם קישור לריל, ובניית אימון (סטים וחזרות לכל תרגיל) שנשמר ב־localStorage ומוצג בבונה השבועי. הפירוט מגיע ממיפוי צפייה אוטומטי ו־verifiedהואfalseעד בדיקה מול הסרטון. «לא מצוין» מוצג כ«לא ממוין». שני רילים שאין להם מיפוי נשארים «לא ממוין». סרטוני Google Drive מ־data/drive_videos.jsonמצטרפים לאותה ספרייה ולאותו בונה. איך מוסיפים רשומה: למטה. - טקסט לכרטיסייה (
frontend/): טקסט חופשי → כרטיסייה. אם השרת המקומי נכשל, רץ פענוח כללים בדפדפן (בלי AI). אין Marketplace ואין חשבון. - מצב אימון: טיימר אחד לכל שלב, דילוג על סט בודד, חזרה שמורידה מונים. נגן: קובץ מקומי כ־
<video>, דרייב/יוטיוב כ־iframe, ובלי רשת — טקסט התרגיל. החלף מציע חלופה מאותה קבוצת שרירים. לינק#CLIP.פותח תרגיל בודד מהספרייה. - פתח כמתאמן: אותו לינק־hash בלי קוד גישה — כדי שאפשר לנסות את הזרימה בדמו. שתף אימון ללקוח עדיין דורש מסלול מאמן.
- לינק מתאמן: התוכנית ב־hash של הכתובת, בלי התחברות. בסיום — סיכום ל־
wa.meוקודTH1לייבוא. - יומן ביצוע (
journal.html): ייבוא הקוד מהוואטסאפ, רשת 28 יום, בלי לקוחות מזויפים. הצע שבוע הבא משנה סטים לפי קושי/דילוגים. תזכורת בוואטסאפ למי שבלי ביצוע מיובא. זה כלי מקומי, לא CRM שנמכר. - הצעה למאמנים (
offer.html): מסלול תוכן בלבד ב־₪59 למושב מאמן — שיתוף אימון ללקוח ודף ממותג. אין סליקה באתר; קוד גישה אחרי תשלום מחוץ לאתר. בלי קוד, כפתור «שתף אימון ללקוח» חסום. בקשת קוד: טופס Google «משוב על האפליקציות» של הבעלים, עם TrainerHub ממולא מראש (מאז 28.9) — הערך האחדCONTACTב־js/contact.js. אם מרוקנים אותו, הדף חוזר לטופס issue בעברית (ציבורי). - דף אחד להדפסה (
pitch.html) וייצוא אימון ל־PDF (workout-print.html, הדפסה מהדפדפן). גרסת תרגול נושאת סימן מים; מיתוג המאמן רק אחרי קוד. - תיק בטיחות (
booklet.html+js/booklet.js+content/booklet/team-safety-file.json): תבנית ריקה של תיק קבוצה לאימון בשטח — מבדק שטח, טבלת סיכונים, תגובה לאירועים ורשימת חניכים להדפסה. בלי שמות או פרטים אישיים. - סריקת שטח (
js/site-profile.js+js/site-plan.js+js/site-scan.js+worker/site-scan/): פרופיל שטח (רוחב, משטח, מדרגות/ספסל/קיר/שיפוע, סכנות, צל) שממנו נבנה אימון מהחוברת — שיטה לשטח מוגבל כשצר, תרגילי מדרגות/ספסל/קיר כשזוהו, משחקי תופסת רק כששטח רחב, חלוקה לגלים/תחנות לפי גודל הקבוצה ושורת אזהרה לכל סכנה, עם שורת הסבר בעברית לכל בחירה. הזיהוי מהתמונות הוא רשות: בלי AI הכול עובד מהצ'קליסט הידני «מה יש בשטח?», וכל כשל (אין פרוקסי, אין מפתח, תשובה שבורה) מחזיר את המאמן לאותו צ'קליסט עם שורה בעברית. ה־AI, כשהוא מחובר, רץ מאחוריworker/site-scan/(Cloudflare Worker, תוכנית חינם) אוbackend/main.pyבפיתוח מקומי — מפתח Gemini לא נמצא במאגר ולא בדפדפן, והתמונות לא נשמרות. הפריסה והמפתח הם צעד של הבעלים: worker/site-scan/README.md. המסך עצמו הואsite-scan.html(כפתור «📷 סרוק את השטח» בדף הבית ובחוברת). מחשבון סיכונים: אחרי הבנייה מוצג כרטיס לכל סיכון, עם ציון סבירות × חומרה (1–100) ורמה (נמוך, בינוני או גבוה). הציון לקוח מטבלת הסיכונים שבתיק הקבוצה (content/booklet/team-safety-file.json), ומפגע שסומן בשטח מעלה את הסבירות ב-2. בכרטיס מופיעים גם אמצעי ההקטנה מהחוברת וגם שורת האזהרה של השטח (THSitePlan.risks). צילומי מסך:docs/screenshots/field-scan-risks/. - מצב פילוט (
js/pilot.js):?pilot=acharai(או קוד גישה) מפעיל פילוט לעמותת אחריי — יכולות המאמן בלי תשלום ומיתוג «עמותת אחריי» בשיתוף ובהדפסה. משוב בסוף אימון (אימון, שטח, דירוג, מה עבד ומה לשפר) נשמר במכשיר ויוצא כ־JSON או כהודעת וואטסאפ שהמאמן שולח בעצמו — בלי טלפונים, מיילים ופרטי מתאמנים. הכול ב־localStorage, בלי שרת. מאמן שכבר יש לו מיתוג משלו שומר אותו. אין סליקה ואין וואטסאפ־שרת. קובצי הווידאו אינם נשמרים בהיסטוריית Git: גרסאות H.264 המותאמות לדפדפן מתפרסמות כנכסי release, והקטלוג שומר כתובות יציבות בלבד (ראו videos/README.md).backend/אופציונלי ולא רץ ב־Pages. אין GitHub Actions. מחקר המחיר: MONETIZATION.md. מסמכי האקתון/תמחור ישנים ב־docs/archive/.
המאגר הוא data/exercises.json. מוסיפים אובייקט אחד לסוף המערך exercises. אחר כך מריצים את הבדיקה.
קבוצות שריר מותרות, בדיוק כך: ליבה, חזה, גב, רגליים/ישבן, גוף מלא/HIIT, מוביליטי, אחר, לא ממוין. תווית מעורבת מהמיפוי (למשל «חזה ושכיבות סמיכה / גוף מלא») נכנסת ל־muscle_group הראשונה ול־secondary_group אם יש קבוצה קבועה נוספת. תיאור שאינו קבוצה (תזונה, ילדים, זריזות) נשמר ב־muscle_detail.
verified ברירת המחדל היא false. הפירוט הנוכחי הגיע ממיפוי צפייה אוטומטי ולא נבדק מול הסרטון. אחרי בדיקה מול הווידאו מותר להפוך רשומה ל־true, ובתנאי שיש לה שם ו־source_title.
איור לכרטיס: שדה poster הוא נתיב יחסי לקובץ שקיים ב־assets/posters/. אם הוא ריק, סרטון Drive מקבל https://drive.google.com/thumbnail?id=<fileId>&sz=w480 ויוטיוב מקבל https://i.ytimg.com/vi/<id>/hqdefault.jpg. בלי אף אחד מאלה הכרטיס מציג מציין מקום בצבע קבוצת השריר ולא מבקש assets/posters/<reel_id>.png או .jpg שאינם במאגר. poster_uncertain: true מסמן איור שההתאמה לריל לא ודאית — הכרטיס מציג «איור לא ודאי».
equipment_tags היא רשימת תגיות מהרשימה הסטנדרטית (משקל גוף, מזרן, ספסל, קיר…). קבוצת השראה היא טיפים שאינם תרגיל (תזונה, שינה, מוטיבציה, לימפה) והם לא נכנסים לבונה. סריקת סביבה (scan.html + js/scan-match.js) בוחרת תרגילים שכל הציוד שלהם זוהה, או משקל גוף, ובונה ימים קבועים. מודל ראייה אופציונלי: TH_VISION_ENDPOINT ב־POST /api/environment-scan. בלי מפתח הדפדפן מזהה עם COCO-SSD או לפי צ'יפים.
מחרוזת סטים/חזרות שמכילה לא מצוין נשמרת כ־sets_reps: "לא ממוין", עם sets: null ו־reps: "". בלי source_title הרשומה נשארת לא ממוינת: name_he הוא ריל לא ממוין, בלי סטים, ציוד או שלבים. כך נשארו שני הרילים שאינם במיפוי (DdHOFvtKk9z, DdI_86lNFfY). המיפוי הוסיף את DeO8oVyADue (פוסט) ואת DdS9ue-knAM.
| שדה | סוג | הערה |
|---|---|---|
id |
string | ig- ועוד ה־shortcode של הריל. ייחודי. |
name_he |
string | שם בעברית, או ריל לא ממוין. |
muscle_group |
string | אחת הקבוצות למעלה. |
secondary_group |
string | קבוצות קבועות נוספות, מופרדות ב־·, או ריק. |
muscle_detail |
string | תיאור חופשי מהתווית (תזונה, ילדים…), או ריק. |
sets |
number או null | מספר שלם חיובי, או null אם לא ידוע. |
reps |
string | חזרות כפי שנמסרו (20). ריק אם לא ידוע. |
sets_reps |
string | תווית תצוגה. לא ממוין כשהמקור הוא לא מצוין. |
equipment |
string | ציוד מהמיפוי. ריק אם אין מקור. |
steps_he |
string[] | שלבי ביצוע בעברית. תרגיל מאומת: 3–5 שלבים קצרים למתאמן מתחיל. |
safety_he |
string | אופציונלי. דגש בטיחות אחד; חובה כש-verified הוא true. |
difficulty |
number או null | אופציונלי. 1 קל, 2 בינוני, 3 מתקדם; חובה כש-verified הוא true. |
alternatives |
string[] | אופציונלי. עד 2 מזהים מהספרייה מאותה muscle_group. |
source_url |
string | https://www.instagram.com/reel/<shortcode>/ או /p/<shortcode>/. |
creator |
string | שם משתמש בלי @. |
poster |
string | נתיב יחסי אופציונלי לקובץ קיים. ריק לא מנחש assets/posters/<reel_id>.png. לא כתובת חיצונית (תמונת Drive או יוטיוב נבנית מהמזהה). |
poster_uncertain |
boolean | true רק כשהאיור הותאם לריל בלי ודאות. ברירת מחדל false. |
verified |
boolean | false עד בדיקה מול הסרטון. |
source_title |
string | השם המלא מהמיפוי, או ריק. |
source_muscle_group |
string | original_group מהמיפוי, או ריק. |
source_muscle_label |
string | תווית השריר הגולמית מהמיפוי, או ריק. |
source_sets_reps |
string | הסטים/חזרות כפי שנכתבו במיפוי, או ריק. |
source_notes |
string | הערת מקור, או ריק. |
דוגמה לרשומה מהמיפוי, עדיין לא מאומתת:
{
"id": "ig-DfDEp8PRL3f",
"name_he": "4 תרגילים על ספסל: ברך שמאל/ימין, פוש-אפ מוגבה, נגיעת כתף",
"muscle_group": "ליבה",
"secondary_group": "",
"muscle_detail": "",
"sets": 3,
"reps": "20",
"sets_reps": "3x20 → 5x20 REPS",
"equipment": "ספסל שטוח צהוב-שחור ROGUE, רצפת גומי",
"steps_he": ["ברך שמאל/ימין", "פוש-אפ מוגבה", "נגיעת כתף"],
"source_url": "https://www.instagram.com/reel/DfDEp8PRL3f/",
"creator": "coachgiress38",
"poster": "",
"verified": false,
"source_title": "Bench Core Blast - 4 תרגילים על ספסל: ברך שמאל/ימין, פוש-אפ מוגבה, נגיעת כתף",
"source_muscle_group": "בטן ו-Core",
"source_muscle_label": "בטן ו-Core / ליבה",
"source_sets_reps": "3x20 → 5x20 REPS",
"source_notes": "מיפוי Meta AI, לא אומת מול הסרטון"
}דוגמה לרשומה בלי מיפוי:
{
"id": "ig-DdHOFvtKk9z",
"name_he": "ריל לא ממוין",
"muscle_group": "לא ממוין",
"secondary_group": "",
"muscle_detail": "",
"sets": null,
"reps": "",
"sets_reps": "לא ממוין",
"equipment": "",
"steps_he": [],
"source_url": "https://www.instagram.com/reel/DdHOFvtKk9z/",
"creator": "mjoepersonaltrainer",
"poster": "",
"verified": false,
"source_title": "",
"source_muscle_group": "",
"source_muscle_label": "",
"source_sets_reps": "",
"source_notes": ""
}בדיקה אחרי ההוספה:
node scripts/validate-exercises.js
python scripts/validate_exercises.py
npm testשני הסקריפטים בודקים את אותה סכימה (js/reel-library.js ו־scripts/validate_exercises.py). קובץ שלא עומד בה יוצא בקוד 1 ומדפיס את השדות השבורים. אותו ריצה בודקת גם ש־data/drive_videos.json הוא מערך תקין.
הספרייה טוענת את data/drive_videos.json בנוסף ל־79 הרילים. הקובץ הוא מערך, וכיום יש בו 93 סרטונים. מערך ריק עדיין תקין. אין המצאה של סטים, חזרות, ציוד או שלבים: הכרטיס מציג את שם הקובץ ואת הקבוצה הממופה.
כל פריט:
| שדה | סוג | הערה |
|---|---|---|
fileId |
string | מזהה הקובץ ב־Drive. נכנס לכתובת https://drive.google.com/file/d/<fileId>/preview. |
name |
string | שם הסרטון כפי שהוא ב־Drive. זה השם בכרטיס. |
folder |
string | נתיב תיקייה, למשל כושר/חזה. המיפוי משתמש בשם האחרון (חזה). |
muscleGroup |
string | בקובץ המסונכרן זה שם תיקיית Drive, לא קבוצת האפליקציה. אפשר להשאיר ריק. |
[
{ "fileId": "1a2b3c4d5e6f7g8h", "name": "פלאנק.mp4", "folder": "כושר/חזה", "muscleGroup": "חזה" }
]תיקייה מוכרת ממופה לקבוצה שכבר קיימת בספרייה. לא קשור ו־לבדיקה לא נכנסים לכרטיסים ולא לבונה.
| תיקיית Drive | קבוצה בספרייה |
|---|---|
| בטן | ליבה |
| גב | גב |
| רגליים | רגליים/ישבן |
| חזה | חזה |
| כתפיים | אחר |
| ידיים | אחר |
| גוף מלא HIIT | גוף מלא/HIIT |
| קרדיו | גוף מלא/HIIT |
| חימום | מוביליטי |
| מתיחות וגמישות | מוביליטי |
| זמן תגובה וקואורדינציה | אחר |
| זמן תגובה וקאורדינצייה | אחר |
| לא קשור | דילוג |
| לבדיקה | דילוג |
כרטיס Drive מציג את השם, את קבוצת השריר, תמונה ממוזערת (loading="lazy") עם כפתור הפעלה (נגן ה־iframe לכתובת ה־preview נוצר רק בלחיצה, כמו בספריית הסרטונים ובתוצאת אימון), וקישור «פתיחה ב-Drive» (/view). אין סטים, חזרות או שלבים עד שהרשומה מועשרת. «הוסף לאימון» מכניס אותו לבונה כמו תרגיל ריל, והסטים והחזרות נרשמים שם.
פסק דין ל־CRM: PARK. ליתד תוכן (ספרייה + בונה + שיתוף, בלי CRM): נתיב כסף צר במחיר מוצע ₪59 — לא אומת בראיונות. פירוט ב־RESEARCH.md ו־MONETIZATION.md.
- השוק הישראלי כבר מלא. AutoFit, Coach, Boostapp, Tazman ו־BaseCRM מוכרים למאמנים עברית + וואטסאפ + ניהול לקוחות, במחיר ₪0–450.
- ה־ICP שנבחר כבר מטרה שלהם. מאמן/ת עצמאי/ת בישראל עם 15–40 מתאמנים משלמים שעדיין רץ על וואטסאפ + אקסל — לא רשת ולא סטודיו עם עשרה מדריכים.
- הצעד הבא הוא 10 ראיונות, לא קוד. שיחות קצרות מקבוצת מאמני הכושר של ישראל (כ־25.7K חברים): אם מחר מפסיקים את הוואטסאפ — לאיזה כלי עוברים, וכמה מוכנים לשלם? שאלות, כללי עצירה והמשך וטבלה למילוי: docs/WTP_INTERVIEW_LOG.md.
הועלה מהמחשב של אבירן — יולי 2026. תיקוני הדמו והמיצוב — אוגוסט 2026.
- פרטים ומדידות בכרטיס המתאמן הקיים: כינוי, מטרה, רמה, ימי אימון ומדידות (משקל, היקף מותן, הערה). הנתונים נשמרים באותה רשומת
trainerhub_clients(שדותnickname/goal/level/days/measurements) — בלי מפתח או DB חדש. ראוTH.setClientDetails,TH.addMeasurementב־js/core.js. - גיבוי ושחזור מוצפן: מוריד קובץ JSON מוצפן (PBKDF2‑SHA256 210k → AES‑GCM‑256, WebCrypto בדפדפן) של כל מפתחות
trainerhub_*(כלTH.KEYS+ pilot). שחזור כותב רק את המפתחות שבקובץ — שום דבר אחר לא נמחק. אין שרת ואין מפתחות בקוד; בלי הסיסמה אין שחזור. ראוTH.encryptBackup/decryptBackup/restoreBackup.
בדיקה ידנית:
- פתחו
journal.html, הוסיפו מתאמן עם מטרה ורמה. - בכרטיס → «פרטים ומדידות»: סמנו ימים, «שמור פרטים», הזינו משקל → «הוסף מדידה להיום». שורת הסיכום בכרטיס מתעדכנת.
- «גיבוי ושחזור מוצפן»: סיסמה (6+ תווים) → «הורד גיבוי מוצפן». פתחו את הקובץ — אין בו שמות קריאים.
- בחלון גלישה בסתר: בחרו את הקובץ, סיסמה שגויה → «סיסמה שגויה». סיסמה נכונה → אישור → המתאמן חוזר.
בדיקות: node --test test/backup-client-details.test.js; Playwright (דסקטופ + 360px): NODE_PATH=<playwright> TH_SCREENSHOTS=1 node --test test/backup-client-details-e2e.test.js (מדולג אם Playwright לא מותקן). צילומים: docs/screenshots/client-details-*.png, backup-*.png.
- חיפוש וסינון מעל רשימת המתאמנים: לפי שם, כינוי, טלפון או תוכנית; סינון לפי פעילים, בלי ביצוע שבוע+, מטרה או רמה.
- תובנות מתאמן (
#insights): מפת חום של 12 שבועות, גרף היענות שבועית (מול ימי האימון שהוגדרו, ברירת מחדל 3), נפח (חזרות × ק״ג לפי יום) וגרף התקדמות במשקל הגוף מהמדידות. כל הגרפים הם SVG נגיש ונבנים בלי ספריות. - שיאים אישיים: «תיעוד סט» שומר דרך
js/journal-storage.jsהקיים (מפתחtrainerhub_journal_entries, עכשיו עםclientId).js/session-tracker.jsהקיים מראה כמה תרגילים מהתוכנית המשויכת תועדו היום. שני המודולים כבר נמצאים ב־precache שלsw.js(#551).
בדיקה ידנית:
- ב־
journal.html, עם 2 מתאמנים או יותר: הקלידו חלק משם; בחרו «מטרה: …». שורת הסטטוס מראה «מוצגים X מתוך Y». - ב«תובנות מתאמן» בחרו מתאמן: מפת חום, היענות, והתקדמות (אחרי 2 מדידות משקל).
- תעדו סט (squat, 5, 60): מופיע «🏆 שיא אישי חדש», גרף הנפח מופיע, והשיא נכנס לרשימה. סט קל יותר לא משנה את השיא.
בדיקות: node --test test/journal-insights.test.js. Playwright (דסקטופ + 360px): TH_SCREENSHOTS=1 node --test test/journal-insights-e2e.test.js. צילומים: docs/screenshots/journal-filter-*.png, journal-insights-*.png.
הכול בתוך frontend/workout-mode.html ו-js/core.js. אין מסך חדש ואין אחסון חדש.
- תיעוד סט: בכל סט חזרות יש שדות «חזרות» ו«משקל ק״ג». המשקל ממולא מראש מהסט הקודם או מהיומן. בסיום האימון כל הסטים נשמרים כרשומה אחת ב-
trainerhub_journal_entries(דרךjs/journal-storage.js), יחד עםclientIdכשהאימון הגיע מקישור של מאמן. התרשימים והשיאים ב-journal.htmlמשתמשים ברשומה הזו. - סוף מנוחה: רטט
[200,100,200]וצפצוף כפול שנוצר ב-AudioContext (אין קובצי שמע). השמע "מתעורר" בלחיצה על «התחל». - הקראה בעברית: כשמתחילה מנוחה הדפדפן מקריא "מנוחה N שניות. הבא: …" עם speechSynthesis ב-he-IL. כפתור «קול» מכבה ומדליק את ההקראה. ההעדפה נשמרת ב-
trainerhub_workout_prefsונכללת בגיבוי המוצפן. - אופליין: אין שום קריאת רשת.
journal-storage.jsכבר נמצא ב-precache שלsw.js.
- בונים אימון ב-
index.htmlעם מנוחה קצרה ופותחים את מצב האימון. בטלפון: מצב טיסה. - לוחצים «התחל», מזינים חזרות ומשקל ולוחצים «סיימתי סט». אמורים לשמוע הקראה של התרגיל הבא.
- בסוף המנוחה הטלפון אמור לרטוט ולצפצף פעמיים, ובסט הבא המשקל כבר ממולא.
- לוחצים «קול» (🔇). במנוחה הבאה לא אמורה להיות הקראה. אחרי רענון ההעדפה נשארת.
- מסיימים את האימון. במסך הסיכום אמור להופיע «נשמרו N סטים ביומן», והסטים אמורים להופיע ב-
journal.htmlבתובנות.
בדיקות: test/workout-cues.test.js ו-test/workout-cues-e2e.test.js (Playwright, בדסקטופ וב-360px, אופליין). צילומי מסך: docs/screenshots/workout-sets-*.png.
- קוד הדיווח TH1 כולל עכשיו, כשדה אופציונלי
x, את הסטים והמשקלים של כל תרגיל, ואת דירוג הקושי (RPE 1–10) שהמתאמן בחר במסך הסיום של מצב האימון. קודים ישנים בליxממשיכים להיפתח כרגיל. - ייבוא ביומן (
journal.html): כשהקוד כולל פירוט, הסטים נשמרים ביומן האימונים (trainerhub_journal_entries), והקושי של כל תרגיל נשמר בלוג של המתאמן. - קוד QR לקישור השיתוף, ב-
index.htmlוב-journal.html(«שתף אימון ללקוח»). הקוד נוצר בדפדפן על ידי מקודד שנכתב בתוךjs/core.js(TH.qrMatrix/qrSvg/shareQrMarkup), בלי ספרייה ובלי שירות חיצוני. הקובץcore.jsכבר נמצא ברשימת ה-precache שלsw.js(#551), ולכן הכול עובד גם אופליין.
- פותחים את
frontend/workout-mode.htmlעם אימון פעיל, רושמים סטים ומסיימים. - במסך הסיום בוחרים קושי לתרגיל הראשון, ובודקים שהקוד בתיבה «קוד לייבוא ביומן המאמן» מתעדכן.
- מעתיקים את הקוד ומדביקים אותו ביומן תחת «ייבוא קוד מהוואטסאפ». ההודעה צריכה לכלול «כולל פירוט ל-N תרגילים».
- מדביקים קוד TH1 ישן, בלי פירוט, ומוודאים שהוא עדיין מתקבל.
- במנוי מאמן לוחצים «שתף אימון ללקוח». מתחת לכרטיס מופיע קוד QR, וסריקה שלו בטלפון פותחת את הקישור.
בדיקות: test/share-qr.test.js ו-test/share-qr-e2e.test.js (Playwright, דסקטופ ו-360px). צילומי מסך: docs/screenshots/share-qr-*.png ו-docs/screenshots/report-exrpe-*.png.
weekly.html: נוספה בחירה «תקופתיות (מחזור עומס)» של 4 עד 12 שבועות. בכל בלוק של 4 שבועות יש 3 שבועות העמסה הדרגתית (+5% בכל שבוע, +2.5% במטרת סיבולת, וסט נוסף בשבוע השלישי) ואחריהם שבוע פריקה (60% עומס ו-40% פחות סטים). לכל שבוע יש הסבר בעברית.- התאמה אוטומטית: מזינים בכל שבוע את הביצוע בפועל: קושי (1–5), מספר דילוגים וכאב. השבוע הבא מתעדכן מיד:
- כאב: מקדימים שבוע פריקה.
- שני דילוגים או יותר, או קושי 4 ומעלה: חוזרים על אותו עומס, והשבועות הבאים בבלוק זזים בהתאם.
- שבוע קל ונקי: +2.5% נוספים.
- איזון דחיפה/משיכה/רגליים: סופרים את הסטים בשלב המרכזי, ומוצגת אזהרה כשקבוצה אחת נמוכה מ-60% מהקבוצה המובילה.
js/core.js:suggestNextFromLog(compact, log, {plan, week})מקבל עכשיו גם כאב וגם קושי לכל תרגיל (log.exמקוד TH1), ומחזירdecisionsעם הסבר לכל החלטה. אפשר לקרוא לו גם בדיוק כמו קודם, עם שני הפרמטרים הישנים.- נוספו
periodizePlan,adjustNextWeek,applyPlanWeekו-pplBalance. - מבנה ה-phases לא השתנה: רק מספר הסטים וההערות בשלב המרכזי. אין מפתח חדש ב-localStorage.
- פותחים את
weekly.html, בוחרים «8 שבועות» ולוחצים «בנה אימון». מתחת לימי האימון מופיעה רשימה של 8 שבועות, עם שבועות פריקה בשבוע 4 ובשבוע 8, ושורת איזון ⚖️. - מסמנים «כאב» בשבוע 1. שבוע 2 הופך לשבוע פריקה, עם הסבר.
- מבטלים את הסימון ומזינים 2 דילוגים. שבוע 2 חוזר ל-100% עם ההסבר «אימונים דולגו».
- לוחצים «הצג שבוע» בשבוע 4. מספר הסטים בימי האימון יורד, ובהערה מופיע «שבוע 4: 60% עומס». הכפתורים «התחל אימון», «שתף» ו«הדפסה» משתמשים בשבוע המוצג.
בדיקות: test/periodization.test.js ו-test/periodization-e2e.test.js (דסקטופ ו-360px). צילומי מסך: docs/screenshots/period-plan-*.png ו-docs/screenshots/period-adjust-*.png.
הדוח החודשי בנוי בתוך הקוד הקיים: הכפתור «דוח חודשי» בכרטיס המתאמן ב־journal.html שומר את הדוח במפתח ההדפסה הקיים (trainerhub_print_workout) ופותח את workout-print.html. אותו דף מציג את הדוח באותו עיצוב הדפסה. אין מסך חדש ואין מפתח אחסון חדש.
התזכורות משתמשות ב־Notification API של הדפדפן בלבד, בלי שרת ובלי push. ההגדרה ותאריך התזכורת האחרונה נשמרים ב־trainerhub_workout_prefs.
בדיקה ידנית:
- ביומן, בחרו חודש בשדה «חודש לדוח החודשי».
- לחצו «דוח חודשי» בכרטיס של מתאמן. הדוח מציג אימונים מול המתוכנן, התמדה, דקות, קושי ממוצע, משקל בתחילת החודש ובסופו, שיאי החודש ויומן החודש. אפשר להדפיס או לשמור כ־PDF.
- לחצו «הפעל תזכורות» ואשרו התראות בדפדפן. מתאמן שהיום הוא יום אימון שלו ועדיין לא יובא לו ביצוע מקבל התראה. ההתראה נשלחת פעם אחת ביום לכל היותר.
- לחצו «כבה תזכורות» כדי לבטל.
בדיקות: test/reports.test.js ו־test/reports-e2e.test.js (מחשב שולחני ו־360px). צילומי מסך: docs/screenshots/report-month-*.png ו־docs/screenshots/reminders-*.png.