تخطَّ إلى المحتوى
kazma.
البحث في كاظمه والتوثيق
EN

الترحيل (بين الأجهزة)

الترحيل بين الأجهزة (kazma migrate)

Section titled “الترحيل بين الأجهزة (kazma migrate)”

انقل تثبيت كاظمه كاملًا — الإعدادات، والأسرار، والذاكرة، وسجل الدردشة، واللقطات، والمهام المجدولة، والأصول — من جهاز إلى آخر (WSL→Windows، أو Linux→Mac، أو خادم→حاسوب محمول) دون الأعطال الصامتة التي يسببها النسخ واللصق الساذج.

ينهار النسخ الساذج للملفات بثلاث طرق محددة: تصبح الخزنة المشفرة غير قابلة لفك التشفير (مفتاح خاطئ)، وتشير المسارات المضمّنة في الملفات إلى مسار ميت /home/user/...، وبيانات Postgres (سجل الدردشة، والإعدادات، ونقاط التفتيش) لا يشملها النسخ إطلاقًا. يمنع kazma migrate الثلاثة جميعًا.


على الجهاز المصدر:

نافذة طرفيّة
kazma migrate export --out my-kazma.zip

على الجهاز الهدف (بعد نسخ my-kazma.zip إليه):

نافذة طرفيّة
kazma migrate verify my-kazma.zip
kazma migrate import my-kazma.zip --workspace /path/to/kazma --dry-run # preview first
kazma migrate import my-kazma.zip --workspace /path/to/kazma # real import

هذا كل شيء لتثبيت يعتمد على SQLite. للمصادر المعتمدة على Postgres، انظر § هجرة Postgres أدناه.


أرشيف .zip يحتوي على:

