לדלג לתוכן

Provisa

חבּרו את מסדי הנתונים שלכם. שאלו בעזרת GraphQL, gRPC, SQL או MCP — על גבי כל API או פרוטוקול — תוך 5 דקות.

Provisa משרתת כל שטח API (REST, GraphQL, SQL, gRPC, MCP ועוד) על גבי התוצאה המאוחדת מכלל המקורות שלכם. היא מסוגלת לכך משום שהיא שכבה סמנטית פעילה (active semantic layer): הגדרה יחידה של אחוזת הנתונים שלכם — כל דומיין, כל קשר וכל מדיניות בכל המקורות, למעט מערכות המקור עצמן — אשר גם מפעילה את האחוזה וגם מממשלת אותה. ההגדרה אינה תיעוד שמנוע כלשהו עשוי להתייעץ בו — היא עצמה המנוע. הדומיינים והקשרים הרשומים הם נתיבי ה-JOIN החוקיים היחידים, ומדיניות הגישה מתקמפלת לתוך כל תוכנית שאילתה. מודל אחד, שלושה תפקידים:

  • הגדרה — דומיינים, עמודות וקשרים מוצהרים פעם אחת. ההצהרה הזו היא הסכמה שכל צרכן רואה, והיא קבוצת נתיבי ה-JOIN היחידה שכל שאילתה רשאית לנקוט.
  • אכיפה — אבטחה ברמת השורה, מיסוך עמודות, נראות עמודות ואישור שאילתות מוחלים inline על נתיב הביצוע. שום שאילתה אינה מגיעה לנתונים בלי לעבור דרכם, כך שהכיסוי מלא מבחינה מבנית ולא תלוי בשקדנות.
  • ביקורת (Audit) — מכיוון שכל בקשה עוברת באותו נתיב מסודר, מי שאל מה, תחת איזה תפקיד ומול איזו מדיניות נרשם באופן אחיד. Trace מבוזרים, מדדים ויומנים עצמם רשומים כטבלאות הניתנות לשאילתה לצד נתוני העסק שלכם.

ליבה אחת מסודרת משרתת כל שפה ופרוטוקול תעבורה. שאלו בעזרת GraphQL, Cypher או SQL; צרכו על גבי pgwire, Bolt, gRPC, REST, Arrow Flight או JDBC. כל שפת שאילתה מונמכת לייצוג ביניים יחיד שבו הממשל מוזרק פעם אחת — כך שמדיניות אינה יכולה לסטות בין שפות — וה-IR הזה מכוון מחדש לדיאלקט הילידי של כל מקור ביציאה. הוספת שפה היא חזית חדשה על גבי הליבה המשותפת, לא מנוע חדש.

האחוזה היא גם אנליטית וגם טרנזקציונלית. קריאות חוצות-מקורות מתפרסות דרך שכבת הפדרציה; כתיבות וקריאות ממקור בודד מנותבות ישירות לדרייבר המקור — מסודרות באותה מידה, אך טרנזקציוניות ומתחת ל-100 מילישניות. סטרימינג עמודתי של Arrow Flight מובנה.

כל המודל בנוי מחופן פרימיטיבים — דומיינים, קשרים, תפקידים ומדיניות. אוצר מילים קטן, כך שההגדרה קלה להבנה ופשוטה להערכה ולביקורת: אפשר לקרוא את קבוצת המדיניות ולדעת מה היא עושה. Provisa היא מהדר שאילתות קליל, לא runtime שיושב בנתיב הנתונים. היא ממירה בקשה לשאילתות ילידיות, מנתבת אותן, ויוצאת מהדרך — ולכן האחוזה מבצעת היטב.

עיצוב זה תומך בשתי דרכי שימוש, שאינן סותרות זו את זו:

  • כפיגום למודרניזציה — מדלו את האחוזה שלכם, תנו ל-Provisa לחולל את ה-SQL הילידי לכל מקור, ואז לכדו את ה-SQL הזה ואמצו אותו ישירות במערכת היעד. Provisa היא שכבת המעבר, לא תלות קבועה.
  • כתשתית קבועה לאכיפת מדיניות — השאירו אותה במקומה כנתיב המסודר שכל שאילתה נוקטת, כך שהגדרה, אכיפה וביקורת נשארות מאוחדות כל עוד האחוזה קיימת.

מודל הפדרציה

כל המודל מצטמצם לשני חוזים ושתי מדיניות: מקורות מצטמצמים לטבלאות דו-ממדיות על גבי מערכת טיפוסים אחת, שאילתות מצטמצמות ל-IR דמוי-SQL אחד, נגישות (reachability) קובעת מה נשאל בזמן אמת לעומת מה ממוריאליזציה (materialized), ואסטרטגיית רעננות מממשלת כל עותק ממוריאליזציה וכל ערכת נתונים נגזרת. צורת נתונים בכניסה, צורת שאילתה בכניסה, ממשל ב-JOIN, שאילתות ילידיות ביציאה. שאר החלק הזה סוקר כל רכיב.

המודל נשען על צמצום אחד: כל מקור מבוטא כאוסף של טבלאות דו-ממדיות על גבי מערכת טיפוסים כללית ויחידה. זהו החוזה שמקור חייב לעמוד בו כדי להצטרף לאחוזה, והוא אותו חוזה עבור כולם. מקורות מסוימים כבר מתאימים — טבלת MySQL או PostgreSQL היא יחס דו-ממדי מוקלד. מקורות מסוימים מתאימים בעזרת הטלה (projection): תוצאת שאילתת GraphQL, לאחר שטוח, היא טבלה. מקורות מסוימים זרים לצורה — מאגרי משולשים (triplestores) של SPARQL, Neo4j — אך נשארים ברי-עבודה, כי המשתמש מספק שאילתה שתוצאתה טבלאית; השאילתה היא המתאם (adapter). יהיה המקור אשר יהיה, האחוזה רואה שורות, עמודות וטיפוסים כלליים, ותו לא. קליטת מקור מסוג חדש היא עמידה בחוזה האחד הזה, לעיתים בשלב של התערבות אנושית, לא כתיבת אינטגרציה ייעודית.

