لنفرض أن فريقك يعمل بأسلوب Scrum أو Kanban، فالحل الأول الذي يخطر على البال غالباً هو جدول Excel مشترك أو سبورة بيضاء Whiteboard عليها أوراق ملونة، وهذا الحل يعمل في الأسبوع الأول، ولكنه يفشل بسرعة لأنك لا تعرف من غير حالة المهمة ومتى، ولا يصل إشعار Notification لمن ينتظر أن ينهي زميله عمله، وتضيع المرفقات والنقاشات بين البريد والمحادثات. والحل الثاني هو أن تنتقل إلى Jira أو Trello، وهما أداتان ممتازتان، ولكن بيانات مشاريعك كلها سوف تكون على سيرفرات Servers الشركة المزودة، وتدفع اشتراكاً عن كل مستخدم، وقد تفرض عليك الأنظمة أو العقود في مؤسستك أن تبقى هذه البيانات داخلها.
لذلك فالحل الأنسب لكثير من الفرق هو أداة مفتوحة المصدر Open Source تعمل على سيرفرك أنت، وTaiga واحدة من أشهر هذه الأدوات، وهي منصة لإدارة المشاريع Project Management بالأساليب الرشيقة Agile، بنيت في الأصل لفرق تطوير البرمجيات ثم صارت تستخدمها فرق التصميم والتسويق والعمليات أيضاً، ففي المشروع الواحد تجد لوحة Kanban، وقائمة مهام Scrum التي تسمى Backlog مقسمة إلى سبرنتات Sprints مع نقاط التقدير Story Points، وتجد الملاحم Epics التي تجمع قصص المستخدمين User Stories الكبيرة، ومتتبعاً للمشكلات Issues، وWiki، وفيها كذلك تقارير Burndown وWebhooks وتكاملات مع GitHub وGitLab.
وقد يتساءل البعض: هل تصلح Taiga لكل أنواع المشاريع؟ والإجابة أنها تناسب الفريق الذي يريد أداة واضحة وسهلة التعلم تعمل على سيرفراته، وأما إذا كنت تدير محافظ مشاريع كبيرة Project Portfolios وتحتاج إلى مخططات Gantt وإدارة تفصيلية للموارد Resource Management، فهي ليست الخيار الأفضل لك، والسبب أنها مبنية حول الفريق وقصصه وسبرنتاته، وليست مبنية حول الجداول الزمنية وتوزيع الموارد.
لكن تذكر: الإصدار 6 من Taiga هو الذي يحصل اليوم على التحديثات، حيث تتولى صيانته شركة Taiga Cloud Services وأولويتها إصلاح الأخطاء Bug Fixes وتحسين الأداء Performance أكثر من إضافة الميزات، وأما الجيل التالي الذي كان اسمه Taiga Next فقد انتقل إلى فريق آخر وصار منتجاً مستقلاً باسم Tenzu، لذلك لا تنتظر من Taiga 6 تغييرات كبيرة، وإنما إصدارات صيانة Maintenance Releases مثل الإصدار 6.10 الذي نستخدمه في هذا الدليل.
وسوف نناقش في هذا المقال ما يلي:
- الخدمات التسع التي تتكون منها Taiga ودور كل واحدة منها، ثم التثبيت من المستودع الرسمي
taiga-dockerمع ملف.envبأسرار مولدة وتثبيت إصدار كل Image. - إنشاء حساب المدير، وربط النطاق مع شهادة TLS عبر Reverse Proxy يدعم WebSocket.
- إنشاء أول مشروع Kanban، ودعوة الأعضاء بالبريد، وتحديد من يحق له إنشاء المشاريع.
- النسخ الاحتياطي والاستعادة والتحديث، ثم أشهر المشكلات وحلولها.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر Linux بمعالجين CPU وذاكرة RAM بحجم 4 GB، فالحزمة تشغل تسع Containers، ولكن أغلبها خفيف ولا يستهلك إلا القليل.
- Docker Engine مع ملحق Docker Compose كما في دليل تثبيت Docker على Ubuntu، ومعهما
git. - نطاق فرعي Subdomain مثل
tasks.example.comيشير إلى السيرفر (203.0.113.10)، وReverse Proxy يدعم WebSocket ويصدر شهادة TLS، مثل Nginx Proxy Manager. - حساب SMTP ترسل منه Taiga الدعوات وإشعارات التغيير ورسائل إعادة تعيين كلمة المرور Password Reset.
مكونات Taiga وما يفعله كل جزء منها Architecture
قد تبدو Taiga من الوهلة الأولى تطبيقاً واحداً، لكن في الواقع فهي تسع خدمات Services تعمل معاً، ومن المهم أن تعرف دور كل واحدة منها قبل التثبيت، والسبب أن أغلب المشكلات التي سوف تواجهها لاحقاً، مثل التحديثات الفورية التي لا تصل أو المرفقات التي لا تفتح، تعود إلى خدمة بعينها من هذه الخدمات:
| الخدمة | الدور |
|---|---|
taiga-back | واجهة ال API المبنية على Django، ومعها لوحة الإدارة Admin Panel على المسار /admin/ |
taiga-async | نفس ال Image، ولكنها تعمل هنا عاملاً Worker ينفذ مهام Celery في الخلفية Background، مثل التصدير Export والاستيراد Import والإشعارات المؤجلة |
taiga-front | الواجهة Frontend، وهي تطبيق AngularJS يقدمه nginx |
taiga-events | سيرفر WebSocket يرسل التحديثات الفورية Real-time Updates إلى المتصفحات |
taiga-protected | يتحقق من توكنات الوصول Access Tokens قبل أن يقدم المرفقات Attachments، فلا يفتحها إلا من يملك الصلاحية Permission |
taiga-db | قاعدة البيانات Database، وهي PostgreSQL |
taiga-async-rabbitmq وtaiga-events-rabbitmq | وسيطا رسائل Message Brokers من RabbitMQ، الأول لطوابير Queues مهام Celery، والثاني ينقل الأحداث Events من الخلفية Backend إلى taiga-events |
taiga-gateway | سيرفر nginx داخلي يجمع الخدمات السابقة خلف منفذ Port واحد، ويوجه المسارات Paths /api و/admin و/events و/media كل منها إلى خدمته |
تثبيت Taiga خطوة بخطوة Installation
تنزيل المستودع الرسمي taiga-docker
سوف تجد في الإنترنت ملفات Compose جاهزة وImages يبنيها أفراد لتشغيل Taiga، ولا ينصح باستخدامها لأنك لا تعرف متى تتوقف صيانتها ولا ما الذي تغير فيها، لذلك نعتمد على التثبيت الرسمي المبني على المستودع Repository المسمى taiga-docker، وفيه ملف Compose وإعداد nginx للبوابة Gateway وسكربتان مساعدان، وسوف نعمل على الفرع Branch المسمى stable لأنه الفرع الذي يشير إليه التوثيق:
cd /opt
sudo git clone https://github.com/taigaio/taiga-docker.git
cd taiga-docker
sudo git checkout stableوفي المجلد سوف تجد الملفات التالية:
docker-compose.yml: الخدمات التسع.docker-compose-inits.yml: خدمة مؤقتة اسمهاtaiga-manageلتنفيذ أوامر Django الإدارية Management Commands.taiga-gateway/taiga.conf: إعداد nginx الخاص بالبوابة.launch-taiga.shوtaiga-manage.sh: سكربتان يغلفان أوامرdocker composeحتى لا تكتبها كاملة كل مرة..env: ملف الإعدادات Config File، وقيمه الافتراضية غير آمنة، فغيرها كلها كما في الخطوة التالية.
ملف .env بأسرار مولدة Secrets
القيم الافتراضية في ملف .env منشورة في المستودع نفسه، فقيمة SECRET_KEY فيه هي taiga-secret-key وكلمة مرور قاعدة البيانات هي taiga، وأي شخص يقرأ المستودع يعرفها، وهذا خطير لأن SECRET_KEY هو المفتاح الذي توقع به Taiga توكنات الدخول وروابط المرفقات، لذلك قم بتوليد قيم عشوائية أولاً:
for n in SECRET_KEY POSTGRES_PASSWORD RABBITMQ_PASS RABBITMQ_ERLANG_COOKIE; do echo "$n=$(openssl rand -hex 32)"; doneوسوف يطبع الأمر أربعة أسطر بالشكل NAME=قيمة، وكل قيمة منها 64 حرفاً من النظام الست عشري Hexadecimal، والآن قم بكتابة ملف .env كاملاً بهذه القيم، ومعها نطاقك Domain وبيانات SMTP:
sudo nano /opt/taiga-docker/.env# عنوان Taiga
TAIGA_SCHEME=https
TAIGA_DOMAIN=tasks.example.com
SUBPATH=""
WEBSOCKETS_SCHEME=wss
# مفتاح التوقيع؛ يستخدمه back وevents وprotected معاً
SECRET_KEY="ضع_قيمة_SECRET_KEY"
# قاعدة البيانات
POSTGRES_USER=taiga
POSTGRES_PASSWORD=ضع_قيمة_POSTGRES_PASSWORD
# البريد
EMAIL_BACKEND=smtp
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
[email protected]
EMAIL_HOST_PASSWORD=كلمة_مرور_SMTP
[email protected]
EMAIL_USE_TLS=True
EMAIL_USE_SSL=False
# RabbitMQ
RABBITMQ_USER=taiga
RABBITMQ_PASS=ضع_قيمة_RABBITMQ_PASS
RABBITMQ_VHOST=taiga
RABBITMQ_ERLANG_COOKIE=ضع_قيمة_RABBITMQ_ERLANG_COOKIE
# مدة صلاحية روابط المرفقات بالثواني
ATTACHMENTS_MAX_AGE=360
# التسجيل الذاتي والقياس عن بعد
PUBLIC_REGISTER_ENABLED=False
ENABLE_TELEMETRY=Falseفي الإعداد أعلاه لاحظ التالي:
TAIGA_DOMAINهو النطاق كما يكتبه المستخدم في المتصفح دونhttps://، ومع HTTPS اجعلWEBSOCKETS_SCHEME=wss، والسبب أن المتصفح يرفض أن يفتح اتصال WebSocket غير مشفر Unencrypted من صفحة مشفرة.- لا تقم بتفعيل
EMAIL_USE_TLSوEMAIL_USE_SSLمعاً، فالأول للمنفذ 587 مع STARTTLS والثاني للمنفذ 465، وإذا أردت أن تجرب دون سيرفر بريد Mail Server فاجعلEMAIL_BACKEND=console، وهو خيار في Django يكتب الرسائل في سجل Log الخدمةtaiga-backولا يرسلها. PUBLIC_REGISTER_ENABLED=Falseيمنع إنشاء الحسابات من صفحة الدخول، فلا ينضم أحد إلا بدعوة Invitation، وهذا ما تريده غالباً لسيرفر يخص فريقك وحده.ENABLE_TELEMETRY=Falseيوقف إرسال بيانات الاستخدام المجهولة Anonymous Telemetry، وقيمته في الملف الرسميTrue.
وبعد الحفظ اجعل الملف مقروءاً للمالك فقط، لأنه يحمل كل كلمات المرور:
sudo chmod 600 /opt/taiga-docker/.envتثبيت الإصدارات Version Pinning في docker-compose.yml
الحل الأسهل هو أن تشغل ملف Compose الرسمي كما هو، ولكن هذا الحل غير مناسب لسيرفر إنتاج Production لعدة أسباب، فالملف يستخدم الوسم Tag المسمى latest لكل Images الخاصة بـ Taiga، وهذا يعني أن أي أمر pull قد يرقيك إلى إصدار جديد دون أن تقصد، وتنفذ معه ترحيلات قاعدة البيانات Migrations تلقائياً فلا رجوع عنها إلا من نسخة احتياطية، ويعتمد الملف كذلك إصدارات قديمة انتهى دعمها End of Life هي PostgreSQL (12.3) وRabbitMQ (3.8) وnginx (1.19)، وينشر البوابة على المنفذ 9000 لكل عناوين السيرفر. لذلك عدلنا الملف، فثبتنا كل Image على إصدار محدد وحديث، وأطلنا فحص صحة Healthcheck قاعدة البيانات، ومررنا إعداد التسجيل الذاتي Self Registration، وربطنا البوابة بالعنوان المحلي Localhost خلف ال Reverse Proxy.
وأما فحص الصحة فسبب تعديله أن الفحص الأصلي ينتهي على بعض الأقراص قبل أن يكمل PostgreSQL تهيئته الأولى Initialization، فتفشل بقية الخدمات بالخطأ dependency failed to start، والملف بعد التعديل سوف يكون كما يلي:
sudo nano /opt/taiga-docker/docker-compose.ymlx-environment:
&default-back-environment
# قاعدة البيانات
POSTGRES_DB: "taiga"
POSTGRES_USER: "${POSTGRES_USER}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_HOST: "taiga-db"
# Taiga
TAIGA_SECRET_KEY: "${SECRET_KEY}"
TAIGA_SITES_SCHEME: "${TAIGA_SCHEME}"
TAIGA_SITES_DOMAIN: "${TAIGA_DOMAIN}"
TAIGA_SUBPATH: "${SUBPATH}"
PUBLIC_REGISTER_ENABLED: "${PUBLIC_REGISTER_ENABLED}"
# البريد
EMAIL_BACKEND: "django.core.mail.backends.${EMAIL_BACKEND}.EmailBackend"
DEFAULT_FROM_EMAIL: "${EMAIL_DEFAULT_FROM}"
EMAIL_USE_TLS: "${EMAIL_USE_TLS}"
EMAIL_USE_SSL: "${EMAIL_USE_SSL}"
EMAIL_HOST: "${EMAIL_HOST}"
EMAIL_PORT: "${EMAIL_PORT}"
EMAIL_HOST_USER: "${EMAIL_HOST_USER}"
EMAIL_HOST_PASSWORD: "${EMAIL_HOST_PASSWORD}"
# RabbitMQ
RABBITMQ_USER: "${RABBITMQ_USER}"
RABBITMQ_PASS: "${RABBITMQ_PASS}"
# القياس عن بعد
ENABLE_TELEMETRY: "${ENABLE_TELEMETRY}"
x-volumes:
&default-back-volumes
- taiga-static-data:/taiga-back/static
- taiga-media-data:/taiga-back/media
# - ./config.py:/taiga-back/settings/config.py
services:
taiga-db:
image: postgres:16.15-alpine
environment:
POSTGRES_DB: "taiga"
POSTGRES_USER: "${POSTGRES_USER}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 15s
retries: 20
start_period: 30s
volumes:
- taiga-db-data:/var/lib/postgresql/data
networks:
- taiga
restart: unless-stopped
taiga-back:
image: taigaio/taiga-back:6.10.2
environment: *default-back-environment
volumes: *default-back-volumes
networks:
- taiga
depends_on:
taiga-db:
condition: service_healthy
taiga-events-rabbitmq:
condition: service_started
taiga-async-rabbitmq:
condition: service_started
restart: unless-stopped
taiga-async:
image: taigaio/taiga-back:6.10.2
entrypoint: ["/taiga-back/docker/async_entrypoint.sh"]
environment: *default-back-environment
volumes: *default-back-volumes
networks:
- taiga
depends_on:
taiga-db:
condition: service_healthy
taiga-events-rabbitmq:
condition: service_started
taiga-async-rabbitmq:
condition: service_started
restart: unless-stopped
taiga-async-rabbitmq:
image: rabbitmq:4.3.6-management-alpine
environment:
RABBITMQ_ERLANG_COOKIE: "${RABBITMQ_ERLANG_COOKIE}"
RABBITMQ_DEFAULT_USER: "${RABBITMQ_USER}"
RABBITMQ_DEFAULT_PASS: "${RABBITMQ_PASS}"
RABBITMQ_DEFAULT_VHOST: "${RABBITMQ_VHOST}"
hostname: "taiga-async-rabbitmq"
volumes:
- taiga-async-rabbitmq-data:/var/lib/rabbitmq
networks:
- taiga
restart: unless-stopped
taiga-front:
image: taigaio/taiga-front:6.10.3
environment:
TAIGA_URL: "${TAIGA_SCHEME}://${TAIGA_DOMAIN}"
TAIGA_WEBSOCKETS_URL: "${WEBSOCKETS_SCHEME}://${TAIGA_DOMAIN}"
TAIGA_SUBPATH: "${SUBPATH}"
# الواجهة تكتب القيمة في conf.json كما هي، لذلك تكتب بحروف صغيرة: "true" أو "false"
PUBLIC_REGISTER_ENABLED: "false"
networks:
- taiga
restart: unless-stopped
taiga-events:
image: taigaio/taiga-events:6.10.0
environment:
RABBITMQ_USER: "${RABBITMQ_USER}"
RABBITMQ_PASS: "${RABBITMQ_PASS}"
TAIGA_SECRET_KEY: "${SECRET_KEY}"
networks:
- taiga
depends_on:
taiga-events-rabbitmq:
condition: service_started
restart: unless-stopped
taiga-events-rabbitmq:
image: rabbitmq:4.3.6-management-alpine
environment:
RABBITMQ_ERLANG_COOKIE: "${RABBITMQ_ERLANG_COOKIE}"
RABBITMQ_DEFAULT_USER: "${RABBITMQ_USER}"
RABBITMQ_DEFAULT_PASS: "${RABBITMQ_PASS}"
RABBITMQ_DEFAULT_VHOST: "${RABBITMQ_VHOST}"
hostname: "taiga-events-rabbitmq"
volumes:
- taiga-events-rabbitmq-data:/var/lib/rabbitmq
networks:
- taiga
restart: unless-stopped
taiga-protected:
image: taigaio/taiga-protected:6.10.1
environment:
MAX_AGE: "${ATTACHMENTS_MAX_AGE}"
SECRET_KEY: "${SECRET_KEY}"
networks:
- taiga
restart: unless-stopped
taiga-gateway:
image: nginx:1.30.5-alpine
ports:
- "127.0.0.1:9000:80"
volumes:
- ./taiga-gateway/taiga.conf:/etc/nginx/conf.d/default.conf
- taiga-static-data:/taiga/static
- taiga-media-data:/taiga/media
networks:
- taiga
depends_on:
- taiga-front
- taiga-back
- taiga-events
restart: unless-stopped
volumes:
taiga-static-data:
taiga-media-data:
taiga-db-data:
taiga-async-rabbitmq-data:
taiga-events-rabbitmq-data:
networks:
taiga:في الإعداد أعلاه لاحظ التالي:
- كل Image مثبتة على رقم إصدار كامل مثل
taigaio/taiga-back:6.10.2، وبالتالي لا يتغير شيء على السيرفر إلا عندما تغير أنت الرقم بنفسك كما في قسم التحديث. - منفذ البوابة مربوط بالعنوان
127.0.0.1فقط، والسبب أن ال Reverse Proxy وحده هو الذي يجب أن يصل إليه، فلا يستطيع أحد أن يتجاوز شهادة TLS ويفتح Taiga عبرhttp://203.0.113.10:9000. PUBLIC_REGISTER_ENABLEDيكتب بحرف كبيرFalseفيtaiga-backلأن Django يقارنه بالنصTrue، ويكتب بحروف صغيرةfalseفيtaiga-frontلأن الواجهة تنسخ القيمة كما هي إلى ملفconf.json، وإذا وصلتهاFalseبحرف كبير صار الملف JSON غير صالح فلا تستطيع الواجهة قراءة إعداداتها، وهذا هو الشكل الذي يطلبه توثيق Taiga لكل خدمة.restart: unless-stoppedيعيد تشغيل الخدمات تلقائياً بعد إعادة تشغيل السيرفر، وهو غير موجود في الملف الرسمي.
وثبت الوسم أيضاً في docker-compose-inits.yml، حتى تعمل الأوامر الإدارية بنفس الإصدار:
sudo sed -i 's|taigaio/taiga-back:latest|taigaio/taiga-back:6.10.2|' /opt/taiga-docker/docker-compose-inits.ymlpostgres:12.3 فلا تقم بتغيير الوسم مباشرة، بل اتبع قسم التحديث.التشغيل وإنشاء حساب المدير Admin
الآن سوف نقوم بتشغيل الخدمات كلها بالسكربت المساعد:
cd /opt/taiga-docker
sudo ./launch-taiga.shوفي التشغيل الأول ينفذ taiga-back ترحيلات قاعدة البيانات Migrations ويجمع الملفات الثابتة Static Files، وهذا قد يأخذ دقيقة أو اثنتين، لذلك تابع السجل حتى يظهر السطر Listening at: http://0.0.0.0:8000، وهو السطر الذي يعني أن ال API جاهز لاستقبال الطلبات:
sudo docker compose logs -f taiga-backبعد ذلك قم بإنشاء حساب المدير superuser بالسكربت المساعد، وهو يشغل python manage.py في Container مؤقت، ويسألك عن الاسم والبريد وكلمة المرور، وعند انتهائه سوف تجد الرسالة Superuser created successfully.:
sudo ./taiga-manage.sh createsuperuserثم تأكد أن الواجهة وال API يعملان عبر البوابة، فالأمر الأول يجب أن يطبع 200، والثاني يجب أن يعرض الخدمات التسع كلها بحالة running:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:9000/api/v1/
sudo docker compose psربط النطاق مع شهادة TLS
البوابة taiga-gateway تجمع المسارات كلها على المنفذ المحلي 9000، وبالتالي يكفي أن يوجه ال Reverse Proxy كل الطلبات Requests إليها، ففي Nginx Proxy Manager أنشئ Proxy Host للنطاق tasks.example.com يوجه الطلبات إلى المنفذ 9000 على السيرفر، بهذه الإعدادات:
- فعل Websockets Support، والسبب أن المسار
/eventsاتصال WebSocket يبقى مفتوحاً مدة طويلة، ودونه لا تصل التحديثات الفورية إلى المتصفحات. - اطلب شهادة Let's Encrypt مع Force SSL وHTTP/2.
- في تبويب Advanced ضع حداً لحجم الرفع Upload Size يساوي حد البوابة وهو 100M، ومهلة Timeout طويلة لاتصالات الأحداث:
client_max_body_size 100M;
proxy_read_timeout 1d;
proxy_send_timeout 1d;وإذا كنت تستخدم Caddy فيكفي هذا الإعداد، لأن Caddy يمرر اتصالات WebSocket دون إعداد إضافي:
tasks.example.com {
reverse_proxy 127.0.0.1:9000
}وبعد تفعيل HTTPS تأكد أن TAIGA_SCHEME=https وWEBSOCKETS_SCHEME=wss في ملف .env، ثم أعد إنشاء ال Containers حتى تقرأ القيم الجديدة:
cd /opt/taiga-docker
sudo docker compose up -d --force-recreateالاستخدام الأساسي
الدخول وإنشاء أول مشروع
افتح https://tasks.example.com وادخل باسم المدير وكلمة مروره، ولاحظ أن صفحة الدخول لا تعرض رابطاً للتسجيل لأن التسجيل الذاتي معطل:

