לדלג לתוכן

Provisa

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

Provisa שם API אחד מעל כל הנתונים שלכם. כוונו אותו אל מסדי הנתונים ויישומי העסק שלכם, תארו איך הם מתחברים, ושאלו את התוצאה המצורפת דרך REST, GraphQL, SQL, gRPC, MCP, JSON:API, Arrow Flight, pgwire או Bolt.

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

  • פדרציה. 73 מחברים מגיעים ליותר מ-85 סוגי מקורות, ביניהם Salesforce, ServiceNow ו-Stripe. מערכות ה-SaaS שהעסק שלכם רץ עליהן נקראות כטבלאות לצד מסדי הנתונים, במקומן, בלי צנרת למחסן נתונים קודם. שאלו עליהן ב-SQL, GraphQL או Cypher, בתשעה פרוטוקולים.
  • מדדים. מדד הוא צבירה בעלת שם ומנוהלת. מגדירים אותו פעם אחת, וכל כלי וכל שפה שמבקשים אותו מקבלים את אותה הגדרה.
  • אונטולוגיה. מילון המונחים העסקי הוא גרף של מושגים, ההגדרות שלהם והקשרים ביניהם. Provisa ממפה אותו לטבלאות ולעמודות שמחזיקות את הערכים, וזה מה שמאפשר לו לענות על שאלות על הנתונים שלכם. מושג נשאר טיוטה עד שהוא מגיע לנתונים, ישירות או דרך מושגים אחרים. המילון אומר מה מושג הוא; מדד אומר איך מחשבים מספר.
  • ממשל. שש שכבות של בדיקות מהודרות לכל תוכנית שאילתה, בכל שפה ובכל פרוטוקול, וכל בקשה נרשמת באותו אופן: מי שאל על מה, באיזה תפקיד, תחת איזו מדיניות. עקבות, מדדים ויומנים רשומים כטבלאות שאפשר לשאול עליהן, לצד נתוני העסק.

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

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

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

אפשר להשתמש בו בשתי דרכים, והן משתלבות:

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

לנסות הדגמה

הדרך המהירה ביותר היא הדגמה חיה בדפדפן, בלי להתקין דבר: provisa.dev/demos. כל אחת פותחת ארגז חול פרטי עם סיור מודרך.

מעותק של המאגר הזה אפשר להריץ כל הדגמה במחשב שלכם:

./start-ui-install.sh --list-demos     # the demos you can run, and which are published
./start-ui-install.sh --demo weblogs   # start one, with its tour

הדגמה מפורסמת נמשכת כחבילה מוכנה; האחרות רצות מתוך demo/named/<name>/. כל האפשרויות מפורטות ב-docs/sales-engineer-demos.md.

מודל הפדרציה

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

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

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

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

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

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

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

מודלים ממדיים נובעים מכאן ישירות. העובדות והממדים של סכמת כוכב הם מערכי נתונים נגזרים כמו כל מערך אחר. ממד הוא הטלה מתואמת ובלי כפילויות, וטבלת עובדות היא צירוף עם צבירה שצומצם לגרעין, לכל אחד מדיניות בנייה ורעננות משלו. ממדים משתנים לאט לא צריכים שום דבר מיוחד: תמונת מצב מקובעת היא היסטוריה מסוג 2, ובנייה מחדש לפי לוח זמנים היא סוג 1. מכיוון שהסכמה מוגדרת במודל ואינה קשורה לטבלאות של מחסן אחד, את אותן עובדות וממדים אפשר לבנות ב-Oracle, ב-Databricks, או להשאיר וירטואליים מעל מנוע MPP, בלי למדל מחדש.

