Unified Downloads & 10 Daily Free Quota Architecture (user_download_list Engine)

# Unified Downloads & 10 Daily Free Quota Architecture (user_download_list Engine) ## 1. Core Philosophy & Anti-Table-Duplication Standard To maintain extreme database efficiency and avoid table fragmentation, Pixahunt strictly adheres to the **Anti-Table-Duplication Rule**. We do not create separate per-module download tracking tables (such as `photo_downloads`, `wallpaper_downloads`, `mockup_downloads`, `svg_downloads`). Instead, all asset downloads across all media categories are consolidated into a single, high-performance master table: `user_download_list`. --- ## 2. Database Schema & Storage Efficiency ### Migration * `database/migrations/2026_10_12_202000_create_user_download_list_table.php` ### Table: `user_download_list` | Column | Type | Description | |---|---|---| | `id` | `BIGINT UNSIGNED AUTO_INCREMENT` | Primary Key | | `user_id` | `BIGINT UNSIGNED` | Foreign Key referencing `users.id` (Indexed, Cascade on Delete) | | `download_date` | `DATE` | Current UTC calendar date (Indexed) | | `downloads` | `JSON` | List of downloaded asset items for that date | | `download_count` | `INT UNSIGNED` | Running total count for the day (Default 0) | | `created_at` | `TIMESTAMP` | Record creation timestamp | | `updated_at` | `TIMESTAMP` | Last download update timestamp | ### Composite Index * `UNIQUE INDEX unique_user_daily_download (user_id, download_date)` > [!IMPORTANT] > **1 Row Per User Per Day Guarantee:** > Regardless of whether a user downloads 1 asset or 100 assets, exactly **ONE single database row** is stored for that user on that calendar day. Each download appends a lightweight object to the `downloads` JSON array and increments `download_count`. This eliminates millions of redundant rows annually. --- ## 3. Daily Free Quota & Pro Rules ### 10 Daily Free Quota Rule * Every registered user without an active Pro subscription receives **10 free downloads every calendar day**. * Once 10 downloads are consumed on a given date, the user is prevented from downloading further free assets until the next calendar day, or until they upgrade to Pro. * Friendly warning banner is displayed: *"Daily download limit reached (10/10). Upgrade to Pro for unlimited downloads."* ### Pro Subscription Status * Checked via `User::isPro()` which inspects active verified Pro subscriptions. * Pro users have **unlimited daily downloads** and are never capped by the 10-item limit. ### Pro Assets vs. Free Assets * **Free Assets:** Can be downloaded by any user within their 10 daily download quota. Free assets **MUST NOT** show a PRO lock badge or disable download buttons for regular users. * **Pro Assets (`is_pro = 1`):** Require an active Pro subscription to unlock and download. --- ## 4. Service Layer: `DownloadManagerService` **Namespace:** `App\Services\DownloadManagerService` ### Core Methods: 1. `canDownload(?User $user, bool $isProAsset): array` - Evaluates whether the user can download the item. - Returns: ```php [ 'allowed' => true|false, 'reason' => 'ok'|'login_required'|'pro_required'|'daily_limit_reached', 'remaining' => 7, // integer remaining downloads 'is_pro_user' => false, ] ``` 2. `recordDownload(User $user, string $assetType, int $assetId, array $metadata = []): UserDownloadList` - Atomically fetches or creates the daily row via `firstOrCreate(['user_id' => $user->id, 'download_date' => $today])`. - Appends item: `['type' => $assetType, 'id' => $assetId, 'downloaded_at' => now(), 'metadata' => $metadata]`. - Increments `download_count`. 3. `getDailyRecord(User $user, ?string $date = null): ?UserDownloadList` 4. `getRemainingDownloads(User $user): int` --- ## 5. Front-End & UI Guidelines 1. **Brand Colors:** - Primary download action buttons must use the secondary action brand color: `bg-orange-500` / `hover:bg-orange-600` (text: `text-white`). 2. **Quota Indicator:** - Display live remaining count on detail pages: `{{ $remainingDownloads }}/10 Left Today`. - If user is Pro, show `Pro Member (Unlimited)`. 3. **CDN Strict Delivery:** - All display thumbnails are delivered via Bunny CDN (`\App\Models\SiteSetting::current()->cdn`). - Actual original assets are streamed securely through controller download endpoints with quota enforcement. 4. **Templates Updated:** - `resources/views/frontend/photos/show.blade.php` - `resources/views/frontend/photos/wallpaper_show.blade.php`