export type PlatformRole = 'super_admin' | 'admin' | 'partner' | 'user';
export type CompanyRole = 'owner' | 'admin' | 'manager' | 'rep' | 'viewer';
// Permission keys used by hasCompanyPermission()
export type CompanyPermission =
| 'create_org' // Only owner
| 'manage_team' // owner, admin, manager
| 'view_analytics' // owner, admin, manager
| 'edit_integrations'// owner, admin
| 'view_reports' // owner, admin, manager, rep, viewer
| 'edit_settings'; // owner, admin
export interface User {
id: number;
email: string;
full_name: string;
role: PlatformRole;
companyRole?: CompanyRole;
isSuperAdmin?: boolean;
tenantId?: string | number;
tenantSlug?: string;
}
export interface LoginResponse {
success: boolean;
user: User;
}
export interface AuthState {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => Promise<void>;
signup: (data: SignupData) => Promise<void>;
updateProfile: (display_name: string) => Promise<void>;
changePassword: (currentPassword: string, newPassword: string) => Promise<{ success: boolean; message: string }>;
isRole: (role: string) => boolean;
hasRole: (...roles: string[]) => boolean;
// Company role enforcement
companyRole: CompanyRole | undefined;
roleLevel: number;
hasCompanyPermission: (permission: CompanyPermission) => boolean;
hasRoleAtLeast: (minRole: CompanyRole) => boolean;
}
export interface SignupData {
email: string;
password: string;
companyName: string;
fullName: string;
planInterest?: string;
}
export interface Organization {
id: number;
name: string;
slug: string;
industry: string;
status: string;
subStatus: string;
tier: string;
groupId: string | null;
referrerPartnerId: string | null;
annual_revenue: number;
target_revenue: number;
revenue_growth: number;
active_projects: number;
size: string;
location: string;
website: string;
commission_rate: number;
last_updated: string | null;
}
export interface Plan {
id: string;
name: string;
priceCents: number | null;
tagline: string;
highlights: string[];
limits: {
markets: number;
seats: number;
integrations: number;
storageGb: number;
};
trialDays: number;
popular: boolean;
trialEligible: boolean;
}
export interface DashboardStats {
totalOrganizations: number;
totalUsers: number;
totalActive: number;
totalSuspended: number;
totalRevenue: number;
avgRevenue: number;
recentActivity: ActivityItem[];
systemHealth?: {
emailFailures: number;
integrationErrors: number;
activeAlerts: number;
lastSync: string | null;
};
}
export interface ActivityItem {
id: string;
type: string;
description: string;
timestamp: string | null;
user_id: string | null;
}
export interface AnalyticsData {
totalOrganizations: number;
totalRevenue: number;
avgRevenue: number;
revenueByIndustry: Record<string, number>;
revenueTrend: RevenuePoint[];
userGrowth: UserGrowthPoint[];
topOrganizations: {
id: number;
name: string;
revenue: number;
}[];
}
export interface RevenuePoint {
month: string;
revenue: number;
forecast: number;
}
export interface UserGrowthPoint {
month: string;
users: number;
}
export interface CommissionData {
total_commission: number;
commission_rate: number;
pending: number;
paid: number;
organizations: number;
monthly_breakdown: {
organization_id: number;
organization_name: string;
monthly_revenue: number;
commission_amount: number;
status: string;
}[];
next_payout_date: string;
currency: string;
}
export interface AuditLog {
id: string;
action: string;
entityType: string;
entityId: string | null;
actorEmail: string;
timestamp: string | null;
description: string;
}
export interface ApiUser {
id: number;
email: string;
fullName: string;
role: string;
companyRole: CompanyRole | null;
status: string;
lastLogin: string | null;
}
export interface PartnerProfile {
id: number;
email: string;
full_name: string;
company: string;
role: string;
organization_count: number;
total_portfolio_revenue: number;
is_active: boolean;
}
export interface PaginatedResponse<T> {
items: T[];
total: number;
nextCursor: string | null;
}
export interface Lead {
id: string;
name: string;
email: string;
phone: string | null;
company: string;
status: string; // new, assigned, contacted, converted, lost
source: string;
assignedTo: string | null;
createdAt: string;
notes: string | null;
}
// ============================================================================
// Enterprise types
// ============================================================================
export interface SSOConfig {
id: string;
company_id: string;
provider_name: string;
sso_url: string;
sso_binding: string;
idp_cert: string;
entity_id: string;
acs_url: string;
sp_metadata_url: string;
sp_cert: string;
enabled: boolean;
created_at: string | null;
updated_at: string | null;
}
export interface BrandingSettings {
logo_url: string;
primary_color: string;
secondary_color: string;
favicon_url: string;
custom_domain: string;
app_name: string;
login_bg_url: string;
}
// ============================================================================
// Portfolio types
// ============================================================================
export interface Portfolio {
id: string;
name: string;
description: string;
created_by: string;
created_by_name: string;
created_by_email: string;
company_count: number;
companies: {
id: string;
name: string;
industry: string;
annual_revenue: number | null;
}[];
created_at: string | null;
updated_at: string | null;
}
// ============================================================================
// Email Campaign types
// ============================================================================
export type EmailCampaignStatus = 'draft' | 'scheduled' | 'sending' | 'sent' | 'completed' | 'paused' | 'failed';
export interface EmailCampaign {
id: string;
name: string;
status: EmailCampaignStatus;
subject: string;
body: string;
created_by: string;
created_by_name: string;
created_by_email: string;
sent_at: string | null;
total_sent: number;
delivered: number;
opened: number;
bounced: number;
failed: number;
log_count: number;
created_at: string | null;
updated_at: string | null;
}
export type EmailLogStatus = 'pending' | 'sent' | 'delivered' | 'opened' | 'bounced' | 'failed';
export interface EmailDeliveryLog {
id: string;
campaign_id: string;
recipient: string;
status: EmailLogStatus;
sent_at: string | null;
delivered_at: string | null;
opened_at: string | null;
error_message: string;
created_at: string | null;
}
// ============================================================================
// Team / Organization member types
// ============================================================================
export interface TeamMember {
id: number;
name: string;
email: string;
role: CompanyRole;
status: string;
lastLogin: string | null;
}
// ============================================================================
// Revenue Leak types
// ============================================================================
export type LeakSeverity = 'low' | 'medium' | 'high' | 'critical';
export interface RevenueLeak {
id: string;
source: string;
description: string;
estimated_loss: number | null;
severity: LeakSeverity;
resolved: boolean;
resolved_at: string | null;
resolution_notes: string;
detected_at: string | null;
metadata_json: Record<string, unknown>;
created_at: string | null;
}
export interface RevenueLeakCreate {
source: string;
description?: string;
estimated_loss?: number | null;
severity?: LeakSeverity;
metadata_json?: Record<string, unknown>;
}
export interface RevenueLeakUpdate extends Partial<RevenueLeakCreate> {
resolution_notes?: string;
}
// Scan response
export interface ScanResult {
success: boolean;
scanned: number;
new_leaks: number;
updated_leaks: number;
already_resolved: number;
leaks: RevenueLeak[];
alerts?: Record<string, unknown>;
errors?: string[];
}
// Remediation suggestion
export interface RemediationSuggestion {
index: number;
title: string;
description: string;
action_type: string;
effort: 'low' | 'medium' | 'high';
impact_score: number;
}
export interface RemediationResponse {
leak_id: string;
detector_id: string | null;
suggestions: RemediationSuggestion[];
}
// Resolution history
export interface ResolutionEntry {
leak_id: string;
resolved_at: string;
resolved_by: number | string;
resolution_notes: string;
}
export interface ResolutionHistoryResponse {
leak_id: string;
resolution_history: ResolutionEntry[];
}
// Recurring leaks
export interface RecurringLeakGroup {
detector_id: string;
source: string;
severity: LeakSeverity;
total_loss: number;
count: number;
first_detected: string;
last_detected: string;
}
export interface RecurringLeaksResponse {
days: number;
recurring_leaks: RecurringLeakGroup[];
}
// Resolution stats
export interface ResolutionStats {
total_resolved: number;
avg_resolution_time_hours: number;
recurring_count: number;
recurring_pct: number;
by_severity: Record<LeakSeverity, number>;
}
export interface StatsResponse {
days: number;
stats: ResolutionStats;
}
// Severity tuning
export interface SeverityRule {
detector_id?: string;
source?: string;
min_loss?: number;
min_recurrence?: number;
severity: LeakSeverity;
}
export interface SeverityRulesResponse {
severity_rules: SeverityRule[];
}
// Alert settings
export interface AlertSettings {
slack_channel?: string | null;
slack_connector_id?: string | null;
severity_threshold?: LeakSeverity;
enabled?: boolean;
}
export interface AlertSettingsResponse {
alert_settings: AlertSettings;
slack_connected?: boolean;
slack_workspaces?: Array<{ id: string; workspace: string }>;
}
// ============================================================================
// Multi-Location Rollup types (P4)
// ============================================================================
export interface LocationRollup {
location_id: string;
location_name: string;
revenue: number;
transaction_count: number;
avg_transaction: number;
pct_of_total: number;
}
export interface LocationAlert {
type: 'concentration' | 'underperformer' | 'variance';
severity: LeakSeverity;
location_id: string;
location_name: string;
message: string;
pct_of_total?: number;
revenue?: number;
avg_revenue?: number;
}
export interface LocationLocationsResponse {
locations: {
total_locations: number;
total_revenue: number;
avg_revenue_per_location: number;
max_variance_pct: number;
period_days: number;
};
breakdown: LocationRollup[];
alerts: LocationAlert[];
}
export interface LocationComparisonItem extends LocationRollup {
ranking: number;
vs_avg_pct: number;
vs_median_pct: number;
}
export interface LocationComparisonResponse {
comparison: {
total_locations: number;
total_revenue: number;
avg_revenue: number;
median_revenue: number;
period_days: number;
};
locations: LocationComparisonItem[];
}
export interface LocationDetectorCandidate {
dedupe_key: string;
detector: string;
source: string;
severity: LeakSeverity;
description: string;
estimated_loss: number;
metadata: Record<string, unknown>;
rule_params: Record<string, unknown>;
}
export interface LocationDetectorResponse {
detector: string;
company_id: string;
candidates_found: number;
candidates: LocationDetectorCandidate[];
}
// ============================================================================
// Optimization Move types
// ============================================================================
export type MoveType = 'budget_shift' | 'channel_change' | 'target_audience';
export type MoveStatus = 'recommended' | 'accepted' | 'rejected' | 'implemented';
export interface OptimizationMove {
id: string;
move_type: MoveType;
description: string;
source_channel: string;
target_channel: string;
current_spend: number | null;
recommended_spend: number | null;
expected_impact: number | null;
confidence: number | null;
status: MoveStatus;
implemented_at: string | null;
actual_result: number | null;
created_at: string | null;
updated_at: string | null;
}
export interface OptimizationMoveCreate {
move_type?: MoveType;
description?: string;
source_channel?: string;
target_channel?: string;
current_spend?: number | null;
recommended_spend?: number | null;
expected_impact?: number | null;
confidence?: number | null;
}
export interface OptimizationMoveUpdate extends Partial<OptimizationMoveCreate> {
status?: MoveStatus;
actual_result?: number | null;
}
// ============================================================================
// Forecast types
// ============================================================================
export type ForecastType = 'revenue' | 'pipeline' | 'cost';
export interface Forecast {
id: string;
forecast_type: ForecastType;
period: string;
period_start: string | null;
period_end: string | null;
projected_value: number;
actual_value: number | null;
confidence: number | null;
methodology: string;
assumptions_json: Record<string, unknown>;
variance: number | null;
variance_pct: number | null;
data_source: string | null;
created_at: string | null;
updated_at: string | null;
}
// Sync result from POST /forecasts/sync
export interface ForecastSyncResult {
company_id: string;
revenue_updated: number;
pipeline_updated: number;
cost_updated: number;
future_created: number;
errors: string[];
duration_seconds: number;
}
export interface ForecastCreate {
forecast_type?: ForecastType;
period?: string;
period_start?: string | null;
period_end?: string | null;
projected_value: number;
actual_value?: number | null;
confidence?: number | null;
methodology?: string;
assumptions_json?: Record<string, unknown>;
}
export interface ForecastUpdate extends Partial<ForecastCreate> {}
// ============================================================================
// Coaching Assignment types
// ============================================================================
export type AssignmentStatus = 'active' | 'completed' | 'paused';
export interface CoachingAssignment {
id: string;
coach_id: string;
coach_name: string;
coach_email: string;
rep_id: string;
rep_name: string;
rep_email: string;
focus_area: string;
description: string;
start_date: string | null;
end_date: string | null;
status: AssignmentStatus;
created_at: string | null;
}
export interface CoachingAssignmentCreate {
coach_id: string;
rep_id: string;
focus_area?: string;
description?: string;
start_date?: string | null;
end_date?: string | null;
status?: AssignmentStatus;
}
export interface CoachingAssignmentUpdate extends Partial<CoachingAssignmentCreate> {}
// ============================================================================
// Coaching Scorecard types
// ============================================================================
export interface CoachingScorecard {
id: string;
assignment_id: string;
rep_id: string;
rep_name: string;
evaluation_date: string | null;
overall_score: number | null;
communication_score: number | null;
technical_score: number | null;
closing_score: number | null;
follow_up_score: number | null;
strengths: string;
improvement_areas: string;
notes: string;
created_at: string | null;
}
export interface CoachingScorecardCreate {
assignment_id: string;
rep_id: string;
evaluation_date?: string | null;
overall_score?: number | null;
communication_score?: number | null;
technical_score?: number | null;
closing_score?: number | null;
follow_up_score?: number | null;
strengths?: string;
improvement_areas?: string;
notes?: string;
}
export interface CoachingScorecardUpdate extends Partial<CoachingScorecardCreate> {}
// ============================================================================
// User list (for dropdowns)
// ============================================================================
export interface UserListItem {
id: string;
name: string;
email: string;
}
// ============================================================================
// Settings types
// ============================================================================
export interface CompanySettings {
id: string;
name: string;
industry: string;
size: string;
annual_revenue: number | null;
target_revenue: number | null;
address: string;
city: string;
state: string;
zip_code: string;
website: string;
logo_url: string;
tier: string;
created_at: string | null;
}
export interface UserSettings {
notifications_email: boolean;
notifications_org: boolean;
notifications_commission: boolean;
notifications_security: boolean;
theme: string;
timezone: string;
locale: string;
date_format: string;
week_start: string;
}
// ============================================================================
// SMS / Call connector types
// ============================================================================
export type SmsDirection = 'inbound' | 'outbound';
export type SmsStatus = 'queued' | 'sent' | 'delivered' | 'received' | 'failed' | 'rejected';
export type SmsKeywordFlag = 'STOP' | 'YES' | 'CALL_ME' | '';
export interface SmsMessage {
id: string;
company_id: string;
connector_id: string;
lead_id: string | null;
from_phone: string;
to_phone: string;
direction: SmsDirection;
body: string;
status: SmsStatus;
error_code: string;
error_message: string;
provider_message_sid: string;
keyword_flag: SmsKeywordFlag;
created_at: string;
updated_at: string;
}
export type CallDisposition =
| ''
| 'connected'
| 'voicemail'
| 'no_answer'
| 'busy'
| 'appointment_set'
| 'unknown';
export interface CallRecord {
id: string;
company_id: string;
connector_id: string;
lead_id: string | null;
triggered_sms_id: string | null;
from_phone: string;
to_phone: string;
direction: 'outbound' | 'inbound';
disposition: CallDisposition;
duration_seconds: number | null;
recording_url: string;
provider_call_sid: string;
created_at: string;
started_at: string | null;
ended_at: string | null;
}
export type TouchpointType =
| 'sms_sent'
| 'sms_received'
| 'sms_delivered'
| 'sms_failed'
| 'call_outbound'
| 'call_connected'
| 'call_voicemail'
| 'call_no_answer'
| 'email_sent'
| 'status_change'
| 'note_added';
export type TouchpointDirection = 'outbound' | 'inbound' | 'system';
export interface LeadTouchpoint {
id: string;
company_id: string;
lead_id: string | null;
touchpoint_type: TouchpointType;
direction: TouchpointDirection;
content: string;
reference_id: string;
reference_type: string;
created_at: string;
}
export type OptOutReason = 'stop' | 'manual' | 'bounced' | 'complaint';
export interface OptOutRecord {
id: string;
company_id: string;
phone: string;
reason: OptOutReason;
source_message_id: string | null;
created_at: string;
}
export interface LeadMetrics {
lead_id: string;
lead_created_at: string | null;
time_to_first_contact_minutes: number | null;
time_to_first_sms_minutes: number | null;
time_to_first_call_minutes: number | null;
first_contact_type: string | null;
first_contact_at: string | null;
}
// ============ Smart Coaching ============
export type CoachingSeverity = 'high' | 'medium' | 'low';
export type CoachingCategory =
| 'market'
| 'forecast'
| 'goal'
| 'scale'
| 'intelligence';
export interface CoachingInsight {
id: string;
category: CoachingCategory | string;
severity: CoachingSeverity;
title: string;
narrative: string;
rules_data?: Record<string, unknown>;
action_url?: string;
dismissed: boolean;
}
export interface CoachingInsightsResponse {
insights: CoachingInsight[];
overall_score: number;
cache_age_seconds?: number;
}
export interface CoachingScore {
overall_score: number;
}
// ============================================================================
// Subscription / Billing types
// ============================================================================
export interface SubscriptionPlan {
name: string;
price: number;
currency: string;
features: string[];
limits: {
seats: number;
markets: number;
integrations: number;
storageGb: number;
};
}
export interface SubscriptionInfo {
current_plan: string;
plan: SubscriptionPlan;
status: string;
billing_cycle: string;
}
export interface UsageInfo {
plan: string;
usage: {
seats: number;
markets: number;
integrations: number;
storageGb: number;
};
limits: {
seats: number;
markets: number;
integrations: number;
storageGb: number;
};
percentages: {
seats: number;
markets: number;
integrations: number;
storageGb: number;
};
}