לצמצום הזה יש תאום בצד השאילתות. SQL — על פני כל הדיאלקטים והמוזרויות שלו — הוא בעיקרו השפה לניתוח על גבי ערכות נתונים דו-ממדיות, מה שהופך צורה דמוית-SQL ליעד האוניברסלי הטבעי לשאילתות. לכן כל בקשה, בכל שפה שבה היא מגיעה, מונמכת לייצוג הביניים הזה כצעדה הראשון ממש. חלקן מונמכות בקלות — SQL עצמה, ואפילו GraphQL; חלקן קשות — הסמנטיקה של נתיבים וגרפים ב-Cypher דורשת עבודה של ממש — אך כולן ברות-ביצוע. ניתוב כל בקשה ל-IR אחד לפני שקורה כל דבר אחר הוא מה שמאפשר לממשל לחול במקום אחד בדיוק, על צורה אחת, בלי קשר לשפה שבה הוא הגיע.

מעל שתי הצורות האחידות הללו — מקורות טבלאיים וצורת שאילתה יחידה — פדרציה כאן משמעה גם שאילתה חיה וגם warehousing — אותו טווח שמנוע שאילתה חי כמו Trino מכסה, בתוספת המימוש (materialization) שמנועים כאלה נשענים עליו. המושג המאחד ביניהם הוא נגישות (reachability): עבור כל מקור, האם המנוע יכול לשאול אותו במקום, או שנתוניו חייבים תחילה להתממריאליז למקום שניתן לשאול בו? נגישות מחלקת את האחוזה למה שנשאל בזמן אמת ומה שמועתק תחילה.

רוב מסדי הנתונים כבר נושאים מושג כלשהו של קישור חי — ATTACH של DuckDB, postgres_fdw של PostgreSQL, קישורים חיצוניים של Databricks. כך שרוב מסדי הנתונים יכולים לפעול כמנוע פדרציה במידה מסוימת. אף אחד אינו מקיף: כל אחד מגיע לקבוצת מקורות מסוימת וממריאליז את השאר, בלי תיאור אחד של מה הוא מה. המודל סוגר את הפער הזה על ידי הפיכת הנגישות למפורשת — קבוצה מוגדרת של שיטות, לכל מקור, שמצהירות מה המנוע יכול להגיע אליו בזמן אמת, ובאלימינציה — מה חייב להתממריאליז.

מה שנותר הוא רעננות: עבור כל מקור שאינו נגיש, עד כמה עדכני חייב להיות עותקו הממוריאליז? בפועל זה מצטמצם לקבוצה קטנה של אסטרטגיות — על פי דרישה, על פי לוח זמנים, על פי אות שינוי (CDC, watermark, snapshot), או מוצמד (pinned). בחירת אחת לכל מקור היא מדיניות הרעננות כולה.

ערכות נתונים אנליטיות — טבלאות נגזרות, אגרגציות, פלטי טרנספורמציה — מתקפלות לאותה צורה. גם הן חייבות להתבטא ב-IR, ומכיוון שכך, שושלת (lineage) אינה מערכת נפרדת שיש לתחזק: הנתיב מכל מערכת מקור לפלט הסופי הוא ה-IR שהפיק אותו, קריא מקצה לקצה. בנייתן מעלה את שאלת הרעננות שלב אחד הלאה — האם ערכת הנתונים מתרעננת על פי לוח זמנים, רק כשתנאיה הקודמים מתמלאים, ברציפות כמעט-בזמן-אמת, או כתמונת מצב היסטורית מוצמדת? הדרכים לבטא כיצד ומתי לבנות ערכת נתונים הן אותה קבוצה קטנה וברת-מנייה, כך שערכת נתונים נגזרת נושאת מדיניות בנייה באותו אוצר מילים בדיוק שעותק מקור נושא.

מודלים ממדיים הם יישום ישיר. טבלאות עובדות (fact) וממדים (dimension) בסכמת כוכב הן ערכות נתונים אנליטיות ככל אחרות — ממד הוא הטלה מותאמת ומנוקה מכפילויות (conformed, deduplicated); טבלת עובדות היא JOIN ואגרגציה שמצומצמים לגרגר (grain) — כל אחת נושאת מדיניות בנייה ורעננות משלה. ממדים משתנים לאט (SCD) אינם דורשים מנגנון מיוחד: תמונת מצב מוצמדת היא היסטוריית Type 2, בנייה מחדש מתוזמנת היא Type 1. ומכיוון שהסכמה מוגדרת ב-IR ולא קשורה פיזית לטבלאות של warehouse אחד, אותן הגדרות עובדות וממדים מכוונות מחדש — ממומרות ב-Oracle, ב-Databricks, או נשארות וירטואליות מעל מנוע MPP — בלי מודלינג מחדש. המודל מחולל את סכמת הכוכב; הוא אינו נועל אותה למנוע אחד.

