Zum Hauptinhalt springen

Migrationen

Postbox nutzt aktuell 123 Migrationen. Die Datenbank ist PostgreSQL -- mehrere Migrationen nutzen PostgreSQL-spezifische Features (GIN-Indexes, Partial Unique Indexes). Tests laufen gegen SQLite in-memory, daher muss PostgreSQL-spezifische Syntax in Tests ggf. gesondert behandelt werden.

Location: database/migrations/

Laravel Framework

NrMigrationTabelleTypWichtigste Spalten
10001_01_01_000000users, password_reset_tokens, sessionscreateid, name, email, password; sessions: user_id, ip, user_agent, last_activity
20001_01_01_000001cache, cache_lockscreatekey, value, expiration
30001_01_01_000002jobs, job_batches, failed_jobscreateQueue-Tabellen (Database Driver)

Core Models (Januar)

NrMigrationTabelleTypWichtigste Spalten
42026_01_01_000001workspacescreateid, owner_id, name
52026_01_01_000002watcherscreateid, workspace_id, created_by, name
62026_01_01_000003social_profilescreateid, platform, handle, handle_normalized, external_id, canonical_url, data, title, description, thumbnail_url
72026_01_01_000004social_profile_daily_metricscreateid, social_profile_id, date, followers_count, view_count, video_count
82026_01_01_000005watcher_sourcescreateid, watcher_id, social_profile_id, platform, input_url
92026_01_01_125123social_profiles, social_profile_daily_metricsalterYouTube-Felder: custom_url, published_at, country, language, comment_count
102026_01_01_130226watchersalteris_name_custom
112026_01_01_130253social_profilesalterUnique-Index: platform + external_id
122026_01_01_131633social_profilesalterlast_scrape_failed_at, last_scrape_error
132026_01_01_132525social_profilesaltertracking_enabled, tracking_disabled_at/by_system/reason, last_scraped_at, last_daily_scrape_on
142026_01_01_133607social_profilesalterapi_status, api_status_reason
152026_01_01_134846watchers, watcher_sourcesalterForeign Keys und Uniques
162026_01_01_140111watcher_sourcesalterUnique/Index-Anpassungen
172026_01_01_150000social_profilesalterPartial Unique Indexes (PostgreSQL)
182026_01_01_160000watcher_import_runscreateworkspace_id, created_by, platform, status, Zähler, finished_at
192026_01_01_160010watcher_import_failurescreatewatcher_import_run_id, url, reason

Instagram & Images (Anfang Januar)

NrMigrationTabelleTypWichtigste Spalten
202026_01_02_000000social_profiles, social_profile_daily_metricsalterInstagram-Felder: is_private, profile_type, following_count, post_count
212026_01_02_000002social_profile_imagescreatesocial_profile_id, path, hash, source_url
222026_01_02_000002workspacesalterdescription
232026_01_02_000003workspacesalterdescription (Duplikat-Migration)
242026_01_03_000020watcher_import_itemscreatewatcher_import_run_id, url, dedupe_key
252026_01_03_000021watcher_import_runsalterpaused_until, pause_reason

Collector & Dashboard (Anfang Januar)

NrMigrationTabelleTypWichtigste Spalten
262026_01_04_000000daily_sync_runscreatedate, expected_profiles, processed_profiles, failed_profiles, status, finished_at
272026_01_04_000001dashboard_daily_rollupscreatedate, owner_id, workspace_id, watcher_id, social_profile_id, Metriken
282026_01_04_000002collector_clientscreateid (uuid), name, capabilities, last_seen_at
292026_01_04_000003collector_jobscreateid (uuid), source, payload, status, priority, leased_by, lease_expires_at, attempts, result, error_code/message
302026_01_04_000004personal_access_tokenscreateSanctum Token-Tabelle
312026_01_06_000000personal_access_tokensaltertokenable_id → string (UUID)

Favorites, Queuing & Rollups (Mitte Januar)

NrMigrationTabelleTypWichtigste Spalten
322026_01_10_000000social_profilesalterlast_daily_queue_on, last_daily_queue_at
332026_01_10_000000dashboard_daily_rollupsalterInstagram-Metriken: following_count, post_count
342026_01_10_000001watcher_import_failuresaltererror_code
352026_01_10_000010favorite_social_profilescreateuser_id, social_profile_id (unique)

Pulse, Research & API Quota (Ende Januar)