الملفالمحتوى
manifest.jsonالإصدار، ونظام/مضيف المصدر، وبصمة sha256 لكل ملف، وبصمة مفتاح الخزنة، وأعداد الجداول
meta.envKAZMA_VAULT_KEY + KAZMA_PUBLIC_URL (لازمة لفك تشفير الخزنة + OAuth)
config.yamlكل إعدادات ConfigStore (الأسرار مراجع vault:// وليست نصًا صريحًا)
data/vault.dbمخزن الأسرار المشفر (29+ سرًّا) — ينتقل مع مفتاح الخزنة
data/*.dbكل قواعد بيانات SQLite (اللقطات، والذاكرة، وcron، والدردشة، ونقاط التفتيش، إلخ)
data/documents.dbالبيانات الوصفية لـذكاء المستندات (الإصدارات، وACL، والتدقيق، والمهام حين تكون على SQLite) عند وجود مخزن المنصة
document-store/ (شجرة الحزمة)الكتل المعنونة بالمحتوى + البيانات الوصفية التي يشير إليها فهرس المستندات (documents.db، أو فهرس Postgres في data/postgres.dump؛ شجرة SHA-256 غير قابلة للتغيير). تُستعاد إلى documents.storage_root الهدف
data/postgres.dumpنسخة Postgres الاحتياطية (فقط عندما يكون المصدر معتمدًا على Postgres)
data/workspaces.dbجدول مساحات العمل (تُعاد كتابة المسارات الجذرية عند الاستيراد)
assets/كل ما ينتقل غير ذلك من مجلد البيانات: سجل عمّال السرب وقوالبه، ومرفقات الدردشة، والمستندات، والتصديرات، والصور، ومساحة العمل الافتراضية، وأي ملف تحفظه أنت (أو الوكيل) هناك. ولا يُحمَل: هوية التثبيت (install_id)، ونسخه الاحتياطية، وسجلاته، وما يُعاد بناؤه (المتجهات وفهارس الشيفرة)
pathmap.jsonجذر مساحة عمل المصدر + دليل البيانات (لترجمة المسارات)

ملاحظات مخزن المستندات: لا يحتوي documents.db على أي مسارات مطلقة مضمّنة تحتاج إعادة كتابة (المحتوى معنون بالمحتوى). يأخذ التصدير لقطة من قاعدة البيانات أولًا، ثم ينسخ الكتل والبيانات الوصفية التي تشير إليها؛ والكتلة المُشار إليها المفقودة تُعلِّم الحزمة بأنها ناقصة، فيرفضها verify (ومن ثَمّ import). يَنسخ الاستيراد documents.db الموجود لدى الهدف إلى النسخة الاحتياطية السابقة للاستيراد (بأفضل جهد)، ويُثبِّت القاعدة المُجهَّزة، ويضيف ملفات المحتوى المُجهَّزة التي يفتقدها الهدف (وتُبقى الملفات الموجودة أصلًا)، في جذر مخزن المستندات الذي يُحل بعد استيراد الإعدادات، حتى يُحترم documents.storage_root المخصص؛ ولا يُثبَّت documents.db إلا حين يكون فهرس الهدف على SQLite. ومخزن المستندات الذي تفشل استعادته يُفشل الاستيراد (ok: false؛ منذ 2026-10-13 — كان تحذيرًا بجانب استيراد ناجح). انظر عمليات معالجة المستندات.

مخزن مستندات على Postgres ينتقل فهرسًا وملفات (منذ 2026-10-13). حين تكون البيانات الوصفية للمستندات على Postgres (KAZMA_DOCUMENTS_METADATA_BACKEND=postgres، أو auto/غير مضبوط في تثبيت يعمل على Postgres)، يكون الفهرس داخل data/postgres.dump ويؤخذ أولًا، ثم ينسخ المُصدِّر كل ملف محتوى وبيانات وصفية يشير إليه من جذر التخزين (وحتى ذلك التاريخ كان يقرأ documents.db المحلي الفارغ ولا يحمل أي ملف محتوى). وتقرّر واجهة سطر الأوامر بحسب الخلفيات المضبوطة، إذ لا خدمة عاملة لديها. ويُرفض بالاسم فهرسُ Postgres بجانب طابور SQLite (وضع احتياطي). والتثبيت الذي بياناته الوصفية للمستندات على SQLite بجانب مهام على Postgres يحمل documents.db ومحتواه (والترقيات المقروءة من الطابور) ومهامه داخل data/postgres.dump، مأخوذة في لحظات مختلفة. ولنقل مخزن عند لحظة زمنية واحدة بدلًا من ذلك، استخدم النسخ الاحتياطي المنسَّق للمستندات (python scripts/document_pg_backup.py backup على المصدر؛ وعلى الهدف، بعد kazma migrate import، ‏restore ... --replace-document-tables): انظر معالجة المستندات ← النسخ الاحتياطي.


هذه أنماط الانهيار الصامت التي يمنعها kazma migrate:

أ. إقران الخزنة — vault.db + KAZMA_VAULT_KEY ينتقلان معًا

Section titled “أ. إقران الخزنة — vault.db + KAZMA_VAULT_KEY ينتقلان معًا”

ملح تشفير الخزنة يعيش داخل vault.db، لذا فقاعدة البيانات غير قابلة لفك التشفير بدون مفتاحها المطابق. تحمل الحزمة كليهما. عند الاستيراد:

  • المفاتيح متطابقة → يُثبَّت vault.db وتُفك شيفرات الأسرار. ✅
  • مفتاح الهدف فارغ → يُكتب مفتاح الحزمة إلى .env الهدف. ✅
  • المفاتيح مختلفة → يُجهَض الاستيراد إلا إذا مررت --reset-vault-key (الذي يأخذ نسخة احتياطية من vault.db الموجودة في الهدف أولًا، ثم يكتب مفتاح الحزمة).
نافذة طرفيّة
kazma migrate import my-kazma.zip --workspace /path --reset-vault-key

ب. ترجمة المسارات — إعادة كتابة المسارات المضمّنة تلقائيًا

Section titled “ب. ترجمة المسارات — إعادة كتابة المسارات المضمّنة تلقائيًا”

التثبيت المصدر عند /home/user/kazma يكون قد خبّز ذلك المسار داخل workspaces.root_path، وsnapshots.state_json (كتل SupervisorState الكاملة)، ورسائل الدردشة، وحلقات الذاكرة، ومحفزات cron. يعيد المُستورد كتابتها جميعًا إلى المسار الهدف، عبر اصطلاحات فواصل المسار بين أنظمة التشغيل.

\Users\me\kazma
# Linux source → Windows target
kazma migrate import my-kazma.zip --workspace "C:\Users\me\kazma"

إعادة الكتابة سلسلة فرعية على مستوى البايت (وليست تحليل JSON) لذا تتعامل بكفاءة مع snapshots.db بحجم 300+ MB. ترتيب بادئات المسار يمنع إعادة الكتابة الجزئية (/home/u/kazma لن يُفسد /home/u/kazma-repos/ShipX).

ج. الاستيراد الذرّي — تجهيز → نسخ احتياطي → تبديل

Section titled “ج. الاستيراد الذرّي — تجهيز → نسخ احتياطي → تبديل”

الاستيراد لا يمس البيانات الحية أثناء التنفيذ:

  1. التجهيز — فك ضغط الحزمة إلى kazma-data/.migrate-staging-<ts>/
  2. إعادة كتابة المسارات للنسخ المُجهَّزة
  3. نسخة احتياطية لقواعد البيانات الحية إلى kazma-data/.migrate-backup-<ts>/
  4. التبديل: التجهيز → الحي (آمن مع WAL، ملف واحد في كل مرة)

الفشل قبل التبديل يترك البيانات الحية دون مساس. يُحتفظ بدليل التجهيز عند الفشل للفحص. للتراجع: انسخ ملفات .db من دليل النسخة الاحتياطية فوق الملفات الحية.


عندما يكون المصدر معتمدًا على Postgres، تتضمن الحزمة أيضًا data/postgres.dump منتَجًا بواسطة pg_dump -Fc (تنسيق مخصص — يتعامل مع كتل bytea أصليًا، أصغر بنحو 7× من النص العادي).

يجد محرك الترحيل الملفات التنفيذية تلقائيًا:

  1. pg_dump / pg_restore على PATH
  2. docker exec ${KAZMA_DB_CONTAINER:-kazma-db} <bin> — الخيار الافتراضي الشائع لنشر Docker
  3. خطأ واضح مع تلميح تثبيت إن لم يتوفر أي منهما

لتجاوز اسم الحاوية:

نافذة طرفيّة
KAZMA_DB_CONTAINER=my-postgres kazma migrate export --out my-kazma.zip

يجب أن يكون لدى الهدف KAZMA_DB_BACKEND=postgres + KAZMA_DATABASE_URL مضبوطَين:

نافذة طرفيّة
export KAZMA_DB_BACKEND=postgres
export KAZMA_DATABASE_URL=postgresql://kazma:kazma_change_me@127.0.0.1:5433/kazma
export KAZMA_DB_CONTAINER=kazma-db-win
kazma migrate import my-kazma.zip --workspace /path/to/kazma --reset-vault-key

يعيد pg_restore --clean --if-exists إنشاء المخطط (يمكن لقاعدة بيانات الهدف أن تكون فارغة)، ثم يحمل البيانات. تُستعاد ملفات SQLite (الخزنة، والذاكرة، واللقطات) جنبًا إلى جنب.

عند تشغيل pg_dump / pg_restore عبر docker exec، تُنفَّذ داخل الحاوية، حيث يستمع Postgres على localhost:5432 — وليس على منفذ المضيف المُمرَّر (مثل 5433). يكتشف المحرك حالة Docker ويتجاوز تلقائيًا. تجاوز المنفذ الداخلي إذا كانت حاويتك تستمع في مكان آخر:

نافذة طرفيّة
KAZMA_DB_INTERNAL_PORT=5432 # default; change only if your container differs

نافذة طرفيّة
kazma migrate export [--out PATH] [--no-assets]
العلمالافتراضيالغرض
--out PATHkazma-bundle-<timestamp>.zipمسار حزمة المخرجات
--no-assets(الأصول مضمّنة)يترك ملفات مجلد البيانات خارج الحزمة (حزمة أصغر من الإعدادات وقواعد البيانات). ويظل سجل عمّال السرب وقوالبه ينتقلان
نافذة طرفيّة
kazma migrate verify BUNDLE [--no-hash]

يفحص سلامة الحزمة: البنية، وتوافق البيان، وبصمة sha256 لكل ملف، وبصمة مفتاح الخزنة، وأعداد صفوف الجداول. يتخطى --no-hash إعادة حساب التجزئة (البطيئة) لفحص بنيوي سريع.

نافذة طرفيّة
kazma migrate import BUNDLE [--workspace PATH] [--reset-vault-key] [--dry-run]
العلمالافتراضيالغرض
--workspace PATHالدليل الحاليجذر مساحة عمل الهدف (تُعاد كتابة المسارات إليه)
--reset-vault-key(إجهاض عند عدم التطابق)الكتابة فوق مفتاح خزنة الهدف بمفتاح الحزمة (يأخذ نسخة احتياطية من vault.db الموجودة أولًا)
--dry-run(استيراد حقيقي)تحقق + تخطيط فقط؛ دون أي كتابات

المتغيرالافتراضيالغرض
KAZMA_DB_CONTAINERkazma-dbاسم حاوية Docker لاكتشاف pg_dump / pg_restore
KAZMA_DB_INTERNAL_PORT5432منفذ Postgres الداخلي للحاوية (عند التشغيل عبر docker exec)

انظر أيضًا: متغيرات البيئة · قابلية النقل · التعافي من الكوارث


كل استيراد ينشئ نسخة احتياطية ما قبل الاستيراد عند kazma-data/.migrate-backup-<ts>/: قواعد البيانات التي استبدلها، وتحت files/ كل ملف لدى الهدف استبدلته الحزمة بملف مختلف. للتراجع:

نافذة طرفيّة
# Stop Kazma, then copy the backup .db files back over the live ones
cp kazma-data/.migrate-backup-<ts>/*.db kazma-data/
# and the replaced files, if any
cp -r kazma-data/.migrate-backup-<ts>/files/. kazma-data/

التصدير الذي لا يستطيع قراءة ملف يسمّيه في البيان (manifest)، فيرفض verify (ومن ثَمّ import) تلك الحزمة. والاستيراد الذي لا يستطيع استعادة ملف يبلّغ عنه، ولا يبلّغ عن نجاح، ويترك نسخة الحزمة منه في مجلد التجهيز.

بالنسبة إلى Postgres، فإن pg_restore --clean --if-exists غير متغيّر الأثر (idempotent) — إعادة تشغيل الاستيراد تستعيد من الحزمة بشكل نظيف.