Data Vault נכנס באותו אופן, שכבה אחת קודם. Hubs הם מערכים של מפתחות עסקיים בלי כפילויות, links הם הקשרים הרשומים ביניהם, ו-satellites הם מערכי תכונות של הוספה בלבד, עם חותמת זמן, ששומרים את ההיסטוריה. Satellite הוא פשוט מערך נגזר באסטרטגיית אות השינוי: תאריך טעינה ועוד hashdiff הם לכידת שינויים שמוחלת על תכונות תיאוריות, והיסטוריה של הוספה בלבד היא אסטרטגיית תמונת המצב המקובעת. טבלאות point-in-time ו-bridge הן עוד מערכים נגזרים, שנבנו למהירות השאילתות. כך ש-raw vault הוא אוסף של מערכי נתונים נגזרים במודל, וסכמת כוכב היא הטלה ממנו, שניהם מחוללים ושניהם ניידים בין מנועים. את המתודולוגיה אתם עדיין מחליטים: מה הופך ל-hub, מה הגרעין של satellite, איך מפצלים. אחרי שהחלטתם, ההחלטה חיה במודל. שום ETL לא מרתך אותה למחסן אחד.

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

  • entity היא הטלה של מקור עם מפתח ובלי כפילויות, שיכולה לשמור היסטוריה. הצהירו על המפתח, התכונות ומצב ההיסטוריה, ו-Provisa בונה תצוגה מוחשית. בקשו היסטוריה, והוא בונה במקום זאת MV דו-זמני (scd2 → delta, snapshot → snapshot). מבנה אחד נותן לכם ממד של Kimball (SCD1 או SCD2) או hub עם satellite של Data Vault.
  • fact מצטרף למפתחות של ישויות, מצטמצם לגרעין מוצהר ומצבר מדדים. Provisa בונה MV של צבירה ועוד הקשרים הרשומים אל הישויות. מבנה אחד נותן לכם טבלת עובדות של כוכב או link של Data Vault; עובדה בלי מדדים היא link של קבוצת מפתחות טהורה.

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

מסע בזמן (Time Travel)

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

מה ששומר על הניידות הוא שהכול בהוספה בלבד. גרסה שנכתבה לעולם לא מתעדכנת ולא נמחקת. הטריק הדו-זמני הרגיל, לסגור שורה בכתיבה חוזרת של תאריך "תקף עד", דורש UPDATE, ומנועים רבים לא יכולים לעשות אותו בזול, או בכלל, מעל מאגר מאוחד. לכן כל רענון מוסיף, ואיזו גרסה הייתה בתוקף ברגע נתון מחושב בזמן הקריאה מתוך היומן. יש שתי דרכים להוסיף:

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

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

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

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

תכונות

ממשקי שאילתה

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

  • GraphQL — סכמות לכל תפקיד עם נראות ברמת השדה, סינון, דפדוף מבוסס סמן ושאילתות צבירה (count, sum, avg, min, max). הסכמה מציעה רק קשרים רשומים, כך שכל שאילתה תקינה מבנית מעצם בנייתה, ו-GraphQL הוא הדרך המהירה ביותר לשאילתה פשוטה ונכונה. Apollo APQ כלול: שאילתות עוברות גיבוב ונרשמות בשרת, קריאות מאוחרות יותר שולחות רק את הגיבוב ב-HTTP GET, והתגובות ניתנות לשמירה במטמון CDN בלי שינוי בלקוח. טבלאות חיפוש מתחת לסף שורות שניתן להגדרה מופיעות כטיפוסי enum.
  • SQL — SQL מלא על נתונים מאוחדים, ללא מגבלות ובעל כושר ביטוי רב יותר מ-GraphQL. כתבו SQL סטנדרטי, כולל תת-שאילתות מתואמות, והוא רץ על פני מקורות בלי שינוי. שאילתה על מקור יחיד מדלגת לגמרי על שכבת הפדרציה (פחות מ-100 ms).
  • Cypher — שפת שאילתת גרפים מעל אותה סכמה מפודררת. עברו על קשרים כקצוות גרף; אחדו מקורות; נתיבים באורך משתנה. הממשל חל באופן זהה ל-GraphQL ול-SQL.
  • gRPC model API — קובץ .proto שנוצר מהסכמה הרשומה, עם RPC מוגדרי טיפוס לשאילתה ולהוספה לכל טבלה בשורש הסכמה של תפקיד, ותגובות בזרימה. כמו 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) ומיון. היא שואלת טבלה אחת בכל פעם בתחביר סינון סטנדרטי, ולכן השתמשו ב-SQL או ב-GraphQL כשאתם צריכים שפת שאילתה כללית.
  • Query Language Explorer — כתבו שאילתת GraphQL וראו תרגומי Semantic SQL ו-Cypher חיים בפאנלים צדדיים; העתיקו אחד מהם או קפצו ישירות לעורך ה-SQL או הגרף. תהליך עבודה מעשי הוא לשרטט קטעי שאילתה ב-GraphQL, ואז לתפור את ה-SQL שנוצר לתוך תצוגות או דוחות מורכבים.

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

Query Language Explorer

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

