גלגול לאחור של ייבוא מוצרים עם שמירת תמונת מצב

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

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
גלגול לאחור של ייבוא מוצרים עם שמירת תמונת מצב
בינוני
~3-5 ימים

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

שאלות נפוצות

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

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

החזרת ייבוא מוצרים עם שמירת תמונת מצב

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

יישמנו החזרה עבור קטלוגים עד 500,000 מוצרים. במקום שחזור גיבוי מלא (שיכול לקחת 2-3 שעות), החזרה מבוססת תמונת מצב מסתיימת תוך 2-5 דקות עבור 10,000 שורות. זהו חיסכון של 99% בזמן — חוסך משאבים ללא אובדן נתונים. אנו מבטיחים שלמות: ההחזרה מתבצעת בטרנזקציה אחת — או שהיא מסתיימת לחלוטין או שלא מתבצעת כלל.

אילו בעיות פותר מנגנון ההחזרה?

בעיות מרכזיות במהלך ייבוא:

  • שאילתות N+1 בעת עדכון ישויות קשורות — מובילות להאטה.
  • ייבוא חלקי בעת כשל — הקטלוג נשאר במצב לא שלם.
  • נעילות טבלה ארוכות במהלך פעולות המוניות.

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

כיצד פועל מנגנון ההחזרה?

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

תמונת מצב לפני ייבוא

לפני הייבוא, אנו מאחסנים תמונות מצב של השורות המושפעות:

CREATE TABLE import_product_snapshots (
    id bigserial PRIMARY KEY,
    import_id int REFERENCES import_runs(id) ON DELETE CASCADE,
    product_id int,
    operation varchar(10), -- create | update (delete отдельно)
    data_before jsonb, -- состояние ДО импорта (NULL для create)
    created_at timestamptz DEFAULT now()
);

שירות לכידת תמונות מצב

class ImportSnapshotService {
    public function captureBeforeImport(int $importId, array $skus, int $sourceId): void {
        // Берём существующие данные товаров, которые будем изменять
        $products = Product::whereIn('sku', $skus)
            ->where('source_id', $sourceId)
            ->get(['id', 'sku', 'name', 'price', 'qty', 'description', 'category_id', 'deleted_at', 'updated_at']);

        $snapshots = $products->map(fn($p) => [
            'import_id' => $importId,
            'product_id' => $p->id,
            'operation' => 'update',
            'data_before' => json_encode($p->toArray()),
            'created_at' => now()->toDateTimeString(),
        ])->all();

        // Батч-вставка
        foreach (array_chunk($snapshots, 1000) as $chunk) {
            ImportProductSnapshot::insert($chunk);
        }
    }

    public function captureNewProduct(int $importId, int $productId): void {
        ImportProductSnapshot::create([
            'import_id' => $importId,
            'product_id' => $productId,
            'operation' => 'create',
            'data_before' => null,
        ]);
    }
}

מנגנון החזרה

class ImportRollbackService {
    public function rollback(ImportRun $import): RollbackResult {
        if (!in_array($import->status, ['success', 'partial', 'failed'])) {
            throw new \RuntimeException('Import is not in a rollbackable state');
        }

        if ($import->rolled_back_at) {
            throw new \RuntimeException('Import already rolled back');
        }

        $restored = $deleted = 0;

        DB::transaction(function () use ($import, &$restored, &$deleted) {
            $snapshots = ImportProductSnapshot::where('import_id', $import->id)
                ->orderByDesc('id') // обратный порядок для зависимостей
                ->get();

            foreach ($snapshots as $snapshot) {
                if ($snapshot->operation === 'create') {
                    // Созданные товары — удаляем (soft)
                    Product::find($snapshot->product_id)?->delete();
                    $deleted++;
                } else {
                    // Обновлённые товары — восстанавливаем предыдущее состояние
                    $before = json_decode($snapshot->data_before, true);
                    Product::where('id', $snapshot->product_id)->update($before);
                    $restored++;
                }
            }

            $import->update([
                'rolled_back_at' => now(),
                'rolled_back_by' => auth()->id(),
                'rollback_result' => compact('restored', 'deleted'),
            ]);
        });

        return new RollbackResult($restored, $deleted);
    }
}

הכל רץ בטרנזקציה אחת — או שההחזרה מסתיימת לחלוטין או ששום דבר לא משתנה. עבור ייבואים גדולים (מעל 50,000 שורות), אנו משתמשים באצווה של 1000 רשומות כל אחת כדי למנוע נעילות ארוכות. התקדמות ההחזרה מנוטרת בזמן אמת דרך ממשק אינטרנט.