ومن Projects ← New project تختار قالب المشروع Project Template، فاختر Scrum إذا كان فريقك يعمل بسبرنتات ويقدر المهام بالنقاط، وKanban إذا كان العمل تدفقاً مستمراً Workflow من مهام مستقلة، ويمكنك أيضاً أن تنسخ إعدادات مشروع موجود، أو تستورد مشاريعك من Trello وJira وGitHub:

وفي مثالنا اخترنا Kanban، وأدخلنا اسم المشروع ووصفه، وجعلناه خاصاً Private حتى لا يراه إلا أعضاؤه:

لوحة Kanban وقصص المستخدمين
البطاقة في Taiga اسمها «قصة مستخدم» User Story، وتنتقل القصة بين أعمدة الحالات Statuses وهي New وReady وIn progress وReady for test وDone، وتستطيع أن تضيف قصة بالزر + أعلى أي عمود، أو تضيف عدة قصص دفعة واحدة بالزر الذي بجانبه فيصبح كل سطر تكتبه قصة مستقلة، ثم تسحب البطاقات بين الأعمدة كلما تقدم العمل:

وعندما تفتح أي قصة تستطيع أن تضيف إليها وصفاً ومرفقات ومهام فرعية Tasks وتعليقات، ومن الصفحة نفسها تسندها Assign إلى عضو، وتضيف مراقبين Watchers يصلهم إشعار بكل تغيير، وتقدر نقاطها لكل دور من الأدوار UX وDesign وFront وBack:

