किसी डेटाबेस को एक स्कीमा से लिंक करें और Entity Enricher आपकी एनरिच की गई एंटिटीज़ को आपके स्वामित्व वाली रिलेशनल टेबल्स के रूप में बनाए रखता है: एक असली company टेबल जिसमें एक revenue कॉलम हो — कोई एक्सपोर्ट फ़ाइल नहीं। एक बार तैयार-चलने-योग्य SQL स्नैपशॉट डाउनलोड करें, फिर idempotent upserts के एक इंक्रीमेंटल डेल्टा फ़ीड के साथ अपने डेटाबेस को कन्वर्ज्ड रखें।
एक बार स्टोर करें, मांग पर प्रोजेक्ट करें। एनरिचमेंट वर्तमान एंटिटी स्थिति को एंटिटी लेयर में लिखते हैं; प्रत्येक लिंक्ड डेटाबेस उस स्थिति का एक प्रोजेक्शन है, जो एक बार के स्नैपशॉट और एक डेल्टा फीड के रूप में डिलीवर होता है जिसे आप एक्नॉलेज करते हैं। स्कीमा को एडिट करने की कीमत री-प्रोजेक्शन है, कभी डेटा माइग्रेशन नहीं।
database_sync: false पास करते हैं); अन्य उपयोगकर्ताओं के एनरिचमेंट सामान्य रूप से रूट होते रहते हैं।.sql स्नैपशॉट (टेबल + डेटा) डाउनलोड करें और उसे अपने PostgreSQL पर लागू करें। DDL में join इंडेक्स और foreign key शामिल होते हैं (किसी इकाई को डिलीट करने पर child और link पंक्तियाँ cascade होती हैं)। फ़ाइल हेडर आपको बताता है कि किस delta कर्सर से फिर से शुरू करना है।हर एंटिटी प्रकार की एक डेटाबेस कुंजी होती है — वह कॉलम सेट जिसे आपकी टेबल अपने यूनिक इंडेक्स और upsert कॉन्फ़्लिक्ट टारगेट के रूप में इस्तेमाल करती हैं। जब आप कोई डेटाबेस लिंक करते हैं, तो एक AI वर्गीकरण पास आपकी समीक्षा के लिए पूरा डेटाबेस मॉडल (कुंजियाँ, कॉलम प्रकार, इंडेक्स, ओनरशिप) प्रस्तावित करता है, और एक सरल क्रम पर वापस लौटता है: ऑब्जेक्ट का सिमेंटिक ID, अगर उसके पास हो; अन्यथा कोई Id जैसा फ़ील्ड (id, product_id, …); अन्यथा ऑब्जेक्ट की प्राकृतिक कुंजियाँ। आपकी टेबल में सिमेंटिक ID एक semantic_id कॉलम के रूप में आता है — नाम id आपके अपने उपयोग के लिए मुक्त रहता है। आप उन्हें डेटाबेस के “Model” टैब में कभी भी बदल सकते हैं — प्रकाशित होने के बाद यह माइग्रेशन-स्तर का बदलाव होता है: उसके बाद स्नैपशॉट दोबारा डाउनलोड करें। जब तक उस टैब से स्कीमा प्रकाशित नहीं किया जाता, आपके डेटाबेस तक कुछ नहीं पहुँचता (सिर्फ़ लिंक करने से न कोई टेबल जाती है, न कोई रो)।
डेटाबेस की कभी nullable नहीं होती। null वैल्यू किसी रो से मैच नहीं करती, इसलिए एंटिटी को अपडेट करने के बजाय हर एनरिचमेंट पर एक नई डुप्लिकेट रो इंसर्ट हो जाएगी — यही वजह है कि जिस एनरिचमेंट की की खाली लौटती है उसे सेव करने के बजाय अस्वीकार कर दिया जाता है। एडिटर दोनों फ्लैग को अलग रखता है, और जो स्कीमा दोनों सेट करती है उसे सेव करते समय या डेटाबेस लिंक करते समय अस्वीकार कर दिया जाता है, साथ ही उसे ठीक करने के दो तरीके बताए जाते हैं: प्रॉपर्टी को हमेशा मौजूद बनाएँ, या टाइप की की किसी दूसरी प्रॉपर्टी पर रखें।
जब कोई डेटाबेस कुंजी सिमेंटिक ID के बजाय एनरिच किया गया टेक्स्ट फ़ील्ड हो, तो सहेजा गया मान मॉडल का उत्तर होगा — वह टेक्स्ट नहीं जो आपने भेजा था। अपने अनुरोध में किसी कंपनी को Embraer बताने से वह फ़ील्ड तय नहीं हो जाता: एनरिचमेंट का उत्तर Embraer S.A. हो सकता है — सुधरी हुई स्पेलिंग, विस्तारित कानूनी प्रत्यय, हटाया गया disambiguator — और पंक्ति की कुंजी वही बनता है। इसलिए आपके भेजे गए मान से पंक्ति खोजने पर वह छूट सकती है (हर सहेजी गई एनरिचमेंट के साथ लौटाई गई entity_keys का उपयोग करें), और बाद का कोई रन यदि उसे अलग शब्दों में कहे तो वह अलग कुंजी है — वह आपकी पंक्ति अपडेट करने के बजाय दूसरी पंक्ति जोड़ देगा। एनरिच किए गए टेक्स्ट से बनी किसी भी कुंजी के साथ ऐसा होना अपेक्षित है। समाधान है उस टाइप पर सिमेंटिक ID: एक ही नाम के अलग-अलग रूप एक स्थिर पहचान पर आ जाते हैं, इसलिए मॉडल चाहे जैसे भी लिखे, पंक्ति बनी रहती है। इसे स्कीमा जनरेट करते समय ही चालू करें — बाद में जोड़ने का मतलब है हर ऑब्जेक्ट को एडिट करना।
arrays के अंदर nested ऑब्जेक्ट अपनी खुद की टेबल बन जाते हैं, जहाँ junction rows क्रम को बनाए रखती हैं; बिना identity वाले value ऑब्जेक्ट अपने parent के columns में flatten होकर रहते हैं। Property नाम हूबहू (quoted) उपयोग किए जाते हैं — आपके column नाम आपके schema के property नाम ही होते हैं, जिन्हें केवल तभी छोटा किया जाता है जब कोई nested path उस सीमा से बड़ा हो जाए जिसे PostgreSQL नाम दे सकता है।
यह प्रोजेक्शन नियतात्मक है — वही स्कीमा हमेशा वही टेबल्स और कॉलम पर मैप होता है। प्रॉपर्टी नाम ज्यों-के-त्यों कॉलम नाम बन जाते हैं (कोट किए हुए); टाइप नाम snake-case में बदलकर टेबल नाम बनते हैं (VideoGame → video_game)। एकमात्र अपवाद लंबाई है: PostgreSQL 63 बाइट से बड़े आइडेंटिफ़ायर को धारण नहीं कर सकता, इसलिए कोई गहराई से नेस्टेड पथ फ़िट होने के लिए अपने पैरेंट ऑब्जेक्ट्स को छोटा कर देता है (morphological_description_ → morpdesc_) — उस ऑब्जेक्ट के हर कॉलम के लिए वही प्रीफ़िक्स, जो लिंक करने से पहले Model टैब में दिखता और संपादन योग्य होता है। कोई प्रॉपर्टी अपने प्रीफ़िक्स को पूरी तरह हटाकर उस कॉलम से मेल भी खा सकती है जो आपके database में पहले से मौजूद है (product_identifiers.stock_keeping_unit → sku) — नाम के बगल में Model टैब में मौजूद लिंक टॉगल। हर टेबल में एक _sync_revision कॉलम होता है जो रीप्ले को अभिसारी बनाए रखने के लिए उपयोग होता है।
| आपके schema में | आपके डेटाबेस में |
|---|---|
| पहचान वाला ऑब्जेक्ट (semantic ID या keys) | अपना अलग table; डेटाबेस keys यूनीक इंडेक्स और upsert टारगेट बन जाती हैं |
| स्केलर फ़ील्ड (string, number, boolean) | एक typed कॉलम (TEXT, BIGINT, NUMERIC, BOOLEAN) |
| क्लोज़्ड सेट (ऐसा फ़ील्ड जो मानों की एक सूची तक सीमित हो) | एक सामान्य TEXT कॉलम — न कोई CHECK, न कोई database enum type। सूची तब लागू होती है जब AI उत्तर देता है, इसलिए बाद में उसमें कोई मान जोड़ने से आपका डेटाबेस कभी माइग्रेट नहीं होता। अगर आप चाहें तो अपना खुद का constraint जोड़ें — sync उसे कभी नहीं छूता |
| Nullable या non-nullable फ़ील्ड | डिफ़ॉल्ट रूप से non-nullable फ़ील्ड एक NOT NULL कॉलम बनती है, जो नीचे दिए क्वालिटी गेट के साथ जुड़ी होती है — सबसे सख़्त गेट पर आवश्यक रेफ़रेंस को भी NOT NULL फ़ॉरेन की मिलती हैं; एनफ़ोर्समेंट बंद कर दें — रजिस्ट्रेशन के समय, या बाद में: पहले सिंक के बाद किया गया बदलाव फ़ीड में एक गार्डेड माइग्रेशन के रूप में जाता है — ताकि हर कॉलम nullable रहे और पूर्णता केवल गेट लागू करे |
| बहुभाषी फ़ील्ड | एक JSONB कॉलम जो हर भाषा को रखता है |
| एम्बेडेड वैल्यू ऑब्जेक्ट (कोई पहचान नहीं) | प्रीफ़िक्स वाले कॉलम में फ़्लैट किया गया (dimensions_width) |
| वैल्यू ऑब्जेक्ट की ऐरे | पैरेंट पर कीड, ऑर्डर्ड, डिलीट पर कैस्केडिंग एक चाइल्ड टेबल |
एंटिटी की ऐरे / $ref रिलेशन | सोर्स और टारगेट रो को लिंक करने वाली एक जंक्शन टेबल, ऑर्डर सुरक्षित |
Key फ़ील्ड (identifying) | तेज़ लुकअप के लिए एक सेकेंडरी इंडेक्स |
| क्वेरी-शेप्ड इंडेक्स (क्रमबद्ध फ़ील्ड सूची) | हर घोषित शेप के लिए एक मल्टी-कॉलम इंडेक्स, उसी क्रम में जिस लिस्ट-स्क्रीन क्वेरी की वह सेवा करता है — पहले फ़ैसेट और क्लोज़्ड सेट, अंत में सॉर्ट या रेंज कॉलम, बहुभाषी फ़ील्ड भी शामिल (ऐसा शेप आपके डेटाबेस को मिली हर भाषा के लिए एक बार भेजा जाता है); वर्गीकरण पास द्वारा एक कारण के साथ प्रस्तावित, Model टैब में क्यूरेट किया गया, प्रति एंटिटी कई |
| सर्च फ़ील्ड (इंडेक्स इंटेंट) | उस टेक्स्ट पर ट्रिग्राम इंडेक्स (pg_trgm) जिसे आपके सर्च बॉक्स टुकड़ों से मैच करते हैं — बहुभाषी कॉलम पर प्रति भाषा और बिना सीमा के; ड्रॉपडाउन वैल्यू पर कभी नहीं, वह इसके बजाय क्वेरी-आकार वाले इंडेक्स में आती है (बहुभाषी वाले भी शामिल — ऐसा इंडेक्स आपके डेटाबेस को मिली हर भाषा के लिए एक बार भेजा जाता है); एक्सटेंशन रहित रेप्लिका पर तब तक छोड़ दिया जाता है (no-op) जब तक कोई डेटाबेस स्वामी उसे इंस्टॉल न कर दे |
| कोऑर्डिनेट जोड़ी (अक्षांश + देशांतर) | जोड़ी पर एक ही स्पेशियल इंडेक्स (नेटिव PostgreSQL GiST, कोई एक्सटेंशन नहीं) — रेडियस, नियरेस्ट-नेबर और मैप-व्यूपोर्ट क्वेरी |
| इंटरवल जोड़ी (आरंभ + अंत सीमाएँ) | जोड़ी पर एक ही रेंज इंडेक्स — ओवरलैप और "इस तारीख़ को कौन-सा मान लागू था" जैसी क्वेरी |
एक डेटाबेस एक से अधिक स्कीमा सिंक कर सकता है। लिंक की गई स्कीमाओं में समान नाम वाले एंटिटी टाइप एक ही टेबल में आते हैं, जो उनके डेटाबेस की (key) से मर्ज होते हैं — हर स्कीमा की एनरिचमेंट केवल अपने ही कॉलम अपडेट करती है, इसलिए दो स्कीमाओं द्वारा एनरिच की गई कंपनी एक ही पंक्ति बन जाती है जो दोनों कॉलम सेट रखती है। किसी एक स्कीमा के लिए अनन्य टाइप बस अपनी अलग टेबल जोड़ देते हैं, जो फ़ीड में एक स्वचालित माइग्रेशन डेल्टा के माध्यम से पहुँचती हैं — दोबारा डाउनलोड की ज़रूरत नहीं।
जब आप कोई स्कीमा लिंक करते हैं, तो एक तुलना चरण ठीक-ठीक दिखाता है कि कौन-सी टेबल मर्ज होंगी (उनकी की और जोड़े गए कॉलम के साथ) और कौन-सी नई हैं; जो स्कीमा किसी टेबल को साझा करती है वह उस टेबल की मौजूदा डेटाबेस की अपना लेती है, जो आपकी समीक्षा के लिए दिखाई जाती है। यदि स्कीमाएँ कुछ भी साझा नहीं करतीं, तो फ़्लो इसके बजाय एक समर्पित डेटाबेस सुझाता है। किसी स्कीमा को अनलिंक करने से आपका डेटाबेस कभी नहीं छुआ जाता — सिंक की गई टेबल बनी रहती हैं।
किसी स्कीमा को अनलिंक करना, या किसी सिंक को हटाना, हमारी ओर दो चीज़ें पीछे छोड़ देता है: संग्रहीत एंटिटी स्टेट जिसमें अब कुछ नहीं लिखता, और स्कीमा जो डेटाबेस प्रॉपर्टीज़ रखता है (database keys, कॉलम प्रकार, इंडेक्स, स्वामित्व)। दोनों पुष्टिकरण उन्हें हटाने की पेशकश करते हैं, और केवल उन स्कीमा के लिए जिनके पास कोई डेटाबेस नहीं बचा है — जो अभी भी कहीं और सिंक है वह सब कुछ रखता है। स्कीमा स्वयं, इसके संवर्धन रिकॉर्ड और इसकी लागत कभी प्रभावित नहीं होते।
एक लिंक की गई स्कीमा में एक प्रकाशित कॉन्ट्रैक्ट होता है: वह वर्शन जिसे आपके एनरिचमेंट और आपका डेटाबेस वास्तव में इस्तेमाल करते हैं। स्कीमा को एडिट करना सिर्फ़ एक वर्किंग कॉपी को छूता है — शब्दावली के बदलाव अपने-आप लागू हो जाते हैं, जबकि संरचनात्मक बदलाव (नए फ़ील्ड, टाइप या की में बदलाव) तब तक इंतज़ार करते हैं जब तक आप Publish नहीं दबाते। प्रकाशित करने पर सटीक प्रभाव का पूर्वावलोकन दिखता है और सही माइग्रेशन डेल्टा फ़ीड में भेजा जाता है: नए कॉलम ALTER TABLE डेल्टा के रूप में आते हैं, और भारी बदलाव (एक नई डेटाबेस की, एक टाइप बदलाव) आपके अपने डेटाबेस पर गार्डेड माइग्रेशन के रूप में चलते हैं — अगर डेटा उन्हें रोकता है (कोई गुम या डुप्लिकेट की वैल्यू), तो फ़ीड सटीक समस्या के साथ रुक जाती है और आपके ठीक करते ही अपने-आप दोबारा कोशिश करती है।
पब्लिशिंग डेटाबेस के Model टैब में होती है (जब तक स्कीमा लिंक रहता है, Workflow Editor वहां इशारा करता हुआ एक बैनर दिखाता है)। पब्लिश करने से पहले, यह दोनों पक्ष दिखाता है: वह कॉन्ट्रैक्ट जिस पर आपका डेटाबेस आज है, और उन सभी बदलावों का diff जो आपकी वर्किंग कॉपी करेगी। किसी एडिट से संतुष्ट नहीं? पब्लिश किए गए पर वापस लौटें कॉन्ट्रैक्ट को वापस रख देता है — यह undo किया जा सकता है, और जो ड्राफ़्ट आपने अलग रखा था वह 24 घंटे तक पुनर्स्थापित करने योग्य रहता है।
एक ऐसी स्कीमा को दोबारा लिंक करना जिसे अनलिंक रहते हुए एडिट किया गया था, उसी तरह काम करता है: सिंक याद रखता है कि आपके डेटाबेस में पहले से क्या है और सिर्फ़ अंतर भेजता है, साथ ही बीच में लिखी गई रो के लिए एक स्नैपशॉट रिफ़्रेश भी। कभी भी मैन्युअल DROP नहीं।
यही वादा हमारे अपने अपग्रेड पर भी लागू होता है। जब कोई नया रिलीज़ यह सुधारता है कि schemas किस तरह tables से मैप होते हैं, तो आपका sync आपके लिए माइग्रेट कर दिया जाता है — additive बदलाव अपने आप फ़ीड में आ जाते हैं। यदि कोई अपग्रेड उन tables को फिर से आकार देता है जो आप पहले से रखते हैं, तो हम आपके डेटा को बिना सूचना कभी नहीं छूते: डिलीवरी रुक जाती है और आपका Database Sync पेज आपसे इसे लागू करने के लिए कहता है, पहले ठीक-ठीक यह दिखाते हुए कि क्या बदलता है।
बहुभाषी enrichment यहाँ भी प्रथम-श्रेणी है: स्थानीयकृत मान enrichment की हर भाषा वाले JSONB columns के रूप में आते हैं — {"en": "Headache", "fr": "Céphalée"} — ताकि एक ही database आपके सभी locales को एक साथ सेवा दे। अपनी queries में ही एक भाषा चुनें (name->>'fr'), और JSON delta payloads उन्हीं भाषा-कुंजीबद्ध objects को ले जाते हैं।
हर डेटाबेस रजिस्ट्रेशन के समय एक सवाल का जवाब देता है: जब कोई संवर्धन कमियों के साथ लौटे — यानी non-nullable फ़ील्ड अधूरी रह जाएँ — तो क्या लिखा जाता है? तीन जवाब मिलकर एक सीढ़ी बनाते हैं। कुछ नहीं: कहीं भी एक कमी, चाहे किसी नेस्टेड ऑब्जेक्ट के भीतर हो, और एंटिटी अस्वीकार हो जाती है। एंटिटी, उसके अधूरे चाइल्ड्स के बिना (डिफ़ॉल्ट): एंटिटी की अपनी पंक्ति पूरी होनी चाहिए, पर टूटा हुआ चाइल्ड पूरे संवर्धन को डुबोने के बजाय छोड़ दिया जाता है और रिपोर्ट कर दिया जाता है। सब कुछ: कमियाँ NULL बनकर दर्ज होती हैं और कुछ भी अस्वीकार नहीं होता — लेकिन एंटिटी स्टेट last-write-wins है, नवीनतम संवर्धन ही पंक्ति है, इसलिए बाद का कोई अधूरा रन वह मिटा देता है जो पहले किसी रन ने भरा था। ठीक यही मिटाव रोकने के लिए दोनों सख़्त स्तर मौजूद हैं।
जो संवर्धन गेट में विफल होते हैं, वे फिर भी रिकॉर्ड के रूप में सहेजे जाते हैं और record.created वेबहुक भी ट्रिगर करते हैं — database.saved को false के साथ — जो आपको ठीक-ठीक बताता है कि कौन-से आवश्यक फ़ील्ड गायब थे — ताकि अधूरा डेटा कभी चुपचाप गायब न हो। हर गायब फ़ील्ड यह भी बताता है कि मॉडल ने उसे अज्ञात घोषित किया या बस छोड़ दिया: पहले के लिए एक अधिक सक्षम मॉडल, वेब सर्च या स्रोत दस्तावेज़ चाहिए, और दूसरे के लिए स्कीमा या इनपुट पर एक नज़र। केवल डेटाबेस की फ़ील्ड हमेशा आवश्यक होते हैं: जिस संवर्धन में की का मान गायब हो, वह किसी भी स्तर पर अस्वीकार कर दिया जाता है।
सख़्त स्तरों पर, एक चेकबॉक्स इसी कॉन्ट्रैक्ट को आपके अपने डेटाबेस में हर हमेशा-मौजूद फ़ील्ड पर NOT NULL कॉलम के रूप में दोहराता है। सबसे सख़्त स्तर पर आवश्यक रेफ़रेंस की फ़ॉरेन की भी कंस्ट्रेन्ड होती हैं — स्वीकृत किसी पंक्ति में वे अनुपस्थित नहीं हो सकतीं। अधूरे चाइल्ड छोड़ें के तहत वे जानबूझकर nullable रहती हैं: अपनी कोई वैल्यू न रखने वाला लिस्ट आइटम हटा दिया जाता है, और जिस साझा वन-टू-वन रेफ़रेंस का टारगेट अधूरा है (वह स्टेडियम जिसका उद्घाटन वर्ष कोई नहीं जानता) उसे डिटैच कर दिया जाता है — वह टारगेट न लिखा जाता है न अपडेट होता है, और सहेजी गई पंक्ति वहाँ किसी से नहीं जुड़ती, यानी ठीक उन्हीं फ़ॉरेन-की कॉलमों में NULL लिख दिया जाता है। दोनों की जानकारी संवर्धन रिस्पॉन्स में दी जाती है, और टॉप-लेवल फ़ील्ड की कमियाँ हमेशा अस्वीकार कराती हैं। पहले सिंक के बाद पॉलिसी बदलना कभी बेकार मेहनत नहीं होती: वह फ़ीड में एक गार्डेड माइग्रेशन के रूप में जाती है, आपके डेटाबेस में पहले से मौजूद पंक्तियों के विरुद्ध वैलिडेट की हुई।
दूसरा गेट डुप्लिकेट पहचानों को पकड़ता है: जब एक ही सूची की दो आइटम एक ही डेटाबेस की पर पहुँचती हैं — मॉडल ने दो अलग कंपनियों के लिए एक ही id गढ़ दी हो, या की उन्हें अलग न कर पाती हो — तो केवल एक ही row रह सकती है, इसलिए आखिरी वाली लिखी जाती है और पहले वाली हटा दी जाती हैं; वही last-write-wins नियम जो हर जगह लागू है। हर टकराव की रिपोर्ट दोनों आइटम की पहचान वाली वैल्यू और एक फ़ैसले के साथ दी जाती है: डुप्लिकेट ने वही वैल्यू दोहराईं और कुछ नहीं खोया, जबकि परस्पर विरोधी हटाव ने वे वैल्यू खो दीं जिनका वह नाम लेता है — या तो मॉडल ने एक ही चीज़ को गड़बड़ वैल्यू के साथ दोहराया, या ये अलग-अलग चीज़ें हैं और की को एक विभेदक प्रॉपर्टी चाहिए (कोई क्षेत्र, कोई वर्ष, कोई संस्करण)। यह सूची रिकॉर्ड पर रखी जाती है, ताकि आंशिक राइट भी रिस्पॉन्स के बहुत बाद तक बता सके कि उसने क्या खोया।
पुनः एनरिचमेंट से पहले एक बात जान लें: जो सूची अपने पैरेंट की होती है, उसके लिए नवीनतम एनरिचमेंट की सूची ही असली सूची है। कोई चाइल्ड रो जिसे नवीनतम उत्तर दोहराता नहीं, वह आपके डेटाबेस से हटा दी जाती है — असली रिमूवल इसी तरह आप तक पहुँचता है, और रिस्पॉन्स इसकी रिपोर्ट नहीं करता। यह तब मायने रखता है जब सूची ऐसी हो जिसे मॉडल गिनने के बजाय याद करके बताता है: किसी तत्व के आइसोटोप या किसी व्यक्ति के पुरस्कार दो बार पूछें और दूसरा उत्तर छोटा हो सकता है, जिससे वे रो हट जाती हैं जो सही थीं। यदि आपको हर रन का संघ (यूनियन) चाहिए तो अपना खुद का इतिहास संभालकर रखें।
संवर्धन अपने आप लिंक किए गए डेटाबेस तक पहुँच जाते हैं। बाकी सब कुछ — ऐसा परिणाम जिसे स्कीमा ठीक करने से पहले गेट ने अस्वीकार कर दिया, ऐसा रन जिसे आपने जान-बूझकर बाहर रखा, या ऐसा आउटपुट जिसे आप पहले देखना या सुधारना चाहते हैं — डेटाबेस में रिकॉर्ड भेजने से होकर जाता है: उन्हें इतिहास पेज पर चुनें, या वर्कफ़्लो से API कॉल करें।
राउंड-ट्रिप। Database Sync बंद करके संवर्धन करें, परिणाम को अपने वर्कफ़्लो में नया रूप दें या स्वीकृत करें, फिर उसे भेजें। आप जो भेजते हैं उसे स्कीमा के प्रकाशित कॉन्ट्रैक्ट के विरुद्ध दोबारा वैलिडेट किया जाता है और उसी एडमिशन गेट से गुज़ारा जाता है जिससे कोई संवर्धन गुज़रता है — इंजेक्शन कभी वह नहीं लिख सकता जो संवर्धन नहीं लिख सका।
जानने योग्य दो बातें। किसी रिकॉर्ड को बिना बदले भेजने पर वह उसी रिकॉर्ड के अंतर्गत संग्रहित होता है। संशोधित आउटपुट भेजने पर एक नया रिकॉर्ड बनता है जो मूल रिकॉर्ड की ओर इशारा करता है, क्योंकि रिकॉर्ड एक ऑडिट ट्रेल हैं: उन्हें उद्धृत करने वाले डेटा के नीचे वे कभी नहीं बदलते, इसलिए आपके डेटाबेस में जो है वह हमेशा ठीक उन्हीं मानों वाले रिकॉर्ड तक ट्रेस किया जा सकता है। और मान्यता जाँच कॉन्ट्रैक्ट के आज के स्वरूप का उपयोग करती है — यदि रिकॉर्ड बनने के बाद स्कीमा बदल गया है, तो History पेज भेजने से पहले उसे चिह्नित कर देता है।
History पेज हर रिकॉर्ड के लिए यह भी दिखाता है कि वह डेटाबेस तक पहुँचा या नहीं: भेजा गया, आंशिक रूप से भेजा गया, या कारण सहित अस्वीकृत। वेब ऐप, API, MCP, n8n और Make से उपलब्ध।
फ़ीड हर डेटाबेस के लिए एक सख़्त FIFO कतार है: एक विंडो fetch करें (वैकल्पिक रूप से लीज़ के साथ, ताकि क्रैश हुए वर्कर का बैच किसी भी नए डेटा से पहले दोबारा डिलीवर हो), उसे लागू करें, और acknowledge करें। वेबहुक नोटिफ़िकेशन डिबाउंस किए जाते हैं — हर नया डेल्टा quiet-period टाइमर रीसेट कर देता है, ताकि एनरिचमेंट की एक झड़ी की सूचना एक ही बार जाए; एक कॉन्फ़िगर करने योग्य अधिकतम देरी इस प्रतीक्षा की सीमा तय करती है, और पूरा भर चुका fetch पेज तुरंत ट्रिगर हो जाता है। दो पर्ज विकल्प तय करते हैं कि Entity Enricher क्या रखता है: acknowledgement पर डिलीवर हो चुकी डेल्टा कॉपियाँ हटाना, और — डेटा मिनिमाइज़ेशन के लिए — एंटिटी स्टेट को ही हटाना, जब स्कीमा से जुड़ा हर डेटाबेस उसे प्राप्त कर ले। दोनों में दिनों में एक वैकल्पिक देरी दी जा सकती है: तब डिलीवर हो चुकी कॉपियाँ acknowledgement के बाद उतने समय तक बनी रहती हैं (एक रीप्ले विंडो), और डिलीवर हो चुकी एंटिटी तब तक रखी जाती है जब तक उतने समय तक उसमें कोई अपडेट न आए; प्रति घंटा चलने वाला पर्ज एक्सपायर हो चुके डेटा को हटा देता है। ध्यान दें कि स्टेट पर्ज मिनिमाइज़ेशन है, इरेज़र नहीं: एनरिचमेंट रिकॉर्ड तब तक बने रहते हैं जब तक आप उन्हें ख़ुद न हटाएँ, और यह पर्ज की गई एंटिटीज़ के लिए क्रॉस-एनरिचमेंट मर्जिंग बंद कर देता है।
प्रति-टेबल checksum endpoint आपको किसी भी समय यह सत्यापित करने देता है कि आपका रेप्लिका कन्वर्ज हो गया है, बिना कुछ भी फिर से डाउनलोड किए।
सब कुछ ऐप में एक ही जगह मिलता है — Database Sync, साइडबार में History के ठीक नीचे: किसी भी स्कीमा पर डेटाबेस रजिस्टर करें (डेटाबेस की-रिव्यू के साथ), स्कीमा लिंक या अनलिंक करें, किसी लिंक्ड स्कीमा के एनरिचमेंट फ़ीड को उसके स्विच से रोकें (दोबारा चालू करने तक कोई नया डेटा या नोटिफिकेशन नहीं — स्कीमा पब्लिकेशन फिर भी अपना DDL भेजते हैं, और रुकाव के दौरान चली एनरिचमेंट रेप्लिका तक सिर्फ़ स्नैपशॉट री-पुल से पहुँचती हैं), उसके विकल्प एडिट करें, वेबहुक एंडपॉइंट देखें और उसकी साइनिंग की दिखाएँ, स्नैपशॉट डाउनलोड करें, मौजूदा एंटिटी स्टेट ब्राउज़ करें, पेंडिंग डेल्टा क्यू जाँचें (केवल-पढ़ने योग्य — आपके वर्कफ़्लो का कर्सर कभी नहीं छुआ जाता), और जनरेट हुई टेबलों का एंटिटी-रिलेशनशिप डायग्राम उनकी कीज़ और जंक्शनों के साथ देखें। मल्टी-डेटाबेस सिंक पर डायग्राम एक स्कीमा पर फ़ोकस कर सकता है: दूसरी स्कीमाओं से फ़ीड होने वाली टेबलें, कॉलम और लिंक धूसर पड़ जाते हैं — अपनी जगह दिखते फिर भी रहते हैं — जिससे आप ठीक-ठीक देख पाते हैं कि हर स्कीमा साझा टेबलों में क्या योगदान देता है।
जब कई डेटाबेस एक ही मशीन पर आते हैं, तो Sync hosts टूलबार बटन हर डेटाबेस के लिए अलग पेयरिंग की झंझट खत्म कर देता है: उस मशीन को एक बार पेयर करें, फिर उसे रजिस्ट्रेशन असाइन करें। होस्ट हर एक को क्लेम करता है, फ़िज़िकल डेटाबेस मौजूद न होने पर उसे बनाता है, और सिंक करना शुरू कर देता है — यानी डेटाबेस रजिस्टर करना यहीं लिया गया एक निर्णय बन जाता है, सर्वर पर कोई टर्मिनल सेशन नहीं। पेयरिंग हर Entity Enricher सर्वर के लिए अलग होती है, इसलिए एक मशीन कई इंस्टेंस को साथ-साथ सर्व कर सकती है।
आपका डेटाबेस जिस स्टेटमेंट को अस्वीकार करता है — आमतौर पर इसकी वजह किसी नए यूनिक इंडेक्स के तहत पहले से मौजूद डुप्लिकेट होते हैं — वह अपने पीछे की कतार को नहीं अटकाता। उस एनरिचमेंट का बैच क्वारंटीन कर दिया जाता है, फ़ीड चलती रहती है, और वह बैच Quarantine टैब में उस स्टेटमेंट के साथ सूचीबद्ध हो जाता है जिसे आपके डेटाबेस ने अस्वीकार किया था। वजह ठीक करें और दोबारा इंजेक्ट करें — जो किसी पुराने स्टेटमेंट को दोहराने के बजाय एंटिटी को उसकी वर्तमान स्थिति से फिर से प्रोजेक्ट करता है — या उसे हटा दें।
GET /api/databases//changes?since=…&format=sql फिर POST /api/databases//ack।Supabase इस्तेमाल कर रहे हैं? हमारी Supabase MCP तुलना JSON और छोटे टेबल डायग्राम के साथ दिखाती है कि EE के रिलेशनशिप और sync नियम प्रोडक्ट कैटलॉग की रक्षा कैसे करते हैं।
sync में कुछ भी कभी आपके डेटाबेस सर्वर पर नहीं चलता — ऊपर दिया गया हर path एक outbound consumer है जो आपके दिए गए किसी भी DSN से जुड़ता है। Azure Database for PostgreSQL, OVHcloud, AWS RDS, Supabase या कोई भी अन्य managed instance ठीक एक self-hosted instance की तरह ही काम करता है: consumer को cloud DSN की ओर इंगित करें (managed provider आमतौर पर TLS लागू करते हैं, इसलिए sslmode=require जोड़ें) और लागू करें।
--dsn को managed instance की ओर इंगित करता है, बस इतना ही काफी है।delta_available webhook एक Azure Function / AWS Lambda / OVHcloud function को जगाता है जो REST feed खींचता है, SQL चलाता है, और acknowledge करता है।दो नियम किसी भी हाथ से बनाए गए consumer को सुरक्षित रखते हैं: प्रत्येक batch के statements को क्रम में, एक ही transaction के भीतर निष्पादित करें, और केवल commit के बाद acknowledge करें। Deltas idempotent और revision-guarded होते हैं, इसलिए acknowledgement से पहले क्रैश होने का मतलब बस यह है कि batch फिर से डिलीवर हो जाता है और दोबारा लागू करने पर परिणाम एक जैसा रहता है।
डेटाबेस पेड प्लान्स में उपलब्ध हैं (आप कितने रजिस्टर कर सकते हैं, यह प्लान तय करता है)। लॉन्च डायलेक्ट PostgreSQL है; हर डेटाबेस अपना डायलेक्ट घोषित करता है, और MySQL / MariaDB, SQL Server तथा Oracle प्रस्तावित हैं।