Instagram Models
Die Instagram-Domäne nutzt ein Collector-System für das Scraping. CollectorClient-Instanzen (authentifiziert via Sanctum) leasen CollectorJob-Aufträge, führen sie aus und liefern Ergebnisse zurück. Keywords und Related Profiles werden aus den gescrapten Daten extrahiert.
CollectorJob
Scraping-Auftrag für Instagram-Profile. Verwendet UUID als Primary Key. Durchläuft einen definierten Status-Lifecycle mit Lease-Mechanismus zur Parallelisierung.
Tabelle: collector_jobs
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | uuid | PK | UUID-basierte Primary Key |
source | string | nein | Quell-Identifier (z.B. daily_scrape) |
payload | json | nein | Auftragsdaten (Handle, Profil-ID, etc.) |
status | string | nein | Aktueller Status (siehe Lifecycle) |
priority | integer | nein | Priorität (höher = wichtiger) |
leased_by | uuid (FK) | ja | Collector-Client, der den Job bearbeitet |
lease_expires_at | datetime | ja | Ablaufzeit des Leases |
attempts | integer | nein | Bisherige Versuche |
result | json | ja | Scraping-Ergebnis bei Erfolg |
error_code | string | ja | Fehlercode bei Fehler |
error_message | text | ja | Fehlermeldung |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
leasedBy() | belongsTo | CollectorClient | leased_by | Bearbeitender Client |
Casts: payload → array, result → array, lease_expires_at → datetime
Status-Lifecycle:
queued → leased → completed
→ failed → queued (Retry)
→ expired (Lease abgelaufen) → queued
| Status | Beschreibung |
|---|---|
queued | Wartet auf Bearbeitung |
leased | Von Client übernommen |
completed | Erfolgreich abgeschlossen |
failed | Fehlgeschlagen |
Methoden:
| Methode | Return | Beschreibung |
|---|---|---|
isLeaseExpired() | bool | Prüft ob Lease abgelaufen |
isLeasedTo($client) | bool | Prüft ob Lease einem bestimmten Client gehört |
markLeased($client) | void | Setzt Status auf leased mit Client und Ablaufzeit |
markCompleted($result) | void | Setzt Status auf completed mit Ergebnis |
markFailed($code, $msg) | void | Setzt Status auf failed mit Fehlerdetails |
Location: app/Models/CollectorJob.php
CollectorClient
Authentifizierter Scraping-Client. Erweitert Authenticatable für Sanctum API-Token-Auth. Jeder Client hat definierte Capabilities und einen Heartbeat über last_seen_at.
Tabelle: collector_clients
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | uuid | PK | UUID-basierte Primary Key |
name | string | nein | Client-Name |
capabilities | json | ja | Unterstützte Funktionen (Array) |
last_seen_at | datetime | ja | Letzter Heartbeat |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
leasedJobs() | hasMany | CollectorJob | leased_by | Aktuell geleaste Jobs |
Traits: HasApiTokens (Sanctum), HasFactory, HasUuids
Casts: capabilities → array, last_seen_at → datetime
Auth-Mechanismus: Der Client authentifiziert sich per Sanctum Bearer-Token. Tokens werden über die personal_access_tokens-Tabelle verwaltet. Die tokenable_id-Spalte ist ein String (UUID), nicht Integer.
Location: app/Models/CollectorClient.php
InstagramProfileKeyword
Aus der Instagram-Bio extrahierte Keywords. Werden per AI-Detection oder Regex-Parsing gewonnen.
Tabelle: instagram_profile_keywords
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Zugehöriges Profil |
keyword | string | nein | Extrahiertes Keyword |
source | string | ja | Herkunft (bio_parse, ai_detection, etc.) |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
socialProfile() | belongsTo | SocialProfile | social_profile_id | Zugehöriges Profil |
Location: app/Models/InstagramProfileKeyword.php
InstagramRelatedProfile
Verwandte Instagram-Profile mit Relevanz-Score und Match-Begründung. Wird per cross-platform:queue-related und Instagram-spezifischen Discovery-Mechanismen befüllt.
Tabelle: instagram_related_profiles
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Quell-Profil |
related_social_profile_id | bigint (FK) | nein | Verwandtes Profil |
relevance_score | integer | ja | Relevanz (0–100) |
match_reason | string | ja | Grund der Verknüpfung |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
sourceProfile() | belongsTo | SocialProfile | social_profile_id | Quell-Profil |
relatedProfile() | belongsTo | SocialProfile | related_social_profile_id | Verwandtes Profil |
Casts: relevance_score → integer
Ausschluss-Filter: Analog zu YouTubeRelatedChannel muss bei der Anzeige der Related-Profile immer gegen notExcluded() gefiltert werden:
->whereHas('relatedProfile', fn ($q) => $q
->whereNull('blocked_at')
->whereNull('sanitized_at')
->whereNull('archived_at')
)
Location: app/Models/InstagramRelatedProfile.php
InstagramPost
Einzelner Instagram-Post mit Metadaten. Wird bei jedem Scrape per Upsert aktualisiert (Metadaten-Update, last_seen_at aktualisieren, first_seen_at beibehalten). Dient als Parent fuer die Zeitreihen-Metriken.
Tabelle: instagram_posts
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Auto-Increment Primary Key |
social_profile_id | bigint (FK) | nein | Zugehoeriges Profil |
shortcode | string(100) | nein | Instagram-Post-Identifier (z.B. ABC123, bis zu 40+ Zeichen moeglich) |
type | string(20) | ja | Post-Typ: image, video, carousel, reel |
url | string(500) | ja | URL zum Post |
thumbnail_url | text | ja | CDN-URL des Post-Thumbnails |
alt_text | text | ja | Accessibility-Text des Posts |
first_seen_at | datetime | nein | Wann der Post erstmals gesehen wurde |
last_seen_at | datetime | nein | Wann der Post zuletzt in recent_posts auftauchte |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Unique Constraint: (social_profile_id, shortcode) — ein Post pro Profil.
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
profile() | belongsTo | SocialProfile | social_profile_id | Zugehoeriges Profil |
metrics() | hasMany | InstagramPostMetric | instagram_post_id | Alle Metrik-Snapshots |
latestMetric() | hasOne | InstagramPostMetric | instagram_post_id | Neuester Datenpunkt |
Casts: first_seen_at -> datetime, last_seen_at -> datetime
Location: app/Models/InstagramPost.php
InstagramPostMetric
Einzelner Metriken-Datenpunkt fuer einen Instagram-Post. Jeder Scrape erzeugt einen neuen Datenpunkt (Timestamp-Granularitaet, kein Dedup). Ermoeglicht Engagement-Verlauf pro Post ueber die Zeit.
Tabelle: instagram_post_metrics
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Auto-Increment Primary Key |
instagram_post_id | bigint (FK) | nein | Zugehoeriger Post |
likes_count | unsigned integer | nein | Anzahl Likes zum Scrape-Zeitpunkt |
comments_count | unsigned integer | nein | Anzahl Comments zum Scrape-Zeitpunkt |
scraped_at | datetime | nein | Zeitpunkt des Scrapes |
created_at | datetime | nein | Erstellt am |
Unique Constraint: (instagram_post_id, scraped_at) — ein Datenpunkt pro Post pro Scrape-Zeitpunkt.
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
post() | belongsTo | InstagramPost | instagram_post_id | Zugehoeriger Post |
Casts: scraped_at -> datetime, likes_count -> integer, comments_count -> integer
Datenvolumen-Projektion:
- ~54.000 Rows/Tag (3.000 Profile x 12 Posts x 1,5 Scrapes)
- ~1,6 Mio Rows/Monat, ~20 Mio Rows/Jahr
- ~80 Bytes pro Row inkl. Indizes
Location: app/Models/InstagramPostMetric.php