@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.
Files changed (140) hide show
  1. package/CRM_PLAN.md +343 -0
  2. package/about.md +122 -0
  3. package/config/app.config.ts +185 -0
  4. package/config/billing.config.ts +187 -0
  5. package/config/dashboard.config.ts +372 -0
  6. package/config/dev.config.ts +55 -0
  7. package/config/features.config.ts +336 -0
  8. package/config/flows.config.ts +511 -0
  9. package/config/permissions.config.ts +297 -0
  10. package/config/theme.config.ts +111 -0
  11. package/entities/activities/activities.config.ts +61 -0
  12. package/entities/activities/activities.fields.ts +362 -0
  13. package/entities/activities/activities.service.ts +503 -0
  14. package/entities/activities/activities.types.ts +117 -0
  15. package/entities/activities/messages/en.json +123 -0
  16. package/entities/activities/messages/es.json +123 -0
  17. package/entities/activities/migrations/020_activities_table.sql +123 -0
  18. package/entities/activities/migrations/021_activities_metas.sql +114 -0
  19. package/entities/activities/migrations/022_activities_sample_data.sql +420 -0
  20. package/entities/campaigns/campaigns.config.ts +61 -0
  21. package/entities/campaigns/campaigns.fields.ts +413 -0
  22. package/entities/campaigns/campaigns.service.ts +426 -0
  23. package/entities/campaigns/campaigns.types.ts +124 -0
  24. package/entities/campaigns/messages/en.json +145 -0
  25. package/entities/campaigns/messages/es.json +145 -0
  26. package/entities/campaigns/migrations/001_campaigns_table.sql +127 -0
  27. package/entities/campaigns/migrations/002_campaigns_metas.sql +114 -0
  28. package/entities/campaigns/migrations/003_campaigns_sample_data.sql +364 -0
  29. package/entities/companies/companies.config.ts +61 -0
  30. package/entities/companies/companies.fields.ts +429 -0
  31. package/entities/companies/companies.service.ts +566 -0
  32. package/entities/companies/companies.types.ts +125 -0
  33. package/entities/companies/messages/en.json +146 -0
  34. package/entities/companies/messages/es.json +146 -0
  35. package/entities/companies/migrations/001_companies_table.sql +150 -0
  36. package/entities/companies/migrations/002_companies_metas.sql +114 -0
  37. package/entities/companies/migrations/003_companies_sample_data.sql +246 -0
  38. package/entities/contacts/contacts.config.ts +61 -0
  39. package/entities/contacts/contacts.fields.ts +359 -0
  40. package/entities/contacts/contacts.service.ts +509 -0
  41. package/entities/contacts/contacts.types.ts +108 -0
  42. package/entities/contacts/messages/en.json +117 -0
  43. package/entities/contacts/messages/es.json +117 -0
  44. package/entities/contacts/migrations/001_contacts_table.sql +134 -0
  45. package/entities/contacts/migrations/002_contacts_metas.sql +114 -0
  46. package/entities/contacts/migrations/003_contacts_sample_data.sql +421 -0
  47. package/entities/leads/leads.config.ts +61 -0
  48. package/entities/leads/leads.fields.ts +336 -0
  49. package/entities/leads/leads.service.ts +496 -0
  50. package/entities/leads/leads.types.ts +114 -0
  51. package/entities/leads/messages/en.json +132 -0
  52. package/entities/leads/messages/es.json +132 -0
  53. package/entities/leads/migrations/001_leads_table.sql +150 -0
  54. package/entities/leads/migrations/002_leads_metas.sql +120 -0
  55. package/entities/leads/migrations/003_leads_sample_data.sql +242 -0
  56. package/entities/notes/messages/en.json +114 -0
  57. package/entities/notes/messages/es.json +114 -0
  58. package/entities/notes/migrations/020_notes_table.sql +118 -0
  59. package/entities/notes/migrations/021_notes_metas.sql +114 -0
  60. package/entities/notes/migrations/022_notes_sample_data.sql +275 -0
  61. package/entities/notes/notes.config.ts +61 -0
  62. package/entities/notes/notes.fields.ts +283 -0
  63. package/entities/notes/notes.service.ts +320 -0
  64. package/entities/notes/notes.types.ts +102 -0
  65. package/entities/opportunities/messages/en.json +107 -0
  66. package/entities/opportunities/messages/es.json +107 -0
  67. package/entities/opportunities/migrations/010_opportunities_table.sql +145 -0
  68. package/entities/opportunities/migrations/011_opportunities_metas.sql +114 -0
  69. package/entities/opportunities/migrations/012_opportunities_sample_data.sql +438 -0
  70. package/entities/opportunities/opportunities.config.ts +61 -0
  71. package/entities/opportunities/opportunities.fields.ts +416 -0
  72. package/entities/opportunities/opportunities.service.ts +525 -0
  73. package/entities/opportunities/opportunities.types.ts +135 -0
  74. package/entities/pipelines/messages/en.json +115 -0
  75. package/entities/pipelines/messages/es.json +115 -0
  76. package/entities/pipelines/migrations/001_pipelines_table.sql +106 -0
  77. package/entities/pipelines/migrations/002_pipelines_metas.sql +114 -0
  78. package/entities/pipelines/migrations/003_pipelines_sample_data.sql +91 -0
  79. package/entities/pipelines/pipelines.config.ts +62 -0
  80. package/entities/pipelines/pipelines.fields.ts +193 -0
  81. package/entities/pipelines/pipelines.service.ts +383 -0
  82. package/entities/pipelines/pipelines.types.ts +78 -0
  83. package/entities/products/messages/en.json +135 -0
  84. package/entities/products/messages/es.json +135 -0
  85. package/entities/products/migrations/001_products_table.sql +117 -0
  86. package/entities/products/migrations/002_products_metas.sql +114 -0
  87. package/entities/products/migrations/003_products_sample_data.sql +247 -0
  88. package/entities/products/products.config.ts +62 -0
  89. package/entities/products/products.fields.ts +361 -0
  90. package/entities/products/products.service.ts +437 -0
  91. package/entities/products/products.types.ts +125 -0
  92. package/lib/crm-constants.ts +77 -0
  93. package/lib/crm-utils.ts +185 -0
  94. package/lib/selectors.ts +333 -0
  95. package/messages/en.json +131 -0
  96. package/messages/es.json +131 -0
  97. package/migrations/999_theme_sample_data.sql +473 -0
  98. package/package.json +18 -0
  99. package/pendings.md +205 -0
  100. package/permissions-matrix.md +216 -0
  101. package/styles/components.css +414 -0
  102. package/styles/crm-theme.css +358 -0
  103. package/styles/globals.css +576 -0
  104. package/styles/variables.css +111 -0
  105. package/templates/dashboard/(main)/activities/components/ActivityCard.tsx +169 -0
  106. package/templates/dashboard/(main)/activities/components/ActivityTimeline.tsx +165 -0
  107. package/templates/dashboard/(main)/activities/page.tsx +297 -0
  108. package/templates/dashboard/(main)/campaigns/page.tsx +373 -0
  109. package/templates/dashboard/(main)/companies/page.tsx +296 -0
  110. package/templates/dashboard/(main)/contacts/page.tsx +347 -0
  111. package/templates/dashboard/(main)/layout.tsx +98 -0
  112. package/templates/dashboard/(main)/leads/page.tsx +335 -0
  113. package/templates/dashboard/(main)/opportunities/[id]/edit/page.tsx +95 -0
  114. package/templates/dashboard/(main)/opportunities/create/page.tsx +94 -0
  115. package/templates/dashboard/(main)/opportunities/page.tsx +350 -0
  116. package/templates/dashboard/(main)/pipelines/[id]/edit/page.tsx +95 -0
  117. package/templates/dashboard/(main)/pipelines/[id]/page.tsx +143 -0
  118. package/templates/dashboard/(main)/pipelines/create/page.tsx +94 -0
  119. package/templates/dashboard/(main)/pipelines/page.tsx +234 -0
  120. package/templates/dashboard/(main)/products/[id]/edit/page.tsx +97 -0
  121. package/templates/dashboard/(main)/products/[id]/page.tsx +509 -0
  122. package/templates/dashboard/(main)/products/create/page.tsx +96 -0
  123. package/templates/dashboard/(main)/products/page.tsx +308 -0
  124. package/templates/shared/ActionButtons.tsx +41 -0
  125. package/templates/shared/CRMDashboard.tsx +519 -0
  126. package/templates/shared/CRMDataTable.tsx +441 -0
  127. package/templates/shared/CRMMetricCard.tsx +76 -0
  128. package/templates/shared/CRMMobileNav.tsx +172 -0
  129. package/templates/shared/CRMSidebar.tsx +346 -0
  130. package/templates/shared/CRMTopBar.tsx +265 -0
  131. package/templates/shared/DealCard.tsx +123 -0
  132. package/templates/shared/EntityCard.tsx +58 -0
  133. package/templates/shared/OpportunityForm.tsx +649 -0
  134. package/templates/shared/PipelineForm.tsx +367 -0
  135. package/templates/shared/PipelineKanban.tsx +194 -0
  136. package/templates/shared/QuickFilters.tsx +47 -0
  137. package/templates/shared/StageColumn.tsx +175 -0
  138. package/templates/shared/StageSelect.tsx +177 -0
  139. package/templates/shared/StagesRepeater.tsx +317 -0
  140. package/templates/shared/index.ts +9 -0