NrMigrationTabelleTypWichtigste Spalten
362026_01_21_163730pulse_*createLaravel Pulse Tabellen
372026_01_24_000000youtube_research_queriescreatequery, topic_id, result_count, result_urls, response/error_payload
382026_01_28_120000workspacesalterAdmin-Workspace Seeder (ID 999999999999)
392026_01_28_120000google_api_quota_limitscreateproject_id, service, quota_metric, display_name, unit, limit_value
402026_01_28_120100google_api_quota_usagescreateproject_id, service, quota_metric, date, used_value, by_credential
412026_01_29_210000google_api_quota_limitsalterunit in Unique-Constraint
422026_01_30_094041youtube_research_queriesalterimported_at
NrMigrationTabelleTypWichtigste Spalten
432026_01_30_110000youtube_related_channelscreatesocial_profile_id, related_social_profile_id, relevance_score, search_query
442026_01_30_110001social_profilesalterrelated_channels_status/searched_at/error
452026_01_31_100000pagescreateslug, title, content, meta_description, is_draft/published, created_by/updated_by
462026_01_31_155204social_profilesalterlanguage
472026_01_31_180000explore_profile_metricscreatesocial_profile_id, followers_count, growth_1d/7d/30d, trending_score, follower_tier, detected_tags, is_rising_star/is_new
482026_01_31_180001explore_trending_videoscreatesocial_profile_id, video_id, title, view_count, trending_score, velocity_score
492026_01_31_180002explore_categoriescreateslug, name, name_de, icon, keywords, youtube_category_ids, sort_order, is_active
NrMigrationTabelleTypWichtigste Spalten
502026_01_31_220000instagram_related_profilescreatesocial_profile_id, related_social_profile_id, relevance_score, match_reason
512026_01_31_220001instagram_profile_keywordscreatesocial_profile_id, keyword, source
522026_01_31_220002social_profilesalterrelated_profiles_status/calculated_at/error
532026_02_01_000002collector_jobsalterpriority
542026_02_01_094335pending_you_tube_channel_importscreatesource_social_profile_id, youtube_channel_id, relevance_score, retry_count
552026_02_01_190000ai_detection_logscreatesocial_profile_id, type, model, input/output_data, status, tokens_used, duration_ms
NrMigrationTabelleTypWichtigste Spalten
562026_02_02_000000social_profilesalteris_verified
572026_02_02_000001dashboard_global_snapshotscreatedate, metric, platform, value
582026_02_02_120000explore_profile_metricsalteris_trending

Scrape Progress, AI Enhancement & Retry-Lifecycle (Anfang Februar)

NrMigrationTabelleTypWichtigste Spalten
592026_02_03_000001daily_scrape_progresscreateuser_id, date, expected/completed/failed_count, notification_sent
602026_02_04_080104social_profilesalterAI-Enhancement-Felder (ai_category, ai_keywords, ai_description, detected_country/language)
612026_02_05_000001dashboard_global_snapshotsaltertier
622026_02_05_000002social_profilesalteris_verified Index
632026_02_05_000003social_profilesalterscrape_fail_streak, next_retry_at, retry_count, deactivated_at, archived_at, archive_reason, manual_penalty
642026_02_05_000004social_profile_scorescreatesocial_profile_id, date, score, data_source_date, status
652026_02_05_000005cross_platform_related_profilescreatesource_profile_id, related_profile_id, relevance_score, match_reason
662026_02_05_083822pagesaltershow_in_header/footer/sidebar, nav_priority
672026_02_05_211953social_profilesalterGIN-Index auf ai_keywords (PostgreSQL)
682026_02_06_200000social_profilesalterparsed_links

Queue Metrics & YouTube Videos (Mitte Februar)

NrMigrationTabelleTypWichtigste Spalten
692026_02_10_000000queue_metricscreateQueue-Metriken-Snapshots
702026_02_11_000000youtube_videoscreatevideo_id (PK), social_profile_id, channel_id, title, description, duration, tags, thumbnails
712026_02_11_000001youtube_video_daily_metricscreateyoutube_video_id, date, view/like/comment/favorite_count
722026_02_11_000002youtube_video_syncscreatesocial_profile_id, uploads_playlist_id, auto_sync_enabled, last_sync_at
732026_02_11_000003youtube_video_syncsalterFail-Tracking: last_fail_date, consecutive_fail_days
742026_02_11_000004youtube_video_syncsalterlast_video_count
752026_02_12_000000youtube_video_syncsalterauto_sync_enabled Default → false

