לדלג לתוכן

Provisa

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

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

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

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

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

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

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

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

מודל הפדרציה

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

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

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

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

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

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

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

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

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

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

  • entity — היטל מפתח, מנוקה כפילויות, אופציונלית-מוהיסטר, של מקור. הצהירו מפתח ישות, את התכונות, ומצב היסטוריה; Provisa מנמיך אותו לתצוגה ממוטריאלת (Materialized View), וכשמתבקשת היסטוריה — ל-MV דו-זמני (bitemporal) (scd2 → delta, snapshot → snapshot). מבנה אחד משרת ממד (Dimension) של Kimball (SCD1/SCD2) וגם hub + satellite של Data Vault.
  • fact — JOIN למפתחות ישות, מוצמצם לגרעין מוצהר, עם מדדים צבורים. Provisa מנמיך אותו ל-MV צובר בתוספת קשרים רשומים לישויות. מבנה אחד משרת טבלת עובדה (Fact Table) של star וגם link של Data Vault (עובדה חסרת-מדד היא link טהור של קבוצת מפתחות).

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

מסע בזמן (Time Travel)

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

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

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

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

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

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

תכונות

ממשקי שאילתה

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

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

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

Query Language Explorer

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

Graph Visualization

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

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

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

Natural Language Query

פרוטוקולי תעבורה

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

  • pgwire — כל לקוח PostgreSQL (psql, DBeaver, DataGrip, asyncpg, SQLAlchemy, read_sql של pandas) מתחבר בפורט 5439 כאילו היה שרת Postgres. מקבל SQL בלבד. ה-pipeline המלא של הממשל חל. 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.

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

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

Data Sources

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

Table Registration

אבטחה וממשל

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

Security Roles

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

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

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

  • API ניהולי — GraphQL ב-/admin/graphql; העלאה/הורדת קונפיגורציה, עריכת קשרים, אישור שאילתה
  • צופה דוחות/admin/reports מציג את תצוגות הניהול המובנות של תחום התפעול ואת כל הדוחות המותאמים הרשומים; דורש את יכולת ה-observability
  • תצוגה מקדימה של טבלה — לכל טבלה רשומה יש צופה נתונים מוממשל מדופדף-שרת עם מסננים דחופים (pushed-down), קיבוץ-לפי רב-רמתי, וייצוא CSV
  • GraphQL Voyager — הדמיה אינטראקטיבית מוגבלת-תפקיד של הסכמה כתרשים ישות-קשר
  • גילוי קשרים מבוסס LLM — הצעות מועמד למפתח זר מופעלות על ידי Claude
  • לקוח Pythonpip install provisa-client; GraphQL/SQL → DataFrames, Arrow Flight → טבלאות pyarrow, ניב SQLAlchemy, תמיכת ADBC
  • קליטת נתונים — נקודות קצה HTTP לדחיפת נתוני אירוע JSON לתוך הפלטפורמה
  • ייבוא Hasura v2 / DDN — המרת מטא-דאטה של 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. בלי זה, קורא יכול היה להסיק את הערך הבלתי ממוסך על ידי חיפוש בינארי שלו בתוך מסנן גם אם הפלט ממוסך. הדחייה נאכפת בזמן ניתוח (parse) של השאילתה, לפני ביצוע.

ממשל קשרים

תנאי JOIN ב-SQL חייבים להתאים לקשר רשום ומאושר בין טבלאות. JOINs לא מאושרים נדחים. כל קשר נושא סיבה ותיאור קריאים לאדם — הכוונה למשתמשים ולסוכנים אוטונומיים כאחד לגבי הסיבה לקיומו של נתיב מעבר. זוהי מדיניות ממשל, לא גבול אבטחה קשיח: שכבות 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 (מצב trust), הסיסמה מתעלמת וכל שם תפקיד מוגדר מתקבל כשם משתמש — התחברו כ-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)

כל השאילתות רצות דרך ה-pipeline המלא של הממשל — גישת תחום, RLS, מיסוך, ו-Predicate Guard חלים בדיוק כפי שהם עבור 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 לעיל) — בחירת אחד מצמצמת את ה-session לזכויות התחום של אותו תפקיד; המשתמש לעולם אינו יכול לחרוג מהתפקידים שהוא מחזיק.

לקוח 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 להתייחסות מלאה.

תיעוד

נושא מסמך
מדריך התחלה מהירה למפתחים (הרצה מקוד מקור) docs/quickstart.md
התייחסות מלאה לקונפיגורציית YAML docs/configuration.md
התייחסות לנקודות קצה (GraphQL, REST, Flight, gRPC) docs/api-reference.md
עיצוב מערכת ומפת רכיבים docs/architecture.md
מודל אבטחה (RLS, מיסוך, אימות) docs/security.md
אחסון סודות והתייחסויות ${secret:NAME} docs/secrets.md
מילון עסקי ואצירת מונחים docs/glossary.md
סביבות (dev / staging / prod) docs/environments.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).

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

שינוי קנה מידה אופקי — הריצו מספר מופעי Provisa מאחורי מאזן עומסים. כל מופע הוא מערכת מתפקדת באופן מלא. כל המופעים חייבים להצביע על אותו DB קונפיגורציה (הגדירו CONFIG_DB_HOST בקופסאות משניות) ואופציונלית מופע Redis משותף (REDIS_URL) עבור מטמון מאוחד. רוב השאילתות מתפזרות בשקיפות; JOINs חוצי-מקורות גדולים מאוד עלולים לחרוג ממשאבי מופע בודד ולדרוש קופסה גדולה יותר או 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. שימוש בייצור מעל סף המענק לשימוש נוסף (Additional Use Grant) (פחות מ-100 עובדים/קבלנים ומתחת ל-$1M הכנסה בשנה הקודמת) דורש רישיון מסחרי. ראו LICENSE.

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