Data Vault מתאים באותה דרך, שכבה אחת קודם לכן. ה-hubs שלו הם ערכות נתונים של מפתחות עסקיים מנוקות כפילויות, ה-links שלו הם הקשרים הרשומים ביניהם, וה-satellites שלו הם ערכות נתונים של תכונות (attributes) עם חותמת זמן, insert-only — הרשומה ההיסטורית. satellite הוא פשוט ערכת נתונים נגזרת על אסטרטגיית הרעננות של אות-שינוי: תאריך טעינה בתוספת hashdiff הוא CDC המוחל על תכונות תיאוריות, והיסטוריה insert-only היא אסטרטגיית תמונת המצב המוצמדת. טבלאות point-in-time ו-bridge הן ערכות נתונים נגזרות נוספות, בנויות לביצועי שאילתה. אז raw vault הוא קבוצת ערכות נתונים אנליטיות ב-IR, וסכמת כוכב היא הטלה ממנו — שתיהן מחוללות, שתיהן ניידות בין מנועים. מה שהמודל אינו עושה הוא להחליט על המתודולוגיה: מה הופך ל-hub, הגרגר של satellite, אסטרטגיית הפיצול. אלה נשארות בחירות מודלינג; ברגע שנקבעו, הן חיות כ-IR נייד ולא כ-ETL מולחם ל-warehouse אחד.

שני הדפוסים מוצהרים דרך שני קיצורי דרך ממדרגה ראשונה במקום views כתובים ידנית — הפרימיטיבים שמהם בנויה כל סכמת כוכב וכל Data Vault, נשמרים ניטרליים מבחינת מתודולוגיה:

  • entity — הטלה מוקלדת, מנוקה כפילויות, ואופציונלית מהוסטרת (historized) של מקור. הצהירו מפתח ישות, את התכונות, ומצב היסטוריה; Provisa מנמיכה אותה ל-Materialized View, וכאשר מבוקשת היסטוריה — ל-MV דו-זמני (bitemporal) (scd2 ← דלתא, snapshot ← תמונת מצב). קונסטרוקט אחד משרת גם ממד (dimension) של קימבל (SCD1/SCD2 ) וגם hub + satellite של Data Vault.
  • fact — JOIN למפתחות ישויות, מצומצם לגרגר מוצהר, עם מדדים מצטברים. Provisa מנמיכה אותו ל-MV אגרגטיבי בתוספת קשרים רשומים לישויות. קונסטרוקט אחד משרת גם טבלת עובדות (fact table) של כוכב וגם link של Data Vault (עובדה חסרת מדדים היא link טהור של קבוצת מפתחות).

מכיוון שההנמכה טהורה — מפרט entity/fact הופך בדיוק להגדרות ה-MV, הדו-זמניות והקשרים שמודלן היה כותב ידנית בכל מקרה — ה-warehouse הוא IR עד הסוף, ומכוון מחדש בין מנועים בלי מודלינג מחדש. הצהירו warehouse בממשק הניהול (טופס Model לישויות ולעובדות) או דרך ה-API הניהולי (registerEntity / registerFact); המודל מחולל את כוכב קימבל או את ה-Data Vault, הוא לא כופה אחד מהם.

נסיעה בזמן (Time Travel)

נסיעה בזמן היא רעיון פשוט — לשמור כל גרסה של שורה במקום לדרוס אותה, כך שאפשר לשאול מה היו הנתונים ברגע כלשהו בעבר. ההבדל הוא עד כמה יעיל כל מנוע לעשות זאת, וזו בדיוק הסיבה ש-Provisa הופכת אותה לתכונה של ההגדרה של ה-Materialized View ולא של מנוע האחסון (REQ-1162). הצהירו זאת פעם אחת; זה עובד על כל backend שמממריאליז.

הכלל ששומר על ניידות הוא append-only: גרסה, ברגע שנכתבה, לעולם אינה מתעדכנת או נמחקת. פרישת שורה על ידי כתיבה חוזרת של תאריך "valid-to" — הטריק הדו-זמני הרגיל — דורשת UPDATE, שהרבה מנועים אינם יכולים לבצע בזול (או בכלל) מעל אחסון פדרטיבי, אז Provisa לא עושה זאת. במקום זאת כל רענון מוסיף (appends), ו"איזו גרסה הייתה בתוקף בזמן T" נגזרת בזמן קריאה מהיומן הבלתי-משתנה. יש בדיוק שתי דרכים להוסיף:

  • Snapshot — הוספת כל ערכת הנתונים הרעננה, מתויגת בזמן המערכת של רענון זה. אין diffing; נכון על כל מנוע; האחסון גדל בעותק מלא בכל רענון.
  • Delta — הוספה רק של מה שהשתנה, בתוספת tombstones עבור מפתחות שהוסרו. הדלתא מחושבת על ידי המנוע (anti-joins בתוך INSERT … SELECT), ולעולם לא מקופלת שורה-שורה ב-Provisa. קטן יותר, ודורש מפתח ישות.

זמן המערכת (מתי Provisa רשמה גרסה) מנוהל בדרך זו; זמן התוקף (מתי עובדה נכונה בעסק) מסופק מתוך ה-SELECT של ה-view עצמה ונשמר. מנועים שמציעים יותר — snapshots ילידיים של Iceberg, MERGE ששומר פחות שורות — יכולים להיות מכוונים ליעילות מאחורי אותה הצהרה; הנתיב ה-append-only הוא הרצפה שנכונה בכל מקום.

הקריאה שקופה. שאילתה רגילה מול MV דו-זמני משחזרת את המצב הנוכחי מיומן ההוספה כברירת מחדל; כדי לנסוע בזמן, שלחו כותרת X-Provisa-As-Of: <timestamp> וכל השאילתה נענית כפי שהאחוזה הייתה באותו רגע — סמנטיקה זהה על כל תשתית. הפעילו זאת עבור כל Materialized View בממשק הניהול (בקרת Time Travel: כבוי / snapshot / delta בתוספת מפתח ישות) או דרך ה-API הניהולי.

נגישות בתוספת רעננות הן מודל כללי לפדרציית נתונים: הגדרה שאומרת מה חי, מה ממוריאליז, ועד כמה רענן כל עותק נשאר — עצמאית מהטווח של מנוע כלשהו. התוצאה היא חופש מנעילת ספק קניינית. המודל נייד; האחוזה אינה שבויה בידי הספק שהפדרציה שלו נקרית להגיע כרגע ליותר מקורות.