מדריך יישום שלב אחר שלב

  1. צור את טבלת תמונות המצב (SQL למעלה).
  2. יישם את CREATE TABLE import_product_snapshots ( id bigserial PRIMARY KEY, import_id int REFERENCES import_runs(id) ON DELETE CASCADE, product_id int, operation varchar(10), -- create | update (delete отдельно) data_before jsonb, -- состояние ДО импорта (NULL для create) created_at timestamptz DEFAULT now() ); — קרא לו לפני הייבוא עבור כל קבוצת שורות.
  3. יישם את class ImportSnapshotService { public function captureBeforeImport(int $importId, array $skus, int $sourceId): void { // Берём существующие данные товаров, которые будем изменять $products = Product::whereIn('sku', $skus) ->where('source_id', $sourceId) ->get(['id', 'sku', 'name', 'price', 'qty', 'description', 'category_id', 'deleted_at', 'updated_at']); $snapshots = $products->map(fn($p) => [ 'import_id' => $importId, 'product_id' => $p->id, 'operation' => 'update', 'data_before' => json_encode($p->toArray()), 'created_at' => now()->toDateTimeString(), ])->all(); // Батч-вставка foreach (array_chunk($snapshots, 1000) as $chunk) { ImportProductSnapshot::insert($chunk); } } public function captureNewProduct(int $importId, int $productId): void { ImportProductSnapshot::create([ 'import_id' => $importId, 'product_id' => $productId, 'operation' => 'create', 'data_before' => null, ]); } } — הפעל אותו בעת שגיאה או דרך כפתור.
  4. בדוק התאמה (תמונת מצב נשמרה, בתוך 7 ימים, הייבוא לא הוחזר כבר).
  5. שלב עם ממשק הניהול: כפתור החזרה ופס התקדמות.

תנאי התאמה להחזרה

לא כל ייבוא ניתן להחזרה. אנו בודקים:

תנאי החזרה אפשרית?
תמונת מצב נשמרה במלואה כן
פחות מ-7 ימים כן (מדיניות שמירה)
הייבוא כבר הוחזר לא
ייבוא אחר רץ מעליו חלקית (רק שורות לא מושפעות)
מוצרים שנמחקו פיזית (לא מחיקה רכה) לא
public function canRollback(ImportRun $import): bool
{
    return !$import->rolled_back_at && $import->created_at->isAfter(now()->subDays(7)) && ImportProductSnapshot::where('import_id', $import->id)->exists();
}

למה החזרה מצטברת חשובה?

החזרת 100,000 שורות בטרנזקציה אחת נועלת את מסד הנתונים לעשרות שניות. הגישה המצטברת מפצלת את הפעולה לאצוות, ומפחיתה את עומס השרת. אנו משתמשים בשיטת class ImportRollbackService { public function rollback(ImportRun $import): RollbackResult { if (!in_array($import->status, ['success', 'partial', 'failed'])) { throw new \RuntimeException('Import is not in a rollbackable state'); } if ($import->rolled_back_at) { throw new \RuntimeException('Import already rolled back'); } $restored = $deleted = 0; DB::transaction(function () use ($import, &$restored, &$deleted) { $snapshots = ImportProductSnapshot::where('import_id', $import->id) ->orderByDesc('id') // обратный порядок для зависимостей ->get(); foreach ($snapshots as $snapshot) { if ($snapshot->operation === 'create') { // Созданные товары — удаляем (soft) Product::find($snapshot->product_id)?->delete(); $deleted++; } else { // Обновлённые товары — восстанавливаем предыдущее состояние $before = json_decode($snapshot->data_before, true); Product::where('id', $snapshot->product_id)->update($before); $restored++; } } $import->update([ 'rolled_back_at' => now(), 'rolled_back_by' => auth()->id(), 'rollback_result' => compact('restored', 'deleted'), ]); }); return new RollbackResult($restored, $deleted); } } שמחילה תמונות מצב בנתחים ומעדכנת התקדמות. זה מאפשר החזרה ללא הפרעה לפעולות החנות.

החזרה מדורגת של נתונים קשורים

הייבוא משפיע לא רק על טבלת ImportSnapshotService. במהלך ההחזרה, אנו מוחקים אוטומטית תמונות קשורות, מפרטים ומסננים. בשיטת ImportRollbackService, מתבצע ניקוי מדורג. תמונות מצב נשמרות למשך 7 ימים לאחר ייבוא מוצלח, ואז נמחקות על ידי מתזמן (public function canRollback(ImportRun $import): bool { return !$import->rolled_back_at && $import->created_at->isAfter(now()->subDays(7)) && ImportProductSnapshot::where('import_id', $import->id)->exists(); } ).

השוואת גישות להחזרה

גישה מהירות אמינות מורכבות
תמונת מצב מהירה (2-5 דקות לכל 10k) גבוהה (טרנזקציונית) בינונית
מחיקה רכה מיידית נמוכה (סמנים שאריים) נמוכה
Event Sourcing תלוי באירועים גבוהה מאוד גבוהה

הבחירה שלנו היא שילוב של תמונות מצב ואצווה. זה אופטימלי עבור רוב חנויות המקוונות.

מה כלול בפיתוח

  • שירות תמונות מצב (PHP/Laravel)
  • מנגנון החזרה עם אצווה
  • ממשק ניהול (כפתור החזרה, פס התקדמות)
  • בדיקות התאמה ומחיקה מדורגת
  • ניקוי TTL של תמונות מצב
  • תיעוד API והדרכת צוות

לוח זמנים ליישום

  • פונקציונליות בסיסית (תמונת מצב + החזרה בטרנזקציה) — יומיים
  • אצווה, מדורג, בדיקות — +יום אחד
  • ממשק ניהול ובדיקות — +יום אחד

לוח זמנים סופי: 4 עד 6 ימים תלוי במורכבות הקטלוג.

בקשו ייעוץ — נעריך את הפרויקט שלכם ביום אחד. אנו מבטיחים שההחזרה לא תאבד אף מוצר. השלמנו 50+ יישומי ייבוא מוצלחים לקטלוגים מ-1,000 עד 500,000 מוצרים. צרו קשר לדיון בפרטים.

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