First Commit

This commit is contained in:
marco
2026-09-01 07:49:48 -03:00
commit 28b1044038
399 changed files with 41659 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $user_id
* @property string $message
* @property string|null $response
* @property string|null $provider
* @property string|null $model
* @property int $input_tokens
* @property int $output_tokens
* @property \Illuminate\Support\Carbon|null $sent_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
*/
class ChatMessage extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'message',
'response',
'provider',
'model',
'input_tokens',
'output_tokens',
'sent_at',
];
/** @var array<string, string> */
protected $casts = [
'input_tokens' => 'integer',
'output_tokens' => 'integer',
'sent_at' => 'datetime',
];
/**
* Get the user that owns the chat message.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property int $user_id
* @property string $name
* @property string $pdf_path
* @property string|null $extracted_content
* @property string $processing_status
* @property string|null $error_message
* @property bool $is_active
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
* @property-read Collection<int, CustomSubjectQuestion> $questions
*/
class CustomSubject extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'name',
'pdf_path',
'extracted_content',
'processing_status',
'error_message',
'is_active',
];
/** @var array<string, string> */
protected $casts = [
'is_active' => 'boolean',
];
/**
* Get the user who owns the custom subject.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the questions for this custom subject.
*/
public function questions(): HasMany
{
return $this->hasMany(CustomSubjectQuestion::class);
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $custom_subject_id
* @property int $user_id
* @property string $question
* @property string|null $answer
* @property string|null $provider
* @property string|null $model
* @property int $input_tokens
* @property int $output_tokens
* @property \Illuminate\Support\Carbon $asked_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read CustomSubject $customSubject
* @property-read User $user
*/
class CustomSubjectQuestion extends Model
{
/** @var array<int, string> */
protected $fillable = [
'custom_subject_id',
'user_id',
'question',
'answer',
'provider',
'model',
'input_tokens',
'output_tokens',
'asked_at',
];
/** @var array<string, string> */
protected $casts = [
'asked_at' => 'datetime',
];
/**
* Get the custom subject associated with this question.
*/
public function customSubject(): BelongsTo
{
return $this->belongsTo(CustomSubject::class);
}
/**
* Get the user who asked this question.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Enums\MessageType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $user_id
* @property int $subject_id
* @property string $content
* @property string $type
* @property array|null $metadata
* @property int $input_tokens
* @property int $output_tokens
* @property \Illuminate\Support\Carbon|null $sent_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
* @property-read Subject $subject
*/
class Insight extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'subject_id',
'content',
'type',
'metadata',
'input_tokens',
'output_tokens',
'sent_at',
];
/** @var array<string, string> */
protected $casts = [
'metadata' => 'array',
'sent_at' => 'datetime',
'type' => MessageType::class,
];
/**
* Get the user that owns the insight.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the subject associated with the insight.
*/
public function subject(): BelongsTo
{
return $this->belongsTo(Subject::class);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $user_id
* @property int $subject_id
* @property string $frequency
* @property array|null $weekdays
* @property string|null $preferred_time
* @property bool $is_active
* @property \Illuminate\Support\Carbon|null $last_sent_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
* @property-read Subject $subject
*/
class InsightSchedule extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'subject_id',
'frequency',
'weekdays',
'preferred_time',
'is_active',
'last_sent_at',
];
/** @var array<string, string> */
protected $casts = [
'weekdays' => 'array',
'is_active' => 'boolean',
'last_sent_at' => 'datetime',
'preferred_time' => 'datetime:H:i',
];
/**
* Get the user associated with this schedule.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the subject associated with this schedule.
*/
public function subject(): BelongsTo
{
return $this->belongsTo(Subject::class);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Invoice extends Model
{
protected $fillable = ['user_id', 'user_subscription_id', 'invoice_number', 'amount', 'currency', 'status', 'payment_method', 'paid_at', 'pdf_path'];
protected $casts = [
'amount' => 'decimal:2',
'paid_at' => 'datetime',
];
public function user(): BelongsTo { return $this->belongsTo(User::class); }
public function subscription(): BelongsTo { return $this->belongsTo(UserSubscription::class, 'user_subscription_id'); }
}
+25
View File
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $key
* @property string|null $value
* @property string $type
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
*/
class Setting extends Model
{
/** @var array<int, string> */
protected $fillable = [
'key',
'value',
'type',
];
}
+66
View File
@@ -0,0 +1,66 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property int|null $user_id
* @property string $name
* @property string|null $description
* @property string|null $introduction
* @property bool $is_system
* @property bool $is_active
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User|null $user
* @property-read Collection<int, UserSubject> $userSubjects
* @property-read Collection<int, Insight> $insights
*/
class Subject extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'name',
'description',
'introduction',
'message_type',
'custom_instructions',
'is_system',
'is_active',
];
/** @var array<string, string> */
protected $casts = [
'is_system' => 'boolean',
'is_active' => 'boolean',
];
/**
* Get the user who created the subject.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the user subjects associated with this subject.
*/
public function userSubjects(): HasMany
{
return $this->hasMany(UserSubject::class);
}
/**
* Get the insights associated with this subject.
*/
public function insights(): HasMany
{
return $this->hasMany(Insight::class);
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class SubscriptionPlan extends Model
{
protected $fillable = ['name', 'description', 'price', 'currency', 'duration_days', 'token_limit', 'is_active'];
protected $casts = [
'price' => 'decimal:2',
'duration_days' => 'integer',
'token_limit' => 'integer',
'is_active' => 'boolean',
];
public function userSubscriptions(): HasMany
{
return $this->hasMany(UserSubscription::class);
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Represents a Telegram user connection with their own bot configuration.
*
* @property int $id
* @property int $user_id
* @property string $telegram_user_id
* @property string|null $bot_token User's own Telegram bot token
* @property string|null $bot_username User's own Telegram bot username
* @property string|null $chat_id Telegram chat ID for sending messages
* @property string|null $telegram_username
* @property string|null $telegram_first_name
* @property string|null $telegram_last_name
* @property bool $is_active
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
*/
class TelegramUser extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'telegram_user_id',
'bot_token',
'bot_username',
'chat_id',
'telegram_username',
'telegram_first_name',
'telegram_last_name',
'is_active',
];
/** @var array<string, string> */
protected $casts = [
'is_active' => 'boolean',
];
/**
* Get the user associated with this telegram user.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Check if the user has a fully configured bot.
*/
public function isFullyConfigured(): bool
{
return !empty($this->bot_token) && !empty($this->chat_id);
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $user_id
* @property int $input_tokens
* @property int $output_tokens
* @property int $total_tokens
* @property string|null $model
* @property string|null $provider
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
*/
class TokenUsage extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'input_tokens',
'output_tokens',
'total_tokens',
'model',
'provider',
];
/** @var array<string, string> */
protected $casts = [
'input_tokens' => 'integer',
'output_tokens' => 'integer',
'total_tokens' => 'integer',
];
/**
* Get the user associated with this token usage.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
+145
View File
@@ -0,0 +1,145 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
/**
* @property int $id
* @property string $name
* @property string $email
* @property \Illuminate\Support\Carbon|null $email_verified_at
* @property string $password
* @property string|null $remember_token
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string|null $phone
* @property string $locale
* @property bool $is_active
* @property bool $is_approved
* @property-read Collection<int, UserSubject> $userSubjects
* @property-read Collection<int, Insight> $insights
* @property-read Collection<int, InsightSchedule> $insightSchedules
* @property-read Collection<int, TelegramUser> $telegramUsers
* @property-read Collection<int, TokenUsage> $tokenUsages
* @property-read Collection<int, Subject> $subjects
*/
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable, HasRoles;
/** @var array<int, string> */
protected $fillable = [
'name',
'email',
'password',
'phone',
'locale',
'timezone',
'is_active',
'is_approved',
'token_limit',
];
/** @var array<string, string> */
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
'is_active' => 'boolean',
'is_approved' => 'boolean',
'token_limit' => 'integer',
];
/** @var array<int, string> */
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the user subjects for the user.
*/
public function userSubjects(): HasMany
{
return $this->hasMany(UserSubject::class);
}
/**
* Get the user interests for the user.
*/
public function userInterests(): HasMany
{
return $this->hasMany(UserInterest::class);
}
/**
* Get the insights for the user.
*/
public function insights(): HasMany
{
return $this->hasMany(Insight::class);
}
/**
* Get the insight schedules for the user.
*/
public function insightSchedules(): HasMany
{
return $this->hasMany(InsightSchedule::class);
}
/**
* Get the telegram users for the user.
*/
public function telegramUsers(): HasMany
{
return $this->hasMany(TelegramUser::class);
}
/**
* Get the token usages for the user.
*/
public function tokenUsages(): HasMany
{
return $this->hasMany(TokenUsage::class);
}
/**
* Get the subjects created by the user.
*/
public function subjects(): HasMany
{
return $this->hasMany(Subject::class);
}
/**
* Get the user consents.
*/
public function consents(): HasMany
{
return $this->hasMany(UserConsent::class);
}
/**
* Get the user subscriptions.
*/
public function subscriptions(): HasMany
{
return $this->hasMany(\App\Models\UserSubscription::class);
}
/**
* Get the user notifications.
*/
public function notifications(): HasMany
{
return $this->hasMany(\App\Models\UserNotification::class);
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UserConsent extends Model
{
protected $fillable = [
'user_id',
'terms_version',
'privacy_version',
'cookie_version',
'accepted_at',
'ip_address',
'user_agent',
];
protected $casts = [
'accepted_at' => 'datetime',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $user_id
* @property string $interest
* @property-read \Illuminate\Support\Carbon|null $created_at
* @property-read \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
*/
class UserInterest extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'interest',
];
/**
* Get the user that owns the interest.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UserNotification extends Model
{
protected $fillable = ['user_id', 'type', 'title', 'message', 'is_read', 'read_at'];
protected $casts = [
'is_read' => 'boolean',
'read_at' => 'datetime',
];
public function user(): BelongsTo { return $this->belongsTo(User::class); }
public function markAsRead(): void
{
$this->update(['is_read' => true, 'read_at' => now()]);
}
public function typeIcon(): string
{
return match ($this->type) {
'payment_due' => '💰',
'payment_overdue' => '🔴',
'subscription_expiring' => '⚠️',
'subscription_expired' => '🚫',
'payment_received' => '✅',
'admin_message' => '📢',
'new_registration' => '👋',
default => '📌',
};
}
}
+96
View File
@@ -0,0 +1,96 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Represents the relationship between a user and a subject they are subscribed to.
*
* @property int $id
* @property int $user_id
* @property int $subject_id
* @property bool $is_active
* @property string $frequency Frequency of insight delivery (daily, weekly, biweekly, monthly)
* @property array|null $preferred_times Array of preferred delivery times in H:i format
* @property string|null $preferred_time (deprecated) Single preferred time, use preferred_times instead
* @property array|null $weekdays Days of the week for delivery (0=Sunday, 6=Saturday)
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read User $user
* @property-read Subject $subject
*/
class UserSubject extends Model
{
/** @var array<int, string> */
protected $fillable = [
'user_id',
'subject_id',
'is_active',
'frequency',
'preferred_times',
'weekdays',
'insight_language',
'delivery_channels',
];
/** @var array<string, string> */
protected $casts = [
'is_active' => 'boolean',
'weekdays' => 'array',
'preferred_times' => 'array',
'delivery_channels' => 'array',
];
/**
* Get default delivery channels.
*/
public static function getDefaultChannels(): array
{
return ['dashboard'];
}
/**
* Check if a specific delivery channel is enabled.
*/
public function hasChannel(string $channel): bool
{
$channels = $this->delivery_channels ?? self::getDefaultChannels();
return in_array($channel, $channels, true);
}
/**
* Get the user associated with this user subject.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the subject associated with this user subject.
*/
public function subject(): BelongsTo
{
return $this->belongsTo(Subject::class);
}
/**
* Get the preferred times as a formatted string for display.
*/
public function getFormattedTimesAttribute(): string
{
if (empty($this->preferred_times)) {
return __('Any time');
}
$times = collect($this->preferred_times)
->map(fn ($time) => substr($time, 0, 5))
->implode(', ');
return $times;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class UserSubscription extends Model
{
protected $fillable = ['user_id', 'subscription_plan_id', 'start_date', 'end_date', 'status', 'payment_approved', 'cancelled_at'];
protected $casts = [
'start_date' => 'datetime',
'end_date' => 'datetime',
'payment_approved' => 'boolean',
'cancelled_at' => 'datetime',
];
public function user(): BelongsTo { return $this->belongsTo(User::class); }
public function plan(): BelongsTo { return $this->belongsTo(SubscriptionPlan::class, 'subscription_plan_id'); }
public function invoices(): HasMany { return $this->hasMany(Invoice::class); }
public function isActive(): bool
{
return $this->status === 'active' && $this->end_date > now();
}
public function isExpiringSoon(int $days = 7): bool
{
return $this->isActive() && $this->end_date <= now()->addDays($days);
}
}