Full-stack SSOT Orchestrator — CLI שמאמת את העקביות של 5 מקורות SSOT בבת אחת ומייצר קוד.
הסדקים של Vibe Coding
עם התפשטות Vibe Coding, דפוסים מתחילים להתגלות.
אומרים לבינה מלאכותית “בנה פונקציית הזמנה” והיא בונה. “הוסף ביטול” והיא מוסיפה. כשמוסיפים את הפיצ’ר החמישי, השני נשבר. שינו את סכמת API אבל לא תיקנו את הצד הקדמי. הוסיפו עמודה ל-DB אבל שכבת השירות לא יודעת על כך.
הסיבה פשוטה: הבינה המלאכותית לא יכולה לזכור את כל הקוד.
אז מה אנשים עושים: כשמגלים את השבר, אומרים לבינה המלאכותית “תתקן גם את זה”. מתקנים, ומשהו אחר נשבר. “תתקן גם את זה.” הלולאה חוזרת על עצמה. ככל שהפרויקט גדל, הלולאה מתארכת — עד שבשלב מסוים “להתחיל מחדש יהיה יותר מהר” הופך למסקנה הגיונית.
למה קוד גדל?
בקוד מעורבבים שני דברים.
החלטות: מה להציג, איזה API לקרוא, באיזה סדר לעבד, מה לאחסן. חיווט: הקוד שמממש את ההחלטות האלה בפריימוורק מסוים.
נניח שבונים מערכת הזמנות.
החלטה: "ביצירת הזמנה — שאילתת חדר, אם לא קיים 404, אם קיים יצירה"
שורת החלטה אחת זו מתפזרת על פני React hooks, Go handlers, שאילתות SQL, סכמות API ומשאבי Terraform. כל אחד עטוף בתחביר הפריימוורק שלו, עם טיפול בשגיאות והמרות טיפוסים.
מתוך 100,000 שורות קוד, 12,500 הן החלטות. 87,500 השורות הנותרות הן חיווט.
לסוכני בינה מלאכותית יש חלון הקשר סופי. כשמוסיפים את הפיצ’ר העשירי, הם לא זוכרים את תשעת הקודמים. לא ניתן לקרוא 100,000 שורות בבת אחת.
אם מפרידים רק את ההחלטות — 12,500 שורות. 55% מהקשר של 200K טוקנים. גודל שהבינה המלאכותית יכולה לקרוא בבת אחת.
5 מקורות SSOT
Fullend מתאים DSL אחת לכל אחת מ-5 השכבות המרכיבות תוכנה. כל DSL הופכת למקור אמת יחיד (SSOT) של השכבה שלה.
| שכבה | DSL | הצהרה |
|---|---|---|
| מסך | STML (HTML5 + data-*) | מה מוצג ומה קורה |
| חוזה API | OpenAPI 3.x | אילו בקשות מתקבלות ואילו תשובות נשלחות |
| זרימת שירות | SSaC (Go comment DSL) | באיזה סדר מעבדים |
| מבנה נתונים | SQL DDL + sqlc | מה מאוחסן |
| תשתית | Terraform HCL | היכן מריצים |
OpenAPI, SQL DDL ו-Terraform הם תקנים תעשייתיים. למסך ולזרימת שירות לא היו DSL מסוג SSOT מתאימות. החלטות צד קדמי שקעו ב-React hooks, זרימות שירות התפזרו ב-Go handlers. לכן תכננו את STML ואת SSaC. אלה ה-DSL שנוצרו בפרויקט הזה.
specs/
├── frontend/*.html → STML
├── api/openapi.yaml → OpenAPI 3.x
├── service/*.go → SSaC
├── db/*.sql → SQL DDL + sqlc queries
└── terraform/*.tf → HCL
specs/ היא האמת. artifacts/ ניתנת לשחזור בכל עת.
אימות בודד כבר קיים
כלי אימות ל-3 שכבות כבר קיימים.
- sqlc בודק את העקביות של DDL ושאילתות.
- מאמתי OpenAPI בודקים את תקפות הסכמה.
- Terraform בודק תחביר ותלויות של HCL.
גם ל-STML וגם ל-SSaC בנינו מאמתים מובנים. SSaC בודק עקביות פנימית של זרימות שירות, STML בודק התאמה בין הצהרות UI ל-OpenAPI.
כל אחת מ-5 השכבות יכולה לאמת את עצמה. הבעיה מתרחשת ביניהן.
הצד הקדמי מציג שדה עם data-bind="memo", אבל בסכמת תשובת API אין memo. SSaC קורא ל-@model Reservation.SoftDelete, אבל בשאילתות sqlc אין מתודת SoftDelete. OpenAPI מצהיר על x-sort: [created_at], אבל בטבלת DDL אין אינדקס לעמודה המתאימה.
כלים בודדים רואים רק את השכבה שלהם. הסדקים בין השכבות נשארים בלתי נראים.
הסתרת המבנה
“עדיין צריך ללמוד 5 DSLs?”
נכון. אבל אין צורך לחשוף את המבנה למשתמש.
אם מכניסים מראש את ערימת הטכנולוגיה וכללי SSOT לתוך System Prompt של הסוכן, המשתמש צריך רק לומר “בנה פונקציית הזמנה”. הסוכן מוסיף בעצמו נקודות קצה ב-OpenAPI, יוצר טבלאות ב-DDL, מצהיר זרימות שירות ב-SSaC, מצייר מסכים ב-STML ומריץ fullend validate כדי לבדוק עקביות.
המשתמש רואה רק את התוצאה. מבנה הוא משהו שהסוכן צורך — לא משהו שהמשתמש צריך ללמוד.
חוויית Vibe Coding נשארת כמו שהיא. מה שמשתנה: מאחורי הקלעים שום דבר לא נשבר.
התפקיד של Fullend
Fullend הוא מאמת צולב. הוא לא ממציא מחדש כלים בודדים. הוא קורא לכל כלי ובודק את הגבולות בין השכבות.
fullend validate specs/
✓ DDL 3 tables, 18 columns
✓ OpenAPI 7 endpoints
✓ SSaC 7 service functions
✓ STML 4 pages, 6 bindings
✓ Cross 0 mismatches
All SSOT sources are consistent.
אם משהו נכשל:
✓ DDL 3 tables, 18 columns
✓ OpenAPI 7 endpoints
✗ SSaC CancelReservation
@model Reservation.SoftDelete — method not found in sqlc queries
✗ Cross 1 mismatch
FAILED: Fix errors before codegen.
כשהאימות עובר, נוצר קוד.
fullend gen specs/ artifacts/
sqlc מייצר מודלי DB, oapi-codegen מייצר טיפוסי API, SSaC מייצר פונקציות שירות, STML מייצר רכיבי React, ו-Fullend מייצר את קוד הדבק שמחבר ביניהם.
כללי אימות צולב
הערך הייחודי של Fullend נמצא באימות הצולב.
OpenAPI ↔ DDL
| יעד אימות | כלל |
|---|---|
| x-sort.allowed | האם העמודה המתאימה קיימת בטבלה |
| x-filter.allowed | האם העמודה המתאימה קיימת בטבלה |
| x-include.allowed | האם מדובר בטבלה מחוברת בקשר FK |
SSaC ↔ DDL
| יעד אימות | כלל |
|---|---|
| @model Model.Method | האם המתודה קיימת בשאילתות sqlc |
| @result Type | האם היא תואמת לטיפוס שנגזר מטבלת DDL |
| @param שם | האם ניתן להמיר לעמודת DDL |
SSaC ↔ OpenAPI
| יעד אימות | כלל |
|---|---|
| שם פונקציה | האם הוא תואם ל-operationId |
| @param request | האם השדה קיים בסכמת הבקשה |
| @result + response | האם השדה קיים בסכמת התשובה |
STML ↔ SSaC — שניהם מפנים לאותו operationId ב-OpenAPI. כשהאימות משני הצדדים עובר, ההתאמה בין ה-API שהצד הקדמי קורא לו לבין ה-API שהצד האחורי מעבד מובטחת אוטומטית.
תכנון לסוכנים
Fullend תוכנן עבור סוכני בינה מלאכותית.
כדי שסוכן יכתוב specs, הוא צריך להכיר את 10 סוגי הרצפים של SSaC, את 12 תכונות data-* של STML, את הרחבות x- של OpenAPI ואת כללי התאמת שמות. לשם כך מסופק מדריך של כ-350 שורות לבינה מלאכותית. צריך להכניס אותו פעם אחת ל-System Prompt של הסוכן.
לולאת האימות אחרי כתיבת ה-specs פשוטה.
זרימת עבודה של סוכן:
1. עריכת specs/
2. fullend validate specs/
3. אם יש שגיאות → תיקון ה-SSOT הרלוונטי → חזרה ל-2
4. 0 שגיאות → fullend gen specs/ artifacts/
אין צורך להבין את כל המערכת. אם מתקנים רק את המקומות ש-validate מצביע עליהם, העקביות משוחזרת. מודלים חכמים מצליחים בניסיון הראשון, מודלים קטנים בשלושה ניסיונות. התוצאה זהה.
גודל SSOT לפי היקף
| היקף | דוגמה | SSOT | קוד מימוש | ניצול הקשר |
|---|---|---|---|---|
| קטן | הזמנת מספרה | ~1,500 שורות | ~10,000 שורות | ~8% |
| בינוני | ברמת Jira, Notion | ~12,500 שורות | ~100,000 שורות | ~55% |
| גדול | ברמת Shopify | ~30,000 שורות | ~300,000 שורות | ~90% |
על בסיס הקשר של 200K טוקנים. עד לגודל SaaS בינוני, סוכן יכול לקרוא את כל התכנון בבת אחת.
דפוסים מתוך חריגים
מה שלא ניתן לכסות עם 10 סוגי רצפים עובר ל-call. מה שלא ניתן לכסות עם תכונות data-* עובר ל-custom.ts. אם Escape Hatch זה עולה על 20% מהכלל, המשמעות של המבניות נשחקת.
אולם חריגים הופכים לנצפים ברגע שהם מבודדים. כשפרויקטים רבים ימבנו עם Fullend, דפוסים חוזרים יתגלו ב-call ו-custom.ts.
גם 10 סוגי הרצפים של SSaC לא תוכננו מראש. הם התכנסו ל-10 לאחר תצפית על מאות דוגמאות של קוד שירות. אותו עיקרון יחזור על עצמו ב-Escape Hatches. דפוסי call שמופיעים לעיתים קרובות יהפכו לסוגי רצפים חדשים, ודפוסי custom.ts שמופיעים לעיתים קרובות יהפכו לתכונות data-* חדשות.
החריגים לא נעלמים — מתוך החריגים צומח מבנה.
הרחבת ערימת הטכנולוגיה
כרגע Fullend קבוע על Go + React + PostgreSQL + Terraform. זה מכוון. בשלב PoC, העדיפות היא לחדור ערימה אחת מקצה לקצה.
עם זאת, 3 מתוך 5 מקורות SSOT (OpenAPI, SQL DDL, Terraform) כבר בלתי תלויים בשפה. 10 סוגי הרצפים של SSaC הם דפוסים שאינם תלויים בשפה — הם רק מבוטאים כהערות Go. STML מבוסס על תכונות HTML5 data-* ואינו תלוי בפריימוורק.
הרחבה היא שאלה של הוספת backends לייצור קוד. לוגיקת האימות וכללי האימות הצולב נשארים כפי שהם.
הקשר ל-GEUL
5 DSLs מרכיבות את SSOT של תוכנה. SSOT הוא נתונים מובנים. נתונים מובנים הם גרף. גרף ניתן לקידוד ב-GEUL.
data-fetch="ListReservations" של STML הוא יחס בין ישויות. @sequence get → @model → @guard → @response של SSaC הוא רצף אירועים. הגדרות נקודות הקצה של OpenAPI הן חוזים. כולם מבנים סמנטיים שניתן לבטא כקשתות Triple, קשתות Event6 וצמתי Entity של GEUL.
הדרך שבה Fullend מבצע אימות צולב בין 5 DSLs — התאמה סמלית, בדיקת עקביות טיפוסים, שלמות ייחוס — פועלת לפי אותו עיקרון כמו אימות מכני בזרמי GEUL.
רישיון
MIT — GitHub