# 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 ```