ولاحظ أن القالب يحدد الوحدات المفعلة Modules فقط، ويمكنك أن تغيرها لاحقاً من Settings ← Project ← Modules، ففعل Scrum لتحصل على Backlog وسبرنتات، وIssues لتتبع الأخطاء Bugs، وWiki للتوثيق Documentation، وEpics لتجميع القصص الكبيرة:

ومن Settings ← Attributes تعدل أسماء الحالات وألوانها، وأنواع المشكلات وأولوياتها Priorities، بحسب طريقة عمل فريقك، ومن Settings ← Integrations تضيف Webhooks ترسل كل تغيير إلى نظام آخر، ومن هناك أيضاً تربط المشروع بمستودع في GitHub أو GitLab أو Bitbucket أو Gogs، فتتحدث القصص من رسائل ال commit.
دعوة الأعضاء Members وتحديد أدوارهم Roles
من Settings ← Members ← New member تدعو الأعضاء بالبريد وتحدد دور كل واحد منهم، والأدوار الافتراضية هي UX وDesign وFront وBack وProduct Owner وStakeholder، وصلاحيات كل دور تضبطها من Settings ← Permissions، ويمكنك أن تجعل أي عضو مديراً للمشروع:

وتصل الدعوة بالبريد، ومنها ينشئ العضو حسابه حتى والتسجيل العام معطل، وهذا هو الفرق بين الدعوة والتسجيل الذاتي، والرسالة كما يعرضها Mailpit سوف تكون كما يلي:

من يحق له إنشاء المشاريع؟
افتراضياً يستطيع أي مستخدم أن ينشئ ما يشاء من المشاريع دون حد، والمؤسسات غالباً لا تريد ذلك، لأن كل مستخدم سوف ينشئ مشروعه الخاص وتتفرق المهام من جديد. ويمكنك أن تضع حداً لكل مستخدم من لوحة إدارة Django على https://tasks.example.com/admin/ بحساب ال superuser، فافتح Users واختر المستخدم، وفي قسم Project ownerships restrictions حدد أقصى عدد من المشاريع الخاصة والعامة التي يملكها، أو ضع 0 لتمنعه من إنشاء أي مشروع، ثم اضغط Save:

ولكن هذا الحد يطبق على كل مستخدم موجود وحده، وإذا أردت أن تكون القيمة الافتراضية للمستخدمين الجدد صفراً، فلا يوجد متغير بيئة Environment Variable لذلك، وإنما تستخرج ملف الإعداد الذي تستخدمه ال Image، وتضيف إليه سطرين، ثم تربطه Mount بال Containers المسماة taiga-back وtaiga-async، والربط موجود أصلاً في قسم x-volumes كسطر معلق Commented Line هو ./config.py:/taiga-back/settings/config.py. ولاحظ أن الملف المربوط يحل محل الأصلي كله، لذلك نبدأ من نسخة منه:
cd /opt/taiga-docker
sudo docker compose cp taiga-back:/taiga-back/settings/config.py ./config.py
printf "
MAX_PRIVATE_PROJECTS_PER_USER = 0
MAX_PUBLIC_PROJECTS_PER_USER = 0
" | sudo tee -a config.pyثم أزل علامة التعليق عن السطر - ./config.py:/taiga-back/settings/config.py في docker-compose.yml، ونفذ sudo docker compose up -d، وبعده sudo docker compose restart taiga-gateway، والسبب أن البوابة تحفظ عنوان taiga-back القديم وتعيد الخطأ 502 بعد إعادة إنشائه، كما سيأتي في المشكلات الشائعة. وبعد ذلك ارفع الحد يدوياً من لوحة الإدارة لمن يحق له إنشاء المشاريع. لكن تذكر: أنشئ حساباً تجريبياً وتأكد من القيمة الافتراضية قبل أن تعتمد عليها، فهذا الإعداد لا يظهر في واجهة Taiga نفسها.
الدخول الموحد SSO (اختياري)
ال Images الرسمية لـ Taiga تدعم الدخول بحساب GitHub أو GitLab، ومنه GitLab المستضاف ذاتياً Self-hosted، وتفعله عبر متغيرات البيئة مثل ENABLE_GITLAB_AUTH وGITLAB_API_CLIENT_ID وGITLAB_URL في taiga-back، وGITLAB_CLIENT_ID وGITLAB_URL في taiga-front. ولكن انتبه إلى أن Taiga تخفي أزرار الدخول بـ GitHub وGitLab وتعطل إضافتهما ما دام التسجيل الذاتي معطلاً، فلا يعمل هذا الدخول إلا إذا جعلت PUBLIC_REGISTER_ENABLED مفعلاً في الخدمتين، وهذا يعني أن أي شخص لديه حساب على سيرفر GitLab يستطيع أن ينشئ لنفسه حساباً في Taiga، لذلك لا تفعله إلا إذا كان سيرفر GitLab خاصاً بمؤسستك.
وأما الدخول عبر OpenID Connect العام، وهو ما تحتاجه لربط Taiga بنظام مثل Authentik، فليس موجوداً في ال Images الرسمية، والإضافات المتاحة له قديمة أو يصونها أفراد وتحتاج إلى بناء Images مخصصة، لذلك لا ننصح بها في بيئة الإنتاج، والحل الأبسط إذا أردت طبقة حماية موحدة أمام Taiga هو أن تضعها خلف Authentik Forward Auth وتبقي على حسابات Taiga المحلية Local Accounts.
كيف تتأكد أن كل شيء يعمل
- ال API يستجيب عبر النطاق، فالأمر
curl -s -o /dev/null -w '%{http_code}\n' https://tasks.example.com/api/v1/يعيد200. - افتح اللوحة نفسها في متصفحين بحسابين مختلفين وحرك بطاقة في أحدهما، فيجب أن تتحرك في الآخر دون تحديث الصفحة Refresh، وإذا لم يحدث ذلك فاتصال
/eventsلا يمر عبر ال Reverse Proxy. - ارفع مرفقاً إلى قصة وافتحه، ثم انسخ رابطه وافتحه من نافذة خاصة Private Window بعد ست دقائق، فيجب أن يرفض الطلب، والسبب أن صلاحية الرابط لا تتجاوز عدد الثواني في
ATTACHMENTS_MAX_AGE. - ادع عضواً وتأكد أن الدعوة وصلته.
ال Containers التسع تعمل، وحالة taiga-db هي healthy:
cd /opt/taiga-docker
sudo docker compose psالنسخ الاحتياطي Backup والاستعادة Restore
هناك ثلاثة أشياء يجب أن تنسخها: قاعدة PostgreSQL، وال Volume المسمى taiga-media-data وفيه المرفقات والصور الرمزية Avatars وملفات التصدير، وملفات الإعداد .env وdocker-compose.yml وtaiga-gateway/taiga.conf، وأما Volumes الخاصة بـ RabbitMQ والملفات الثابتة فلا تحتاج إلى نسخها لأن Taiga تعيد بناءها عند التشغيل. والأوامر سوف تكون كما يلي:
sudo mkdir -p /opt/backup/taiga
cd /opt/taiga-docker
sudo docker compose exec -T taiga-db pg_dump -U taiga -Fc taiga | sudo tee /opt/backup/taiga/taiga-$(date +%F).dump >/dev/nullsudo docker compose run --rm --no-deps -v /opt/backup/taiga:/backup --entrypoint sh taiga-back -c 'tar czf /backup/media-$(date +%F).tgz -C /taiga-back media'
sudo tar czf /opt/backup/taiga/config-$(date +%F).tgz .env docker-compose.yml docker-compose-inits.yml taiga-gatewayولا تترك هذه الملفات على نفس السيرفر، لأن النسخة التي تضيع مع السيرفر ليست نسخة احتياطية، فانقلها إلى مكان آخر بعد كل تشغيل.
وأما الاستعادة على سيرفر جديد فتكون بأن تعيد ملفات الإعداد إلى /opt/taiga-docker، وتشغل قاعدة البيانات وحدها، ثم تستورد النسخة، وتعيد المرفقات، وبعدها تشغل الخدمات كلها:
cd /opt/taiga-docker
sudo docker compose up -d taiga-db
sudo docker compose exec -T taiga-db pg_restore -U taiga -d taiga --clean --if-exists --no-owner < /opt/backup/taiga/taiga-2026-09-26.dump
sudo docker compose run --rm --no-deps -v /opt/backup/taiga:/backup --entrypoint sh taiga-back -c 'tar xzf /backup/media-2026-09-26.tgz -C /taiga-back'
sudo ./launch-taiga.shويمكنك أيضاً أن تصدر كل مشروع وحده بصيغة JSON من Settings ← Project ← Export، ثم تستورده في أي تثبيت Taiga آخر، وهذا مفيد لنقل مشروع بعينه، ولكنه لا يغني عن نسخ قاعدة البيانات لأنه لا يحمل المستخدمين وإعدادات السيرفر.
التحديث Upgrade إلى إصدار أحدث
خذ نسخة احتياطية أولاً، ثم غير وسوم ال Images الأربع الخاصة بـ Taiga إلى الإصدار الجديد، واسحبها، وأعد التشغيل، وانتبه إلى أن Images الأربع back وfront وevents وprotected قد تختلف أرقام إصداراتها قليلاً، فراجع صفحات الوسوم وملاحظات الإصدار. وعند الإقلاع ينفذ taiga-back الترحيلات الجديدة تلقائياً، وبعد ذلك أعد تشغيل البوابة حتى تعرف العناوين الجديدة للخدمات:
cd /opt/taiga-docker
sudo nano docker-compose.yml
sudo sed -i 's|taigaio/taiga-back:6.10.2|taigaio/taiga-back:6.10.3|' docker-compose-inits.yml
sudo docker compose pull
sudo ./launch-taiga.sh
sudo docker compose restart taiga-gateway
sudo docker compose logs -f taiga-backوالرقم 6.10.3 هنا مثال فقط، فاستخدم الإصدار الذي تريد الانتقال إليه فعلاً.
taiga-back، وهي ثغرة تنفيذ أوامر عن بعد Remote Code Execution سببها فك تسلسل بيانات غير موثوقة Unsafe Deserialization في ال API، ويستطيع استغلالها أي مستخدم لديه حساب في Taiga، وصنفت حرجة Critical، وأصابت الإصدارات 6.8.3 وما قبلها حتى أصلحها الإصدار 6.9.0. والدرس هنا مزدوج، فكل حساب على السيرفر هو شخص قد يستغل ثغرة كهذه، لذلك أبق التسجيل الذاتي معطلاً، وتثبيت الإصدارات لا يعني أن تنسى التحديث، فتابع ملاحظات الإصدار والتنبيهات الأمنية وحدث عند صدورها.وأما ترقية PostgreSQL من تثبيت قديم على postgres:12.3 إلى الإصدار 16 فلا يكفي فيها تغيير الوسم، والسبب أن ملفات البيانات غير متوافقة بين الإصدارات الرئيسية Major Versions، فإذا غيرت الوسم فقط فلن يقلع PostgreSQL الجديد على ملفات الإصدار القديم. والطريقة الآمنة هي أن تأخذ نسخة pg_dump كما في قسم النسخ الاحتياطي، وتوقف الخدمات، وتحذف Volume قاعدة البيانات القديم، وتغير الوسم، ثم تشغل taiga-db فارغة وتستعيد النسخة بالأمر pg_restore:
cd /opt/taiga-docker
sudo docker compose exec -T taiga-db pg_dump -U taiga -Fc taiga | sudo tee /opt/backup/taiga/before-pg16.dump >/dev/null
sudo docker compose down
sudo docker volume rm taiga-docker_taiga-db-data
sudo sed -i 's|postgres:12.3|postgres:16.15-alpine|' docker-compose.yml
sudo docker compose up -d taiga-db
sudo docker compose exec -T taiga-db pg_restore -U taiga -d taiga --no-owner < /opt/backup/taiga/before-pg16.dump
sudo ./launch-taiga.shوقبل الحذف تأكد من اسم ال Volume بالأمر docker volume ls، فاسمه يبدأ باسم المجلد الذي فيه ملف Compose.
مشكلات شائعة وحلولها
dependency failed to start: taiga-db is unhealthy
فحص الصحة في الملف الرسمي يجري 5 محاولات كل ثانيتين، وهذه مدة أقصر من التهيئة الأولى لـ PostgreSQL على بعض السيرفرات، لذلك أطل مدة الفحص كما في الملف أعلاه، ثم شغل ./launch-taiga.sh مرة أخرى فتبدأ ال Containers التي لم تعمل.
التغييرات لا تظهر فوراً لدى الآخرين
السبب هنا أن اتصال WebSocket على /events لا يعمل، فتأكد أن Websockets Support مفعل في ال Reverse Proxy، وأن WEBSOCKETS_SCHEME=wss مع HTTPS، ثم راجع سجل taiga-events، فإذا ظهر فيه خطأ في الاتصال بـ RabbitMQ فتأكد أن RABBITMQ_USER وRABBITMQ_PASS متطابقان في كل الخدمات، وإذا كانت taiga-events-rabbitmq قد أنشئت أول مرة بكلمة مرور مختلفة فأعد إنشاءها بـ Volume فارغ، لأن RabbitMQ يقرأ كلمة المرور من المتغيرات عند الإنشاء الأول فقط.
المرفقات لا تفتح أو تعطي 404
تأكد أن قيمة SECRET_KEY واحدة في taiga-back وtaiga-protected، فكلاهما يقرأ القيمة نفسها من .env، وتأكد أن ال Reverse Proxy لا يعيد كتابة Rewrite المسار /media/، وتذكر أن الحجم الأقصى للمرفق يحدده client_max_body_size في البوابة وفي ال Reverse Proxy معاً.
خطأ CSRF أو تسجيل خروج Logout متكرر
يحدث هذا عندما لا تطابق قيمتا TAIGA_SCHEME وTAIGA_DOMAIN العنوان الذي يفتحه المستخدم فعلاً، مثلاً أن يفتح الموقع عبر HTTPS والإعداد http، والحل أن تصحح القيمتين ثم تعيد إنشاء ال Containers.
الدعوات لا تصل
ابحث عن أخطاء SMTP في سجلي taiga-back وtaiga-async، وتذكر أن EMAIL_BACKEND=console لا يرسل شيئاً وإنما يكتب الرسائل في السجل، وأن EMAIL_USE_TLS وEMAIL_USE_SSL لا يعملان معاً.
الخطأ 502 Bad Gateway بعد تحديث أو إعادة إنشاء خدمة
إذا أعدت إنشاء taiga-back أو taiga-front وحدها، كما يحدث بعد docker compose up -d مع ملف معدل أو بعد سحب إصدار جديد، فسوف تجد أن الموقع يعيد 502، وفي سجل taiga-gateway رسالة connect() failed (111: Connection refused) إلى عنوان IP قديم، والسبب أن nginx في البوابة يحفظ عناوين الخدمات عند إقلاعه ولا يعرف أن ال Container الجديد أخذ عنواناً آخر، والحل أن تعيد تشغيل البوابة بالأمر sudo docker compose restart taiga-gateway.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- جداول Excel لا تكفي لإدارة عمل فريق، وJira وTrello يضعان بياناتك على سيرفرات غيرك، وTaiga تعطيك Scrum وKanban على سيرفرك من المستودع الرسمي
taiga-docker. - ولد كل الأسرار في
.env، وثبت إصدار كل Image بدلlatest، واربط البوابة بالعنوان127.0.0.1خلف Reverse Proxy يدعم WebSocket. - أبق التسجيل الذاتي معطلاً وادع الأعضاء بالبريد، واكتب
PUBLIC_REGISTER_ENABLEDبحرف كبير فيtaiga-backوبحروف صغيرة فيtaiga-front. - انسخ قاعدة البيانات وال Volume المسمى
taiga-media-dataوملفات الإعداد، وانقلها خارج السيرفر. - تابع التنبيهات الأمنية وحدث عند صدورها، وأعد تشغيل البوابة بعد كل تحديث.
سجل التحديثات (Changelog)
- سبتمبر 2026: كتابة الدليل واختباره على Taiga 6.10 (taiga-back 6.10.2).
- أكتوبر 2026: مراجعة تقنية وإعادة اختبار على نفس الإصدارات، وتصحيح قيمة
PUBLIC_REGISTER_ENABLEDفيtaiga-front، وإضافة إعادة تشغيل البوابة بعد التحديث، وتصحيح قسم الدخول الموحد، وتحديث حالة صيانة Taiga 6.