@@ -0,0 +1,131 @@
1
+ {
2
+ "crm": {
3
+ "name": "CRM Enterprise",
4
+ "description": "Solución CRM completa para equipos de ventas y marketing",
5
+ "tagline": "Cierra más negocios, haz crecer tu empresa",
6
+
7
+ "navigation": {
8
+ "leads": "Prospectos",
9
+ "contacts": "Contactos",
10
+ "companies": "Empresas",
11
+ "opportunities": "Oportunidades",
12
+ "activities": "Actividades",
13
+ "campaigns": "Campañas",
14
+ "reports": "Reportes",
15
+ "settings": "Configuración"
16
+ },
17
+
18
+ "quickActions": {
19
+ "newLead": "Nuevo Prospecto",
20
+ "newContact": "Nuevo Contacto",
21
+ "newCompany": "Nueva Empresa",
22
+ "newOpportunity": "Nueva Oportunidad",
23
+ "scheduleActivity": "Programar Actividad",
24
+ "createCampaign": "Crear Campaña"
25
+ },
26
+
27
+ "dashboard": {
28
+ "welcome": "¡Bienvenido de nuevo!",
29
+ "welcomeWithName": "¡Bienvenido de nuevo, {name}!",
30
+ "overview": "Resumen de Ventas",
31
+ "pipelineValue": "Valor del Pipeline",
32
+ "openDeals": "Negocios Abiertos",
33
+ "wonThisMonth": "Ganados Este Mes",
34
+ "conversionRate": "Tasa de Conversión",
35
+ "upcomingActivities": "Próximas Actividades",
36
+ "recentLeads": "Prospectos Recientes",
37
+ "topOpportunities": "Mejores Oportunidades"
38
+ },
39
+
40
+ "pipeline": {
41
+ "title": "Pipeline de Ventas",
42
+ "totalValue": "Valor Total",
43
+ "dealCount": "Negocios",
44
+ "stages": {
45
+ "qualification": "Calificación",
46
+ "needsAnalysis": "Análisis de Necesidades",
47
+ "proposal": "Propuesta",
48
+ "negotiation": "Negociación",
49
+ "closedWon": "Ganado",
50
+ "closedLost": "Perdido"
51
+ }
52
+ },
53
+
54
+ "reports": {
55
+ "title": "Reportes",
56
+ "sales": "Reporte de Ventas",
57
+ "marketing": "Reporte de Marketing",
58
+ "pipeline": "Reporte de Pipeline",
59
+ "activity": "Reporte de Actividades",
60
+ "forecast": "Pronóstico de Ventas"
61
+ },
62
+
63
+ "features": {
64
+ "convert": {
65
+ "title": "Convertir Prospecto",
66
+ "description": "Convertir este prospecto en contacto y empresa",
67
+ "createContact": "Crear Contacto",
68
+ "createCompany": "Crear Empresa",
69
+ "success": "Prospecto convertido exitosamente",
70
+ "alreadyConverted": "Este prospecto ya ha sido convertido"
71
+ },
72
+ "bulkImport": {
73
+ "title": "Importar Datos",
74
+ "description": "Importar datos desde archivo CSV o Excel",
75
+ "selectFile": "Seleccionar archivo",
76
+ "mapping": "Mapear columnas",
77
+ "preview": "Vista previa",
78
+ "import": "Importar"
79
+ },
80
+ "bulkExport": {
81
+ "title": "Exportar Datos",
82
+ "description": "Exportar datos a archivo CSV o Excel",
83
+ "allRecords": "Todos los registros",
84
+ "selectedRecords": "Registros seleccionados",
85
+ "filteredRecords": "Registros filtrados"
86
+ }
87
+ },
88
+
89
+ "roles": {
90
+ "owner": "Administrador",
91
+ "admin": "Gerente",
92
+ "member": "Representante",
93
+ "viewer": "Visor",
94
+ "descriptions": {
95
+ "owner": "Acceso completo a todas las funciones y configuraciones del CRM",
96
+ "admin": "Puede gestionar equipo, ver reportes y realizar operaciones masivas",
97
+ "member": "Puede gestionar prospectos, contactos, oportunidades y actividades",
98
+ "viewer": "Acceso de solo lectura a los datos del CRM"
99
+ }
100
+ },
101
+
102
+ "stats": {
103
+ "totalLeads": "Total de Prospectos",
104
+ "qualifiedLeads": "Prospectos Calificados",
105
+ "totalOpportunities": "Total de Oportunidades",
106
+ "wonOpportunities": "Oportunidades Ganadas",
107
+ "pipelineValue": "Valor del Pipeline",
108
+ "avgDealSize": "Tamaño Promedio",
109
+ "winRate": "Tasa de Éxito",
110
+ "activeCampaigns": "Campañas Activas"
111
+ },
112
+
113
+ "empty": {
114
+ "noLeads": {
115
+ "title": "Aún no hay prospectos",
116
+ "description": "Comienza a capturar prospectos para hacer crecer tu pipeline.",
117
+ "action": "Agregar tu primer prospecto"
118
+ },
119
+ "noOpportunities": {
120
+ "title": "Aún no hay oportunidades",
121
+ "description": "Crea oportunidades a partir de prospectos calificados.",
122
+ "action": "Crear oportunidad"
123
+ },
124
+ "noActivities": {
125
+ "title": "No hay actividades programadas",
126
+ "description": "Programa llamadas, reuniones y tareas.",
127
+ "action": "Programar actividad"
128
+ }
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,473 @@
1
+ -- ============================================================================
2
+ -- CRM Theme - Sample Data Migration
3
+ -- Scenario: Single-tenant (one company, multiple users with different roles)
4
+ -- Teams Mode: single-tenant
5
+ -- ============================================================================
6
+
7
+ -- ============================================
8
+ -- STEP 0: CLEANUP (preserves superadmin)
9
+ -- ============================================
10
+ DO $$
11
+ DECLARE
12
+ v_superadmin_id TEXT;
13
+ BEGIN
14
+ -- Get superadmin ID to preserve
15
+ SELECT id INTO v_superadmin_id FROM "users" WHERE role = 'superadmin' LIMIT 1;
16
+
17
+ -- Clean theme entities (if tables exist)
18
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'notes') THEN
19
+ TRUNCATE "notes" CASCADE;
20
+ END IF;
21
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'activities') THEN
22
+ TRUNCATE "activities" CASCADE;
23
+ END IF;
24
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'opportunities') THEN
25
+ TRUNCATE "opportunities" CASCADE;
26
+ END IF;
27
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'campaigns') THEN
28
+ TRUNCATE "campaigns" CASCADE;
29
+ END IF;
30
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'contacts') THEN
31
+ TRUNCATE "contacts" CASCADE;
32
+ END IF;
33
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'leads') THEN
34
+ TRUNCATE "leads" CASCADE;
35
+ END IF;
36
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'companies') THEN
37
+ TRUNCATE "companies" CASCADE;
38
+ END IF;
39
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'products') THEN
40
+ TRUNCATE "products" CASCADE;
41
+ END IF;
42
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'pipelines') THEN
43
+ TRUNCATE "pipelines" CASCADE;
44
+ END IF;
45
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'invoices') THEN
46
+ TRUNCATE "invoices" CASCADE;
47
+ END IF;
48
+
49
+ -- Note: personal team deletion trigger removed in simplified architecture
50
+
51
+ -- Clean team-related data (except superadmin's)
52
+ IF v_superadmin_id IS NOT NULL THEN
53
+ DELETE FROM "api_audit_log" WHERE "userId" != v_superadmin_id;
54
+ DELETE FROM "api_key" WHERE "userId" != v_superadmin_id;
55
+ DELETE FROM "team_members" WHERE "userId" != v_superadmin_id;
56
+ DELETE FROM "teams" WHERE "ownerId" != v_superadmin_id;
57
+ DELETE FROM "users_metas" WHERE "userId" != v_superadmin_id;
58
+ DELETE FROM "session" WHERE "userId" != v_superadmin_id;
59
+ DELETE FROM "account" WHERE "userId" != v_superadmin_id;
60
+ DELETE FROM "users" WHERE id != v_superadmin_id;
61
+ ELSE
62
+ DELETE FROM "api_audit_log";
63
+ DELETE FROM "api_key";
64
+ DELETE FROM "team_members";
65
+ DELETE FROM "teams";
66
+ DELETE FROM "users_metas";
67
+ DELETE FROM "session";
68
+ DELETE FROM "account";
69
+ DELETE FROM "users";
70
+ END IF;
71
+
72
+ -- Cleanup complete
73
+
74
+ RAISE NOTICE 'CRM theme cleanup complete. Superadmin preserved.';
75
+ END $$;
76
+
77
+ -- ============================================
78
+ -- STEP 1: CREATE USERS
79
+ -- ============================================
80
+ -- Single-tenant: 4 users in one company with different roles
81
+
82
+ INSERT INTO "users" (
83
+ id,
84
+ email,
85
+ name,
86
+ "firstName",
87
+ "lastName",
88
+ role,
89
+ "emailVerified",
90
+ language,
91
+ country,
92
+ timezone,
93
+ "createdAt",
94
+ "updatedAt"
95
+ ) VALUES
96
+ -- CEO / Owner
97
+ (
98
+ 'usr-crm-ceo',
99
+ 'crm_owner_roberto@nextspark.dev',
100
+ 'Roberto Martínez',
101
+ 'Roberto',
102
+ 'Martínez',
103
+ 'member',
104
+ true,
105
+ 'es',
106
+ 'ES',
107
+ 'Europe/Madrid',
108
+ NOW(),
109
+ NOW()
110
+ ),
111
+ -- Sales Manager / Admin
112
+ (
113
+ 'usr-crm-sales-mgr',
114
+ 'crm_admin_sofia@nextspark.dev',
115
+ 'Sofía Gómez',
116
+ 'Sofía',
117
+ 'Gómez',
118
+ 'member',
119
+ true,
120
+ 'es',
121
+ 'AR',
122
+ 'America/Argentina/Buenos_Aires',
123
+ NOW(),
124
+ NOW()
125
+ ),
126
+ -- Sales Rep / Member
127
+ (
128
+ 'usr-crm-sales-rep',
129
+ 'crm_member_miguel@nextspark.dev',
130
+ 'Miguel Castro',
131
+ 'Miguel',
132
+ 'Castro',
133
+ 'member',
134
+ true,
135
+ 'es',
136
+ 'MX',
137
+ 'America/Mexico_City',
138
+ NOW(),
139
+ NOW()
140
+ ),
141
+ -- Marketing / Member
142
+ (
143
+ 'usr-crm-marketing',
144
+ 'crm_member_laura@nextspark.dev',
145
+ 'Laura Vega',
146
+ 'Laura',
147
+ 'Vega',
148
+ 'member',
149
+ true,
150
+ 'en',
151
+ 'US',
152
+ 'America/New_York',
153
+ NOW(),
154
+ NOW()
155
+ )
156
+ ON CONFLICT (email) DO NOTHING;
157
+
158
+ -- ============================================
159
+ -- STEP 2: CREATE TEAM
160
+ -- ============================================
161
+ -- Single-tenant: Only ONE work team (the company)
162
+
163
+ INSERT INTO "teams" (
164
+ id,
165
+ name,
166
+ slug,
167
+ description,
168
+ "ownerId",
169
+ "createdAt",
170
+ "updatedAt"
171
+ ) VALUES
172
+ (
173
+ 'team-crm-company',
174
+ 'Ventas Pro S.A.',
175
+ 'ventas-pro-sa',
176
+ 'Enterprise CRM for Ventas Pro sales team',
177
+ 'usr-crm-ceo',
178
+ NOW(),
179
+ NOW()
180
+ )
181
+ ON CONFLICT (id) DO NOTHING;
182
+
183
+ -- ============================================
184
+ -- STEP 3: CREATE TEAM MEMBERSHIPS
185
+ -- ============================================
186
+
187
+ INSERT INTO "team_members" (
188
+ id,
189
+ "teamId",
190
+ "userId",
191
+ role,
192
+ "joinedAt"
193
+ ) VALUES
194
+ -- Owner - CEO has full control
195
+ ('tm-crm-ceo', 'team-crm-company', 'usr-crm-ceo', 'owner', NOW()),
196
+ -- Admin - Sales Manager can manage team
197
+ ('tm-crm-sales-mgr', 'team-crm-company', 'usr-crm-sales-mgr', 'admin', NOW()),
198
+ -- Member - Sales Rep can work with leads/contacts
199
+ ('tm-crm-sales-rep', 'team-crm-company', 'usr-crm-sales-rep', 'member', NOW()),
200
+ -- Member - Marketing focuses on campaigns
201
+ ('tm-crm-marketing', 'team-crm-company', 'usr-crm-marketing', 'member', NOW())
202
+ ON CONFLICT (id) DO NOTHING;
203
+
204
+ -- ============================================
205
+ -- STEP 4: CREATE ACCOUNTS (Password: Test1234)
206
+ -- ============================================
207
+
208
+ INSERT INTO "account" (
209
+ id,
210
+ "userId",
211
+ "accountId",
212
+ "providerId",
213
+ "accessToken",
214
+ "refreshToken",
215
+ "idToken",
216
+ "accessTokenExpiresAt",
217
+ "refreshTokenExpiresAt",
218
+ "scope",
219
+ "password",
220
+ "createdAt",
221
+ "updatedAt"
222
+ ) VALUES
223
+ (
224
+ 'acc-crm-ceo',
225
+ 'usr-crm-ceo',
226
+ 'crm_owner_roberto@nextspark.dev',
227
+ 'credential',
228
+ NULL, NULL, NULL, NULL, NULL, NULL,
229
+ '3db9e98e2b4d3caca97fdf2783791cbc:34b293de615caf277a237773208858e960ea8aa10f1f5c5c309b632f192cac34d52ceafbd338385616f4929e4b1b6c055b67429c6722ffdb80b01d9bf4764866',
230
+ NOW(),
231
+ NOW()
232
+ ),
233
+ (
234
+ 'acc-crm-sales-mgr',
235
+ 'usr-crm-sales-mgr',
236
+ 'crm_admin_sofia@nextspark.dev',
237
+ 'credential',
238
+ NULL, NULL, NULL, NULL, NULL, NULL,
239
+ '3db9e98e2b4d3caca97fdf2783791cbc:34b293de615caf277a237773208858e960ea8aa10f1f5c5c309b632f192cac34d52ceafbd338385616f4929e4b1b6c055b67429c6722ffdb80b01d9bf4764866',
240
+ NOW(),
241
+ NOW()
242
+ ),
243
+ (
244
+ 'acc-crm-sales-rep',
245
+ 'usr-crm-sales-rep',
246
+ 'crm_member_miguel@nextspark.dev',
247
+ 'credential',
248
+ NULL, NULL, NULL, NULL, NULL, NULL,
249
+ '3db9e98e2b4d3caca97fdf2783791cbc:34b293de615caf277a237773208858e960ea8aa10f1f5c5c309b632f192cac34d52ceafbd338385616f4929e4b1b6c055b67429c6722ffdb80b01d9bf4764866',
250
+ NOW(),
251
+ NOW()
252
+ ),
253
+ (
254
+ 'acc-crm-marketing',
255
+ 'usr-crm-marketing',
256
+ 'crm_member_laura@nextspark.dev',
257
+ 'credential',
258
+ NULL, NULL, NULL, NULL, NULL, NULL,
259
+ '3db9e98e2b4d3caca97fdf2783791cbc:34b293de615caf277a237773208858e960ea8aa10f1f5c5c309b632f192cac34d52ceafbd338385616f4929e4b1b6c055b67429c6722ffdb80b01d9bf4764866',
260
+ NOW(),
261
+ NOW()
262
+ )
263
+ ON CONFLICT ("providerId", "accountId") DO NOTHING;
264
+
265
+ -- ============================================
266
+ -- STEP 5: CREATE USER METADATA
267
+ -- ============================================
268
+
269
+ INSERT INTO "users_metas" (
270
+ "userId",
271
+ "metaKey",
272
+ "metaValue",
273
+ "dataType",
274
+ "isPublic",
275
+ "isSearchable",
276
+ "createdAt",
277
+ "updatedAt"
278
+ ) VALUES
279
+ ('usr-crm-ceo', 'activeTeamId', '"team-crm-company"', 'json', false, false, NOW(), NOW()),
280
+ ('usr-crm-ceo', 'uiPreferences', '{"theme": "light", "sidebarCollapsed": false}', 'json', false, false, NOW(), NOW()),
281
+ ('usr-crm-sales-mgr', 'activeTeamId', '"team-crm-company"', 'json', false, false, NOW(), NOW()),
282
+ ('usr-crm-sales-mgr', 'uiPreferences', '{"theme": "light", "sidebarCollapsed": false}', 'json', false, false, NOW(), NOW()),
283
+ ('usr-crm-sales-rep', 'activeTeamId', '"team-crm-company"', 'json', false, false, NOW(), NOW()),
284
+ ('usr-crm-sales-rep', 'uiPreferences', '{"theme": "dark", "sidebarCollapsed": false}', 'json', false, false, NOW(), NOW()),
285
+ ('usr-crm-marketing', 'activeTeamId', '"team-crm-company"', 'json', false, false, NOW(), NOW()),
286
+ ('usr-crm-marketing', 'uiPreferences', '{"theme": "light", "sidebarCollapsed": false}', 'json', false, false, NOW(), NOW())
287
+ ON CONFLICT ("userId", "metaKey") DO NOTHING;
288
+
289
+ -- ============================================
290
+ -- STEP 6: CREATE API KEYS
291
+ -- ============================================
292
+
293
+ INSERT INTO "api_key" (
294
+ id,
295
+ "userId",
296
+ name,
297
+ "keyHash",
298
+ "keyPrefix",
299
+ scopes,
300
+ "expiresAt",
301
+ "createdAt",
302
+ "updatedAt",
303
+ status
304
+ ) VALUES
305
+ (
306
+ 'apikey-crm-ceo',
307
+ 'usr-crm-ceo',
308
+ 'CEO API Key',
309
+ 'd1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2',
310
+ 'testkey_crm00001',
311
+ ARRAY['*'],
312
+ NULL,
313
+ NOW(),
314
+ NOW(),
315
+ 'active'
316
+ ),
317
+ (
318
+ 'apikey-crm-sales-mgr',
319
+ 'usr-crm-sales-mgr',
320
+ 'Sales Manager API Key',
321
+ 'e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3',
322
+ 'testkey_crm00002',
323
+ ARRAY['leads:read', 'leads:write', 'contacts:read', 'contacts:write', 'opportunities:read', 'opportunities:write'],
324
+ NULL,
325
+ NOW(),
326
+ NOW(),
327
+ 'active'
328
+ ),
329
+ (
330
+ 'apikey-crm-sales-rep',
331
+ 'usr-crm-sales-rep',
332
+ 'Sales Rep API Key',
333
+ 'f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4',
334
+ 'testkey_crm00003',
335
+ ARRAY['leads:read', 'leads:write', 'contacts:read', 'opportunities:read'],
336
+ NULL,
337
+ NOW(),
338
+ NOW(),
339
+ 'active'
340
+ ),
341
+ (
342
+ 'apikey-crm-marketing',
343
+ 'usr-crm-marketing',
344
+ 'Marketing API Key',
345
+ 'a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5c6d1e2f3a4b5',
346
+ 'testkey_crm00004',
347
+ ARRAY['campaigns:read', 'campaigns:write', 'leads:read'],
348
+ NULL,
349
+ NOW(),
350
+ NOW(),
351
+ 'active'
352
+ )
353
+ ON CONFLICT (id) DO NOTHING;
354
+
355
+ -- ============================================
356
+ -- STEP 8: CREATE INVOICES
357
+ -- ============================================
358
+ -- Ventas Pro S.A. subscription: $499/month (Enterprise Plan)
359
+ -- 6 months history: 5 paid + 1 pending (current)
360
+ -- Total: $2,994 ($2,495 paid + $499 pending)
361
+
362
+ INSERT INTO "invoices" (
363
+ id,
364
+ "teamId",
365
+ "invoiceNumber",
366
+ date,
367
+ amount,
368
+ currency,
369
+ status,
370
+ "pdfUrl",
371
+ description
372
+ ) VALUES
373
+ -- Ventas Pro S.A. - 6 months of subscription history ($499/month Enterprise Plan)
374
+ ('inv-crm-001', 'team-crm-company', 'INV-CRM-001',
375
+ NOW() - INTERVAL '5 months', 499.00, 'USD', 'paid',
376
+ 'https://billing.example.com/invoices/inv-crm-001.pdf',
377
+ 'Enterprise Plan - Monthly subscription'),
378
+ ('inv-crm-002', 'team-crm-company', 'INV-CRM-002',
379
+ NOW() - INTERVAL '4 months', 499.00, 'USD', 'paid',
380
+ 'https://billing.example.com/invoices/inv-crm-002.pdf',
381
+ 'Enterprise Plan - Monthly subscription'),
382
+ ('inv-crm-003', 'team-crm-company', 'INV-CRM-003',
383
+ NOW() - INTERVAL '3 months', 499.00, 'USD', 'paid',
384
+ 'https://billing.example.com/invoices/inv-crm-003.pdf',
385
+ 'Enterprise Plan - Monthly subscription'),
386
+ ('inv-crm-004', 'team-crm-company', 'INV-CRM-004',
387
+ NOW() - INTERVAL '2 months', 499.00, 'USD', 'paid',
388
+ 'https://billing.example.com/invoices/inv-crm-004.pdf',
389
+ 'Enterprise Plan - Monthly subscription'),
390
+ ('inv-crm-005', 'team-crm-company', 'INV-CRM-005',
391
+ NOW() - INTERVAL '1 month', 499.00, 'USD', 'paid',
392
+ 'https://billing.example.com/invoices/inv-crm-005.pdf',
393
+ 'Enterprise Plan - Monthly subscription'),
394
+ ('inv-crm-006', 'team-crm-company', 'INV-CRM-006',
395
+ NOW(), 499.00, 'USD', 'pending',
396
+ NULL, -- No PDF yet for pending invoice
397
+ 'Enterprise Plan - Monthly subscription')
398
+ ON CONFLICT (id) DO NOTHING;
399
+
400
+ -- ============================================
401
+ -- STEP 9: SUBSCRIPTIONS (B2B - without userId)
402
+ -- ============================================
403
+ -- Note: CRM theme is single-tenant B2B - NO userId
404
+ -- Subscription belongs to team, not individual user
405
+ -- IMPORTANT: Delete trigger-created free subscription before explicit INSERT
406
+
407
+ DELETE FROM public."subscriptions" WHERE "teamId" = 'team-crm-company';
408
+
409
+ INSERT INTO public."subscriptions" (
410
+ id, "teamId", "planId", status,
411
+ "currentPeriodStart", "currentPeriodEnd", "billingInterval", "paymentProvider",
412
+ "externalSubscriptionId", "externalCustomerId", "createdAt"
413
+ ) VALUES
414
+ -- Ventas Pro S.A. → Enterprise Plan $499/mo (active, monthly)
415
+ ('sub-crm-company', 'team-crm-company', 'plan_enterprise', 'active',
416
+ NOW() - INTERVAL '15 days', NOW() + INTERVAL '15 days', 'monthly', 'stripe',
417
+ 'sub_stripe_ventaspro', 'cus_ventaspro', NOW() - INTERVAL '6 months')
418
+ ON CONFLICT (id) DO NOTHING;
419
+
420
+ -- ============================================
421
+ -- STEP 10: BILLING EVENTS (6 months @ $499 Enterprise)
422
+ -- ============================================
423
+
424
+ INSERT INTO public."billing_events" (id, "subscriptionId", type, status, amount, currency, "createdAt")
425
+ VALUES
426
+ ('be-crm-001', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '6 months'),
427
+ ('be-crm-002', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '5 months'),
428
+ ('be-crm-003', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '4 months'),
429
+ ('be-crm-004', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '3 months'),
430
+ ('be-crm-005', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '2 months'),
431
+ ('be-crm-006', 'sub-crm-company', 'payment', 'succeeded', 49900, 'usd', NOW() - INTERVAL '1 month')
432
+ ON CONFLICT (id) DO NOTHING;
433
+
434
+ -- ============================================
435
+ -- STEP 11: TEAM METADATA (B2B enterprise attributes)
436
+ -- ============================================
437
+
438
+ UPDATE public."teams" SET metadata = '{"industry": "sales", "employeeCount": 4, "segment": "enterprise", "ssoEnabled": false}'::jsonb WHERE id = 'team-crm-company';
439
+
440
+ -- ============================================
441
+ -- SUCCESS SUMMARY
442
+ -- ============================================
443
+
444
+ DO $$
445
+ BEGIN
446
+ RAISE NOTICE '';
447
+ RAISE NOTICE '═══════════════════════════════════════════════════════════';
448
+ RAISE NOTICE ' CRM Theme Sample Data - Single-tenant B2B';
449
+ RAISE NOTICE '═══════════════════════════════════════════════════════════';
450
+ RAISE NOTICE '';
451
+ RAISE NOTICE ' 👥 TEST USERS (all passwords: Test1234):';
452
+ RAISE NOTICE ' crm_owner_roberto@nextspark.dev → owner (full access)';
453
+ RAISE NOTICE ' crm_admin_sofia@nextspark.dev → admin (sales manager)';
454
+ RAISE NOTICE ' crm_member_miguel@nextspark.dev → member (sales rep)';
455
+ RAISE NOTICE ' crm_member_laura@nextspark.dev → member (marketing)';
456
+ RAISE NOTICE '';
457
+ RAISE NOTICE ' 🏢 TEAM (Single-tenant = 1 company):';
458
+ RAISE NOTICE ' Ventas Pro S.A. - 4 members';
459
+ RAISE NOTICE ' Plan: Enterprise $499/mo (active, monthly)';
460
+ RAISE NOTICE ' Billing: 6 months history ($2,994 total)';
461
+ RAISE NOTICE '';
462
+ RAISE NOTICE ' 📊 SUBSCRIPTION:';
463
+ RAISE NOTICE ' MRR: $499.00 (1 Enterprise monthly)';
464
+ RAISE NOTICE ' Status: Active';
465
+ RAISE NOTICE '';
466
+ RAISE NOTICE ' 📝 TEAMS MODE: single-tenant (B2B)';
467
+ RAISE NOTICE ' - No team switcher (only one team)';
468
+ RAISE NOTICE ' - Cannot create additional teams';
469
+ RAISE NOTICE ' - Subscription belongs to team (no userId)';
470
+ RAISE NOTICE '';
471
+ RAISE NOTICE '═══════════════════════════════════════════════════════════';
472
+ END $$;
473
+
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@nextsparkjs/theme-crm",
3
+ "version": "0.1.0-beta.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./config/theme.config.ts",
7
+ "requiredPlugins": [],
8
+ "dependencies": {},
9
+ "peerDependencies": {
10
+ "@nextsparkjs/core": "workspace:*",
11
+ "lucide-react": "^0.539.0",
12
+ "next": "^15.0.0",
13
+ "next-intl": "^4.0.0",
14
+ "react": "^19.0.0",
15
+ "react-dom": "^19.0.0",
16
+ "zod": "^4.0.0"
17
+ }
18
+ }