# 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

```