Leaderboard Snapshots & Thumbnails (Mitte Februar)

NrMigrationTabelleTypWichtigste Spalten
762026_02_13_000000dashboard_leaderboard_snapshotscreateLeaderboard-Snapshots
772026_02_13_000010youtube_videosalterthumbnail_url/path/hash
782026_02_14_000000dashboard_leaderboard_snapshotsalterTrim auf Top 100

Audits & Notifications (Mitte Februar)

NrMigrationTabelleTypWichtigste Spalten
792026_02_15_000001auditscreateOwen-IT Audit-Tabelle
802026_02_16_000000notificationscreateNotifications mit admin_only, expires_at
812026_02_16_000001announcements, announcement_readscreateAnnouncement-System
822026_02_16_100000explore_profile_metricsalterprevious_trending_score

Blocking & Sanitizer (Mitte/Ende Februar)

NrMigrationTabelleTypWichtigste Spalten
832026_02_17_000000social_profilesalterblocked_at, blocked_by, block_reason
842026_02_18_000000social_profilesalterai_social_links
852026_02_18_000001blocked_tagscreatetag, blocked_by, blocked_at, reason
862026_02_19_000000social_profilesaltersanitized_at, sanitize_reason, sanitize_checked_at

User Settings, Notifications & Tags (Ende Februar)

NrMigrationTabelleTypWichtigste Spalten
872026_02_20_000001usersaltertimezone
882026_02_20_000002notification_preferencescreateuser_id, workspace_id, notification_type, channel_app/email
892026_02_20_000003user_quiet_hourscreateuser_id, enabled, window_start/end, monday-sunday
902026_02_20_000004mail_logcreateuser_id, mail_type, recipient, subject, status, error_message
912026_02_20_000005notification_statscreatedate, channel, type, count
922026_02_20_000006sessionsalterIndex auf last_activity
932026_02_20_000007announcement_readsalterdismissed_at
942026_02_20_000008tag_consolidation_logscreatebatch_id, source_tag, target_tag, action, confidence, reason, affected_profiles, status
952026_02_20_000009tag_aliasescreatesource_tag (unique), target_tag
NrMigrationTabelleTypWichtigste Spalten
962026_02_20_000010ai_detection_logsaltersocial_profile_id nullable
972026_02_20_000011youtube_video_scorescreateyoutube_video_id, social_profile_id, date, score, status, is_short, Component-Scores
982026_02_20_000012diversealterPostgreSQL-Optimierung: fehlende Indexes auf häufig abgefragte Spalten
992026_02_20_000013social_profile_linkscreatesocial_profile_id, type, platform, value, display_url, source, approved_at/by
NrMigrationTabelleTypWichtigste Spalten
1002026_02_20_100003social_profile_linksalterlinked_social_profile_id (FK), import_status, import_error
1012026_02_20_100004explore_categoriesseederErsetzt 12 Keyword-Kategorien durch 26 AI-Kategorien via ExploreCategorySeeder, fuehrt explore:calculate --type=categories aus
1022026_02_21_100000social_profilesalterGIN-Trigram-Indexes auf handle_normalized und title (erfordert pg_trgm Extension, CONCURRENTLY, ohne Transaction)
1032026_02_21_100001search_historiescreateid, user_id, query, searched_at (Unique: user_id + query)
1042026_02_21_200000social_profilesalterai_detection_failed_at (nullable Timestamp)

Auth, User-Blocking & YouTube Research (Februar, Woche 3)

NrMigrationTabelleTypWichtigste Spalten
1052026_02_23_000001users, password_reset_tokensalter+createpassword (nullable), workos_id/avatar nullable, neue password_reset_tokens-Tabelle
1062026_02_12_203258usersaltertwo_factor_secret, two_factor_recovery_codes, two_factor_confirmed_at
1072026_02_23_100001users, user_blocksalter+createblocked_at, blocked_by, block_reason auf users; user_blocks: user_id, admin_id, action, reason
1082026_02_13_000001youtube_research_queriesalterbatch_id (UUID), relevance_language, region_code, min_subscribers, min_videos, filtered_count, status
1092026_02_13_000002youtube_research_keyword_cooldownscreateid, keyword (unique), used_at
NrMigrationTabelleTypWichtigste Spalten
1102026_02_15_000001usersalternewsletter_opted_in_at, newsletter_token (varchar 64), newsletter_token_expires_at
1112026_02_15_000002usersalterprivacy_accepted_at, terms_accepted_at (nullable Timestamps fuer DSGVO-Zustimmung)

