## YOUR IDENTITY
You are a **Chief Technology Officer** building systems for a CEO with billion-dollar ambitions.
Your reputation is built on:
1. **Enterprise-grade quality** - Fortune 500 standard, not startup MVP
2. **Proactive intelligence** - Systems that tell Ben what he needs to know before he asks
3. **Zero technical debt** - Every line of code you write, you'd proudly show to any engineer
**The Standard:** Would the CTO of LVMH or Kering be impressed by this system?
**Expert Lens:** Warren Buffett - "Risk comes from not knowing what you own." Ben must know EXACTLY what corporate structure he controls, where the risks are, and what needs attention.
---
## TASK: Entity Intelligence System (PART 2 of 4)
### Pre-Work Declaration
```
[APPROACH]
Task: Build corporate intelligence system showing entity structure, compliance, ownership
Files: dashboard/index.html (Team page - Entities tab)
Risk: HIGH - Legal accuracy critical, displays sensitive corporate data
Dependencies: Part 1 COMPLETE - All data in docs/tasks/TASK-043-AUDIT-OUTPUT.md
Security: Validate all data against source documents
```
---
## PHASE 1: DATA VERIFICATION
### Step 1.1: Load and Validate Part 1 Data
**Read:** `docs/tasks/TASK-043-AUDIT-OUTPUT.md`
**CRITICAL:** Do NOT proceed if this file is missing or incomplete.
**Required data - verify ALL present:**
| Entity | Registration # | Must Have |
|--------|---------------|-----------|
| UK - SOFSY INTERNATIONAL LTD | 9825425 | ✅ |
| NL - SOFSY INTERNATIONAL B.V. | 83550674 | ✅ |
| CN - Zhuhai Sofsy Trading | 91440400MA53JYF78N | ✅ |
| TH-BOI - SOFSY INTERNATIONAL LTD | 0105566135004 | ✅ |
| TH-REP - SOFSY INTERNATIONAL LTD | 0100565100334 | ✅ |
| US Tax Registration (UK subsidiary) | 98-1282243 | ✅ |
| AU Tax Registration (UK subsidiary) | 43 734 357 795 | ✅ |
If ANY registration number is missing → STOP and report gap.
### Step 1.2: Identify Compliance Alerts
From Part 1 data, extract:
- **NL Director Change:** Mick dismissed, Rocío appointed (Aug 2023) - NOT FILED with KvK
- **Document expiries:** Any certificates, permits, or registrations expiring within 90 days
- **Missing documents:** Any entity without complete incorporation files
---
## PHASE 2: DATABASE SCHEMA
### Step 2.1: Create Entity Tables
```sql
-- Check if table exists
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'zao_entities'
);
-- If not exists, create:
CREATE TABLE zao_entities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id TEXT NOT NULL DEFAULT 'ben',
-- Core identity
legal_name TEXT NOT NULL,
trading_name TEXT,
entity_type TEXT NOT NULL, -- 'company', 'representative_office', 'tax_registration'
-- Registration
country TEXT NOT NULL,
country_code TEXT, -- ISO 3166-1 alpha-2 (GB, NL, CN, TH, US, AU)
registration_number TEXT,
registration_type TEXT, -- 'companies_house', 'kvk', 'dbd', 'ein', 'abn', etc.
incorporation_date DATE,
-- Structure
parent_entity_id UUID REFERENCES zao_entities(id),
ownership_percentage DECIMAL(5,2) DEFAULT 100.00,
-- Status
status TEXT DEFAULT 'active', -- 'active', 'dormant', 'dissolved', 'pending'
-- Address
registered_address TEXT,
-- Contacts
registered_agent TEXT,
law_firm TEXT,
-- Documents (Google Drive folder IDs)
drive_folder_id TEXT,
incorporation_folder_id TEXT,
-- Compliance
next_filing_due DATE,
annual_return_due DATE,
-- Metadata
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Directors table
CREATE TABLE zao_entity_directors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entity_id UUID NOT NULL REFERENCES zao_entities(id) ON DELETE CASCADE,
person_name TEXT NOT NULL,
role TEXT DEFAULT 'director', -- 'director', 'secretary', 'shareholder', 'legal_rep'
appointed_date DATE,
resigned_date DATE,
status TEXT DEFAULT 'active', -- 'active', 'pending_removal', 'resigned'
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Compliance alerts table
CREATE TABLE zao_entity_alerts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entity_id UUID NOT NULL REFERENCES zao_entities(id) ON DELETE CASCADE,
alert_type TEXT NOT NULL, -- 'filing_due', 'director_change', 'document_expiry', 'action_required'
severity TEXT DEFAULT 'medium', -- 'low', 'medium', 'high', 'critical'
title TEXT NOT NULL,
description TEXT,
due_date DATE,
resolved_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Enable RLS
ALTER TABLE zao_entities ENABLE ROW LEVEL SECURITY;
ALTER TABLE zao_entity_directors ENABLE ROW LEVEL SECURITY;
ALTER TABLE zao_entity_alerts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "ben_entities" ON zao_entities FOR ALL USING (user_id = 'ben');
CREATE POLICY "ben_directors" ON zao_entity_directors FOR ALL USING (
entity_id IN (SELECT id FROM zao_entities WHERE user_id = 'ben')
);
CREATE POLICY "ben_alerts" ON zao_entity_alerts FOR ALL USING (
entity_id IN (SELECT id FROM zao_entities WHERE user_id = 'ben')
);
```
### Step 2.2: Insert Entity Data
**Insert in hierarchical order (parent first):**
```sql
-- 1. UK Parent (root entity)
INSERT INTO zao_entities (
user_id, legal_name, trading_name, entity_type, country, country_code,
registration_number, registration_type, incorporation_date, status,
registered_address, drive_folder_id, incorporation_folder_id, notes
) VALUES (
'ben',
'SOFSY INTERNATIONAL LTD',
'sofsy',
'company',
'United Kingdom',
'GB',
'9825425',
'companies_house',
'2015-10-15',
'active',
'22 Rothes Rd, Dorking, RH4 1LD',
'1oF_jFaygLu9Vp26PEmMoh77E3xPbfS5J',
'1ElzRMiTq9PNQiNc5zh4pcZGAMkBbRmjT',
'Parent holding company. Former name: BM May LTD (until 2018-02-06)'
) RETURNING id; -- Save this ID for subsidiaries
-- Continue for all entities, setting parent_entity_id appropriately
-- NL, CN, TH-BOI, TH-REP are subsidiaries of UK
-- US and AU are tax registrations under UK
```
**IMPORTANT:** After all inserts, run:
```sql
SELECT legal_name, registration_number, parent_entity_id
FROM zao_entities
WHERE user_id = 'ben'
ORDER BY parent_entity_id NULLS FIRST;
```
Verify 7 entities returned with correct hierarchy.
### Step 2.3: Insert Directors
```sql
-- UK Directors
INSERT INTO zao_entity_directors (entity_id, person_name, role, status)
SELECT id, 'Benjamin James May', 'director', 'active'
FROM zao_entities WHERE registration_number = '9825425';
-- NL Directors (including pending change)
INSERT INTO zao_entity_directors (entity_id, person_name, role, status, notes)
SELECT id, 'Benjamin James May', 'director', 'active', NULL
FROM zao_entities WHERE registration_number = '83550674';
INSERT INTO zao_entity_directors (entity_id, person_name, role, status, appointed_date, notes)
SELECT id, 'M.A. May (Mick)', 'director', 'pending_removal', NULL, 'Dismissal resolution signed 31 Aug 2023 - NOT YET FILED with KvK'
FROM zao_entities WHERE registration_number = '83550674';
INSERT INTO zao_entity_directors (entity_id, person_name, role, status, appointed_date, notes)
SELECT id, 'Rocío Lando', 'director', 'pending_appointment', '2023-08-31', 'Appointed in resolution 31 Aug 2023 - NOT YET FILED with KvK'
FROM zao_entities WHERE registration_number = '83550674';
-- Continue for all entities...
```
### Step 2.4: Insert Compliance Alerts
```sql
-- NL Director change alert (CRITICAL)
INSERT INTO zao_entity_alerts (entity_id, alert_type, severity, title, description, due_date)
SELECT id, 'director_change', 'critical',
'Director change not filed with KvK',
'Resolution dated 31 Aug 2023 dismissed Mick May and appointed Rocío Lando. Folder indicates "Not Completed". Verify with TaylorWessing immediately.',
CURRENT_DATE -- Overdue
FROM zao_entities WHERE registration_number = '83550674';
```
---
## PHASE 3: UI IMPLEMENTATION
### Step 3.1: Find Team Page Entities Section
**Search in** `dashboard/index.html` **for:**
```
id="team-entities" OR "Entity" tab within Team page
```
If no section exists, create a new tab in the Team page.
### Step 3.2: Build the Entity Intelligence UI
**Architecture:**
```
┌─────────────────────────────────────────────────────────────────┐
│ ENTITY INTELLIGENCE [Compliance] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────── ALERTS BAR ───────────────────┐ │
│ │ 🔴 1 Critical │ 🟡 0 Warning │ 🟢 6 Healthy │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────── CORPORATE TREE ───────────────┐ │
│ │ │ │
│ │ 🇬🇧 SOFSY INTERNATIONAL LTD │ │
│ │ UK • 9825425 • Active │ │
│ │ │ │ │
│ │ ┌─────────┬──────┴──────┬─────────┐ │ │
│ │ │ │ │ │ │ │
│ │ 🇳🇱 NL 🇨🇳 CN 🇹🇭 TH-BOI 🇹🇭 TH-REP │ │
│ │ ⚠️ Alert Active Active Active │ │
│ │ │ │
│ │ Tax Registrations: 🇺🇸 US EIN • 🇦🇺 AU ABN │ │
│ │ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────── ENTITY DETAIL ────────────────┐ │
│ │ [Selected entity details panel] │ │
│ └───────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### Step 3.3: HTML Structure
```html
<div class="entity-intelligence">
<!-- Alerts Summary Bar -->
<div class="entity-alerts-bar">
<div class="alert-count alert-critical" id="entity-alert-critical">
<span class="alert-dot"></span>
<span class="alert-number">1</span>
<span class="alert-label">Critical</span>
</div>
<div class="alert-count alert-warning" id="entity-alert-warning">
<span class="alert-dot"></span>
<span class="alert-number">0</span>
<span class="alert-label">Warning</span>
</div>
<div class="alert-count alert-healthy" id="entity-alert-healthy">
<span class="alert-dot"></span>
<span class="alert-number">6</span>
<span class="alert-label">Healthy</span>
</div>
</div>
<!-- Corporate Structure Tree -->
<div class="entity-tree">
<div class="entity-tree-root">
<!-- Dynamically populated -->
</div>
</div>
<!-- Entity Detail Panel -->
<div class="entity-detail-panel" id="entity-detail-panel">
<div class="entity-detail-placeholder">
Select an entity to view details
</div>
</div>
</div>
```
### Step 3.4: Entity Card Component
```html
<div class="entity-node" data-entity-id="[UUID]" onclick="selectEntity('[UUID]')">
<div class="entity-node-header">
<span class="entity-flag">🇬🇧</span>
<span class="entity-name">SOFSY INTERNATIONAL LTD</span>
<span class="entity-status status-active">Active</span>
</div>
<div class="entity-node-body">
<div class="entity-meta">
<span class="entity-country">United Kingdom</span>
<span class="entity-reg">#9825425</span>
</div>
<div class="entity-alerts" id="entity-alerts-[UUID]">
<!-- Alert badges if any -->
</div>
</div>
<div class="entity-node-children" id="entity-children-[UUID]">
<!-- Child entities -->
</div>
</div>
```
### Step 3.5: Entity Detail Panel
When an entity is selected, show:
```html
<div class="entity-detail">
<div class="entity-detail-header">
<span class="entity-flag-large">🇬🇧</span>
<div class="entity-detail-title">
<h3>SOFSY INTERNATIONAL LTD</h3>
<span class="entity-type">Private Limited Company</span>
</div>
<span class="entity-status-large status-active">Active</span>
</div>
<!-- Alert Banner (if any) -->
<div class="entity-alert-banner alert-critical" id="entity-detail-alert">
<span class="alert-icon">⚠️</span>
<span class="alert-text">Director change not filed with KvK</span>
<button class="btn btn-small" onclick="viewAlertDetail()">Details</button>
</div>
<!-- Key Information -->
<div class="entity-info-grid">
<div class="info-item">
<span class="info-label">Registration</span>
<span class="info-value">9825425 (Companies House)</span>
</div>
<div class="info-item">
<span class="info-label">Incorporated</span>
<span class="info-value">15 October 2015</span>
</div>
<div class="info-item">
<span class="info-label">Address</span>
<span class="info-value">22 Rothes Rd, Dorking, RH4 1LD</span>
</div>
<div class="info-item">
<span class="info-label">Owns</span>
<span class="info-value">4 subsidiaries + 2 tax registrations</span>
</div>
</div>
<!-- Directors Section -->
<div class="entity-section">
<h4>Directors & Officers</h4>
<div class="directors-list" id="entity-directors">
<!-- Dynamically populated -->
</div>
</div>
<!-- Documents Section -->
<div class="entity-section">
<h4>Key Documents</h4>
<div class="entity-docs-grid">
<a href="[DRIVE_LINK]?authuser=benjamin@sofsy.com" target="_blank" class="doc-link">
<span class="doc-icon">📄</span>
<span class="doc-name">Certificate of Incorporation</span>
</a>
<a href="[DRIVE_LINK]?authuser=benjamin@sofsy.com" target="_blank" class="doc-link">
<span class="doc-icon">📁</span>
<span class="doc-name">All Entity Documents</span>
</a>
</div>
</div>
<!-- Employees in this Entity -->
<div class="entity-section">
<h4>Employed by this Entity</h4>
<div class="entity-employees" id="entity-employees">
<!-- List of employees employed by this entity -->
</div>
</div>
</div>
```
### Step 3.6: CSS Styles
```css
/* Entity Intelligence Styles */
.entity-intelligence {
display: flex;
flex-direction: column;
gap: 24px;
}
.entity-alerts-bar {
display: flex;
gap: 16px;
padding: 16px;
background: var(--bg-card);
border-radius: var(--radius);
border: 1px solid var(--border);
}
.alert-count {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border-radius: var(--radius);
}
.alert-critical { background: rgba(239, 68, 68, 0.15); }
.alert-critical .alert-dot { background: #ef4444; }
.alert-warning { background: rgba(251, 191, 36, 0.15); }
.alert-warning .alert-dot { background: #fbbf24; }
.alert-healthy { background: rgba(34, 197, 94, 0.15); }
.alert-healthy .alert-dot { background: #22c55e; }
.alert-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.entity-tree {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
min-height: 300px;
}
.entity-node {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px;
cursor: pointer;
transition: var(--transition);
}
.entity-node:hover {
border-color: var(--accent);
}
.entity-node.selected {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent);
}
.entity-node-header {
display: flex;
align-items: center;
gap: 12px;
}
.entity-flag {
font-size: 24px;
}
.entity-name {
font-weight: 600;
color: var(--text-primary);
}
.entity-status {
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
text-transform: uppercase;
font-weight: 500;
}
.status-active {
background: rgba(34, 197, 94, 0.15);
color: #22c55e;
}
.status-pending {
background: rgba(251, 191, 36, 0.15);
color: #fbbf24;
}
.entity-node-children {
margin-top: 16px;
margin-left: 32px;
display: flex;
flex-wrap: wrap;
gap: 16px;
}
/* Tree connectors */
.entity-node-children::before {
content: '';
position: absolute;
left: 16px;
top: 0;
bottom: 50%;
width: 2px;
background: var(--border);
}
.entity-detail-panel {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
}
.entity-alert-banner {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
border-radius: var(--radius);
margin-bottom: 24px;
}
.entity-alert-banner.alert-critical {
background: rgba(239, 68, 68, 0.15);
border: 1px solid rgba(239, 68, 68, 0.3);
}
.entity-info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-bottom: 24px;
}
.info-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.info-label {
font-size: 12px;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.info-value {
font-size: 14px;
color: var(--text-primary);
}
.entity-section {
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid var(--border);
}
.entity-section h4 {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 16px;
}
.entity-docs-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.doc-link {
display: flex;
align-items: center;
gap: 8px;
padding: 12px;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-primary);
text-decoration: none;
transition: var(--transition);
}
.doc-link:hover {
border-color: var(--accent);
background: var(--bg-hover);
}
```
### Step 3.7: JavaScript Functions
```javascript
// Entity Intelligence System
let entities = [];
let selectedEntityId = null;
async function loadEntities() {
const { data, error } = await supabase
.from('zao_entities')
.select(`
*,
directors:zao_entity_directors(*),
alerts:zao_entity_alerts(*)
`)
.eq('user_id', 'ben')
.order('parent_entity_id', { nullsFirst: true });
if (error) {
console.error('Failed to load entities:', error);
return;
}
entities = data;
renderEntityTree();
updateAlertCounts();
}
function renderEntityTree() {
const root = entities.find(e => !e.parent_entity_id);
if (!root) return;
const container = document.querySelector('.entity-tree-root');
container.innerHTML = renderEntityNode(root);
}
function renderEntityNode(entity) {
const children = entities.filter(e => e.parent_entity_id === entity.id);
const hasAlerts = entity.alerts && entity.alerts.some(a => !a.resolved_at);
const criticalAlert = entity.alerts?.find(a => a.severity === 'critical' && !a.resolved_at);
const flagEmoji = getCountryFlag(entity.country_code);
return `
<div class="entity-node ${selectedEntityId === entity.id ? 'selected' : ''}"
data-entity-id="${entity.id}"
onclick="selectEntity('${entity.id}')">
<div class="entity-node-header">
<span class="entity-flag">${flagEmoji}</span>
<span class="entity-name">${entity.legal_name}</span>
<span class="entity-status status-${entity.status}">${entity.status}</span>
${criticalAlert ? '<span class="entity-alert-badge">⚠️</span>' : ''}
</div>
<div class="entity-node-body">
<div class="entity-meta">
<span class="entity-country">${entity.country}</span>
<span class="entity-reg">#${entity.registration_number}</span>
</div>
</div>
${children.length > 0 ? `
<div class="entity-node-children">
${children.map(c => renderEntityNode(c)).join('')}
</div>
` : ''}
</div>
`;
}
function getCountryFlag(code) {
const flags = {
'GB': '🇬🇧', 'NL': '🇳🇱', 'CN': '🇨🇳',
'TH': '🇹🇭', 'US': '🇺🇸', 'AU': '🇦🇺'
};
return flags[code] || '🏳️';
}
function selectEntity(entityId) {
selectedEntityId = entityId;
renderEntityTree();
renderEntityDetail(entityId);
}
function renderEntityDetail(entityId) {
const entity = entities.find(e => e.id === entityId);
if (!entity) return;
const panel = document.getElementById('entity-detail-panel');
const criticalAlert = entity.alerts?.find(a => a.severity === 'critical' && !a.resolved_at);
const childCount = entities.filter(e => e.parent_entity_id === entity.id).length;
panel.innerHTML = `
<div class="entity-detail">
<div class="entity-detail-header">
<span class="entity-flag-large">${getCountryFlag(entity.country_code)}</span>
<div class="entity-detail-title">
<h3>${entity.legal_name}</h3>
<span class="entity-type">${entity.entity_type}</span>
</div>
<span class="entity-status-large status-${entity.status}">${entity.status}</span>
</div>
${criticalAlert ? `
<div class="entity-alert-banner alert-critical">
<span class="alert-icon">⚠️</span>
<span class="alert-text">${criticalAlert.title}</span>
<button class="btn btn-small" onclick="viewAlertDetail('${criticalAlert.id}')">Details</button>
</div>
` : ''}
<div class="entity-info-grid">
<div class="info-item">
<span class="info-label">Registration</span>
<span class="info-value">${entity.registration_number} (${entity.registration_type})</span>
</div>
<div class="info-item">
<span class="info-label">Incorporated</span>
<span class="info-value">${entity.incorporation_date || 'Not recorded'}</span>
</div>
<div class="info-item">
<span class="info-label">Address</span>
<span class="info-value">${entity.registered_address || 'Not recorded'}</span>
</div>
<div class="info-item">
<span class="info-label">Subsidiaries</span>
<span class="info-value">${childCount} direct${childCount !== 1 ? 's' : ''}</span>
</div>
</div>
<div class="entity-section">
<h4>Directors & Officers</h4>
<div class="directors-list">
${(entity.directors || []).map(d => `
<div class="director-item ${d.status}">
<span class="director-name">${d.person_name}</span>
<span class="director-role">${d.role}</span>
<span class="director-status status-${d.status}">${d.status.replace('_', ' ')}</span>
${d.notes ? `<span class="director-note">${d.notes}</span>` : ''}
</div>
`).join('')}
</div>
</div>
<div class="entity-section">
<h4>Key Documents</h4>
<div class="entity-docs-grid">
${entity.drive_folder_id ? `
<a href="https://drive.google.com/drive/folders/${entity.drive_folder_id}?authuser=benjamin@sofsy.com"
target="_blank" class="doc-link">
<span class="doc-icon">📁</span>
<span class="doc-name">Entity Folder</span>
</a>
` : ''}
${entity.incorporation_folder_id ? `
<a href="https://drive.google.com/drive/folders/${entity.incorporation_folder_id}?authuser=benjamin@sofsy.com"
target="_blank" class="doc-link">
<span class="doc-icon">📄</span>
<span class="doc-name">Incorporation Docs</span>
</a>
` : ''}
</div>
</div>
</div>
`;
}
function updateAlertCounts() {
let critical = 0, warning = 0, healthy = 0;
entities.forEach(e => {
const unresolvedAlerts = (e.alerts || []).filter(a => !a.resolved_at);
if (unresolvedAlerts.some(a => a.severity === 'critical')) {
critical++;
} else if (unresolvedAlerts.some(a => a.severity === 'high' || a.severity === 'medium')) {
warning++;
} else {
healthy++;
}
});
document.querySelector('#entity-alert-critical .alert-number').textContent = critical;
document.querySelector('#entity-alert-warning .alert-number').textContent = warning;
document.querySelector('#entity-alert-healthy .alert-number').textContent = healthy;
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
if (document.querySelector('.entity-intelligence')) {
loadEntities();
}
});
```
---
## PHASE 4: VERIFICATION
### Required Verification Block
```
[VERIFICATION]
Database tables created: zao_entities, zao_entity_directors, zao_entity_alerts
Entities inserted: 7 (UK parent + 4 subsidiaries + 2 tax registrations)
Directors inserted: [count] with correct statuses
Alerts inserted: At least 1 (NL director change)
RLS policies active: Yes/No
UI renders tree: Yes/No
Entity selection works: Yes/No
Document links have authuser: Yes/No
Alert counts update: Yes/No
Follows Weavey v4: Yes/No
```
### Success Criteria
- [ ] All 7 entities in database with correct hierarchy
- [ ] UK shown as parent, others as subsidiaries
- [ ] NL shows critical alert for director change
- [ ] Clicking entity shows full detail panel
- [ ] Document links work and include ?authuser=benjamin@sofsy.com
- [ ] Alert summary bar shows correct counts
- [ ] Tree visualization shows ownership structure
- [ ] Directors shown with pending changes highlighted
---
## WHEN COMPLETE
```sql
UPDATE dashboard_data
SET data = jsonb_set(data, '{taskStatuses,task-entity-intelligence}',
'{"status":"verified","lastUpdated":"[NOW]","notes":"Entity Intelligence: 7 entities, compliance alerts active"}'::jsonb)
WHERE user_id = 'ben';
```
State: **"PART 2B COMPLETE - Entity Intelligence System operational. Ready for Part 3B."**
---
## CRITICAL REMINDERS
1. **All Google Drive links MUST include** `?authuser=benjamin@sofsy.com`
2. **Verify data against Part 1 audit** - don't make up registration numbers
3. **NL director alert is CRITICAL** - it must be prominent
4. **Test all interactive elements** before declaring complete
5. **This is legal/compliance data** - accuracy is non-negotiable