בניית מערכת זרימת עבודה לפרסום תוכן על Laravel

פרסום תוכן ללא תהליך עבודה ברור מוביל לעיתים קרובות לשגיאות ולדליפות מידע. אנו מפתחים מערכות workflow על Laravel שמבצעות אוטומציה של תהליך המודרציה והפרסום. הצוות שלנו מספק את הפרויקט במפתח מלא—מעיצוב סטטוסים ועד הטמעה ותמיכה—ומבטיח בקרת גרסאות אמינה והרשאות גישה.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
בניית מערכת זרימת עבודה לפרסום תוכן על Laravel
מורכב
מ- 1 שבוע עד 3 חודשים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1306
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

הבעיה של פרסום כאוטי

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

ביותר מ-15 פרויקטים יישמנו גישה זו, והזמן מטיוטה לפרסום ירד בממוצע מ-5 ימים ל-4 שעות. במאמר זה — איך אנחנו עושים זאת על Laravel. כאבים אופייניים: גרסאות אבודות, פרסומים לא מבוקרים, מחזורי אישור ארוכים. המערכת שלנו פותרת אותם באמצעות שרשרת סטטוסים קפדנית והקצאה אוטומטית של עורכים. מערכת זרימת עבודה היא לא רק קבוצת סטטוסים, אלא תקנון שכל המשתתפים פועלים לפיו. אנחנו בונים אותה על Laravel באמצעות ארכיטקטורה מונעת אירועים.

איך להגדיר את שרשרת הסטטוסים?

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

הנה המבנה של טבלת הסטטוסים:

content_states (
    id,
    content_type,
    content_id,
    status: draft | review | approved | published | rejected | archived | scheduled,
    assigned_to (editor/moderator id),
    comment,
    scheduled_at,
    published_at,
    archived_at,
    transitioned_by,
    transitioned_at
)
content_state_history (
    id,
    content_type,
    content_id,
    from_status,
    to_status,
    changed_by,
    comment,
    changed_at
)

יישום על Laravel

אנחנו משתמשים במחלקת content_states ( id, content_type, content_id, status: draft | review | approved | published | rejected | archived | scheduled, assigned_to (editor/moderator id), comment, scheduled_at, published_at, archived_at, transitioned_by, transitioned_at ) content_state_history ( id, content_type, content_id, from_status, to_status, changed_by, comment, changed_at ) עם מערך של מעברים מותרים והרשאות. דוגמה:

class ContentWorkflow {
    private array $transitions = [
        'draft' => ['review'],
        'review' => ['approved', 'rejected', 'revision_needed'],
        'approved' => ['published', 'scheduled'],
        'rejected' => ['draft'],
        'revision_needed' => ['draft'],
        'published'=> ['archived', 'draft'],
        'scheduled'=> ['published', 'draft']
    ];

    private array $permissions = [
        'draft → review' => 'content.submit_for_review',
        'review → approved' => 'content.approve',
        'review → rejected' => 'content.approve',
        'approved → published' => 'content.publish'
    ];

    public function canTransition(User $user, Content $content, string $toStatus): bool {
        $fromStatus = $content->status;
        if (!in_array($toStatus, $this->transitions[$fromStatus] ?? [])) {
            return false;
        }
        $permKey = "{$fromStatus} → {$toStatus}";
        if (isset($this->permissions[$permKey])) {
            return $user->can($this->permissions[$permKey]);
        }
        return true;
    }

    public function transition(Content $content, string $toStatus, User $actor, ?string $comment = null): void {
        if (!$this->canTransition($actor, $content, $toStatus)) {
            throw new WorkflowException("Переход {$content->status} → {$toStatus} недоступен");
        }
        DB::transaction(function () use ($content, $toStatus, $actor, $comment) {
            ContentStateHistory::create([
                'content_type' => get_class($content),
                'content_id' => $content->id,
                'from_status' => $content->status,
                'to_status' => $toStatus,
                'changed_by' => $actor->id,
                'comment' => $comment
            ]);
            $content->update([
                'status' => $toStatus,
                'published_at' => $toStatus === 'published' ? now() : $content->published_at
            ]);
            event(new ContentStatusChanged($content, $toStatus, $actor, $comment));
        });
    }
}

למה היסטוריית מעברים חשובה?

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

הקצאת עורכים

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

class AssignReviewer {
    public function assign(Content $content): User {
        $reviewer = User::where('role', 'editor')
            ->withCount(['assignedContent' => fn($q) => $q->where('status', 'review')])
            ->orderBy('assigned_content_count')
            ->first();

        $content->update(['assigned_to' => $reviewer->id]);
        $reviewer->notify(new ContentAssignedForReview($content));

        return $reviewer;
    }
}

מועדים ותזכורות

