Core Models
Die Core-Domäne umfasst das zentrale SocialProfile-Model und seine direkten Dependents: Metriken, Bilder, Links und Scores.
SocialProfile
Zentrales Model für alle beobachteten Social-Media-Profile (YouTube und Instagram).
Tabelle: social_profiles
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
platform | string | nein | youtube oder instagram |
handle | string | nein | Original-Handle |
handle_normalized | string | nein | Normalisierter Handle (lowercase, ohne Sonderzeichen) |
external_id | string | ja | Plattform-spezifische ID (Channel-ID, Instagram-User-ID) |
canonical_url | string | ja | Kanonische Profil-URL |
data | json | ja | Rohdaten der Plattform-API |
title | string | ja | Anzeigename / Channel-Titel |
description | text | ja | Profil-/Channel-Beschreibung |
thumbnail_url | string | ja | Profilbild-URL |
custom_url | string | ja | Custom URL (YouTube @handle) |
published_at | datetime | ja | Erstellungsdatum auf der Plattform |
country | string(2) | ja | Ländercode (von Plattform) |
language | string | ja | Sprache (von Plattform) |
detected_country | string(2) | ja | AI-erkanntes Land |
detected_language | string | ja | AI-erkannte Sprache |
detected_at | datetime | ja | Zeitpunkt der AI-Erkennung |
ai_category | string | ja | AI-erkannte Kategorie |
ai_category_confidence | float | ja | Confidence der Kategorie-Erkennung |
ai_keywords | json | ja | AI-erkannte Keywords (Array) |
ai_keywords_confidence | float | ja | Confidence der Keyword-Erkennung |
ai_description | text | ja | AI-generierte Beschreibung (englisch) |
ai_description_confidence | float | ja | Confidence der Beschreibung |
ai_description_de | text | ja | AI-Beschreibung deutsch |
ai_description_de_confidence | float | ja | Confidence deutsch |
ai_description_es | text | ja | AI-Beschreibung spanisch |
ai_description_es_confidence | float | ja | Confidence spanisch |
ai_description_it | text | ja | AI-Beschreibung italienisch |
ai_description_it_confidence | float | ja | Confidence italienisch |
ai_description_fr | text | ja | AI-Beschreibung franzoesisch |
ai_description_fr_confidence | float | ja | Confidence franzoesisch |
ai_description_pt | text | ja | AI-Beschreibung portugiesisch |
ai_description_pt_confidence | float | ja | Confidence portugiesisch |
ai_description_quality_score | integer | ja | Qualitaetsscore der AI-Beschreibung (1-10) |
ai_translated_at | datetime | ja | Zeitpunkt der letzten AI-Uebersetzung |
ai_social_links | json | ja | AI-erkannte Social-Links |
ai_manual_category | string | ja | Manuell gesetzte Kategorie (Override) |
ai_manual_description | text | ja | Manuell gesetzte Beschreibung (Override) |
ai_manual_keywords | json | ja | Manuell gesetzte Keywords (Override) |
ai_manual_edited_at | datetime | ja | Letzte manuelle AI-Feld-Aenderung |
ai_manual_edited_by | bigint (FK) | ja | Admin der die Aenderung vornahm |
is_private | boolean | ja | Privates Profil (Instagram) |
profile_type | string | ja | Profil-Typ (Instagram: personal/business/creator) |
is_verified | boolean | ja | Verifiziertes Profil |
last_scraped_at | datetime | ja | Letzter erfolgreicher Scrape |
last_daily_scrape_on | date | ja | Datum des letzten täglichen Scrapes |
last_daily_queue_on | date | ja | Datum der letzten Queue-Einreihung |
last_daily_queue_at | datetime | ja | Zeitpunkt der letzten Queue-Einreihung |
last_scrape_failed_at | datetime | ja | Letzter fehlgeschlagener Scrape |
last_scrape_error | text | ja | Letzte Fehlermeldung |
tracking_enabled | boolean | nein | Master-Schalter: Tracking aktiv |
tracking_disabled_at | datetime | ja | Zeitpunkt der Deaktivierung |
tracking_disabled_by_system | boolean | ja | Vom System deaktiviert (nicht manuell) |
tracking_disabled_reason | string | ja | Grund der Deaktivierung |
api_status | string | ja | API-Status (ok, not_found, suspended, etc.) |
api_status_reason | string | ja | Detail zum API-Status |
scrape_fail_streak | integer | ja | Anzahl aufeinanderfolgender Scrape-Fehler |
next_retry_at | datetime | ja | Nächster geplanter Retry-Zeitpunkt |
retry_count | integer | ja | Anzahl bereits durchgeführter Retries |
deactivated_at | datetime | ja | Deaktiviert durch Fail-Streak |
archived_at | datetime | ja | Permanent archiviert |
archive_reason | string | ja | Grund der Archivierung |
manual_penalty | integer | ja | Manueller Score-Abzug (0–100%) |
blocked_at | datetime | ja | Admin-Sperre |
blocked_by | bigint (FK) | ja | User-ID des sperrenden Admins |
block_reason | string | ja | Sperrgrund |
sanitized_at | datetime | ja | Auto-Deaktivierung durch Sanitizer |
sanitize_reason | string | ja | Grund der Sanitizer-Deaktivierung |
sanitize_checked_at | datetime | ja | Admin-Override-Marker (Schutz vor Re-Sanitize) |
related_channels_status | string | ja | Status der Related-Channels-Suche |
related_channels_searched_at | datetime | ja | Letzter Related-Channels-Lauf |
related_channels_error | text | ja | Fehler bei Related-Channels |
related_profiles_status | string | ja | Status der Related-Profiles-Berechnung |
related_profiles_calculated_at | datetime | ja | Letzter Related-Profiles-Lauf |
related_profiles_error | text | ja | Fehler bei Related-Profiles |
parsed_links | json | ja | Geparste Links aus Beschreibung |
parsed_links_at | datetime | ja | Zeitpunkt des letzten Link-Parsings |
ai_detection_failed_at | datetime | ja | Letzter AI-Detection-Fehler |
first_metric_date | date | ja | Erstes Metrik-Datum (fuer Newcomer-Qualitaetsfilter) |
pro_enabled | boolean | ja | PRO-Status fuer priorisiertes Scraping |
followers_count | bigint | ja | Gecachte Follower-Anzahl (schnelles Filtern) |
slug | string | ja | URL-Slug fuer Public Explorer |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
metrics() | hasMany | SocialProfileDailyMetric | social_profile_id | Alle Tagesmetriken |
latestMetric() | hasOne | SocialProfileDailyMetric | social_profile_id | Neueste Metrik (latestOfMany('date')) |
images() | hasMany | SocialProfileImage | social_profile_id | Profilbilder |
youtubeVideos() | hasMany | YouTubeVideo | social_profile_id | YouTube-Videos |
youtubeVideoSync() | hasOne | YouTubeVideoSync | social_profile_id | Video-Sync-Status |
watcherSources() | hasMany | WatcherSource | social_profile_id | Watcher-Verknüpfungen |
contactLinks() | hasMany | SocialProfileLink | social_profile_id | Alle Kontakt-Links |
approvedContactLinks() | hasMany | SocialProfileLink | social_profile_id | Nur genehmigte Links (whereNotNull('approved_at')) |
relatedChannels() | hasMany | YouTubeRelatedChannel | social_profile_id | Verwandte YouTube-Channels |
pendingYouTubeImports() | hasMany | PendingYouTubeChannelImport | source_social_profile_id | Pending Channel-Imports |
relatedProfiles() | hasMany | InstagramRelatedProfile | social_profile_id | Verwandte Instagram-Profile |
instagramKeywords() | hasMany | InstagramProfileKeyword | social_profile_id | Instagram Keywords |
exploreMetrics() | hasOne | ExploreProfileMetric | social_profile_id | Explore-Metriken |
scores() | hasMany | SocialProfileScore | social_profile_id | Score-Verlauf |
latestScore() | hasOne | SocialProfileScore | social_profile_id | Aktueller Score (latestOfMany('date')) |
crossPlatformRelated() | hasMany | CrossPlatformRelatedProfile | source_profile_id | Cross-Platform-Verknüpfungen |
aiManualOverrideLogs() | hasMany | AiManualOverrideLog | social_profile_id | Audit-Log fuer manuelle AI-Feld-Aenderungen |
aiManualEditedBy() | belongsTo | User | ai_manual_edited_by | Admin der AI-Felder manuell bearbeitet hat |
blockedByUser() | belongsTo | User | blocked_by | Sperrender Admin |
Scopes:
| Scope | SQL-Äquivalent | Verwendung |
|---|---|---|
notBlocked() | WHERE blocked_at IS NULL | Nicht gesperrte Profile |
notSanitized() | WHERE sanitized_at IS NULL | Nicht sanitized Profile |
notExcluded() | WHERE blocked_at IS NULL AND sanitized_at IS NULL AND archived_at IS NULL | Für öffentliche Anzeige |
Casts:
'last_scraped_at' => 'datetime',
'last_daily_scrape_on' => 'date',
'last_daily_queue_on' => 'date',
'last_daily_queue_at' => 'datetime',
'last_scrape_failed_at' => 'datetime',
'tracking_enabled' => 'boolean',
'tracking_disabled_at' => 'datetime',
'tracking_disabled_by_system' => 'boolean',
'scrape_fail_streak' => 'integer',
'next_retry_at' => 'datetime',
'retry_count' => 'integer',
'deactivated_at' => 'datetime',
'archived_at' => 'datetime',
'manual_penalty' => 'integer',
'blocked_at' => 'datetime',
'sanitized_at' => 'datetime',
'sanitize_checked_at' => 'datetime',
'published_at' => 'datetime',
'detected_at' => 'datetime',
'data' => 'array',
'ai_keywords' => 'array',
'ai_social_links' => 'array',
'ai_manual_keywords' => 'array',
'ai_description_quality_score' => 'integer',
'ai_translated_at' => 'datetime',
'parsed_links' => 'array',
'parsed_links_at' => 'datetime',
'first_metric_date' => 'date',
'pro_enabled' => 'boolean',
'is_private' => 'boolean',
'is_verified' => 'boolean',
'related_channels_searched_at' => 'datetime',
'related_profiles_calculated_at' => 'datetime',
'cross_platform_related_calculated_at' => 'datetime',
Accessors: api_status_effective, effective_country, effective_language, effective_category, effective_description, effective_keywords
Die effective_* Accessors implementieren das Dual-Field-System: ai_manual_* hat Vorrang vor ai_*. Alle Consumer (Explore, Discover, PublicExplorer, Tags, etc.) nutzen ausschliesslich effective_*.
Konstanten: TRANSLATION_LANGUAGES = ['de', 'es', 'it', 'fr', 'pt'], PLACEHOLDER_IMAGE
Methoden: platformEnum(), isLanguageDetected(), isBlocked(), isSanitized(), isArchived(), isPendingRetry(), isDeactivated(), isNewcomer(), isProProfile(), isLowPriorityProfile(), hasManualAiOverride(), getAiDescriptionForLocale($locale), getAiDescriptionConfidenceForLocale($locale), availableTranslations(), hasRealImage(), getImageBlurhash(), getDisplayImageUrl($size), formattedFollowers()
Location: app/Models/SocialProfile.php
SocialProfileDailyMetric
Tägliche Metriken-Snapshots eines Profils. Pro Profil und Tag maximal ein Eintrag.
Tabelle: social_profile_daily_metrics
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Zugehöriges Profil |
date | date | nein | Datum des Snapshots |
followers_count | bigint | ja | Follower/Subscriber-Anzahl |
view_count | bigint | ja | Gesamtaufrufe (YouTube) |
video_count | integer | ja | Anzahl Videos (YouTube) |
comment_count | bigint | ja | Kommentare (YouTube) |
following_count | integer | ja | Following-Anzahl (Instagram) |
post_count | integer | ja | Anzahl Posts (Instagram) |
raw | json | ja | Rohdaten des Scrapes |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
profile() | belongsTo | SocialProfile | social_profile_id | Zugehöriges Profil |
Casts: date → date, raw → array
Location: app/Models/SocialProfileDailyMetric.php
SocialProfileImage
Gespeicherte Profilbilder mit Deduplizierung über Content-Hash. Unterstützt optimierte Varianten (Thumbnail + Medium) im WebP/AVIF-Format sowie LQIP (Low Quality Image Placeholder) für progressive Bilddarstellung.
Tabelle: social_profile_images
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Zugehöriges Profil |
path | string | nein | Lokaler Speicherpfad (Original) |
path_medium | string | ja | Medium-Variante (256×256 WebP/AVIF) |
path_thumbnail | string | ja | Thumbnail-Variante (128×128 WebP/AVIF) |
original_width | unsigned int | ja | Originalbreite in px |
original_height | unsigned int | ja | Originalhöhe in px |
file_size | unsigned int | ja | Dateigröße des Originals in Bytes |
blurhash | string(200) | ja | LQIP Base64 Data URI (4×4 WebP) |
hash | string | nein | Content-Hash (SHA-256) für Deduplizierung |
source_url | string | ja | Original-URL des Bildes |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
profile() | belongsTo | SocialProfile | social_profile_id | Zugehöriges Profil |
Public Methods:
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
getUrlForSize() | string $size = 'medium' | ?string | URL für Variante (thumb/medium/original), Fallback auf Original |
hasVariants() | — | bool | Prüft ob Medium + Thumbnail Varianten vorhanden |
Location: app/Models/SocialProfileImage.php
SocialProfileLink
Kontakt-Links eines Profils (URLs, E-Mails, Social-Media-Links). Unterstützt 19 Plattformen mit URL-Templates. Links durchlaufen einen Approval-Workflow.
Tabelle: social_profile_links
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Zugehöriges Profil |
type | string | nein | Typ: url, email, social |
platform | string | ja | Plattform (twitter, tiktok, etc.) |
value | string | nein | Link-Wert (URL/E-Mail/Handle) |
display_url | string | ja | Anzeige-URL |
source | string | ja | Herkunft des Links |
approved_at | datetime | ja | Genehmigungszeitpunkt |
approved_by | bigint (FK) | ja | Genehmigender Admin |
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 |
approver() | belongsTo | User | approved_by | Genehmigender Admin |
Scopes:
| Scope | Beschreibung |
|---|---|
approved() | Nur genehmigte Links |
unapproved() | Nur ungenehmigte Links |
ofType($type) | Nach Typ filtern (url, email, social) |
ofPlatform($platform) | Nach Plattform filtern |
Casts: approved_at → datetime
Konstanten: PLATFORM_URL_TEMPLATES -- URL-Templates für 19 Plattformen (Twitter, TikTok, Facebook, LinkedIn, etc.)
Methoden: isApproved(), generateDisplayUrl() (static), detectPlatformFromUrl() (static), availablePlatforms() (static)
Location: app/Models/SocialProfileLink.php
SocialProfileScore
Berechneter Score (0–100) für ein Profil. Gewichtung: 40% Growth + 30% Momentum + 20% Consistency + 10% Engagement. Tier-normalisiert nach Follower-Größe.
Tabelle: social_profile_scores
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | bigint | PK | Primary Key |
social_profile_id | bigint (FK) | nein | Zugehöriges Profil |
date | date | nein | Berechnungsdatum |
score | integer | nein | Score (0–100) |
data_source_date | date | ja | Datum der Datengrundlage |
status | string | nein | pending, preliminary, stable, no_data |
created_at | datetime | nein | Erstellt am |
updated_at | datetime | nein | Aktualisiert am |
Relations:
| Methode | Typ | Related Model | FK | Beschreibung |
|---|---|---|---|---|
profile() | belongsTo | SocialProfile | social_profile_id | Zugehöriges Profil |
Casts: date → date, data_source_date → date, score → integer
Status-Logik:
| Status | Bedingung | Beschreibung |
|---|---|---|
pending | < 7 Datenpunkte | Noch nicht genug Daten |
preliminary | 7–9 Datenpunkte | Vorläufiger Score |
stable | >= 10 Datenpunkte | Stabiler Score |
no_data | Keine Metriken | Keine Daten vorhanden |
Methoden: isPreliminary(), isPending(), isStable()
Location: app/Models/SocialProfileScore.php