# TikTok Shop Data Ownership Redesign

**Document Version:** 1.0
**Created:** November 19, 2025
**Status:** Proposal (Not Implemented)

---

## Table of Contents
1. [Current Problem](#current-problem)
2. [Current Implementation](#current-implementation)
3. [Proposed Solution](#proposed-solution)
4. [Database Schema Changes](#database-schema-changes)
5. [Implementation Checklist](#implementation-checklist)
6. [Migration Plan](#migration-plan)
7. [Testing Scenarios](#testing-scenarios)

---

## Current Problem

### Issue Description
The TikTok Shop data is currently tied to **WHO uploaded it** (user_id) instead of **WHICH TikTok Shop account** it belongs to. This creates multiple problems:

### Problems Identified

1. **Data Ownership Issue**
   - When Sales Hudin (Manager) uploads TikTok data → permanently tied to `user_id = 11`
   - If his `can_manage_tiktok_shop` permission is removed → he loses access BUT his data still shows in his dashboard Total Revenue
   - This causes incorrect revenue calculations when permission is revoked

2. **Cannot Transfer Ownership**
   - If you appoint a NEW manager to handle TikTok Shop → they cannot see historical data
   - Historical data remains tied to the original uploader
   - No way to reassign TikTok Shop responsibility

3. **No Multi-Shop Support**
   - Cannot distinguish between multiple TikTok Shop accounts
   - User management only has a checkbox `can_manage_tiktok_shop` (yes/no)
   - No way to specify WHICH TikTok Shop account a manager handles

4. **Inconsistent with Store Design**
   - Regular stores have proper assignment: `Store → assigned to User`
   - TikTok Shop lacks this structure
   - Creates confusion in system design

---

## Current Implementation

### Database Schema (Current)

**users table:**
```
- id
- name
- role (admin, manager, seller)
- can_manage_tiktok_shop (boolean) ← Just a checkbox
```

**tiktok_transactions table:**
```
- id
- user_id ← Tied to uploader, used for filtering
- order_id
- type
- order_date
- settled_date
- total_revenue
- net_settlement
- ...
```

### Current Logic Flow

1. **Upload Process:**
   - Manager uploads TikTok Excel file
   - System sets `user_id = auth()->id()` (uploader)
   - Data permanently tied to that user

2. **Dashboard Filtering:**
   - Admin: Sees ALL TikTok data
   - Manager: Sees only where `user_id = their_id`
   - Problem: Data tied to uploader, not shop ownership

3. **Permission Check:**
   - `can_manage_tiktok_shop` = 1 → Can access TikTok features
   - `can_manage_tiktok_shop` = 0 → Blocked from TikTok pages (403)
   - BUT: Historical data still calculated in dashboard stats

### Files Affected (Current)
- `app/Models/TikTokTransaction.php` - Transaction model
- `app/Services/DashboardStatsService.php` - Dashboard calculations (filters by user_id)
- `app/Http/Controllers/TikTokShopController.php` - TikTok Shop page (filters by user_id)
- `database/migrations/*_create_tiktok_transactions_table.php` - Current schema

---

## Proposed Solution

### Design Philosophy
Make TikTok Shops work **exactly like Stores**:
- Stores are separate entities
- Users are assigned to stores
- Data belongs to the store, not the person who created orders

### New Architecture

```
┌─────────────────┐
│  TikTok Shops   │ ← New entity (like Stores)
│  - Shop ID      │
│  - Shop Name    │
│  - Description  │
└────────┬────────┘
         │
         │ assigned_to
         ▼
    ┌─────────┐
    │  Users  │
    │ (Mgr)   │
    └─────────┘
         │
         │ uploads_data_for
         ▼
┌──────────────────────┐
│ TikTok Transactions  │
│ - tiktok_shop_id ←─┐ │
│ - uploaded_by      │ │
└────────────────────┴─┘
         belongs_to
```

### Key Concepts

1. **TikTok Shop Entity**
   - Each TikTok Shop account is a separate entity
   - Has ID, name, description
   - Can be assigned to managers

2. **Data Belongs to Shop**
   - Transactions tagged with `tiktok_shop_id` (shop ownership)
   - Still track `uploaded_by` (user_id for audit trail)
   - Filtering done by `tiktok_shop_id`, NOT `user_id`

3. **Easy Transfer**
   - Change shop assignment → new manager sees all historical data
   - Old manager loses access immediately
   - Data stays with the shop

4. **Multi-Shop Support**
   - Manager can be assigned to multiple TikTok Shops
   - Clear visibility in user management which manager handles which shop
   - Similar to how users can be assigned to multiple stores

---

## Database Schema Changes

### 1. New Table: `tiktok_shops`

```sql
CREATE TABLE `tiktok_shops` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL COMMENT 'Shop name (e.g., "Mamadil TikTok Shop")',
  `description` text NULL COMMENT 'Optional description',
  `is_active` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Active status',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### 2. New Pivot Table: `tiktok_shop_user`

```sql
CREATE TABLE `tiktok_shop_user` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `tiktok_shop_id` bigint(20) UNSIGNED NOT NULL,
  `user_id` bigint(20) UNSIGNED NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `tiktok_shop_user_unique` (`tiktok_shop_id`, `user_id`),
  KEY `tiktok_shop_user_tiktok_shop_id_foreign` (`tiktok_shop_id`),
  KEY `tiktok_shop_user_user_id_foreign` (`user_id`),
  CONSTRAINT `tiktok_shop_user_tiktok_shop_id_foreign`
    FOREIGN KEY (`tiktok_shop_id`) REFERENCES `tiktok_shops` (`id`) ON DELETE CASCADE,
  CONSTRAINT `tiktok_shop_user_user_id_foreign`
    FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### 3. Modify Table: `tiktok_transactions`

```sql
ALTER TABLE `tiktok_transactions`
ADD COLUMN `tiktok_shop_id` bigint(20) UNSIGNED NULL AFTER `id`,
ADD KEY `tiktok_transactions_tiktok_shop_id_foreign` (`tiktok_shop_id`),
ADD CONSTRAINT `tiktok_transactions_tiktok_shop_id_foreign`
  FOREIGN KEY (`tiktok_shop_id`) REFERENCES `tiktok_shops` (`id`) ON DELETE SET NULL;

-- Rename user_id to uploaded_by for clarity
ALTER TABLE `tiktok_transactions`
CHANGE COLUMN `user_id` `uploaded_by` bigint(20) UNSIGNED NULL;

-- Add comment for clarity
ALTER TABLE `tiktok_transactions`
MODIFY COLUMN `uploaded_by` bigint(20) UNSIGNED NULL
  COMMENT 'User who uploaded this transaction (audit trail)';
```

### 4. Modify Table: `users` (Optional)

```sql
-- Can remove can_manage_tiktok_shop since assignment is now in pivot table
-- OR keep it as a general permission flag (recommended)
ALTER TABLE `users`
MODIFY COLUMN `can_manage_tiktok_shop` tinyint(1) DEFAULT 0
  COMMENT 'General permission to access TikTok Shop features';
```

### 5. Similar Update for `tiktok_ads_transactions`

```sql
ALTER TABLE `tiktok_ads_transactions`
ADD COLUMN `tiktok_shop_id` bigint(20) UNSIGNED NULL AFTER `id`,
ADD KEY `tiktok_ads_transactions_tiktok_shop_id_foreign` (`tiktok_shop_id`),
ADD CONSTRAINT `tiktok_ads_transactions_tiktok_shop_id_foreign`
  FOREIGN KEY (`tiktok_shop_id`) REFERENCES `tiktok_shops` (`id`) ON DELETE SET NULL,
CHANGE COLUMN `user_id` `uploaded_by` bigint(20) UNSIGNED NULL
  COMMENT 'User who uploaded this transaction (audit trail)';
```

---

## Implementation Checklist

### Phase 1: Database Layer
- [ ] Create migration for `tiktok_shops` table
- [ ] Create migration for `tiktok_shop_user` pivot table
- [ ] Create migration to modify `tiktok_transactions` table
- [ ] Create migration to modify `tiktok_ads_transactions` table
- [ ] Create `TikTokShop` model with relationships
- [ ] Add `tiktokShops()` relationship to `User` model
- [ ] Update `TikTokTransaction` model relationships

### Phase 2: User Management Interface
- [ ] Create TikTok Shops CRUD (index, create, edit, delete)
- [ ] Add "TikTok Shops" section in Users edit page
- [ ] Multi-select interface to assign shops to managers
- [ ] Display assigned TikTok Shops in Users index
- [ ] Add validation rules for shop assignment

### Phase 3: Import Process
- [ ] Modify TikTok import upload form to select shop
- [ ] Add shop dropdown in upload interface
- [ ] Update `TikTokImportService` to accept `tiktok_shop_id`
- [ ] Update `TikTokAdsImportService` to accept `tiktok_shop_id`
- [ ] Validate user has permission to upload to selected shop

### Phase 4: Query Filtering
- [ ] Update `DashboardStatsService::getPeriodStats()` to filter by `tiktok_shop_id`
- [ ] Update `TikTokShopController::index()` to filter by `tiktok_shop_id`
- [ ] Update `TikTokShopController::dailyStats()` to filter by `tiktok_shop_id`
- [ ] Add helper method `User::getTikTokShopIds()` (similar to `getStoreIds()`)
- [ ] Update all TikTok queries to use shop-based filtering

### Phase 5: Permission Logic
- [ ] Update permission check: `can_manage_tiktok_shop` AND `has assigned shops`
- [ ] Block access if no shops assigned
- [ ] Admin sees all shops
- [ ] Manager sees only assigned shops

### Phase 6: Data Migration
- [ ] Create script to migrate existing `tiktok_transactions.user_id` → `tiktok_shop_id`
- [ ] Create default TikTok Shop for existing data
- [ ] Assign existing managers to default shop
- [ ] Verify data integrity after migration

### Phase 7: Testing
- [ ] Test multi-shop assignment
- [ ] Test shop transfer between managers
- [ ] Test permission revocation (should remove ALL TikTok data from dashboard)
- [ ] Test dashboard calculations with multiple shops
- [ ] Test import process with shop selection

---

## Migration Plan

### Step 1: Create Default Shop (for existing data)
```php
// In migration or seeder
$defaultShop = TikTokShop::create([
    'name' => 'Main TikTok Shop',
    'description' => 'Default shop for existing transactions',
    'is_active' => 1
]);
```

### Step 2: Migrate Existing Transactions
```php
// Map all existing transactions to default shop
TikTokTransaction::whereNull('tiktok_shop_id')
    ->update(['tiktok_shop_id' => $defaultShop->id]);

TikTokAdsTransaction::whereNull('tiktok_shop_id')
    ->update(['tiktok_shop_id' => $defaultShop->id]);
```

### Step 3: Assign Existing Managers
```php
// Find all managers with TikTok permission
$managers = User::where('role', 'manager')
    ->where('can_manage_tiktok_shop', 1)
    ->get();

// Assign them to default shop
foreach ($managers as $manager) {
    $manager->tiktokShops()->attach($defaultShop->id);
}
```

### Step 4: Verify Data
```sql
-- Check all transactions have shop assigned
SELECT COUNT(*) FROM tiktok_transactions WHERE tiktok_shop_id IS NULL;

-- Check manager assignments
SELECT u.name, ts.name
FROM users u
JOIN tiktok_shop_user tsu ON u.id = tsu.user_id
JOIN tiktok_shops ts ON tsu.tiktok_shop_id = ts.id
WHERE u.role = 'manager';
```

---

## Testing Scenarios

### Scenario 1: Single Manager, Single Shop
**Setup:**
- Create "Mamadil TikTok Shop"
- Assign to Manager A
- Upload October 2025 data

**Expected:**
- ✅ Manager A sees October data in dashboard
- ✅ Manager A sees October data in TikTok Shop page
- ✅ Admin sees all data

**Test Revocation:**
- Remove Manager A from shop assignment
- ✅ Manager A gets 403 on TikTok Shop page
- ✅ Manager A dashboard shows NO TikTok revenue
- ✅ Admin still sees all data

---

### Scenario 2: Transfer Ownership
**Setup:**
- Manager A assigned to "Mamadil TikTok Shop" with historical data
- Create Manager B

**Test Transfer:**
- Remove Manager A from shop
- Assign Manager B to shop
- ✅ Manager A sees no TikTok data
- ✅ Manager B sees ALL historical TikTok data (including what Manager A uploaded)

---

### Scenario 3: Multiple Shops
**Setup:**
- Create "Electronics TikTok Shop" → Assign to Manager A
- Create "Fashion TikTok Shop" → Assign to Manager B
- Upload data for each shop

**Expected:**
- ✅ Manager A sees only Electronics data
- ✅ Manager B sees only Fashion data
- ✅ Admin sees combined data from both shops
- ✅ Dashboard Total Revenue = sum of assigned shops only

---

### Scenario 4: Multi-Shop Manager
**Setup:**
- Create Shop A and Shop B
- Assign BOTH shops to Manager X

**Expected:**
- ✅ Manager X sees combined data from both shops
- ✅ Dashboard shows sum of both shops
- ✅ TikTok Shop page shows transactions from both shops (with shop name column)

---

## Key Files to Modify

### Models
- `app/Models/TikTokShop.php` (NEW)
- `app/Models/User.php` - Add relationship
- `app/Models/TikTokTransaction.php` - Update relationship
- `app/Models/TikTokAdsTransaction.php` - Update relationship

### Controllers
- `app/Http/Controllers/TikTokShopController.php` - Change filtering logic
- `app/Http/Controllers/TikTokShopsManagementController.php` (NEW) - CRUD for shops
- `app/Http/Controllers/UserController.php` - Add shop assignment interface

### Services
- `app/Services/DashboardStatsService.php` - Change filtering from user_id to shop_id
- `app/Services/TikTokImportService.php` - Add shop_id parameter
- `app/Services/TikTokAdsImportService.php` - Add shop_id parameter

### Views
- `resources/views/tiktok-shops/index.blade.php` (NEW) - Shop management
- `resources/views/tiktok-shops/create.blade.php` (NEW)
- `resources/views/tiktok-shops/edit.blade.php` (NEW)
- `resources/views/users/edit.blade.php` - Add TikTok Shop assignment
- `resources/views/tiktok-shop/upload.blade.php` - Add shop selector dropdown

### Migrations
- `database/migrations/YYYY_MM_DD_create_tiktok_shops_table.php` (NEW)
- `database/migrations/YYYY_MM_DD_create_tiktok_shop_user_table.php` (NEW)
- `database/migrations/YYYY_MM_DD_modify_tiktok_transactions_add_shop.php` (NEW)
- `database/migrations/YYYY_MM_DD_migrate_existing_tiktok_data.php` (NEW)

---

## Design Consistency Notes

### Similar to Stores Pattern
This design follows the exact same pattern as Stores:

**Stores:**
```
Store → User (via store_user pivot)
Orders → Store (via store_id)
Filter: User sees orders from their assigned stores
```

**TikTok Shops (New):**
```
TikTokShop → User (via tiktok_shop_user pivot)
TikTokTransactions → TikTokShop (via tiktok_shop_id)
Filter: User sees transactions from their assigned shops
```

### User Model Pattern
```php
// Existing Store relationship
public function stores()
{
    return $this->belongsToMany(Store::class, 'store_user');
}

public function getStoreIds()
{
    return $this->stores()->pluck('stores.id')->toArray();
}

// New TikTok Shop relationship (mirror pattern)
public function tiktokShops()
{
    return $this->belongsToMany(TikTokShop::class, 'tiktok_shop_user');
}

public function getTikTokShopIds()
{
    return $this->tiktokShops()->pluck('tiktok_shops.id')->toArray();
}
```

---

## Questions Answered

**Q1: Do you have multiple TikTok Shop accounts?**
- A: YES → This design supports multiple shops

**Q2: Do you plan to have multiple managers handling TikTok shops?**
- A: YES → Each manager can be assigned to specific shops

**Q3: Should TikTok data behave exactly like Store data?**
- A: YES → This design mirrors the Store assignment pattern

---

## Benefits of This Design

1. ✅ **Clear Ownership** - Data belongs to shop, not uploader
2. ✅ **Easy Transfer** - Reassign shop → new manager sees all historical data
3. ✅ **Multi-Shop Support** - Handle multiple TikTok Shop accounts
4. ✅ **Proper Permissions** - No TikTok data shown when permission removed
5. ✅ **Audit Trail** - Still track who uploaded what (`uploaded_by` field)
6. ✅ **Consistent Design** - Matches existing Store pattern
7. ✅ **Scalable** - Easy to add more shops in the future

---

## Notes & Considerations

### Backward Compatibility
- Existing transactions need migration to default shop
- Can run system in "migration mode" before enforcing shop_id requirement
- Make `tiktok_shop_id` nullable during transition period

### Admin Behavior
- Admin sees ALL shops (no filtering)
- Admin can manage all shops in TikTok Shops CRUD
- Admin can assign any shop to any manager

### Upload Process Changes
- Add dropdown: "Select TikTok Shop" in upload form
- Validate: User has permission to upload to selected shop
- If manager has only 1 shop → auto-select it

### Permission Hierarchy
```
Level 1: can_manage_tiktok_shop = 1 (general permission)
Level 2: Assigned to at least one TikTok Shop (specific access)
Both required for manager to see TikTok data
```

---

## Status

**Current Status:** Proposal (Discussion Phase)
**Approved By:** Pending
**Implementation Start:** TBD
**Expected Completion:** TBD

---

## Related Documents
- User Management System Design
- Store Assignment Logic
- Dashboard Revenue Calculation Logic
- TikTok Import Process Documentation

---

**End of Document**