Graph Visualization

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

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

  • שאילתה בשפה טבעית — צינור NL→SQL/Cypher/GraphQL שרץ על Claude. תארו מה אתם רוצים בשפה פשוטה, והצינור כותב שאילתה בשפה שבחרתם, עם לולאת אימות אינטראקטיבית לפני שמשהו רץ.

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).
  • WebSocket / SSE — מנויים (Subscriptions): אירועי שינוי כמעט-בזמן-אמת; backends: PG native, MongoDB native, CDC, polling. חשוף גם מעל Kafka.

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

  • 73 מחברים, יותר מ-85 סוגי מקורות — המספר הגדול סופר בנפרד את שירותי PostgreSQL המתארחים (RDS, Aurora, Cloud SQL, AlloyDB, Azure, Supabase, Neon) ואת פורמטי הקבצים של File Crawler. PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Neo4j, מאגרי טריפלטים של SPARQL, Kafka, Google Sheets, Kaggle, Salesforce, ServiceNow, Stripe והשאר יושבים מאחורי API אחד. מקורות גרף ו-RDF עומדים בשורה אחת עם מקורות רלציוניים.
  • ניתוב חכם — שאילתה על מקור יחיד מדלגת על הפדרציה (פחות מ-100 ms). שאילתה על כמה מקורות עוברת דרך שכבת הפדרציה, על האשכול שלכם או על העובדים המוטמעים.
  • מקורות API — רשמו נקודות קצה של REST, GraphQL, gRPC, WebSocket או RSS כטבלאות שניתן לשאול, כולל כלי עזר ל-SPARQL. צירופים מאוחדים בין מקורות 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 מתעד את הטרנספורמציה שיצרה אותו: צורת הצירוף או ה-SQL שלו, אותות הקלט לכל מקור שממנו נבנה (snapshot של Iceberg, watermark של RDB), ובדיקת דטרמיניזם בעת הרישום. מכיוון שהטרנספורמציה מתועדת, Provisa יכול לכתוב מחדש שאילתה, או חלק ממנה, על MV עדכני בלי שתשנו את השאילתה. ההתאמה פועלת על תבניות צירוף ומקבלת התאמות חלקיות, כך ש-MV שמכסה רק חלק מהצירופים עדיין חל, ושאר הצירופים נשמרים.
  • הטמעת טבלאות חמות (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 מציע מועמדים למפתחות זרים.
  • לקוח Python — pip 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 של מזהי תחומים, ושאילתה שנוגעת בטבלה מחוץ לתחומים האלה נדחית לפני שהיא רצה. זה גבול הבעלות הרחב: תפקיד של משאבי אנוש לא מגיע לטבלאות הכספים, איך שלא ייכתב ה-SQL.

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

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

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

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

שכבה 5 — Predicate Guard

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

ממשל קשרים

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

אף join לא תקף לא רץ אף פעם על הנתונים שלכם. תפקידים מנוהלים כברירת מחדל, ויציאה מזה פירושה להעניק בכוונה את הזכות ignore_relationships לתפקיד שאתם סומכים עליו. טוקן ה-OAuth של סוכן ממופה לתפקיד, כך שסוכן מקבל את אותן שכבות כמו אדם. קטלוגי נתונים עם שכבת הקשר אומרים לסוכן מה הוא צריך לעשות; Provisa אוכף מה הוא יכול לעשות.


השכבות האלה מצטרפות זו לזו. לתפקיד עם גישת תחום, 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, ו-Provisa קורא ממנו את התפקיד.

# 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, והשרת יקצה לכם את התפקיד.

ראו 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)

כל שאילתה עוברת בצינור הממשל המלא, כך שגישת תחום, RLS, הסתרה ושומר הפרדיקטים חלים בדיוק כמו ב-GraphQL וב-REST. דפדפני סכמות (DBeaver, DataGrip, pgAdmin) עובדים בלי הגדרה. Provisa עונה על שאילתות ה-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 URL parameter
engine = create_engine(
    "provisa+http://alice:secret@localhost:8001?role=analyst"
)

# 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/test-data.md
מדריך שיטות הנתונים המזויפים docs/fake-methods.md
הרצה ובנייה של הדגמות במחשב נייד (מהנדסי מכירות) docs/sales-engineer-demos.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 מאחורי מאזן עומסים. כל מופע הוא מערכת שלמה. כל המופעים חייבים להצביע על אותו מסד נתוני תצורה (הגדירו CONFIG_DB_HOST במכונות המשניות), והם יכולים לחלוק מופע Redis אחד (REDIS_URL) למטמון משותף. רוב השאילתות מתפזרות בלי שינוי. צירוף גדול מאוד בין מקורות יכול לחרוג ממופע אחד, ואז צריך מכונה גדולה יותר או אשכול פדרציה חיצוני.

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