תכונות

ממשקי שאילתה

אלה השפות וה-API-ים המובנים שבהם אתם כותבים שאילתות. לכל אחד תחביר וסמנטיקה משלו; הממשל (RLS, מיסוך, נראות עמודות, אכיפת קשרים) חל באחידות על כולם, בלי קשר לפרוטוקול התעבורה שמעביר אותם.

  • GraphQL — סכמות לפי תפקיד עם נראות ברמת שדה, סינון, pagination מבוסס cursor, ושאילתות אגרגטיביות (count, sum, avg, min, max). מוגבל-סכמה לקשרים רשומים — תקין מבנית מעצם הבנייה, הנתיב המהיר ביותר לשאילתה פשוטה ותקינה. Apollo APQ כלול: שאילתות מגובבות (hashed) ונרשמות בצד השרת; קריאות עוקבות שולחות רק את ה-hash דרך HTTP GET, מה שהופך תגובות לניתנות ל-caching ב-CDN בלי שינויי לקוח כלל. טבלאות בדיקה (lookup) מתחת לסף שורות ניתן-להגדרה נחשפות כטיפוסי enum.
  • SQL — SQL מלא על פני נתונים פדרטיביים; לא מוגבל ומבטא יותר מ-GraphQL. כתבו SQL סטנדרטי — כולל תת-שאילתות מתואמות (correlated subqueries) — והוא רץ בין מקורות ללא שינוי. שאילתות ממקור בודד עוקפות את שכבת הפדרציה לגמרי (מתחת ל-100 מילישניות).
  • Cypher — שפת שאילתת גרפים על גבי אותה סכמה פדרטיבית. חצו קשרים כקשתות גרף; אחדו מקורות; נתיבים באורך משתנה. הממשל חל זהה ל-GraphQL ול-SQL.
  • gRPC model API.proto מחולל אוטומטית מהסכמה הרשומה; RPC-ים מוקלדים לשאילתה ולהוספה לכל טבלה, תגובות בסטרימינג. מונע-סכמה באותה מובן כמו GraphQL — מודל הרישום הוא החוזה, protobuf הוא קידוד התעבורה. בשונה מ-Arrow Flight (שהוא תעבורת סטרימינג עמודתית), זהו ממשק שאילתה מלא לכל טבלה.
  • JSON:API — API שאילתה מובנה בכתובת /data/jsonapi/{table}, HTTP בלבד מעצם התכנון. תומך ב-JSON:API 1.1: sparse fieldsets (fields[table]=col1,col2), ביטויי סינון (filter[field][op]=value), מסמכים מורכבים (include=relation), ומיון. אינו שפת שאילתה כללית — שואל טבלה אחת בכל פעם עם תחביר סינון סטנדרטי במקום מחרוזת שאילתה אד-הוק.
  • Query Language Explorer — כתבו שאילתת GraphQL וראו תרגומי Semantic SQL ו-Cypher חיים בפאנלים צדדיים; העתיקו כל אחד או קפצו ישירות לעורך ה-SQL או הגרף. זרימת עבודה מעשית היא לשרטט קטעי שאילתה ב-GraphQL, ואז לתפור את ה-SQL שנוצר לתוך views או דוחות מורכבים.

ה-Explorer מציג שאילתת GraphQL לצד תרגומי SQL ו-Cypher חיים שלה:

Query Language Explorer

אותה סכמה פדרטיבית ניתנת לחקירה כגרף חי — תוויות דומיין וצומת, סוגי קשרים, וחציות באורך משתנה:

Graph Visualization

כלי הרכבת שאילתות

כלים אלה עוזרים לכם לכתוב שאילתות בשפות שלעיל — הם עצמם אינם שפות שאילתה.

  • שאילתה בשפה טבעית — צינור (pipeline) NL→SQL/Cypher/GraphQL המונע על ידי Claude. תארו מה אתם רוצים באנגלית פשוטה; הצינור מפיק שאילתה בשפה שבחרתם עם לולאת אימות אינטראקטיבית לפני ביצוע.

Natural Language Query

פרוטוקולי תעבורה (Wire Protocols)

אלה פרוטוקולי החיבור. SQL, GraphQL ו-Cypher רוכבים עליהם — בחירת פרוטוקול התעבורה אינה משנה את ממשק השאילתה או את התנהגות הממשל.

  • pgwire — כל לקוח PostgreSQL (psql, DBeaver, DataGrip, asyncpg, SQLAlchemy, read_sql של pandas) מתחבר על פורט 5439 כאילו היה שרת Postgres. מקבל SQL בלבד. צינור הממשל המלא חל. pg_catalog ו-information_schema נענים מקטלוג בזיכרון כך שדפדפני סכמה עובדים בלי סיבוב-הלוך-ושוב לפדרציה. TLS אופציונלי.
  • Bolt (Neo4j) — כל לקוח Neo4j (Neo4j Browser, Bloom, דרייברים רשמיים) מתחבר דרך פרוטוקול Bolt ומריץ Cypher מול הגרף הפדרטיבי. כל תפקיד שהמשתמש מחזיק מוצג כמסד נתונים provisa_<role>. אותו ממשל כמו כל תעבורה אחרת. TLS אופציונלי.
  • Arrow Flight — סטרימינג עמודתי בתפוקה גבוהה מעל gRPC; מקבל GraphQL או SQL כקלט שאילתה. ערכות תוצאה בלתי מוגבלות, ללא מימוש בצד השרת, ללא צורך בתשתית נפרדת.
  • JDBC — אינטגרציית כלי BI (Tableau, Power BI, DBeaver) במצב approved או catalog.
  • WebSocket / SSE — מנויים (subscriptions): אירועי שינוי כמעט-בזמן-אמת; backends: PG native, MongoDB native, CDC, polling. חשוף גם דרך Kafka.