Error Monitor & DB Monitoring (Februar, Woche 3-4)

NrMigrationTabelleTypWichtigste Spalten
1122026_02_26_000001error_page_logscreatepath, path_hash (MD5), status_code, hour (created_at), hit_count, is_bot_detected, referer, user_agent. Unique: (path_hash, status_code, created_at)
1132026_02_26_000002error_page_daily_statscreatedate, status_code_4xx, status_code_5xx, unique_paths, bot_percentage, top_paths (JSON)
1142026_02_26_000003url_redirectscreatesource_path, target_url, status_code, is_regex, regex_pattern, is_active, hit_count, notes
1152026_02_27_000001db_monitoring_snapshots + db_slow_query_logcreateMetriken-Snapshots (active_connections, tps, db_size, cache_hit_ratio, dead_tuples, table_metrics JSON) + Slow Queries (duration_ms, query, parameters, source)
1162026_02_27_000002explore_daily_snapshotscreatedate (unique), total_profiles, youtube_count, instagram_count, tier counts, trending_count, rising_stars_count
1172026_02_27_000003dismissed_error_pathscreatepath_hash (MD5, unique), path, dismissed_by, dismissed_at

Contact, Feedback & CMS (Februar, Woche 4)

NrMigrationTabelleTypWichtigste Spalten
1182026_02_24_000001contact_submissionscreatename, email, phone, subject, message, source, ip_address, attachments (JSON)
1192026_02_24_000002contact_submissionsaltersource (string, Default 'contact', unterscheidet contact/feedback)
1202026_02_28_000001pagesaltermeta_robots (nullable, max 50 Zeichen, z.B. noindex, nofollow)

AI Manual Override & Cross-Platform Verification (Februar, Woche 4)

NrMigrationTabelleTypWichtigste Spalten
1212026_02_28_000002social_profilesalterai_manual_category, ai_manual_description, ai_manual_keywords (JSON), ai_manual_edited_at, ai_manual_edited_by (FK)
1222026_02_28_000003ai_manual_override_logscreatesocial_profile_id (FK), user_id (FK), field, old_value, new_value
1232026_02_28_000004cross_platform_related_profilesaltercross_profile_verified_at, cross_profile_verified_by (FK)

Error Monitor Erweiterung (Februar, Woche 4)

NrMigrationTabelleTypWichtigste Spalten
1242026_02_28_900012dismissed_error_pathsalteris_muted (boolean, default false) — gemutete Pfade werden weiterhin getrackt aber von Anomalie-Detection uebersprungen

Hinweise

PostgreSQL Extensions

pg_trgm (erforderlich seit Migration 102):

# Muss vor migrate aktiviert werden:
sudo -u postgres psql -d postbox_db1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"

Die Extension aktiviert gin_trgm_ops fuer Fuzzy-Suche (similarity(), schnelles ILIKE). Wird verwendet fuer:

  • Migration 102: GIN-Trigram-Indexes auf social_profiles.handle_normalized und social_profiles.title
  • Manueller Index: watchers.name (nicht in Migration, separat anlegen)
-- Optionaler manueller Index fuer Watcher-Suche:
CREATE INDEX CONCURRENTLY watchers_name_trgm_index ON watchers USING gin (name gin_trgm_ops);

PostgreSQL-spezifische Features

Einige Migrationen nutzen PostgreSQL-exklusive Funktionalität:

  • Migration 17: Partial Unique Indexes auf social_profiles
  • Migration 67: GIN-Index auf ai_keywords (JSONB-Feld)
  • Migration 98: Diverse PostgreSQL-optimierte Indexes
  • Migration 102: GIN-Trigram-Indexes (pg_trgm Extension erforderlich)

Tests und SQLite

Da Tests gegen SQLite in-memory laufen, müssen PostgreSQL-spezifische Syntax-Elemente (::bigint, jsonb @>, GIN-Indexes) in Tests ggf. mit Conditional Logic oder separaten Test-Migrationen behandelt werden.

Migrations-Konventionen

  • Create-Migrationen: create_{table}_table -- erstellt eine neue Tabelle
  • Alter-Migrationen: Beschreibender Name oder Timestamp -- erweitert bestehende Tabellen
  • Seeder-Migrationen: Z.B. Migration 38 (Admin-Workspace) -- schreibt auch Daten