אישורי נייר נמשכים שבועות. מסמכים הולכים לאיבוד, חתימות מזויפות, עובדים מבזבזים זמן על תזכורות בלתי פוסקות. אנו מפתחים זרימות אישור דיגיטליות שמסיימות את הכאוס הזה. המנוע שלנו משתלב באתר או ב-CRM, מנתב מסמכים אוטומטית לאורך מסלולים מוגדרים מראש, שולט בלוחות זמנים, ושומר יומן ביקורת מלא. לא עוד "אבוד במייל" — הכל שקוף בחלון אחד. במשך 5 שנים יישמנו 50+ פרויקטים, והפחתנו את זמן האישור בממוצע פי 3. ניתן לקרוא עוד על מושג זרימת העבודה ב-ויקיפדיה.
בעיות שזרימת האישור פותרת
אם מנהל נמצא בנסיעת עסקים, התהליך נתקע. המנוע שלנו מעלה אוטומטית את המשימה לסגן או מקצה אותה מחדש לפי כללים. פסקי זמן ניתנים להגדרה בשעות — אם אין תגובה, המערכת מזכירה ואז מעלה לרמה גבוהה יותר. שליטה ידנית צורכת שעות: עובדים עוקבים אחר סטטוסים ידנית. אנו מספקים אזור אישי עם ציר זמן המציג כל שלב: מי, מתי, ומה החליט. היוזם רואה התקדמות, המאשרים רואים את המועד האחרון. שגיאות וכפילויות מסולקות: זרימת העבודה מגדירה במדויק את המסלול עם אימות תפקידים. בפרויקט אחד הפחתנו שגיאות ב-90%. אינטגרציה עם EDS (חתימה אלקטרונית) מיושמת דרך ה-API של החותמים, תומכת בתעודות מוסמכות ולא מוסמכות. המעבר לניהול מסמכים אלקטרוני מספק שקיפות מלאה — זו מערכת חתימת המסמכים באתר.
איך אנו בונים זרימת עבודה גמישה?
אנו משתמשים בטכנולוגיה מוכחת: TypeScript + Node.js (Nest.js) בצד השרת, React עם TypeScript בצד הלקוח. לאחסון — PostgreSQL עם JSONB לתבניות שלבים. מנוע המצב מיושם כמיקרוסרוויס נפרד עם טרנזקציות ברורות.
מודל נתונים — תבניות זרימת עבודה, מופעים לכל מסמך, ומשימות אישור. כל משימה מקושרת לשלב, מבצע, ופסק זמן. JSONB בתבנית מאפשר תיאור גמיש של שלבים: סוג (רציף/מקבילי), תנאי מעבר, הסלמה.
-- Шаблоны workflow CREATE TABLE workflow_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(200), description TEXT, steps JSONB NOT NULL, -- Массив шагов с конфигурацией created_by UUID REFERENCES users(id) ); -- Экземпляр workflow для конкретного документа CREATE TABLE workflow_instances ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), template_id UUID REFERENCES workflow_templates(id), document_id UUID REFERENCES documents(id), initiator_id UUID REFERENCES users(id), current_step INT DEFAULT 1, status VARCHAR(50) DEFAULT 'in_progress', -- in_progress, approved, rejected, cancelled metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), completed_at TIMESTAMPTZ ); -- Задачи согласования CREATE TABLE workflow_tasks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), instance_id UUID REFERENCES workflow_instances(id), step_number INT NOT NULL, assignee_id UUID REFERENCES users(id), assignee_role VARCHAR(100), -- Альтернатива assignee_id для динамических ролей task_type VARCHAR(50), -- 'approve', 'sign', 'review' status VARCHAR(50) DEFAULT 'pending', -- pending, approved, rejected, delegated comment TEXT, due_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, completed_by_id UUID REFERENCES users(id) -- Если делегировал ); המנוע מעבד החלטות: אישור — בודק שלב מקבילי (האם כולם אישרו?), ואז עובר לשלב הבא או משלים את זרימת העבודה. דחייה — עוצר את התהליך או מחזיר לתיקון. בקשת שינויים — שולח מסמך ליוזם עם הערה.
class WorkflowEngine { async processDecision( taskId: string, decision: 'approve' | 'reject' | 'request_changes', comment: string, userId: string ) { const task = await db.workflowTasks.findOne(taskId, { include: 'instance.template' }); if (task.assigneeId !== userId) throw new Error('Not authorized'); await db.workflowTasks.update(taskId, { status: decision, comment, completedAt: new Date(), }); await auditLog.record({ action: `task.${decision}`, userId, taskId, instanceId: task.instanceId, }); switch (decision) { case 'approve': await this.onTaskApproved(task); break; case 'reject': await this.onTaskRejected(task); break; case 'request_changes': await this.returnToInitiator(task, comment); break; } } private async onTaskApproved(task: WorkflowTask) { const instance = task.instance; const template = JSON.parse(instance.template.steps); const currentStep = template[task.stepNumber - 1]; // Параллельный шаг: проверяем все ли в этом шаге одобрили if (currentStep.type === 'parallel') { const stepTasks = await db.workflowTasks.findAll({ instanceId: instance.id, stepNumber: task.stepNumber, }); const allApproved = stepTasks.every(t => t.status === 'approve'); const anyRejected = stepTasks.some(t => t.status === 'reject'); if (anyRejected) return this.onTaskRejected(task); if (!allApproved) return; // Ждём остальных } // Переходим к следующему шагу const nextStep = template[task.stepNumber]; // Следующий элемент if (!nextStep) { // Все шаги пройдены — workflow завершён await this.completeWorkflow(instance.id); } else { await this.activateStep(instance.id, nextStep, task.stepNumber + 1); } } private async activateStep(instanceId: string, step: WorkflowStep, stepNumber: number) { await db.workflowInstances.update(instanceId, { currentStep: stepNumber }); const assignees = await this.resolveAssignees(step); const dueAt = step.deadlineHours ? addHours(new Date(), step.deadlineHours) : null; for (const assignee of assignees) { const task = await db.workflowTasks.create({ instanceId, stepNumber, assigneeId: assignee.id, taskType: step.taskType, dueAt, }); await notifyAssignee(assignee, task); } } } איך האצלה והסלמה עובדות?
המאשר יכול להעביר משימה לעמית עם הערה. המערכת סוגרת את המשימה המקורית ויוצרת חדשה עבור הנציג. כל ההאצלות מתועדות ביומן הביקורת.
async function delegateTask(taskId, delegateToId, reason, requesterId) { const task = await db.workflowTasks.findByPk(taskId); if (task.assigneeId !== requesterId) throw new Error('Not authorized'); // Закрываем текущую задачу await db.workflowTasks.update(taskId, { status: 'delegated', comment: `Делегировано: ${reason}`, completedAt: new Date(), }); // Создаём новую для делегата await db.workflowTasks.create({ ...task.toJSON(), id: undefined, assigneeId: delegateToId, status: 'pending', completedAt: null, metadata: { delegatedFrom: task.assigneeId, reason }, }); await notifyDelegate(delegateToId, taskId); } פסקי זמן נבדקים על ידי משימת cron כל שעה. אם משימה באיחור — נשלחת הודעה למאשר והסלמה למנהל. ניתן להגדיר אישור אוטומטי בפסק זמן.
// Cron job: проверяем просроченные задачи каждый час async function processOverdueTasks() { const overdueTasks = await db.workflowTasks.findAll({ status: 'pending', dueAt: { lt: new Date() }, escalationSentAt: null, }); for (const task of overdueTasks) { const step = getStepConfig(task); if (step.escalationUserId) { // Уведомляем руководителя await notifyEscalation(step.escalationUserId, task); await db.workflowTasks.update(task.id, { escalationSentAt: new Date() }); } if (step.autoApproveOnTimeout) { await workflowEngine.processDecision(task.id, 'approve', 'Auto-approved on timeout', 'system'); } } } הצגת התקדמות
היוזם רואה את ציר הזמן של זרימת העבודה: איזה שלב הושלם, מי אישר, מי עדיין לא הגיב, כמה זמן ממתינים. רכיב React עם רשימה אנכית, סמלי סטטוס (✓, ✗, ⏳), וטולטיפים עם הערות.
הודעות
| אירוע | למי | דחיפות |
|---|---|---|
| משימה הוקצתה | מאשר | מיידי |
| מועד אחרון בעוד 4 שעות | מאשר | Push + אימייל |
| משימה באיחור | מאשר + הסלמה | אימייל |
| מסמך אושר | יוזם | באפליקציה + אימייל |
| מסמך נדחה | יוזם | מיידי, כל הערוצים |
למה ליישם זרימת עבודה באתר?
זרימת עבודה על המנוע שלנו מהירה פי 3 מזרימת נייר ויעילה ב-50% יותר מהודעות אימייל פשוטות. אתה מקבל שקיפות, שליטה, וחיסכון במשאבים. פרויקט טיפוסי מחזיר את עצמו תוך 3–6 חודשים על ידי הפחתת זמן עובדים. החיסכון הממוצע בהוצאות תפעול יכול להיות משמעותי. אנו מבטיחים איכות: 5 שנות ניסיון, מהנדסים מוסמכים, 12 חודשי תמיכה לאחר היישום.
מה כלול בעבודה?
- אנליטיקה: חקר תהליכים עסקיים, תפקידים, וסוגי מסמכים.
- עיצוב: יצירת סכמת זרימת עבודה עם שלבים, תנאים, ותפקידים.
- יישום: פיתוח המנוע, אינטגרציה עם אחסון מסמכים ו-EDS.
- ממשק: אזור אישי ליוזם ולמאשרים.
- בדיקות: כיסוי בדיקות יחידה, בדיקות עומס.
- תיעוד: תיאור API, הוראות משתמש, ניהול.
- הדרכה: סמינר מקוון למשתמשים מרכזיים.
- תמיכה: שבועיים של תמיכה חינמית לאחר ההשקה.
לוחות זמנים משוערים
| תצורה | לוח זמנים |
|---|---|
| זרימת עבודה בסיסית (אישור רציף, משימות, הודעות) | 7–10 ימים |
| מורחבת (מקבילי, האצלה, הסלמה, פסקי זמן) | 12–17 ימים |
| עם בונה תבניות ויזואלי | 19–27 ימים |
לוחות זמנים מדויקים מחושבים לאחר ביקורת של התהליכים שלך. צור קשר — נערוך ביקורת חינמית ונציע פתרון תוך יום אחד. הזמן יישום והפחת את זמן האישור פי 3. קבל ייעוץ היום.







