# LeadPilot — Database Tenant Isolation & Ownership Map

**Document Version:** 1.0.0 (Phase 5 Database Architecture Lock)  
**Status:** Approved & Formally Recorded  

---

## 1. Direct vs. Indirect Workspace Ownership Map

Every tenant entity in LeadPilot possesses an explicit, non-nullable `workspace_id` foreign key. No tenant resource relies on indirect resolution chains:

```
+---------------------------------------------------------------------------------------------------------------+
| TABLE                      | TENANCY ENFORCEMENT METHOD      | GLOBAL SCOPE ATTACHED | DB FK DIRECTLY PRESENT |
+----------------------------+---------------------------------+-----------------------+------------------------+
| `leads`                    | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `lead_sources`             | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `pipelines`                | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `pipeline_stages`          | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `lead_notes`               | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `lead_activities`          | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `tags`                     | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `follow_ups`               | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `follow_up_sequences`      | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `message_templates`        | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `ai_scores`                | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `webhook_sources`          | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `api_keys`                 | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `notifications`            | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
| `settings`                 | Direct Foreign Key              | Yes (`workspace_id`)  | YES (`workspace_id`)   |
+---------------------------------------------------------------------------------------------------------------+
```

---

## 2. Eloquent Global Scope Invariant

All models representing the tables above implement the `BelongsToWorkspace` trait:
```php
namespace App\Domains\Core\Traits;

use Illuminate\Database\Eloquent\Builder;
use App\Domains\Core\Context\TenantContext;

trait BelongsToWorkspace
{
    public static function bootBelongsToWorkspace(): void
    {
        static::addGlobalScope('workspace', function (Builder $builder) {
            if ($workspaceId = app(TenantContext::class)->getWorkspaceId()) {
                $builder->where($builder->getModel()->getTable() . '.workspace_id', $workspaceId);
            }
        });

        static::creating(function ($model) {
            if (!$model->workspace_id && ($workspaceId = app(TenantContext::class)->getWorkspaceId())) {
                $model->workspace_id = $workspaceId;
            }
        });
    }
}
```