אנחנו מגדירים תזכורות אוטומטיות אם תוכן נשאר בסטטוס 'בסקירה' יותר מ-24 שעות. במקרה כזה, נשלחות הודעות לעורך ולעורך הראשי. אסקלציה אפשרית גם כן. מוגדר דרך class ContentWorkflow { private array $transitions = [ 'draft' => ['review'], 'review' => ['approved', 'rejected', 'revision_needed'], 'approved' => ['published', 'scheduled'], 'rejected' => ['draft'], 'revision_needed' => ['draft'], 'published'=> ['archived', 'draft'], 'scheduled'=> ['published', 'draft'] ]; private array $permissions = [ 'draft → review' => 'content.submit_for_review', 'review → approved' => 'content.approve', 'review → rejected' => 'content.approve', 'approved → published' => 'content.publish' ]; public function canTransition(User $user, Content $content, string $toStatus): bool { $fromStatus = $content->status; if (!in_array($toStatus, $this->transitions[$fromStatus] ?? [])) { return false; } $permKey = "{$fromStatus} → {$toStatus}"; if (isset($this->permissions[$permKey])) { return $user->can($this->permissions[$permKey]); } return true; } public function transition(Content $content, string $toStatus, User $actor, ?string $comment = null): void { if (!$this->canTransition($actor, $content, $toStatus)) { throw new WorkflowException("Переход {$content->status} → {$toStatus} недоступен"); } DB::transaction(function () use ($content, $toStatus, $actor, $comment) { ContentStateHistory::create([ 'content_type' => get_class($content), 'content_id' => $content->id, 'from_status' => $content->status, 'to_status' => $toStatus, 'changed_by' => $actor->id, 'comment' => $comment ]); $content->update([ 'status' => $toStatus, 'published_at' => $toStatus === 'published' ? now() : $content->published_at ]); event(new ContentStatusChanged($content, $toStatus, $actor, $comment)); }); } } ו-content_state_history. תזכורות אוטומטיות הפחיתו את מספר החומרים התקועים בסקירה ב-70%.

פרסום מתוזמן

class PublishScheduledContent implements ShouldQueue {
    public function handle(): void
    {
        Content::where('status', 'scheduled')
            ->where('scheduled_at', '<=', now())
            ->each(function (Content $content) {
                app(ContentWorkflow::class)->transition(
                    $content,
                    'published',
                    User::find($content->created_by)
                );
            });
    }
}

המשימה רצה כל 5 דקות דרך מתזמן המשימות.

איך אנחנו מיישמים זרימת עבודה: מבדיקה ועד פריסה

התהליך כולל שישה שלבים:

  1. בדיקת תהליכים קיימים — ראיונות עם עורכים, ניתוח לוגים, מפת סטטוסים.
  2. עיצוב סכמה — הגדרת סטטוסים, מעברים, הרשאות, סוגי התראות.
  3. פיתוח על Laravel — יישום מחלקות Workflow, אירועים, מאזינים.
  4. אינטגרציה עם CMS קיים — חשיפת API, עטיפת CRUD קיים.
  5. בדיקות — בדיקות יחידה לכל מעבר, בדיקות עומס.
  6. פריסה והדרכה — השקה ומפגש עם עורכים.

ציר זמן: מ-3 עד 5 שבועות תלוי במורכבות ההרשאות ובמספר סוגי התוכן.

ממשק לוח בקרה לעורכים

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

השוואה: עם זרימת עבודה לעומת בלי

קריטריון בלי זרימת עבודה עם המערכת שלנו
מהירות פרסום תלויה במקריות פי 3 מהר יותר בזכות אוטומציה
שגיאות מודרציה לעתים קרובות מפספסים תוכן באיכות נמוכה הפחתה של 90%
שקיפות אף אחד לא יודע את הסטטוס היסטוריה מלאה והתראות

השוואת שיטות הקצאת עורכים

שיטה זמן הקצאה סיכון לשגיאות שקיפות
ידנית 5–10 דקות גבוה נמוכה
אוטומטית (שלנו) מיידית נמוך גבוהה
מידע נוסף על הרשאות גישהכל מעבר מקושר להרשאת Laravel. לדוגמה, `content.approve` יכול להיות מוקצה רק לעורך. אנחנו משתמשים בדגלי `content.publish` עבור מנהלים. זה מבטיח שרק משתמשים מורשים יכולים לשנות סטטוס.

מה כלול בעבודה

אנחנו מיישמים את המערכת במפתח מלא תוך 3–5 שבועות. התפוקות כוללות:

  • תיעוד של סכמת הסטטוסים וההרשאות.
  • קוד מקור עם בדיקות.
  • הגדרת התראות (אימייל, Telegram).
  • הדרכה לעורכים ומנהלים.
  • תמיכה ל-30 יום לאחר ההשקה.

אנחנו מבטיחים יציבות: הפתרונות שלנו רצים על 20+ פרויקטים. נבצע הערכה לפרויקט שלך — פשוט צור קשר. כדי לקבל פתרון דומה לאתר שלך, פנה אלינו — נכין הצעה תוך יום אחד.

מקורות: תיעוד אירועים של Laravel ו-ויקיפדיה: זרימת עבודה