Fantasy
+ + ++ Fantasy is a genre of art that uses magic and other supernatural forms as a primary element of plot, theme, or setting. + In its broadest sense, fantasy comprises works by authors, artists, filmmakers and musicians... +
+diff --git a/.copilot/favourites_artworks.md b/.copilot/favourites_artworks.md new file mode 100644 index 00000000..a46c6286 --- /dev/null +++ b/.copilot/favourites_artworks.md @@ -0,0 +1,181 @@ +# 1️⃣ Final SQL – New Favorites Table (Artwork-only) + +**Table name:** `user_favorites` +**Scope:** users ↔ artworks +**Engine:** InnoDB +**Charset:** utf8mb4 + +```sql +CREATE TABLE user_favorites ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + + user_id BIGINT UNSIGNED NOT NULL, + artwork_id BIGINT UNSIGNED NOT NULL, + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + UNIQUE KEY uniq_user_artwork (user_id, artwork_id), + KEY idx_artwork (artwork_id), + KEY idx_user_created (user_id, created_at), + + CONSTRAINT fk_user_favorites_user + FOREIGN KEY (user_id) REFERENCES users(id) + ON DELETE CASCADE, + + CONSTRAINT fk_user_favorites_artwork + FOREIGN KEY (artwork_id) REFERENCES artworks(id) + ON DELETE CASCADE +) ENGINE=InnoDB + DEFAULT CHARSET=utf8mb4 + COLLATE=utf8mb4_unicode_ci; +``` + +This is **production-ready** and matches everything we discussed: + +* no legacy fields +* no duplication +* proper constraints +* fast queries + +--- + +# 2️⃣ VS Code Agent Markdown (Laravel 12 Migration Prompt) + +Save this as for example: + +``` +.vscode/agents/laravel-user-favorites-migration.md +``` + +or + +``` +.cursor/rules/laravel-user-favorites.md +``` + +--- + +```markdown +# Laravel 12 – User Favorites Migration & Model + +## Context +We are migrating legacy "favourites" functionality into a clean, modern Laravel 12 system. +Each user can add artworks to their favorites list. +This is a many-to-many relationship between users and artworks. + +Legacy table MUST NOT be reused. + +--- + +## Goal +Create a Laravel 12 database migration and Eloquent model for a new table named: + +``` + +user_favorites + +```` + +This table stores **which user favorited which artwork**, with a timestamp. + +--- + +## Database Requirements + +### Table: user_favorites + +| Column | Type | Notes | +|------|------|------| +| id | BIGINT UNSIGNED | Primary key | +| user_id | BIGINT UNSIGNED | FK → users.id | +| artwork_id | BIGINT UNSIGNED | FK → artworks.id | +| created_at | TIMESTAMP | When artwork was favorited | + +### Constraints & Indexes + +- UNIQUE (user_id, artwork_id) + → prevents duplicate favorites + +- INDEX artwork_id + → fast favorite count per artwork + +- INDEX (user_id, created_at) + → fast "my favorites" queries + +### Foreign Keys + +- user_id → users.id (ON DELETE CASCADE) +- artwork_id → artworks.id (ON DELETE CASCADE) + +### Engine & Charset + +- Engine: InnoDB +- Charset: utf8mb4 +- Collation: utf8mb4_unicode_ci + +--- + +## Laravel Migration Requirements + +- Use `Schema::create` +- Use `foreignId()->constrained()->cascadeOnDelete()` +- Use `timestamps()` **ONLY if created_at is needed** + (do NOT add updated_at) + +- Add explicit indexes and unique constraints + +--- + +## Laravel Model Requirements + +### Model: UserFavorite + +- Table: `user_favorites` +- `$timestamps = false` (created_at handled manually or via DB default) +- Fillable: + - user_id + - artwork_id + - created_at + +### Relationships + +```php +UserFavorite belongsTo User +UserFavorite belongsTo Artwork +```` + +--- + +## Additional Notes + +* This table is interaction-based, NOT content-based +* Do NOT store favorite counts here +* Favorite counts will be aggregated separately (Redis or statistics table) +* This table must be lean and write-optimized + +--- + +## Deliverables + +* Migration file for Laravel 12 +* Eloquent model `UserFavorite` +* Proper naming and clean schema +* No legacy fields, no polymorphic logic + +Generate clean, production-quality code. + +```` + +--- + +## 3️⃣ How to Use This in VS Code (Quick Steps) + +1. Paste markdown into `.vscode/agents/` or `.cursor/rules/` +2. Open VS Code +3. Ask your AI agent: + > “Create Laravel 12 migration and model based on this document” +4. Review generated migration +5. Run: +```bash +php artisan migrate +```` diff --git a/.copilot/update_user_schema.md b/.copilot/update_user_schema.md new file mode 100644 index 00000000..3c8043a8 --- /dev/null +++ b/.copilot/update_user_schema.md @@ -0,0 +1,312 @@ +# Skinbase – User Schema Review & Upgrade Plan + +**Database:** MySQL / Percona 8.x +**Project:** Skinbase (new system, no legacy dependencies) +**Reviewed tables:** users, user_profiles, user_social_links, user_statistics + +--- + +## 1. Overview + +The current user-related database schema is **well designed**, modern, and suitable +for long-term growth. +Key strengths include: + +- Clear separation of concerns +- Proper use of foreign keys and cascading deletes +- BigInt primary keys +- Soft deletes on users +- Migration-friendly legacy password handling + +This document summarizes: +- what is already good +- recommended optimizations +- future-proofing steps (non-breaking) +- performance considerations for scale + +--- + +## 2. users Table + +### 2.1 What’s Good + +- Unique `username` and `email` +- `legacy_password_algo` allows smooth migration from old systems +- `needs_password_reset` improves security posture +- Role stored as string allows flexibility in early stages +- Soft deletes enabled + +### 2.2 Recommended Indexes + +Add indexes for common query patterns: + +```sql +CREATE INDEX idx_users_active ON users (is_active); +CREATE INDEX idx_users_role ON users (role); +CREATE INDEX idx_users_last_visit ON users (last_visit_at); +```` + +These improve: + +* active user filtering +* admin queries +* “last seen” or online user features + +### 2.3 Future Role Normalization (Planned) + +Current approach is fine short-term: + +```text +role = 'user' | 'admin' | 'moderator' +``` + +Planned future upgrade: + +* `roles` table +* `user_roles` pivot table (many-to-many) + +This allows: + +* multiple roles per user +* temporary or scoped roles +* better permission modeling + +⚠️ No immediate action required — just avoid hard-coding role logic. + +### 2.4 Optional Security Enhancements + +Recommended additions (optional but advised): + +```sql +last_password_change_at TIMESTAMP NULL, +failed_login_attempts INT UNSIGNED DEFAULT 0, +locked_until TIMESTAMP NULL +``` + +Enables: + +* rate limiting +* temporary account locking +* better auditability + +--- + +## 3. user_profiles Table + +### 3.1 Strengths + +* Clean one-to-one relationship with `users` +* Public profile data separated from auth data +* Nullable fields for progressive profile completion +* Inclusive gender enum with safe default +* Localization-ready (`language`, `country_code`) + +### 3.2 Country Handling Recommendation + +Prefer using only: + +```text +country_code (ISO 3166-1 alpha-2) +``` + +Benefits: + +* language-independent +* avoids inconsistent country naming +* easier frontend mapping + +`country` text field can be deprecated later if needed. + +### 3.3 Avatar & Media Metadata (Future) + +Current: + +```text +avatar VARCHAR(255) +``` + +Recommended future approach: + +```text +avatar_hash CHAR(64) +avatar_ext VARCHAR(10) +avatar_updated_at TIMESTAMP +``` + +This aligns with: + +* hash-based file storage +* CDN-friendly URLs +* cache invalidation control + +--- + +## 4. user_social_links Table + +### 4.1 Current Design + +* One row per platform per user +* Unique constraint on `(user_id, platform)` +* Cascade delete enabled + +This is solid. + +### 4.2 Platform Normalization (Recommended) + +Current: + +```text +platform VARCHAR(32) +``` + +Risk: + +* inconsistent values (`twitter`, `x`, `Twitter`, etc.) + +Options: + +**Option A – Enum (simple):** + +```sql +ENUM('twitter','x','instagram','deviantart','artstation','github','website') +``` + +**Option B – Reference Table (best long-term):** + +* `social_platforms` +* foreign key `platform_id` + +Option B is preferred for Skinbase as platforms evolve. + +--- + +## 5. user_statistics Table + +### 5.1 Strengths + +* Isolated counters +* One row per user +* Minimal row size +* Clean FK relationship + +### 5.2 Performance Warning (Important) + +Avoid frequent direct updates like: + +```sql +UPDATE user_statistics SET downloads = downloads + 1; +``` + +At scale, this causes: + +* row locking +* write contention +* degraded performance + +### 5.3 Recommended Strategy + +* Use **Redis** (or in-memory cache) for real-time increments +* Periodically flush aggregated values to MySQL +* Use jobs / cron for batch updates + +This ensures: + +* fast user interactions +* scalable statistics tracking + +--- + +## 6. Charset & Collation + +Current: + +```text +utf8mb4_unicode_ci +``` + +This is correct and safe. + +Optional upgrade (MySQL 8+): + +```text +utf8mb4_0900_ai_ci +``` + +Benefits: + +* newer Unicode rules +* slightly better performance + +Not required immediately. + +--- + +## 7. Tables Planned for Future Expansion + +Not required now, but expected as Skinbase grows: + +### 7.1 user_activity_log + +* logins +* uploads +* profile edits +* moderation actions + +### 7.2 user_followers + +* artist-to-artist following +* social graph features + +### 7.3 user_settings + +* privacy preferences +* notification settings +* email subscriptions + +These should remain **separate tables** to avoid bloating `users`. + +--- + +## 8. Laravel Implementation Notes + +Recommended model casting: + +```php +protected $casts = [ + 'is_active' => 'boolean', + 'needs_password_reset' => 'boolean', + 'email_verified_at' => 'datetime', + 'last_visit_at' => 'datetime', +]; +``` + +Best practices: + +* Eager load profiles (`with('profile')`) +* Cache public profile + statistics +* Keep statistics out of main user queries + +--- + +## 9. Final Verdict + +**Schema quality:** Excellent +**Scalability:** Very good +**Migration readiness:** Excellent +**Long-term Skinbase fit:** Excellent + +The current schema is production-ready and significantly better than typical legacy +user databases. Most future improvements can be introduced **without breaking changes**. + +Primary future wins: + +* Redis-backed statistics +* normalized roles and social platforms +* hash-based media storage + +--- + +**Status:** Approved for production +**Next steps:** API design, public profile queries, legacy user migration + +``` diff --git a/app/Chat.php b/app/Chat.php index faa95f6b..f23720c5 100644 --- a/app/Chat.php +++ b/app/Chat.php @@ -22,7 +22,7 @@ class Chat return; } - $last = DB::connection('legacy')->table('chat') + $last = DB::table('chat') ->select('message') ->where('user_id', $userId) ->orderByDesc('chat_id') @@ -30,7 +30,7 @@ class Chat ->first(); if (!$last || ($last->message ?? '') !== $tekst) { - DB::connection('legacy')->table('chat')->insert([ + DB::table('chat')->insert([ 'time' => now(), 'sender' => $username, 'user_id' => $userId, @@ -43,7 +43,7 @@ class Chat { $output = "
+ Fantasy is a genre of art that uses magic and other supernatural forms as a primary element of plot, theme, or setting. + In its broadest sense, fantasy comprises works by authors, artists, filmmakers and musicians... +
+| Preview | +Title | +Created | +Public | +Approved | +Actions | +
|---|---|---|---|---|---|
|
+
+ |
+
+
+ #{{ $artwork->id }}
+ @if(!empty($artwork->description))
+
+ {{ str($artwork->description)->stripTags()->limit(120) }}
+
+ @endif
+ |
+ {{ optional($artwork->created_at)->format('d.m.Y') }} | ++ @if($artwork->is_public) + Yes + @else + No + @endif + | ++ @if($artwork->is_approved) + Yes + @else + No + @endif + | +
+
+
+ Edit
+
+
+
+
+ |
+
| No artworks found. | +|||||
Layout test area — add components here.
++ + Edit Profile + +
Members who follow you
+No followers yet.
+ @endforelse +{!! $category->description ?? ($contentType->name . ' artworks on Skinbase.') !!}
-{!! $category->description ?? ($contentType->name . ' artworks on Skinbase.') !!}
+ +Once uploads arrive they will appear here. Check back soon.
-Once uploads arrive they will appear here. Check back soon.
+List of uploaded Artworks which were added to user's favourites list
+| Thumb | +Name | +Author | +Date | +Dls | +Views | +Zoom | +Rating | +
|---|---|---|---|---|---|---|---|
|
+ |
+ + @if(auth()->check() && auth()->id() == ($ar->user_id ?? null)) + + @endif + {{ $ar->name }} + | +{{ $ar->uname ?? '' }} | +{{ is_string($ar->datum) ? date('d.m.Y', strtotime($ar->datum)) : '' }} | +{{ (int)($ar->dls ?? 0) }} | +{{ (int)($ar->views ?? 0) }} | +{{ e($ar->zoom ?? '') }} | +{{ e($ar->rating ?? '') }} | +
{{ $user->real_name ?? '' }}
+{{ $user->about_me ?? '' }}
+List of members you are following
+No buddies yet.
+ @endforelse +{!! $tidy ?? '' !!}
+List of comments left on your uploaded artworks.
+| Thumbnail | ++ Name + | ++ Downloads + | ++ Reviews + | ++ Section + | ++ Date + | +
|---|---|---|---|---|---|
|
+
+ |
+
+ {{ $art->name ?? '' }}
+ #{{ (int) $art->id }}
+ |
+ {{ (int) ($art->dls ?? 0) }} | +{{ (int) ($art->num_comments ?? 0) }} | +{{ $art->category_name ?? '' }} | ++ @if(!empty($art->datum)) + {{ is_string($art->datum) ? date('d.m.Y', strtotime($art->datum)) : '' }} + @endif + | +
| No artworks found. | +|||||
Comment by: {{ $author->name ?? $author->uname ?? '' }}
+{!! nl2br(e($author->signature)) !!}
+