@nextsparkjs/theme-crm 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CRM_PLAN.md +343 -0
- package/about.md +122 -0
- package/config/app.config.ts +185 -0
- package/config/billing.config.ts +187 -0
- package/config/dashboard.config.ts +372 -0
- package/config/dev.config.ts +55 -0
- package/config/features.config.ts +336 -0
- package/config/flows.config.ts +511 -0
- package/config/permissions.config.ts +297 -0
- package/config/theme.config.ts +111 -0
- package/entities/activities/activities.config.ts +61 -0
- package/entities/activities/activities.fields.ts +362 -0
- package/entities/activities/activities.service.ts +503 -0
- package/entities/activities/activities.types.ts +117 -0
- package/entities/activities/messages/en.json +123 -0
- package/entities/activities/messages/es.json +123 -0
- package/entities/activities/migrations/020_activities_table.sql +123 -0
- package/entities/activities/migrations/021_activities_metas.sql +114 -0
- package/entities/activities/migrations/022_activities_sample_data.sql +420 -0
- package/entities/campaigns/campaigns.config.ts +61 -0
- package/entities/campaigns/campaigns.fields.ts +413 -0
- package/entities/campaigns/campaigns.service.ts +426 -0
- package/entities/campaigns/campaigns.types.ts +124 -0
- package/entities/campaigns/messages/en.json +145 -0
- package/entities/campaigns/messages/es.json +145 -0
- package/entities/campaigns/migrations/001_campaigns_table.sql +127 -0
- package/entities/campaigns/migrations/002_campaigns_metas.sql +114 -0
- package/entities/campaigns/migrations/003_campaigns_sample_data.sql +364 -0
- package/entities/companies/companies.config.ts +61 -0
- package/entities/companies/companies.fields.ts +429 -0
- package/entities/companies/companies.service.ts +566 -0
- package/entities/companies/companies.types.ts +125 -0
- package/entities/companies/messages/en.json +146 -0
- package/entities/companies/messages/es.json +146 -0
- package/entities/companies/migrations/001_companies_table.sql +150 -0
- package/entities/companies/migrations/002_companies_metas.sql +114 -0
- package/entities/companies/migrations/003_companies_sample_data.sql +246 -0
- package/entities/contacts/contacts.config.ts +61 -0
- package/entities/contacts/contacts.fields.ts +359 -0
- package/entities/contacts/contacts.service.ts +509 -0
- package/entities/contacts/contacts.types.ts +108 -0
- package/entities/contacts/messages/en.json +117 -0
- package/entities/contacts/messages/es.json +117 -0
- package/entities/contacts/migrations/001_contacts_table.sql +134 -0
- package/entities/contacts/migrations/002_contacts_metas.sql +114 -0
- package/entities/contacts/migrations/003_contacts_sample_data.sql +421 -0
- package/entities/leads/leads.config.ts +61 -0
- package/entities/leads/leads.fields.ts +336 -0
- package/entities/leads/leads.service.ts +496 -0
- package/entities/leads/leads.types.ts +114 -0
- package/entities/leads/messages/en.json +132 -0
- package/entities/leads/messages/es.json +132 -0
- package/entities/leads/migrations/001_leads_table.sql +150 -0
- package/entities/leads/migrations/002_leads_metas.sql +120 -0
- package/entities/leads/migrations/003_leads_sample_data.sql +242 -0
- package/entities/notes/messages/en.json +114 -0
- package/entities/notes/messages/es.json +114 -0
- package/entities/notes/migrations/020_notes_table.sql +118 -0
- package/entities/notes/migrations/021_notes_metas.sql +114 -0
- package/entities/notes/migrations/022_notes_sample_data.sql +275 -0
- package/entities/notes/notes.config.ts +61 -0
- package/entities/notes/notes.fields.ts +283 -0
- package/entities/notes/notes.service.ts +320 -0
- package/entities/notes/notes.types.ts +102 -0
- package/entities/opportunities/messages/en.json +107 -0
- package/entities/opportunities/messages/es.json +107 -0
- package/entities/opportunities/migrations/010_opportunities_table.sql +145 -0
- package/entities/opportunities/migrations/011_opportunities_metas.sql +114 -0
- package/entities/opportunities/migrations/012_opportunities_sample_data.sql +438 -0
- package/entities/opportunities/opportunities.config.ts +61 -0
- package/entities/opportunities/opportunities.fields.ts +416 -0
- package/entities/opportunities/opportunities.service.ts +525 -0
- package/entities/opportunities/opportunities.types.ts +135 -0
- package/entities/pipelines/messages/en.json +115 -0
- package/entities/pipelines/messages/es.json +115 -0
- package/entities/pipelines/migrations/001_pipelines_table.sql +106 -0
- package/entities/pipelines/migrations/002_pipelines_metas.sql +114 -0
- package/entities/pipelines/migrations/003_pipelines_sample_data.sql +91 -0
- package/entities/pipelines/pipelines.config.ts +62 -0
- package/entities/pipelines/pipelines.fields.ts +193 -0
- package/entities/pipelines/pipelines.service.ts +383 -0
- package/entities/pipelines/pipelines.types.ts +78 -0
- package/entities/products/messages/en.json +135 -0
- package/entities/products/messages/es.json +135 -0
- package/entities/products/migrations/001_products_table.sql +117 -0
- package/entities/products/migrations/002_products_metas.sql +114 -0
- package/entities/products/migrations/003_products_sample_data.sql +247 -0
- package/entities/products/products.config.ts +62 -0
- package/entities/products/products.fields.ts +361 -0
- package/entities/products/products.service.ts +437 -0
- package/entities/products/products.types.ts +125 -0
- package/lib/crm-constants.ts +77 -0
- package/lib/crm-utils.ts +185 -0
- package/lib/selectors.ts +333 -0
- package/messages/en.json +131 -0
- package/messages/es.json +131 -0
- package/migrations/999_theme_sample_data.sql +473 -0
- package/package.json +18 -0
- package/pendings.md +205 -0
- package/permissions-matrix.md +216 -0
- package/styles/components.css +414 -0
- package/styles/crm-theme.css +358 -0
- package/styles/globals.css +576 -0
- package/styles/variables.css +111 -0
- package/templates/dashboard/(main)/activities/components/ActivityCard.tsx +169 -0
- package/templates/dashboard/(main)/activities/components/ActivityTimeline.tsx +165 -0
- package/templates/dashboard/(main)/activities/page.tsx +297 -0
- package/templates/dashboard/(main)/campaigns/page.tsx +373 -0
- package/templates/dashboard/(main)/companies/page.tsx +296 -0
- package/templates/dashboard/(main)/contacts/page.tsx +347 -0
- package/templates/dashboard/(main)/layout.tsx +98 -0
- package/templates/dashboard/(main)/leads/page.tsx +335 -0
- package/templates/dashboard/(main)/opportunities/[id]/edit/page.tsx +95 -0
- package/templates/dashboard/(main)/opportunities/create/page.tsx +94 -0
- package/templates/dashboard/(main)/opportunities/page.tsx +350 -0
- package/templates/dashboard/(main)/pipelines/[id]/edit/page.tsx +95 -0
- package/templates/dashboard/(main)/pipelines/[id]/page.tsx +143 -0
- package/templates/dashboard/(main)/pipelines/create/page.tsx +94 -0
- package/templates/dashboard/(main)/pipelines/page.tsx +234 -0
- package/templates/dashboard/(main)/products/[id]/edit/page.tsx +97 -0
- package/templates/dashboard/(main)/products/[id]/page.tsx +509 -0
- package/templates/dashboard/(main)/products/create/page.tsx +96 -0
- package/templates/dashboard/(main)/products/page.tsx +308 -0
- package/templates/shared/ActionButtons.tsx +41 -0
- package/templates/shared/CRMDashboard.tsx +519 -0
- package/templates/shared/CRMDataTable.tsx +441 -0
- package/templates/shared/CRMMetricCard.tsx +76 -0
- package/templates/shared/CRMMobileNav.tsx +172 -0
- package/templates/shared/CRMSidebar.tsx +346 -0
- package/templates/shared/CRMTopBar.tsx +265 -0
- package/templates/shared/DealCard.tsx +123 -0
- package/templates/shared/EntityCard.tsx +58 -0
- package/templates/shared/OpportunityForm.tsx +649 -0
- package/templates/shared/PipelineForm.tsx +367 -0
- package/templates/shared/PipelineKanban.tsx +194 -0
- package/templates/shared/QuickFilters.tsx +47 -0
- package/templates/shared/StageColumn.tsx +175 -0
- package/templates/shared/StageSelect.tsx +177 -0
- package/templates/shared/StagesRepeater.tsx +317 -0
- package/templates/shared/index.ts +9 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- Opportunities Table Migration
|
|
3
|
+
-- CRM theme: Sales opportunities in the pipeline
|
|
4
|
+
-- Updated with team support and RLS
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
|
|
7
|
+
-- ============================================
|
|
8
|
+
-- ENUM TYPES
|
|
9
|
+
-- ============================================
|
|
10
|
+
DO $$ BEGIN
|
|
11
|
+
CREATE TYPE opportunity_type AS ENUM ('new_business', 'existing_business', 'renewal');
|
|
12
|
+
EXCEPTION
|
|
13
|
+
WHEN duplicate_object THEN null;
|
|
14
|
+
END $$;
|
|
15
|
+
|
|
16
|
+
DO $$ BEGIN
|
|
17
|
+
CREATE TYPE opportunity_status AS ENUM ('open', 'won', 'lost');
|
|
18
|
+
EXCEPTION
|
|
19
|
+
WHEN duplicate_object THEN null;
|
|
20
|
+
END $$;
|
|
21
|
+
|
|
22
|
+
-- ============================================
|
|
23
|
+
-- TABLE
|
|
24
|
+
-- ============================================
|
|
25
|
+
CREATE TABLE IF NOT EXISTS "opportunities" (
|
|
26
|
+
"id" TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
27
|
+
|
|
28
|
+
-- Opportunity info
|
|
29
|
+
"name" VARCHAR(255) NOT NULL,
|
|
30
|
+
"companyId" TEXT REFERENCES "companies"("id") ON DELETE SET NULL,
|
|
31
|
+
"contactId" TEXT REFERENCES "contacts"("id") ON DELETE SET NULL,
|
|
32
|
+
|
|
33
|
+
-- Pipeline
|
|
34
|
+
"pipelineId" UUID, -- Reference to pipelines table
|
|
35
|
+
"stageId" VARCHAR(100),
|
|
36
|
+
|
|
37
|
+
-- Financials
|
|
38
|
+
"amount" DECIMAL(15,2) DEFAULT 0,
|
|
39
|
+
"currency" VARCHAR(3) DEFAULT 'USD',
|
|
40
|
+
"probability" INTEGER DEFAULT 0 CHECK ("probability" >= 0 AND "probability" <= 100),
|
|
41
|
+
"expectedRevenue" DECIMAL(15,2) GENERATED ALWAYS AS ("amount" * ("probability"::DECIMAL / 100)) STORED,
|
|
42
|
+
|
|
43
|
+
-- Dates
|
|
44
|
+
"closeDate" DATE,
|
|
45
|
+
"wonDate" DATE,
|
|
46
|
+
"lostDate" DATE,
|
|
47
|
+
|
|
48
|
+
-- Classification
|
|
49
|
+
"type" opportunity_type DEFAULT 'new_business',
|
|
50
|
+
"source" VARCHAR(100),
|
|
51
|
+
"competitor" VARCHAR(255),
|
|
52
|
+
"status" opportunity_status DEFAULT 'open',
|
|
53
|
+
"lostReason" TEXT,
|
|
54
|
+
|
|
55
|
+
-- Assignment
|
|
56
|
+
"assignedTo" TEXT REFERENCES "users"("id") ON DELETE SET NULL,
|
|
57
|
+
|
|
58
|
+
-- Ownership
|
|
59
|
+
"userId" TEXT NOT NULL REFERENCES "users"("id") ON DELETE CASCADE,
|
|
60
|
+
"teamId" TEXT NOT NULL REFERENCES "teams"("id") ON DELETE CASCADE,
|
|
61
|
+
|
|
62
|
+
-- Timestamps
|
|
63
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
64
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
-- ============================================
|
|
68
|
+
-- INDEXES
|
|
69
|
+
-- ============================================
|
|
70
|
+
CREATE INDEX IF NOT EXISTS "opportunities_teamId_idx" ON "opportunities" ("teamId");
|
|
71
|
+
CREATE INDEX IF NOT EXISTS "opportunities_userId_idx" ON "opportunities" ("userId");
|
|
72
|
+
CREATE INDEX IF NOT EXISTS "opportunities_companyId_idx" ON "opportunities" ("companyId");
|
|
73
|
+
CREATE INDEX IF NOT EXISTS "opportunities_contactId_idx" ON "opportunities" ("contactId");
|
|
74
|
+
CREATE INDEX IF NOT EXISTS "opportunities_pipelineId_idx" ON "opportunities" ("pipelineId");
|
|
75
|
+
CREATE INDEX IF NOT EXISTS "opportunities_status_idx" ON "opportunities" ("status");
|
|
76
|
+
CREATE INDEX IF NOT EXISTS "opportunities_closeDate_idx" ON "opportunities" ("closeDate");
|
|
77
|
+
CREATE INDEX IF NOT EXISTS "opportunities_assignedTo_idx" ON "opportunities" ("assignedTo");
|
|
78
|
+
CREATE INDEX IF NOT EXISTS "opportunities_amount_idx" ON "opportunities" ("amount" DESC);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS "opportunities_createdAt_idx" ON "opportunities" ("createdAt" DESC);
|
|
80
|
+
|
|
81
|
+
-- ============================================
|
|
82
|
+
-- RLS
|
|
83
|
+
-- ============================================
|
|
84
|
+
ALTER TABLE "opportunities" ENABLE ROW LEVEL SECURITY;
|
|
85
|
+
|
|
86
|
+
-- Drop existing policies
|
|
87
|
+
DROP POLICY IF EXISTS "opportunities_select_policy" ON "opportunities";
|
|
88
|
+
DROP POLICY IF EXISTS "opportunities_insert_policy" ON "opportunities";
|
|
89
|
+
DROP POLICY IF EXISTS "opportunities_update_policy" ON "opportunities";
|
|
90
|
+
DROP POLICY IF EXISTS "opportunities_delete_policy" ON "opportunities";
|
|
91
|
+
|
|
92
|
+
-- Policy: Team members can view opportunities
|
|
93
|
+
CREATE POLICY "opportunities_select_policy" ON "opportunities"
|
|
94
|
+
FOR SELECT
|
|
95
|
+
USING (
|
|
96
|
+
"teamId" = ANY(public.get_user_team_ids())
|
|
97
|
+
OR public.is_superadmin()
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
-- Policy: Team members can create opportunities
|
|
101
|
+
CREATE POLICY "opportunities_insert_policy" ON "opportunities"
|
|
102
|
+
FOR INSERT
|
|
103
|
+
WITH CHECK (
|
|
104
|
+
"teamId" = ANY(public.get_user_team_ids())
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
-- Policy: Team members can update opportunities
|
|
108
|
+
CREATE POLICY "opportunities_update_policy" ON "opportunities"
|
|
109
|
+
FOR UPDATE
|
|
110
|
+
USING (
|
|
111
|
+
"teamId" = ANY(public.get_user_team_ids())
|
|
112
|
+
OR public.is_superadmin()
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
-- Policy: Team members can delete opportunities
|
|
116
|
+
CREATE POLICY "opportunities_delete_policy" ON "opportunities"
|
|
117
|
+
FOR DELETE
|
|
118
|
+
USING (
|
|
119
|
+
"teamId" = ANY(public.get_user_team_ids())
|
|
120
|
+
OR public.is_superadmin()
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
-- ============================================
|
|
124
|
+
-- TRIGGER updatedAt
|
|
125
|
+
-- ============================================
|
|
126
|
+
CREATE OR REPLACE FUNCTION update_opportunities_updated_at()
|
|
127
|
+
RETURNS TRIGGER AS $$
|
|
128
|
+
BEGIN
|
|
129
|
+
NEW."updatedAt" = NOW();
|
|
130
|
+
RETURN NEW;
|
|
131
|
+
END;
|
|
132
|
+
$$ LANGUAGE plpgsql;
|
|
133
|
+
|
|
134
|
+
DROP TRIGGER IF EXISTS opportunities_updated_at_trigger ON "opportunities";
|
|
135
|
+
CREATE TRIGGER opportunities_updated_at_trigger
|
|
136
|
+
BEFORE UPDATE ON "opportunities"
|
|
137
|
+
FOR EACH ROW
|
|
138
|
+
EXECUTE FUNCTION update_opportunities_updated_at();
|
|
139
|
+
|
|
140
|
+
-- ============================================
|
|
141
|
+
-- COMMENTS
|
|
142
|
+
-- ============================================
|
|
143
|
+
COMMENT ON TABLE "opportunities" IS 'Sales opportunities in the pipeline';
|
|
144
|
+
COMMENT ON COLUMN "opportunities"."expectedRevenue" IS 'Calculated as amount * (probability / 100)';
|
|
145
|
+
COMMENT ON COLUMN "opportunities"."stageId" IS 'Current stage ID from pipeline stages JSONB';
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
-- Migration: 002_opportunities_metas.sql
|
|
2
|
+
-- Description: Contacts metas (table, indexes, RLS)
|
|
3
|
+
-- Date: 2025-09-27
|
|
4
|
+
|
|
5
|
+
-- ============================================
|
|
6
|
+
-- TABLE
|
|
7
|
+
-- ============================================
|
|
8
|
+
-- No DROP needed - removed automatically by parent table CASCADE
|
|
9
|
+
CREATE TABLE IF NOT EXISTS public."opportunities_metas" (
|
|
10
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
11
|
+
"entityId" TEXT NOT NULL REFERENCES public."opportunities"(id) ON DELETE CASCADE,
|
|
12
|
+
"metaKey" TEXT NOT NULL,
|
|
13
|
+
"metaValue" JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
14
|
+
"dataType" TEXT DEFAULT 'json',
|
|
15
|
+
"isPublic" BOOLEAN NOT NULL DEFAULT false,
|
|
16
|
+
"isSearchable" BOOLEAN NOT NULL DEFAULT false,
|
|
17
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
18
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
19
|
+
CONSTRAINT opportunities_metas_unique_key UNIQUE ("entityId", "metaKey")
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
COMMENT ON TABLE public."opportunities_metas" IS 'Contacts metadata table - stores additional key-value pairs for opportunities';
|
|
23
|
+
COMMENT ON COLUMN public."opportunities_metas"."entityId" IS 'Generic foreign key to parent opportunitie entity';
|
|
24
|
+
COMMENT ON COLUMN public."opportunities_metas"."metaKey" IS 'Metadata key name';
|
|
25
|
+
COMMENT ON COLUMN public."opportunities_metas"."metaValue" IS 'Metadata value as JSONB';
|
|
26
|
+
COMMENT ON COLUMN public."opportunities_metas"."dataType" IS 'Type hint for the value: json, string, number, boolean';
|
|
27
|
+
COMMENT ON COLUMN public."opportunities_metas"."isPublic" IS 'Whether this metadata is publicly readable';
|
|
28
|
+
COMMENT ON COLUMN public."opportunities_metas"."isSearchable" IS 'Whether this metadata is searchable';
|
|
29
|
+
|
|
30
|
+
-- ============================================
|
|
31
|
+
-- TRIGGER updatedAt (uses Better Auth function)
|
|
32
|
+
-- ============================================
|
|
33
|
+
DROP TRIGGER IF EXISTS opportunities_metas_set_updated_at ON public."opportunities_metas";
|
|
34
|
+
CREATE TRIGGER opportunities_metas_set_updated_at
|
|
35
|
+
BEFORE UPDATE ON public."opportunities_metas"
|
|
36
|
+
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
|
37
|
+
|
|
38
|
+
-- ============================================
|
|
39
|
+
-- INDEXES
|
|
40
|
+
-- ============================================
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_entity_id ON public."opportunities_metas"("entityId");
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_key ON public."opportunities_metas"("metaKey");
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_composite ON public."opportunities_metas"("entityId", "metaKey", "isPublic");
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_is_public ON public."opportunities_metas"("isPublic") WHERE "isPublic" = true;
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_is_searchable ON public."opportunities_metas"("isSearchable") WHERE "isSearchable" = true;
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_searchable_key ON public."opportunities_metas"("metaKey") WHERE "isSearchable" = true;
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_value_gin ON public."opportunities_metas" USING GIN ("metaValue");
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_opportunities_metas_value_ops ON public."opportunities_metas" USING GIN ("metaValue" jsonb_path_ops);
|
|
49
|
+
|
|
50
|
+
-- ============================================
|
|
51
|
+
-- RLS
|
|
52
|
+
-- ============================================
|
|
53
|
+
ALTER TABLE public."opportunities_metas" ENABLE ROW LEVEL SECURITY;
|
|
54
|
+
|
|
55
|
+
-- Cleanup existing policies
|
|
56
|
+
DROP POLICY IF EXISTS "Users can view opportunitie metas" ON public."opportunities_metas";
|
|
57
|
+
DROP POLICY IF EXISTS "Users can create opportunitie metas" ON public."opportunities_metas";
|
|
58
|
+
DROP POLICY IF EXISTS "Users can update opportunitie metas" ON public."opportunities_metas";
|
|
59
|
+
DROP POLICY IF EXISTS "Users can delete opportunitie metas" ON public."opportunities_metas";
|
|
60
|
+
|
|
61
|
+
-- ============================
|
|
62
|
+
-- AUTHENTICATED USER POLICIES
|
|
63
|
+
-- ============================
|
|
64
|
+
-- Inherit permissions from parent entity
|
|
65
|
+
CREATE POLICY "Users can view opportunitie metas"
|
|
66
|
+
ON public."opportunities_metas"
|
|
67
|
+
FOR SELECT TO authenticated
|
|
68
|
+
USING (
|
|
69
|
+
EXISTS (
|
|
70
|
+
SELECT 1 FROM public."opportunities" c
|
|
71
|
+
WHERE c.id = "entityId"
|
|
72
|
+
AND c."userId" = public.get_auth_user_id()
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
CREATE POLICY "Users can create opportunitie metas"
|
|
77
|
+
ON public."opportunities_metas"
|
|
78
|
+
FOR INSERT TO authenticated
|
|
79
|
+
WITH CHECK (
|
|
80
|
+
EXISTS (
|
|
81
|
+
SELECT 1 FROM public."opportunities" c
|
|
82
|
+
WHERE c.id = "entityId"
|
|
83
|
+
AND c."userId" = public.get_auth_user_id()
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
CREATE POLICY "Users can update opportunitie metas"
|
|
88
|
+
ON public."opportunities_metas"
|
|
89
|
+
FOR UPDATE TO authenticated
|
|
90
|
+
USING (
|
|
91
|
+
EXISTS (
|
|
92
|
+
SELECT 1 FROM public."opportunities" c
|
|
93
|
+
WHERE c.id = "entityId"
|
|
94
|
+
AND c."userId" = public.get_auth_user_id()
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
WITH CHECK (
|
|
98
|
+
EXISTS (
|
|
99
|
+
SELECT 1 FROM public."opportunities" c
|
|
100
|
+
WHERE c.id = "entityId"
|
|
101
|
+
AND c."userId" = public.get_auth_user_id()
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
CREATE POLICY "Users can delete opportunitie metas"
|
|
106
|
+
ON public."opportunities_metas"
|
|
107
|
+
FOR DELETE TO authenticated
|
|
108
|
+
USING (
|
|
109
|
+
EXISTS (
|
|
110
|
+
SELECT 1 FROM public."opportunities" c
|
|
111
|
+
WHERE c.id = "entityId"
|
|
112
|
+
AND c."userId" = public.get_auth_user_id()
|
|
113
|
+
)
|
|
114
|
+
);
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- Sample data for opportunities table - CRM Theme
|
|
3
|
+
-- Aligned with schema in 001_opportunities_table.sql
|
|
4
|
+
-- Uses users from 999_theme_sample_data.sql
|
|
5
|
+
-- References companies, contacts, and pipelines from their sample data
|
|
6
|
+
-- NOTE: expectedRevenue is a GENERATED column - DO NOT insert it!
|
|
7
|
+
-- ============================================================================
|
|
8
|
+
|
|
9
|
+
-- Clean existing opportunities data
|
|
10
|
+
DELETE FROM "opportunities" WHERE "teamId" = 'team-crm-company';
|
|
11
|
+
|
|
12
|
+
INSERT INTO "opportunities" (
|
|
13
|
+
id,
|
|
14
|
+
name,
|
|
15
|
+
"companyId",
|
|
16
|
+
"contactId",
|
|
17
|
+
"pipelineId",
|
|
18
|
+
"stageId",
|
|
19
|
+
amount,
|
|
20
|
+
currency,
|
|
21
|
+
probability,
|
|
22
|
+
"closeDate",
|
|
23
|
+
"wonDate",
|
|
24
|
+
"lostDate",
|
|
25
|
+
type,
|
|
26
|
+
source,
|
|
27
|
+
competitor,
|
|
28
|
+
status,
|
|
29
|
+
"lostReason",
|
|
30
|
+
"assignedTo",
|
|
31
|
+
"userId",
|
|
32
|
+
"teamId",
|
|
33
|
+
"createdAt",
|
|
34
|
+
"updatedAt"
|
|
35
|
+
) VALUES
|
|
36
|
+
-- TechnoSoft Solutions Opportunities (company-crm-001)
|
|
37
|
+
(
|
|
38
|
+
'opp-crm-001',
|
|
39
|
+
'TechnoSoft CRM Enterprise Implementation',
|
|
40
|
+
'company-crm-001',
|
|
41
|
+
'contact-crm-001',
|
|
42
|
+
'cf7f1f00-0002-4000-8000-000000000002',
|
|
43
|
+
'stage_011',
|
|
44
|
+
125000.00,
|
|
45
|
+
'USD',
|
|
46
|
+
80,
|
|
47
|
+
DATE(NOW() + INTERVAL '45 days'),
|
|
48
|
+
NULL,
|
|
49
|
+
NULL,
|
|
50
|
+
'new_business',
|
|
51
|
+
'referral',
|
|
52
|
+
'Salesforce',
|
|
53
|
+
'open',
|
|
54
|
+
NULL,
|
|
55
|
+
'usr-crm-sales-mgr',
|
|
56
|
+
'usr-crm-ceo',
|
|
57
|
+
'team-crm-company',
|
|
58
|
+
NOW() - INTERVAL '35 days',
|
|
59
|
+
NOW() - INTERVAL '2 days'
|
|
60
|
+
),
|
|
61
|
+
(
|
|
62
|
+
'opp-crm-002',
|
|
63
|
+
'TechnoSoft Analytics Module Upgrade',
|
|
64
|
+
'company-crm-001',
|
|
65
|
+
'contact-crm-003',
|
|
66
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
67
|
+
'stage_003',
|
|
68
|
+
15000.00,
|
|
69
|
+
'USD',
|
|
70
|
+
50,
|
|
71
|
+
DATE(NOW() + INTERVAL '30 days'),
|
|
72
|
+
NULL,
|
|
73
|
+
NULL,
|
|
74
|
+
'existing_business',
|
|
75
|
+
'existing_customer',
|
|
76
|
+
NULL,
|
|
77
|
+
'open',
|
|
78
|
+
NULL,
|
|
79
|
+
'usr-crm-sales-rep',
|
|
80
|
+
'usr-crm-sales-mgr',
|
|
81
|
+
'team-crm-company',
|
|
82
|
+
NOW() - INTERVAL '20 days',
|
|
83
|
+
NOW() - INTERVAL '3 days'
|
|
84
|
+
),
|
|
85
|
+
|
|
86
|
+
-- Global Manufacturing Corp Opportunities (company-crm-002)
|
|
87
|
+
(
|
|
88
|
+
'opp-crm-003',
|
|
89
|
+
'Global Manufacturing Digital Transformation',
|
|
90
|
+
'company-crm-002',
|
|
91
|
+
'contact-crm-004',
|
|
92
|
+
'cf7f1f00-0002-4000-8000-000000000002',
|
|
93
|
+
'stage_009',
|
|
94
|
+
250000.00,
|
|
95
|
+
'USD',
|
|
96
|
+
30,
|
|
97
|
+
DATE(NOW() + INTERVAL '90 days'),
|
|
98
|
+
NULL,
|
|
99
|
+
NULL,
|
|
100
|
+
'new_business',
|
|
101
|
+
'trade_show',
|
|
102
|
+
'HubSpot',
|
|
103
|
+
'open',
|
|
104
|
+
NULL,
|
|
105
|
+
'usr-crm-sales-rep',
|
|
106
|
+
'usr-crm-sales-mgr',
|
|
107
|
+
'team-crm-company',
|
|
108
|
+
NOW() - INTERVAL '60 days',
|
|
109
|
+
NOW() - INTERVAL '5 days'
|
|
110
|
+
),
|
|
111
|
+
(
|
|
112
|
+
'opp-crm-004',
|
|
113
|
+
'Manufacturing Training & Support Package',
|
|
114
|
+
'company-crm-002',
|
|
115
|
+
'contact-crm-005',
|
|
116
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
117
|
+
'stage_004',
|
|
118
|
+
35000.00,
|
|
119
|
+
'USD',
|
|
120
|
+
75,
|
|
121
|
+
DATE(NOW() + INTERVAL '20 days'),
|
|
122
|
+
NULL,
|
|
123
|
+
NULL,
|
|
124
|
+
'existing_business',
|
|
125
|
+
'existing_customer',
|
|
126
|
+
NULL,
|
|
127
|
+
'open',
|
|
128
|
+
NULL,
|
|
129
|
+
'usr-crm-sales-rep',
|
|
130
|
+
'usr-crm-sales-mgr',
|
|
131
|
+
'team-crm-company',
|
|
132
|
+
NOW() - INTERVAL '25 days',
|
|
133
|
+
NOW() - INTERVAL '1 day'
|
|
134
|
+
),
|
|
135
|
+
|
|
136
|
+
-- Healthcare Innovations Opportunities (company-crm-003)
|
|
137
|
+
(
|
|
138
|
+
'opp-crm-005',
|
|
139
|
+
'Healthcare CRM Pro Implementation',
|
|
140
|
+
'company-crm-003',
|
|
141
|
+
'contact-crm-006',
|
|
142
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
143
|
+
'stage_002',
|
|
144
|
+
45000.00,
|
|
145
|
+
'USD',
|
|
146
|
+
25,
|
|
147
|
+
DATE(NOW() + INTERVAL '60 days'),
|
|
148
|
+
NULL,
|
|
149
|
+
NULL,
|
|
150
|
+
'new_business',
|
|
151
|
+
'linkedin',
|
|
152
|
+
'Zoho',
|
|
153
|
+
'open',
|
|
154
|
+
NULL,
|
|
155
|
+
'usr-crm-sales-mgr',
|
|
156
|
+
'usr-crm-ceo',
|
|
157
|
+
'team-crm-company',
|
|
158
|
+
NOW() - INTERVAL '15 days',
|
|
159
|
+
NOW() - INTERVAL '1 day'
|
|
160
|
+
),
|
|
161
|
+
(
|
|
162
|
+
'opp-crm-006',
|
|
163
|
+
'Healthcare Compliance & Security Audit',
|
|
164
|
+
'company-crm-003',
|
|
165
|
+
'contact-crm-007',
|
|
166
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
167
|
+
'stage_001',
|
|
168
|
+
12000.00,
|
|
169
|
+
'USD',
|
|
170
|
+
10,
|
|
171
|
+
DATE(NOW() + INTERVAL '75 days'),
|
|
172
|
+
NULL,
|
|
173
|
+
NULL,
|
|
174
|
+
'new_business',
|
|
175
|
+
'referral',
|
|
176
|
+
NULL,
|
|
177
|
+
'open',
|
|
178
|
+
NULL,
|
|
179
|
+
'usr-crm-sales-rep',
|
|
180
|
+
'usr-crm-sales-mgr',
|
|
181
|
+
'team-crm-company',
|
|
182
|
+
NOW() - INTERVAL '10 days',
|
|
183
|
+
NOW() - INTERVAL '2 days'
|
|
184
|
+
),
|
|
185
|
+
|
|
186
|
+
-- FinanceFirst Bank Opportunities (company-crm-004)
|
|
187
|
+
(
|
|
188
|
+
'opp-crm-007',
|
|
189
|
+
'FinanceFirst Enterprise CRM Platform',
|
|
190
|
+
'company-crm-004',
|
|
191
|
+
'contact-crm-008',
|
|
192
|
+
'cf7f1f00-0002-4000-8000-000000000002',
|
|
193
|
+
'stage_010',
|
|
194
|
+
180000.00,
|
|
195
|
+
'USD',
|
|
196
|
+
60,
|
|
197
|
+
DATE(NOW() + INTERVAL '120 days'),
|
|
198
|
+
NULL,
|
|
199
|
+
NULL,
|
|
200
|
+
'existing_business',
|
|
201
|
+
'existing_customer',
|
|
202
|
+
'Microsoft Dynamics',
|
|
203
|
+
'open',
|
|
204
|
+
NULL,
|
|
205
|
+
'usr-crm-sales-rep',
|
|
206
|
+
'usr-crm-sales-mgr',
|
|
207
|
+
'team-crm-company',
|
|
208
|
+
NOW() - INTERVAL '90 days',
|
|
209
|
+
NOW() - INTERVAL '10 days'
|
|
210
|
+
),
|
|
211
|
+
|
|
212
|
+
-- EduTech Academy Opportunities (company-crm-005)
|
|
213
|
+
(
|
|
214
|
+
'opp-crm-008',
|
|
215
|
+
'EduTech CRM Pro License & Training',
|
|
216
|
+
'company-crm-005',
|
|
217
|
+
'contact-crm-010',
|
|
218
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
219
|
+
'stage_003',
|
|
220
|
+
28000.00,
|
|
221
|
+
'USD',
|
|
222
|
+
50,
|
|
223
|
+
DATE(NOW() + INTERVAL '35 days'),
|
|
224
|
+
NULL,
|
|
225
|
+
NULL,
|
|
226
|
+
'new_business',
|
|
227
|
+
'webinar',
|
|
228
|
+
NULL,
|
|
229
|
+
'open',
|
|
230
|
+
NULL,
|
|
231
|
+
'usr-crm-sales-rep',
|
|
232
|
+
'usr-crm-sales-mgr',
|
|
233
|
+
'team-crm-company',
|
|
234
|
+
NOW() - INTERVAL '12 days',
|
|
235
|
+
NOW() - INTERVAL '1 day'
|
|
236
|
+
),
|
|
237
|
+
|
|
238
|
+
-- RetailMax Chain Opportunities (company-crm-006)
|
|
239
|
+
(
|
|
240
|
+
'opp-crm-009',
|
|
241
|
+
'RetailMax Multi-Store CRM Solution',
|
|
242
|
+
'company-crm-006',
|
|
243
|
+
'contact-crm-012',
|
|
244
|
+
'cf7f1f00-0002-4000-8000-000000000002',
|
|
245
|
+
'stage_008',
|
|
246
|
+
95000.00,
|
|
247
|
+
'USD',
|
|
248
|
+
15,
|
|
249
|
+
DATE(NOW() + INTERVAL '150 days'),
|
|
250
|
+
NULL,
|
|
251
|
+
NULL,
|
|
252
|
+
'new_business',
|
|
253
|
+
'partner_referral',
|
|
254
|
+
'Pipedrive',
|
|
255
|
+
'open',
|
|
256
|
+
NULL,
|
|
257
|
+
'usr-crm-sales-mgr',
|
|
258
|
+
'usr-crm-ceo',
|
|
259
|
+
'team-crm-company',
|
|
260
|
+
NOW() - INTERVAL '45 days',
|
|
261
|
+
NOW() - INTERVAL '7 days'
|
|
262
|
+
),
|
|
263
|
+
|
|
264
|
+
-- StartupTech Inc Opportunities (company-crm-007)
|
|
265
|
+
(
|
|
266
|
+
'opp-crm-010',
|
|
267
|
+
'StartupTech Growth Package',
|
|
268
|
+
'company-crm-007',
|
|
269
|
+
'contact-crm-014',
|
|
270
|
+
'cf7f1f00-0003-4000-8000-000000000003',
|
|
271
|
+
'stage_017',
|
|
272
|
+
8500.00,
|
|
273
|
+
'USD',
|
|
274
|
+
60,
|
|
275
|
+
DATE(NOW() + INTERVAL '25 days'),
|
|
276
|
+
NULL,
|
|
277
|
+
NULL,
|
|
278
|
+
'new_business',
|
|
279
|
+
'inbound_marketing',
|
|
280
|
+
NULL,
|
|
281
|
+
'open',
|
|
282
|
+
NULL,
|
|
283
|
+
'usr-crm-sales-rep',
|
|
284
|
+
'usr-crm-sales-rep',
|
|
285
|
+
'team-crm-company',
|
|
286
|
+
NOW() - INTERVAL '8 days',
|
|
287
|
+
NOW() - INTERVAL '1 day'
|
|
288
|
+
),
|
|
289
|
+
(
|
|
290
|
+
'opp-crm-011',
|
|
291
|
+
'StartupTech Implementation Services',
|
|
292
|
+
'company-crm-007',
|
|
293
|
+
'contact-crm-015',
|
|
294
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
295
|
+
'stage_002',
|
|
296
|
+
15000.00,
|
|
297
|
+
'USD',
|
|
298
|
+
25,
|
|
299
|
+
DATE(NOW() + INTERVAL '40 days'),
|
|
300
|
+
NULL,
|
|
301
|
+
NULL,
|
|
302
|
+
'new_business',
|
|
303
|
+
'referral',
|
|
304
|
+
NULL,
|
|
305
|
+
'open',
|
|
306
|
+
NULL,
|
|
307
|
+
'usr-crm-sales-rep',
|
|
308
|
+
'usr-crm-sales-rep',
|
|
309
|
+
'team-crm-company',
|
|
310
|
+
NOW() - INTERVAL '5 days',
|
|
311
|
+
NOW() - INTERVAL '1 day'
|
|
312
|
+
),
|
|
313
|
+
|
|
314
|
+
-- Local Consulting Group Opportunities (company-crm-008)
|
|
315
|
+
(
|
|
316
|
+
'opp-crm-012',
|
|
317
|
+
'Local Consulting CRM Setup',
|
|
318
|
+
'company-crm-008',
|
|
319
|
+
'contact-crm-016',
|
|
320
|
+
'cf7f1f00-0003-4000-8000-000000000003',
|
|
321
|
+
'stage_015',
|
|
322
|
+
6500.00,
|
|
323
|
+
'USD',
|
|
324
|
+
15,
|
|
325
|
+
DATE(NOW() + INTERVAL '50 days'),
|
|
326
|
+
NULL,
|
|
327
|
+
NULL,
|
|
328
|
+
'new_business',
|
|
329
|
+
'cold_outreach',
|
|
330
|
+
NULL,
|
|
331
|
+
'open',
|
|
332
|
+
NULL,
|
|
333
|
+
'usr-crm-sales-rep',
|
|
334
|
+
'usr-crm-sales-mgr',
|
|
335
|
+
'team-crm-company',
|
|
336
|
+
NOW() - INTERVAL '20 days',
|
|
337
|
+
NOW() - INTERVAL '5 days'
|
|
338
|
+
),
|
|
339
|
+
|
|
340
|
+
-- Closed Won Opportunities (Historical Data)
|
|
341
|
+
(
|
|
342
|
+
'opp-crm-013',
|
|
343
|
+
'TechnoSoft Initial CRM License',
|
|
344
|
+
'company-crm-001',
|
|
345
|
+
'contact-crm-001',
|
|
346
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
347
|
+
'stage_005',
|
|
348
|
+
18000.00,
|
|
349
|
+
'USD',
|
|
350
|
+
100,
|
|
351
|
+
DATE(NOW() - INTERVAL '30 days'),
|
|
352
|
+
DATE(NOW() - INTERVAL '30 days'),
|
|
353
|
+
NULL,
|
|
354
|
+
'new_business',
|
|
355
|
+
'referral',
|
|
356
|
+
NULL,
|
|
357
|
+
'won',
|
|
358
|
+
NULL,
|
|
359
|
+
'usr-crm-sales-mgr',
|
|
360
|
+
'usr-crm-ceo',
|
|
361
|
+
'team-crm-company',
|
|
362
|
+
NOW() - INTERVAL '75 days',
|
|
363
|
+
NOW() - INTERVAL '30 days'
|
|
364
|
+
),
|
|
365
|
+
(
|
|
366
|
+
'opp-crm-014',
|
|
367
|
+
'Global Manufacturing Server Package',
|
|
368
|
+
'company-crm-002',
|
|
369
|
+
'contact-crm-004',
|
|
370
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
371
|
+
'stage_005',
|
|
372
|
+
42000.00,
|
|
373
|
+
'USD',
|
|
374
|
+
100,
|
|
375
|
+
DATE(NOW() - INTERVAL '15 days'),
|
|
376
|
+
DATE(NOW() - INTERVAL '15 days'),
|
|
377
|
+
NULL,
|
|
378
|
+
'new_business',
|
|
379
|
+
'existing_customer',
|
|
380
|
+
NULL,
|
|
381
|
+
'won',
|
|
382
|
+
NULL,
|
|
383
|
+
'usr-crm-sales-rep',
|
|
384
|
+
'usr-crm-sales-mgr',
|
|
385
|
+
'team-crm-company',
|
|
386
|
+
NOW() - INTERVAL '60 days',
|
|
387
|
+
NOW() - INTERVAL '15 days'
|
|
388
|
+
),
|
|
389
|
+
|
|
390
|
+
-- Closed Lost Opportunities (Learning Data)
|
|
391
|
+
(
|
|
392
|
+
'opp-crm-015',
|
|
393
|
+
'Healthcare Budget Constraints Deal',
|
|
394
|
+
'company-crm-003',
|
|
395
|
+
'contact-crm-006',
|
|
396
|
+
'cf7f1f00-0001-4000-8000-000000000001',
|
|
397
|
+
'stage_006',
|
|
398
|
+
65000.00,
|
|
399
|
+
'USD',
|
|
400
|
+
0,
|
|
401
|
+
DATE(NOW() - INTERVAL '10 days'),
|
|
402
|
+
NULL,
|
|
403
|
+
DATE(NOW() - INTERVAL '10 days'),
|
|
404
|
+
'new_business',
|
|
405
|
+
'trade_show',
|
|
406
|
+
'Salesforce',
|
|
407
|
+
'lost',
|
|
408
|
+
'Budget constraints due to Q4 freezing',
|
|
409
|
+
'usr-crm-sales-mgr',
|
|
410
|
+
'usr-crm-ceo',
|
|
411
|
+
'team-crm-company',
|
|
412
|
+
NOW() - INTERVAL '90 days',
|
|
413
|
+
NOW() - INTERVAL '10 days'
|
|
414
|
+
),
|
|
415
|
+
(
|
|
416
|
+
'opp-crm-016',
|
|
417
|
+
'StartupTech Timing Issues',
|
|
418
|
+
'company-crm-007',
|
|
419
|
+
'contact-crm-014',
|
|
420
|
+
'cf7f1f00-0003-4000-8000-000000000003',
|
|
421
|
+
'stage_019',
|
|
422
|
+
12000.00,
|
|
423
|
+
'USD',
|
|
424
|
+
0,
|
|
425
|
+
DATE(NOW() - INTERVAL '5 days'),
|
|
426
|
+
NULL,
|
|
427
|
+
DATE(NOW() - INTERVAL '5 days'),
|
|
428
|
+
'new_business',
|
|
429
|
+
'website',
|
|
430
|
+
NULL,
|
|
431
|
+
'lost',
|
|
432
|
+
'Not the right timing - revisit in 6 months',
|
|
433
|
+
'usr-crm-sales-rep',
|
|
434
|
+
'usr-crm-sales-rep',
|
|
435
|
+
'team-crm-company',
|
|
436
|
+
NOW() - INTERVAL '45 days',
|
|
437
|
+
NOW() - INTERVAL '5 days'
|
|
438
|
+
);
|