מקורות נתונים

  • 46 סוגי מקורות — PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Neo4j, מאגרי משולשים (triplestores) של SPARQL, Kafka, Google Sheets ועוד דרך API אחד; מקורות גרף ו-RDF הם ממדרגה ראשונה, לא מתאמים (adapters)
  • ניתוב חכם — שאילתות ממקור בודד עוקפות פדרציה (מתחת ל-100 מילישניות); שאילתות מרובות-מקורות מנותבות דרך שכבת הפדרציה — הביאו cluster משלכם או השתמשו בעובדים המובנים (embedded workers)
  • מקורות API — רשמו נקודות קצה של REST, GraphQL, gRPC, WebSocket או RSS כטבלאות הניתנות לשאילתה; עוזרי SPARQL כלולים; JOIN-ים פדרטיביים בין מקורות API ומקורות יחסיים עובדים בשקיפות
  • בדיקת סכמה מרוחקת (Remote schema introspection) — כוונו לכל נקודת קצה של GraphQL, OpenAPI או gRPC; פעולות מתועדות נחשפות אוטומטית כטבלאות, צמתי גרף וקשתות ניתנים לשאילתה עם ממשל מלא מוחל עליהן
  • מקורות קבצים — CSV, Parquet וקבצי SQLite כטבלאות הניתנות לשאילתה; תומך בנתיבים מקומיים ואחסון אובייקטים מרוחק (s3://, ftp://, sftp://)
  • אינטגרציית Kafka — נושאים (topics) כטבלאות לקריאה בלבד; תוצאות שאילתה כ-sinks של Kafka
  • טריגרים מתוזמנים — טריגרי cron ומרווח (APScheduler) שמפעילים webhooks, מוטציות, או פרסומי sink ל-Kafka
  • רמזי ביצועי פדרציה — רמזי ניתוב בהערות SQL עוקפים החלטות ניתוב אוטומטיות

Data Sources

מקורות, קבצים ונקודות קצה מרוחקות נרשמים כטבלאות מסודרות מהממשק:

Table Registration

אבטחה וממשל

  • אבטחה ברמת השורה — הזרקת תנאי WHERE לפי טבלה ולפי תפקיד
  • מיסוך עמודות — מיסוך לפי עמודה (regex, קבוע, קיצוץ) עם עקיפה מבוססת-תפקיד
  • פריסטים לעמודות — ערכים סטטיים בצד השרת או מבוססי משתנה-סשן, מוזרקים בהוספה/עדכון; אינם חשופים בטיפוסי קלט של מוטציה
  • הרשאות כתיבה — בקרת גישת מוטציה לפי עמודה (writable_by)
  • תפקידים בעלי ירושה — תפקידים יורשים RLS, נראות ומיסוך מתפקיד הורה באופן רקורסיבי
  • פונקציות ו-webhooks עקובים — פונקציות DB ו-webhooks יוצאים חשופים כמוטציות GraphQL עם צורות החזרה מוקלדות
  • וו אישור ABAC — וו הרשאה טרום-ביצוע; תעבורת webhook, gRPC או unix_socket; היקף לפי טבלה, לפי מקור, או גלובלי; מדיניות נפילה-חוזרת (fallback) ניתנת להגדרה
  • אימות נתיק — Firebase, Keycloak, OAuth 2.0, פשוט (לבדיקות)

Security Roles

אספקה וביצועים

  • Materialized Views כתמורות (transforms) מתועדות — MV לוכד את התמורה שהפיקה אותו: צורת ה-JOIN שלו או ה-SQL, אותות הקלט לפי-מקור (snapshot של Iceberg, watermark של RDB) שממנו נבנה, ובדיקת דטרמיניזם בעת הרישום. מכיוון שהתמורה מתועדת, שאילתות (או תת-ביטויים) נכתבות מחדש בשקיפות מעל MV רענן — התאמת דפוס-JOIN מבנית עם תמיכה בהתאמה חלקית, כך ש-MV שמכסה תת-קבוצה של JOIN-ים עדיין חל, כאשר JOIN-ים שנותרו נשמרים
  • הטמעת טבלאות חמות — טבלאות בדיקה קטנות ומצטרפות בתדירות גבוהה מוטמעות כ-VALUES CTEs ישירות בתוכנית השאילתה, ומבטלות סיבובי-הלוך-ושוב חוצי-מקורות עבור נתוני ממד
  • caching שאילתות — מטמון תוצאות Redis מחולק לפי תפקיד+RLS; מטמון hash של APQ כלול
  • Observability כנתונים — Trace מבוזרים, מדדים ויומנים נאספים דרך OpenTelemetry, מכווצים ל-Iceberg על S3, ונרשמים אוטומטית כטבלאות הניתנות לשאילתה (traces, metrics, logs, queries) בסכמה הפדרטיבית; שאלו אותן ב-SQL, GraphQL או Cypher לצד נתוני העסק שלכם — צרפו טבלת customers לטבלת queries כדי לראות מי הריץ מה וכמה זמן זה לקח

ניהול ואינטגרציה

  • API ניהולי — GraphQL בכתובת /admin/graphql; העלאה/הורדה של תצורה, עריכת קשרים, אישור שאילתות
  • מציג דוחות/admin/reports מציג את תצוגות הניהול המובנות של תחום התפעול וכל דוח מותאם רשום; דורש את היכולת observability
  • תצוגה מקדימה של טבלה — לכל טבלה רשומה יש מציג נתונים מנוהל עם עימוד בצד השרת, מסננים הנדחפים למקור, קיבוץ רב-שכבתי וייצוא CSV
  • GraphQL Voyager — הדמיה אינטראקטיבית של סכמה בהיקף-תפקיד כדיאגרמת ישות-קשר
  • גילוי קשרים מונע-LLM — הצעות מועמד למפתח זר מונעות על ידי Claude
  • לקוח Pythonpip install provisa-client; GraphQL/SQL ← DataFrames, Arrow Flight ← טבלאות pyarrow, דיאלקט SQLAlchemy, תמיכת ADBC
  • הזרמת נתונים (ingestion) — נקודות קצה HTTP לדחיפת נתוני אירוע JSON לתוך הפלטפורמה
  • ייבוא Hasura v2 / DDN — המרת metadata של Hasura v2 או YAML של supergraph מסוג DDN לתצורת Provisa
  • Apollo Federation — חשיפת Provisa כ-subgraph של Apollo Federation v2

סכמה בהיקף-תפקיד מודמית כדיאגרמת ישות-קשר (GraphQL Voyager):

Schema Voyager

קשרים נרשמים, מאושרים ונאכפים כנתיבי ה-JOIN החוקיים היחידים:

Relationships

מודל אבטחה

כאן "בנתיב שכל שאילתה כבר נוקטת" מפסיק להיות סיסמה. Provisa אוכפת מודל אבטחה רב-שכבתי על פני כל שפת שאילתה (GraphQL, SQL, Cypher) וכל תעבורה (REST, gRPC, Arrow Flight, JDBC, pgwire, Bolt, WebSocket). הממשל מוחל באחידות — אין נתיב שאילתה שעוקף אותו. הכיסוי מלא מבחינה מבנית, לא בזכות שקדנות: הוסיפו מקור, עמודה או קשר וכל שכבה חלה עליו אוטומטית, בלי דבר לזכור לרשום.

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

שכבה 0 — סינון בדיקת סכמה (Introspection)

הסכמה והקטלוג המוצגים לתפקיד מכילים רק את הטבלאות ברשימת ה-domain_access שלו ואת העמודות שעוברות כללי visible_to לפי-עמודה. אובייקטים מחוץ לגישת תפקיד אינם נראים בזמן גילוי — אי אפשר לשאול אותם, להשלים אוטומטית, או להסיק את קיומם. זה חל על סכמת GraphQL, קטלוג SQL, ודפדפן הסכמה של עורך השאילתות.

שכבה 1 — גישה ציבורית

טבלאות בדומיינים ללא הגבלת domain_access נראות לכל זהות מאומתת בלי תצורה נוספת. חיכוך אפס לנתונים ציבוריים באמת.

שכבה 2 — גישת דומיין

כל תפקיד נושא רשימת domain_access של מזהי דומיין. שאילתה שנוגעת בטבלה מחוץ לדומיינים אלה נדחית לפני ביצוע. זהו גבול הבעלות הגס — תפקיד HR אינו יכול להגיע לטבלאות כספים בלי קשר לאופן כתיבת ה-SQL.

שכבה 3 — אבטחה ברמת השורה

לאחר אישור גישת הדומיין, תחזיות WHERE לפי טבלה ולפי תפקיד מוזרקות לכל SELECT בזמן ביצוע. התחזיות מוערכות מול נתונים גולמיים. מנהל אזורי ששואל טבלת הזמנות משותפת רואה רק את שורות האזור שלו אפילו על SELECT *.

שכבה 4 — נראות ומיסוך עמודות

עמודות עם רשימת visible_to שמחריגה את התפקיד המבקש מוסרות מפלט השאילתה. עמודות עם כלל מיסוך מקבלות ערכיהן מוחלפים — עריכת regex, החלפה בקבוע, או קיצוץ — לפני שהתוצאות עוזבות את השרת. המיסוך חל בכל שפות השאילתה ותצורות הפלט.

שכבה 5 — שומר תחזיות (Predicate guard)

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

ממשל קשרים

תנאי JOIN ב-SQL חייבים להתאים לקשר רשום ומאושר בין טבלאות. JOIN-ים לא מאושרים נדחים. כל קשר נושא סיבה והסבר קריאים לבני אדם — הנחיה הן למשתמשים והן לסוכנים אוטונומיים לגבי הסיבה שנתיב חציה קיים. זו מדיניות ממשל, לא גבול אבטחה קשיח: שכבות 2–5 חלות בלי קשר למבנה ה-JOIN, כך שעקיפה מכוונת אינה חושפת נתונים שהתפקיד לא היה יכול להגיע אליהם בשתי שאילתות נפרדות. ניסיונות עקיפה נרשמים וניתנים לביקורת.


השכבות הללו מתחברות. תפקיד עם גישת דומיין, RLS ועמודות ממוסכות — כל חמש האילוצים פעילים בו-זמנית. הוספת מקור נתונים, עמודה או קשר חדשים אינה דורשת עדכון כל כלל — כל שכבה מוגדרת באופן עצמאי וחלה אוטומטית על כל שאילתה שנוגעת באובייקטים מסודרים.

macOS

  1. הורידו את Provisa-macOS.dmg (תמיד הגרסה האחרונה)
  2. גררו את Provisa.app ל-/Applications ולחצו פעמיים כדי להפעיל
  3. ההפעלה הראשונה משלימה הגדרה חד-פעמית (כ-2 דקות, ללא צורך באינטרנט)
  4. פתחו טרמינל:
provisa start   # start all services
provisa open    # open the UI in your browser

Linux

  1. הורידו את Provisa-linux-x86_64.AppImage (תמיד הגרסה האחרונה)
  2. הפכו אותו לבר-הרצה והריצו אותו — ההפעלה הראשונה משלימה הגדרה חד-פעמית (ללא צורך באינטרנט):
chmod +x Provisa-*-linux-x86_64.AppImage
./Provisa-*-linux-x86_64.AppImage
provisa start && provisa open

Windows

  1. הורידו את Provisa-windows-x64.exe (תמיד הגרסה האחרונה)
  2. הריצו את המתקין — אינו דורש הרשאות מנהל
  3. פתחו את Provisa First Launch מתפריט ההתחלה — משלים הגדרה חד-פעמית (כ-5 דקות, ללא צורך באינטרנט)
  4. פתחו טרמינל חדש:
provisa start

שאילתה ראשונה

בפיתוח מקומי (PROVISA_MODE=test), אין צורך באישורים. בייצור, התאמתו עם Bearer token — התפקיד נחלץ ממנו אוטומטית.

# Local dev — no auth required, role defaults to admin
curl -X POST http://localhost:8001/data/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ orders { id amount region } }"}'

# Ad-hoc SQL works the same way
curl -X POST http://localhost:8001/data/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT id, amount, region FROM orders"}'

# Production — authenticate with a Bearer token; role is derived from the token
curl -X POST https://provisa.example.com/data/graphql \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ orders { id amount region } }"}'

JDBC (Tableau, DBeaver, Power BI)

הורידו את provisa-jdbc.jar (תמיד הגרסה האחרונה) והוסיפו אותו לנתיב הדרייברים של כלי ה-BI שלכם.

jdbc:provisa://localhost:8815

התאמתו עם שם המשתמש והסיסמה שלכם ב-Provisa — השרת מקצה את התפקיד שלכם.

  • מצב catalog — הסכמה המלאה נראית; לשימוש עם כלי קטלוג (Collibra, Atlan, DBeaver)

ראו docs/integrations.md לשלבי הגדרה עבור Tableau ו-Power BI.

פרוטוקול תעבורת PostgreSQL (pgwire)

Provisa מדברת את פרוטוקול התעבורה של PostgreSQL על פורט 5439. כל לקוח שמסוגל להתחבר ל-Postgres מתחבר ל-Provisa — ללא דרייבר, ללא מתאם, ללא שינויים בכלים קיימים.

שם המשתמש ב-PostgreSQL בוחר את התפקיד ב-Provisa. עם provider: none (מצב אמון), הסיסמה מתעלמת וכל שם תפקיד מוגדר מתקבל כשם משתמש — התחברו כ-analyst, admin, או כל תפקיד כדי לראות את התצוגה המסודרת של הנתונים עבור התפקיד הזה. עם provider: simple, הסיסמה מאומתת ב-bcrypt. ספקים אחרים (firebase, keycloak, oauth) אינם נתמכים דרך pgwire.

# psql — connect as analyst role
psql -h localhost -p 5439 -U analyst

# psql — connect as admin role
psql -h localhost -p 5439 -U admin

# asyncpg (Python) — role = username, password ignored in trust mode
conn = await asyncpg.connect(host="localhost", port=5439, user="analyst", password="x")
rows = await conn.fetch("SELECT id, amount FROM orders WHERE region = 'west'")

# SQLAlchemy
engine = create_engine("postgresql+psycopg2://analyst:x@localhost:5439/provisa")

# pandas
df = pd.read_sql("SELECT * FROM orders", engine)

כל השאילתות רצות דרך צינור הממשל המלא — גישת דומיין, RLS, מיסוך, ושומר תחזיות חלים בדיוק כפי שהם חלים עבור GraphQL ו-REST. דפדפני סכמה (DBeaver, DataGrip, pgAdmin) עובדים ישר מהקופסה: שאילתות pg_catalog ו-information_schema נענות מקטלוג בזיכרון בהיקף גישת הדומיין של התפקיד, כך שמשתמשים רואים רק את הטבלאות והעמודות שהם מורשים לשאול.

DataGrip מציג את הסכמה המסודרת ואת דיאגרמת המפתחות הזרים שלה דרך pgwire — ללא דרייבר, ללא מתאם:

Provisa in DataGrip over pgwire

TLS מופעל על ידי הגדרת PROVISA_PGWIRE_CERT ו-PROVISA_PGWIRE_KEY. הפורט ניתן להגדרה דרך PROVISA_PGWIRE_PORT (ברירת מחדל 5439).

Bolt (פרוטוקול תעבורת Neo4j)

Provisa מדברת גם את פרוטוקול ה-Bolt של Neo4j, כך שכלים ילידי-גרף מתחברים ישירות ומריצים Cypher מול הגרף הפדרטיבי — ללא ייצוא, ללא מסד נתונים גרף נפרד. כוונו את Neo4j Browser או Bloom ל-Provisa וחצו קשרים בין מקורות עם אותו ממשל (גישת דומיין, RLS, מיסוך) מוחל.

Neo4j Browser מריץ Cypher מול Provisa — תוויות צומת, סוגי קשרים ומפתחות תכונה מגיעים ישירות מהסכמה הרשומה:

Provisa in Neo4j Browser over Bolt

הפעילו אותו על ידי הגדרת PROVISA_BOLT_PORT (ברירת המחדל של Neo4j היא 7687). TLS מופעל עם PROVISA_BOLT_CERT ו-PROVISA_BOLT_KEY. כל תפקיד ב-Provisa שהמשתמש המאומת מחזיק מוצג כמסד נתונים נבחר provisa_<role> (הבוחר provisa_admin לעיל) — בחירה באחד מצמצמת את הסשן לזכויות הדומיין של אותו תפקיד; המשתמש לעולם אינו יכול לחרוג מהתפקידים שהוא מחזיק.

לקוח Python

pip install provisa-client                       # core
pip install "provisa-client[pandas]"             # + DataFrame support
pip install "provisa-client[sqlalchemy]"         # + SQLAlchemy dialect
pip install "provisa-client[adbc]"               # + ADBC over Arrow Flight
from provisa_client import ProvisaClient, connect

# GraphQL → DataFrame
client = ProvisaClient("http://localhost:8001", username="alice", password="secret")
df = client.query_df("{ orders { id amount region } }")

# SQL → DataFrame
df = client.query_df("SELECT id, amount, region FROM orders WHERE region = 'west'")

# Arrow Flight → pyarrow Table (high-throughput columnar)
table = client.flight("{ orders { id amount region } }")

# DB-API 2.0 (PEP 249) — GraphQL or SQL, detected automatically
with connect("http://localhost:8001", username="alice", password="secret") as conn:
    cur = conn.cursor()

    # GraphQL
    cur.execute("{ orders { id amount region } }")
    rows = cur.fetchall()

    # SQL (routed through governance engine — RLS and masking applied)
    cur.execute("SELECT id, amount FROM orders WHERE region = %s", ("west",))
    rows = cur.fetchall()

# SQLAlchemy dialect — provisa+http:// or provisa+https://
from sqlalchemy import create_engine, text
import pandas as pd

engine = create_engine("provisa+http://alice:secret@localhost:8001")

# pandas read_sql — GraphQL or SQL
df = pd.read_sql("{ orders { id amount region } }", engine)
df = pd.read_sql("SELECT id, amount, region FROM orders WHERE region = 'west'", engine)

# raw execute
with engine.connect() as conn:
    rows = conn.execute(text("SELECT id, amount FROM orders")).fetchall()

# role + mode URL parameters (mode=catalog for arbitrary SQL)
engine = create_engine(
    "provisa+http://alice:secret@localhost:8001?role=analyst&mode=catalog"
)

# ADBC — Arrow-native streaming via Flight
from provisa_client.adbc import adbc_connect
with adbc_connect("http://localhost:8001", user="alice", password="secret") as conn:
    with conn.cursor() as cur:
        cur.execute("{ orders { id amount } }")
        table = cur.fetch_arrow_table()

ראו docs/python-client.md לרפרנס מלא.

Documentation

נושא מסמך
מדריך התחלה מהירה למפתחים (הרצה מהמקור) docs/quickstart.md
רפרנס תצורת YAML מלא docs/configuration.md
רפרנס נקודות קצה (GraphQL, REST, Flight, gRPC) docs/api-reference.md
עיצוב מערכת ומפת רכיבים docs/architecture.md
מודל אבטחה (RLS, מיסוך, אימות) docs/security.md
סוגי מקורות נתמכים docs/sources.md
מנויי SSE docs/subscriptions.md
JDBC, כלי BI, לקוחות Arrow Flight, Apollo Federation docs/integrations.md
לקוח Python (provisa-client) docs/python-client.md
API ניהולי docs/admin.md
פריסה (Docker Compose, Kubernetes, macOS) docs/deployment.md
ייבוא Hasura v2 / DDN docs/import.md
זרימת שחרור גרסאות (תגיות alpha/beta/stable) docs/releasing.md

גודל (Sizing)

Provisa כוללת מנוע פדרציה מובנה לשאילתות מרובות-מקורות. בהפעלה הראשונה בוחרים תקציב RAM; Provisa גוזרת את מספר עובדי הפדרציה המקומיים אוטומטית.

RAM מארח עובדים עומס עבודה טיפוסי
< 24 GB 0 פיתוח, שאילתות ממקור בודד, צוותים קטנים
24–47 GB 1 צוות קטן, שאילתות חוצות-מקורות בינוניות
48–95 GB 2 פריסה מחלקתית, שימוש מעורב BI + notebook
96 GB+ 4 מחלקה גדולה, פדרציה מקבילית כבדה

ניתן לשנות את מספר העובדים בכל עת על ידי עריכת ~/.provisa/config.yaml‏ (federation_workers: N) והרצת provisa restart. הגדירו 0 כדי לרוץ במצב תיאום-בלבד (single-node).

קנה מידה מעבר לתיבה בודדת

קנה מידה אופקי (horizontal scale-out) — הריצו מספר מופעי Provisa מאחורי load balancer. כל מופע הוא מערכת פועלת במלואה. כל המופעים חייבים להצביע על אותו config DB (הגדירו CONFIG_DB_HOST בתיבות משניות) ואופציונלית מופע Redis משותף (REDIS_URL) עבור מטמון מאוחד. רוב השאילתות מתפזרות בשקיפות; JOIN-ים חוצי-מקורות גדולים מאוד עלולים לחרוג ממשאבי מופע בודד ולדרוש תיבה גדולה יותר או cluster פדרציה חיצוני.

Redis משותף — הגדירו REDIS_URL בכל מופע כדי להצביע על Redis חיצוני. Redis משותף משמעו שרשומות מטמון ממופע אחד זמינות לכולם, ומשפר את שיעורי הפגיעה (hit rates) על פני ה-cluster.

הביאו cluster פדרציה משלכם — כוונו את Provisa ל-cluster פדרציה חיצוני קיים במקום העובדים המובנים. מומלץ לפריסות בקנה מידה גדול או ענן; ראו docs/deployment.md לתצורה.

רישיון

Business Source License 1.1 (בלתי משונה, לפי התחייבויות ה-Licensor של MariaDB). כל גרסה שמשוחררת עוברת לרישיון השינוי (Change License; GPL v2.0 ואילך) ביום השנה הרביעי לשחרורה הציבורי; קוד נוכחי ואחרון נשאר תחת BSL. שימוש בייצור מעל סיפי מענק השימוש הנוסף (פחות מ-100 עובדים/קבלנים ומתחת ל-$1M הכנסה בשנה הקודמת) דורש רישיון מסחרי. ראו LICENSE.

ה-Licensor אינו מסכים לשימוש ביצירה זו לאימון AI/ML. ראו NOTICE, ai.txt, ו-robots.txt. לרישיונות מסחריים או לאימון AI: kennethstott@gmail.com