gmoonc 0.0.21 → 0.0.22

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/README.md CHANGED
@@ -37,6 +37,44 @@ npx gmoonc --base /dashboard
37
37
  - `--skip-router-patch`: Skip automatic router integration (only copy files and inject CSS)
38
38
  - `--dry-run`: Show what would be done without making changes
39
39
 
40
+ ## Supabase Integration
41
+
42
+ ### Setup Supabase Auth + RBAC
43
+
44
+ ```bash
45
+ npx gmoonc supabase --vite
46
+ ```
47
+
48
+ This command:
49
+ - Installs `@supabase/supabase-js` dependency
50
+ - Generates Supabase client, env validation, and RBAC helpers
51
+ - Creates/updates `.env.example` with Supabase variables
52
+ - Automatically patches existing code to use Supabase provider
53
+
54
+ ### Seed Database
55
+
56
+ After setting up Supabase integration, seed your database with the complete schema:
57
+
58
+ ```bash
59
+ npx gmoonc supabase-seed --vite
60
+ ```
61
+
62
+ **Prerequisites:**
63
+ - `gmoonc` must be installed (`npx gmoonc`)
64
+ - `supabase --vite` must have been executed
65
+ - `.env.local` must contain `SUPABASE_DB_URL` (connection string from Supabase Dashboard → Settings → Database)
66
+
67
+ **What it does:**
68
+ - Executes SQL files in order: tables → functions/triggers → RLS → seed data
69
+ - Creates marker file `.gmoonc/supabase-seed.json` to prevent duplicate execution
70
+ - One-shot by default (delete marker to re-seed)
71
+
72
+ **To get `SUPABASE_DB_URL`:**
73
+ 1. Go to your Supabase project dashboard
74
+ 2. Navigate to Settings → Database
75
+ 3. Copy the "Connection string (URI)"
76
+ 4. Add to `.env.local` as: `SUPABASE_DB_URL=postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres`
77
+
40
78
  ## After installation
41
79
 
42
80
  Your dashboard is now available at:
@@ -63,6 +101,13 @@ The logo is installed at `src/gmoonc/assets/gmoonc-logo.png`. You can replace it
63
101
 
64
102
  ## Changelog
65
103
 
104
+ ### 0.0.22
105
+ - Feature: New `supabase-seed --vite` command to seed Supabase database
106
+ - Feature: Automatic SQL file execution (tables, functions, RLS, seed data)
107
+ - Feature: One-shot protection with marker file
108
+ - Feature: SQL files copied to project for transparency
109
+ - Feature: SUPABASE_DB_URL added to .env.example
110
+
66
111
  ### 0.0.21
67
112
  - Fix: Navigate import now always added when route protection is present in GMooncAppLayout.tsx
68
113
  - Fix: Improved Navigate import detection - checks for route protection code, not just usage
@@ -0,0 +1,117 @@
1
+ -- ============================================
2
+ -- 001_tables.sql: Definição de Tabelas (gmoonc)
3
+ -- ============================================
4
+ -- Contém apenas CREATE TABLE no formato final
5
+ -- Sem ALTER TABLE redundantes
6
+ -- Schema para gmoonc (Sicoop-app refatorado)
7
+
8
+ -- ============================================
9
+ -- profiles - Usuários do Sistema
10
+ -- ============================================
11
+ CREATE TABLE IF NOT EXISTS public.profiles (
12
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
13
+ email TEXT UNIQUE NOT NULL,
14
+ name TEXT NOT NULL,
15
+ role TEXT NOT NULL,
16
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
17
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
18
+ );
19
+
20
+ -- ============================================
21
+ -- roles - Papéis/Funções do Sistema
22
+ -- ============================================
23
+ CREATE TABLE IF NOT EXISTS public.roles (
24
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
25
+ name TEXT UNIQUE NOT NULL,
26
+ description TEXT,
27
+ is_system_role BOOLEAN DEFAULT true,
28
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
29
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
30
+ );
31
+
32
+ -- ============================================
33
+ -- modules - Módulos da Aplicação
34
+ -- ============================================
35
+ CREATE TABLE IF NOT EXISTS public.modules (
36
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
37
+ name TEXT UNIQUE NOT NULL,
38
+ display_name TEXT NOT NULL,
39
+ description TEXT,
40
+ is_active BOOLEAN DEFAULT true,
41
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
42
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
43
+ );
44
+
45
+ -- ============================================
46
+ -- permissions - Permissões por Role e Módulo
47
+ -- ============================================
48
+ CREATE TABLE IF NOT EXISTS public.permissions (
49
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
50
+ role_id UUID NOT NULL REFERENCES public.roles(id) ON DELETE CASCADE,
51
+ module_id UUID NOT NULL REFERENCES public.modules(id) ON DELETE CASCADE,
52
+ can_access BOOLEAN DEFAULT false,
53
+ can_create BOOLEAN DEFAULT false,
54
+ can_read BOOLEAN DEFAULT false,
55
+ can_update BOOLEAN DEFAULT false,
56
+ can_delete BOOLEAN DEFAULT false,
57
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
58
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
59
+ );
60
+
61
+ -- ============================================
62
+ -- messages - Sistema de Mensagens (renomeado de mensagens)
63
+ -- ============================================
64
+ CREATE TABLE IF NOT EXISTS public.messages (
65
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
66
+ user_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE,
67
+ name TEXT NOT NULL,
68
+ email TEXT NOT NULL,
69
+ phone TEXT,
70
+ company_farm TEXT NOT NULL,
71
+ message TEXT NOT NULL,
72
+ status TEXT CHECK (status IS NULL OR status IN ('draft', 'pending', 'in_analysis', 'completed', 'cancelled')) DEFAULT 'pending',
73
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
74
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
75
+ );
76
+
77
+ -- ============================================
78
+ -- notification_categories - Categorias de Notificação
79
+ -- ============================================
80
+ CREATE TABLE IF NOT EXISTS public.notification_categories (
81
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
82
+ name TEXT UNIQUE NOT NULL,
83
+ display_name TEXT NOT NULL,
84
+ description TEXT,
85
+ is_active BOOLEAN DEFAULT true,
86
+ email_template_subject TEXT,
87
+ email_template_body TEXT,
88
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
89
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
90
+ );
91
+
92
+ -- ============================================
93
+ -- notification_settings - Preferências de Notificação
94
+ -- ============================================
95
+ CREATE TABLE IF NOT EXISTS public.notification_settings (
96
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
97
+ user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
98
+ category_id UUID NOT NULL REFERENCES public.notification_categories(id) ON DELETE CASCADE,
99
+ is_enabled BOOLEAN DEFAULT true,
100
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
101
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
102
+ );
103
+
104
+ -- ============================================
105
+ -- notification_logs - Histórico de Notificações
106
+ -- ============================================
107
+ CREATE TABLE IF NOT EXISTS public.notification_logs (
108
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
109
+ category_id UUID NOT NULL REFERENCES public.notification_categories(id) ON DELETE CASCADE,
110
+ user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
111
+ entity_type TEXT NOT NULL,
112
+ entity_id TEXT NOT NULL,
113
+ email_sent BOOLEAN,
114
+ email_error TEXT,
115
+ sent_at TIMESTAMP WITH TIME ZONE,
116
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
117
+ );
@@ -0,0 +1,223 @@
1
+ -- ============================================
2
+ -- 002_rls.sql: Row Level Security e Políticas (gmoonc)
3
+ -- ============================================
4
+ -- Habilita RLS e define políticas de acesso
5
+ -- Políticas para gmoonc
6
+
7
+ -- ============================================
8
+ -- ENABLE RLS em todas as tabelas
9
+ -- ============================================
10
+
11
+ ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
12
+ ALTER TABLE public.roles ENABLE ROW LEVEL SECURITY;
13
+ ALTER TABLE public.modules ENABLE ROW LEVEL SECURITY;
14
+ ALTER TABLE public.permissions ENABLE ROW LEVEL SECURITY;
15
+ ALTER TABLE public.messages ENABLE ROW LEVEL SECURITY;
16
+ ALTER TABLE public.notification_categories ENABLE ROW LEVEL SECURITY;
17
+ ALTER TABLE public.notification_settings ENABLE ROW LEVEL SECURITY;
18
+ ALTER TABLE public.notification_logs ENABLE ROW LEVEL SECURITY;
19
+
20
+ -- ============================================
21
+ -- POLÍTICAS: profiles
22
+ -- ============================================
23
+
24
+ -- Administradores podem ver todos os perfis
25
+ CREATE POLICY "admin_can_read_all_profiles" ON public.profiles
26
+ FOR SELECT
27
+ USING (
28
+ auth.uid() IN (
29
+ SELECT id FROM public.profiles WHERE role = 'administrator'
30
+ )
31
+ );
32
+
33
+ -- Usuários podem ver seu próprio perfil
34
+ CREATE POLICY "users_can_read_own_profile" ON public.profiles
35
+ FOR SELECT
36
+ USING (auth.uid() = id);
37
+
38
+ -- Administradores podem atualizar qualquer perfil
39
+ CREATE POLICY "admin_can_update_all_profiles" ON public.profiles
40
+ FOR UPDATE
41
+ USING (
42
+ auth.uid() IN (
43
+ SELECT id FROM public.profiles WHERE role = 'administrator'
44
+ )
45
+ );
46
+
47
+ -- Usuários podem atualizar seu próprio perfil
48
+ CREATE POLICY "users_can_update_own_profile" ON public.profiles
49
+ FOR UPDATE
50
+ USING (auth.uid() = id);
51
+
52
+ -- ============================================
53
+ -- POLÍTICAS: roles
54
+ -- ============================================
55
+
56
+ -- Todos podem ler roles (necessário para aplicação)
57
+ CREATE POLICY "all_can_read_roles" ON public.roles
58
+ FOR SELECT
59
+ USING (true);
60
+
61
+ -- Apenas administradores podem criar/atualizar/deletar roles
62
+ CREATE POLICY "admin_can_manage_roles" ON public.roles
63
+ FOR ALL
64
+ USING (
65
+ auth.uid() IN (
66
+ SELECT id FROM public.profiles WHERE role = 'administrator'
67
+ )
68
+ );
69
+
70
+ -- ============================================
71
+ -- POLÍTICAS: modules
72
+ -- ============================================
73
+
74
+ -- Todos podem ler módulos
75
+ CREATE POLICY "all_can_read_modules" ON public.modules
76
+ FOR SELECT
77
+ USING (true);
78
+
79
+ -- Apenas administradores podem gerenciar módulos
80
+ CREATE POLICY "admin_can_manage_modules" ON public.modules
81
+ FOR ALL
82
+ USING (
83
+ auth.uid() IN (
84
+ SELECT id FROM public.profiles WHERE role = 'administrator'
85
+ )
86
+ );
87
+
88
+ -- ============================================
89
+ -- POLÍTICAS: permissions
90
+ -- ============================================
91
+
92
+ -- Todos podem ler permissões (necessário para verificar acesso)
93
+ CREATE POLICY "all_can_read_permissions" ON public.permissions
94
+ FOR SELECT
95
+ USING (true);
96
+
97
+ -- Apenas administradores podem gerenciar permissões
98
+ CREATE POLICY "admin_can_manage_permissions" ON public.permissions
99
+ FOR ALL
100
+ USING (
101
+ auth.uid() IN (
102
+ SELECT id FROM public.profiles WHERE role = 'administrator'
103
+ )
104
+ );
105
+
106
+ -- ============================================
107
+ -- POLÍTICAS: messages
108
+ -- ============================================
109
+
110
+ -- Administradores podem ver todas as mensagens
111
+ CREATE POLICY "admin_can_read_all_messages" ON public.messages
112
+ FOR SELECT
113
+ USING (
114
+ auth.uid() IN (
115
+ SELECT id FROM public.profiles WHERE role = 'administrator'
116
+ )
117
+ );
118
+
119
+ -- Usuários podem ver suas próprias mensagens
120
+ CREATE POLICY "users_can_read_own_messages" ON public.messages
121
+ FOR SELECT
122
+ USING (user_id = auth.uid() OR user_id IS NULL);
123
+
124
+ -- Usuários podem criar mensagens
125
+ CREATE POLICY "users_can_create_messages" ON public.messages
126
+ FOR INSERT
127
+ WITH CHECK (user_id = auth.uid() OR user_id IS NULL);
128
+
129
+ -- Administradores podem atualizar qualquer mensagem
130
+ CREATE POLICY "admin_can_update_all_messages" ON public.messages
131
+ FOR UPDATE
132
+ USING (
133
+ auth.uid() IN (
134
+ SELECT id FROM public.profiles WHERE role = 'administrator'
135
+ )
136
+ );
137
+
138
+ -- Usuários podem atualizar suas próprias mensagens
139
+ CREATE POLICY "users_can_update_own_messages" ON public.messages
140
+ FOR UPDATE
141
+ USING (user_id = auth.uid());
142
+
143
+ -- ============================================
144
+ -- POLÍTICAS: notification_categories
145
+ -- ============================================
146
+
147
+ -- Todos podem ler categorias de notificação
148
+ CREATE POLICY "all_can_read_notification_categories" ON public.notification_categories
149
+ FOR SELECT
150
+ USING (true);
151
+
152
+ -- Apenas administradores podem gerenciar categorias
153
+ CREATE POLICY "admin_can_manage_notification_categories" ON public.notification_categories
154
+ FOR ALL
155
+ USING (
156
+ auth.uid() IN (
157
+ SELECT id FROM public.profiles WHERE role = 'administrator'
158
+ )
159
+ );
160
+
161
+ -- ============================================
162
+ -- POLÍTICAS: notification_settings
163
+ -- ============================================
164
+
165
+ -- Usuários podem ver suas próprias configurações
166
+ CREATE POLICY "users_can_read_own_notification_settings" ON public.notification_settings
167
+ FOR SELECT
168
+ USING (user_id = auth.uid());
169
+
170
+ -- Administradores podem ver todas as configurações
171
+ CREATE POLICY "admin_can_read_all_notification_settings" ON public.notification_settings
172
+ FOR SELECT
173
+ USING (
174
+ auth.uid() IN (
175
+ SELECT id FROM public.profiles WHERE role = 'administrator'
176
+ )
177
+ );
178
+
179
+ -- Usuários podem criar suas próprias configurações
180
+ CREATE POLICY "users_can_create_notification_settings" ON public.notification_settings
181
+ FOR INSERT
182
+ WITH CHECK (user_id = auth.uid());
183
+
184
+ -- Usuários podem atualizar suas próprias configurações
185
+ CREATE POLICY "users_can_update_own_notification_settings" ON public.notification_settings
186
+ FOR UPDATE
187
+ USING (user_id = auth.uid());
188
+
189
+ -- Administradores podem gerenciar todas as configurações
190
+ CREATE POLICY "admin_can_manage_all_notification_settings" ON public.notification_settings
191
+ FOR ALL
192
+ USING (
193
+ auth.uid() IN (
194
+ SELECT id FROM public.profiles WHERE role = 'administrator'
195
+ )
196
+ );
197
+
198
+ -- ============================================
199
+ -- POLÍTICAS: notification_logs
200
+ -- ============================================
201
+
202
+ -- Usuários podem ver seus próprios logs
203
+ CREATE POLICY "users_can_read_own_notification_logs" ON public.notification_logs
204
+ FOR SELECT
205
+ USING (user_id = auth.uid());
206
+
207
+ -- Administradores podem ver todos os logs
208
+ CREATE POLICY "admin_can_read_all_notification_logs" ON public.notification_logs
209
+ FOR SELECT
210
+ USING (
211
+ auth.uid() IN (
212
+ SELECT id FROM public.profiles WHERE role = 'administrator'
213
+ )
214
+ );
215
+
216
+ -- Apenas administradores podem criar logs (via sistema)
217
+ CREATE POLICY "admin_can_create_notification_logs" ON public.notification_logs
218
+ FOR INSERT
219
+ WITH CHECK (
220
+ auth.uid() IN (
221
+ SELECT id FROM public.profiles WHERE role = 'administrator'
222
+ )
223
+ );
@@ -0,0 +1,244 @@
1
+ -- ============================================
2
+ -- 003_functions_triggers.sql: Funções e Triggers (gmoonc)
3
+ -- ============================================
4
+ -- Contém todas as funções PL/pgSQL e triggers
5
+ -- Otimizadas para gmoonc
6
+
7
+ -- ============================================
8
+ -- FUNÇÃO: update_updated_at_column
9
+ -- ============================================
10
+ -- Atualiza o campo updated_at automaticamente
11
+ CREATE OR REPLACE FUNCTION public.update_updated_at_column()
12
+ RETURNS TRIGGER AS $$
13
+ BEGIN
14
+ NEW.updated_at = NOW();
15
+ RETURN NEW;
16
+ END;
17
+ $$ LANGUAGE plpgsql;
18
+
19
+ -- ============================================
20
+ -- TRIGGERS: updated_at
21
+ -- ============================================
22
+
23
+ CREATE TRIGGER update_profiles_updated_at
24
+ BEFORE UPDATE ON public.profiles
25
+ FOR EACH ROW
26
+ EXECUTE FUNCTION public.update_updated_at_column();
27
+
28
+ CREATE TRIGGER update_roles_updated_at
29
+ BEFORE UPDATE ON public.roles
30
+ FOR EACH ROW
31
+ EXECUTE FUNCTION public.update_updated_at_column();
32
+
33
+ CREATE TRIGGER update_modules_updated_at
34
+ BEFORE UPDATE ON public.modules
35
+ FOR EACH ROW
36
+ EXECUTE FUNCTION public.update_updated_at_column();
37
+
38
+ CREATE TRIGGER update_permissions_updated_at
39
+ BEFORE UPDATE ON public.permissions
40
+ FOR EACH ROW
41
+ EXECUTE FUNCTION public.update_updated_at_column();
42
+
43
+ CREATE TRIGGER update_messages_updated_at
44
+ BEFORE UPDATE ON public.messages
45
+ FOR EACH ROW
46
+ EXECUTE FUNCTION public.update_updated_at_column();
47
+
48
+ CREATE TRIGGER update_notification_categories_updated_at
49
+ BEFORE UPDATE ON public.notification_categories
50
+ FOR EACH ROW
51
+ EXECUTE FUNCTION public.update_updated_at_column();
52
+
53
+ CREATE TRIGGER update_notification_settings_updated_at
54
+ BEFORE UPDATE ON public.notification_settings
55
+ FOR EACH ROW
56
+ EXECUTE FUNCTION public.update_updated_at_column();
57
+
58
+ -- ============================================
59
+ -- FUNÇÃO: get_user_permissions
60
+ -- ============================================
61
+ -- Retorna as permissões de um usuário
62
+ CREATE OR REPLACE FUNCTION public.get_user_permissions(user_id UUID)
63
+ RETURNS TABLE (
64
+ module_name TEXT,
65
+ can_access BOOLEAN,
66
+ can_create BOOLEAN,
67
+ can_read BOOLEAN,
68
+ can_update BOOLEAN,
69
+ can_delete BOOLEAN
70
+ ) AS $$
71
+ BEGIN
72
+ RETURN QUERY
73
+ SELECT
74
+ m.name,
75
+ p.can_access,
76
+ p.can_create,
77
+ p.can_read,
78
+ p.can_update,
79
+ p.can_delete
80
+ FROM public.permissions p
81
+ JOIN public.modules m ON p.module_id = m.id
82
+ JOIN public.roles r ON p.role_id = r.id
83
+ WHERE r.id = (
84
+ SELECT role FROM public.profiles WHERE id = user_id
85
+ )::UUID;
86
+ END;
87
+ $$ LANGUAGE plpgsql;
88
+
89
+ -- ============================================
90
+ -- FUNÇÃO: check_user_permission
91
+ -- ============================================
92
+ -- Verifica se um usuário tem permissão para uma ação
93
+ CREATE OR REPLACE FUNCTION public.check_user_permission(
94
+ user_id UUID,
95
+ module_name TEXT,
96
+ action TEXT
97
+ ) RETURNS BOOLEAN AS $$
98
+ DECLARE
99
+ user_role TEXT;
100
+ has_permission BOOLEAN;
101
+ BEGIN
102
+ -- Obter role do usuário
103
+ SELECT role INTO user_role FROM public.profiles WHERE id = user_id;
104
+
105
+ IF user_role IS NULL THEN
106
+ RETURN false;
107
+ END IF;
108
+
109
+ -- Verificar permissão baseado na ação
110
+ CASE action
111
+ WHEN 'create' THEN
112
+ SELECT can_create INTO has_permission
113
+ FROM public.permissions p
114
+ JOIN public.roles r ON p.role_id = r.id
115
+ JOIN public.modules m ON p.module_id = m.id
116
+ WHERE r.name = user_role AND m.name = module_name;
117
+ WHEN 'read' THEN
118
+ SELECT can_read INTO has_permission
119
+ FROM public.permissions p
120
+ JOIN public.roles r ON p.role_id = r.id
121
+ JOIN public.modules m ON p.module_id = m.id
122
+ WHERE r.name = user_role AND m.name = module_name;
123
+ WHEN 'update' THEN
124
+ SELECT can_update INTO has_permission
125
+ FROM public.permissions p
126
+ JOIN public.roles r ON p.role_id = r.id
127
+ JOIN public.modules m ON p.module_id = m.id
128
+ WHERE r.name = user_role AND m.name = module_name;
129
+ WHEN 'delete' THEN
130
+ SELECT can_delete INTO has_permission
131
+ FROM public.permissions p
132
+ JOIN public.roles r ON p.role_id = r.id
133
+ JOIN public.modules m ON p.module_id = m.id
134
+ WHERE r.name = user_role AND m.name = module_name;
135
+ ELSE
136
+ RETURN false;
137
+ END CASE;
138
+
139
+ RETURN COALESCE(has_permission, false);
140
+ END;
141
+ $$ LANGUAGE plpgsql;
142
+
143
+ -- ============================================
144
+ -- FUNÇÃO: log_notification
145
+ -- ============================================
146
+ -- Registra uma notificação no histórico
147
+ CREATE OR REPLACE FUNCTION public.log_notification(
148
+ p_category_id UUID,
149
+ p_user_id UUID,
150
+ p_entity_type TEXT,
151
+ p_entity_id TEXT,
152
+ p_email_sent BOOLEAN DEFAULT false,
153
+ p_email_error TEXT DEFAULT NULL
154
+ ) RETURNS UUID AS $$
155
+ DECLARE
156
+ log_id UUID;
157
+ BEGIN
158
+ INSERT INTO public.notification_logs (
159
+ category_id,
160
+ user_id,
161
+ entity_type,
162
+ entity_id,
163
+ email_sent,
164
+ email_error,
165
+ sent_at,
166
+ created_at
167
+ ) VALUES (
168
+ p_category_id,
169
+ p_user_id,
170
+ p_entity_type,
171
+ p_entity_id,
172
+ p_email_sent,
173
+ p_email_error,
174
+ CASE WHEN p_email_sent THEN NOW() ELSE NULL END,
175
+ NOW()
176
+ ) RETURNING id INTO log_id;
177
+
178
+ RETURN log_id;
179
+ END;
180
+ $$ LANGUAGE plpgsql;
181
+
182
+ -- ============================================
183
+ -- FUNÇÃO: is_user_admin
184
+ -- ============================================
185
+ -- Verifica se um usuário é administrador
186
+ CREATE OR REPLACE FUNCTION public.is_user_admin(user_id UUID)
187
+ RETURNS BOOLEAN AS $$
188
+ BEGIN
189
+ RETURN EXISTS (
190
+ SELECT 1 FROM public.profiles
191
+ WHERE id = user_id AND role = 'administrator'
192
+ );
193
+ END;
194
+ $$ LANGUAGE plpgsql;
195
+
196
+ -- ============================================
197
+ -- FUNÇÃO: is_user_employee
198
+ -- ============================================
199
+ -- Verifica se um usuário é funcionário
200
+ CREATE OR REPLACE FUNCTION public.is_user_employee(user_id UUID)
201
+ RETURNS BOOLEAN AS $$
202
+ BEGIN
203
+ RETURN EXISTS (
204
+ SELECT 1 FROM public.profiles
205
+ WHERE id = user_id AND role = 'employee'
206
+ );
207
+ END;
208
+ $$ LANGUAGE plpgsql;
209
+
210
+ -- ============================================
211
+ -- FUNÇÃO: is_user_customer
212
+ -- ============================================
213
+ -- Verifica se um usuário é cliente
214
+ CREATE OR REPLACE FUNCTION public.is_user_customer(user_id UUID)
215
+ RETURNS BOOLEAN AS $$
216
+ BEGIN
217
+ RETURN EXISTS (
218
+ SELECT 1 FROM public.profiles
219
+ WHERE id = user_id AND role = 'customer'
220
+ );
221
+ END;
222
+ $$ LANGUAGE plpgsql;
223
+
224
+ -- ============================================
225
+ -- FUNÇÃO: get_notification_settings_for_user
226
+ -- ============================================
227
+ -- Retorna as configurações de notificação de um usuário
228
+ CREATE OR REPLACE FUNCTION public.get_notification_settings_for_user(user_id UUID)
229
+ RETURNS TABLE (
230
+ category_id UUID,
231
+ category_name TEXT,
232
+ is_enabled BOOLEAN
233
+ ) AS $$
234
+ BEGIN
235
+ RETURN QUERY
236
+ SELECT
237
+ ns.category_id,
238
+ nc.name,
239
+ ns.is_enabled
240
+ FROM public.notification_settings ns
241
+ JOIN public.notification_categories nc ON ns.category_id = nc.id
242
+ WHERE ns.user_id = user_id;
243
+ END;
244
+ $$ LANGUAGE plpgsql;
@@ -0,0 +1,126 @@
1
+ -- ============================================
2
+ -- 004_seed.sql: Dados Iniciais (gmoonc - Fake Data)
3
+ -- ============================================
4
+ -- Dados fictícios 100% fake para desenvolvimento
5
+ -- Todos em inglês conforme gmoonc
6
+ -- Inspirado em Missão Apollo
7
+
8
+ -- ============================================
9
+ -- 1. ROLES (System Roles)
10
+ -- ============================================
11
+
12
+ INSERT INTO public.roles (id, name, description, is_system_role, created_at, updated_at) VALUES
13
+ ('550e8400-e29b-41d4-a716-446655440001'::uuid, 'administrator', 'System Administrator', true, NOW(), NOW()),
14
+ ('550e8400-e29b-41d4-a716-446655440002'::uuid, 'employee', 'Employee/Collaborator', true, NOW(), NOW()),
15
+ ('550e8400-e29b-41d4-a716-446655440003'::uuid, 'customer', 'Customer/End User', true, NOW(), NOW());
16
+
17
+ -- ============================================
18
+ -- 2. MODULES (Application Modules)
19
+ -- ============================================
20
+
21
+ INSERT INTO public.modules (id, name, display_name, description, is_active, created_at, updated_at) VALUES
22
+ ('550e8400-e29b-41d4-a716-446655440010'::uuid, 'admin', 'Administrative Module', 'Administrative functions and system management', true, NOW(), NOW()),
23
+ ('550e8400-e29b-41d4-a716-446655440011'::uuid, 'financial', 'Financial Module', 'Financial management and reporting', true, NOW(), NOW()),
24
+ ('550e8400-e29b-41d4-a716-446655440012'::uuid, 'technical', 'Technical Support Module', 'Technical support and help desk', true, NOW(), NOW()),
25
+ ('550e8400-e29b-41d4-a716-446655440013'::uuid, 'customer', 'Customer Module', 'Customer portal and self-service', true, NOW(), NOW());
26
+
27
+ -- ============================================
28
+ -- 3. PERMISSIONS (Role-Based Access Control)
29
+ -- ============================================
30
+
31
+ INSERT INTO public.permissions (id, role_id, module_id, can_access, can_create, can_read, can_update, can_delete, created_at, updated_at) VALUES
32
+ -- Administrator: Full access to all modules
33
+ ('550e8400-e29b-41d4-a716-446655440100'::uuid, '550e8400-e29b-41d4-a716-446655440001'::uuid, '550e8400-e29b-41d4-a716-446655440010'::uuid, true, true, true, true, true, NOW(), NOW()),
34
+ ('550e8400-e29b-41d4-a716-446655440101'::uuid, '550e8400-e29b-41d4-a716-446655440001'::uuid, '550e8400-e29b-41d4-a716-446655440011'::uuid, true, true, true, true, true, NOW(), NOW()),
35
+ ('550e8400-e29b-41d4-a716-446655440102'::uuid, '550e8400-e29b-41d4-a716-446655440001'::uuid, '550e8400-e29b-41d4-a716-446655440012'::uuid, true, true, true, true, true, NOW(), NOW()),
36
+ ('550e8400-e29b-41d4-a716-446655440103'::uuid, '550e8400-e29b-41d4-a716-446655440001'::uuid, '550e8400-e29b-41d4-a716-446655440013'::uuid, true, true, true, true, true, NOW(), NOW()),
37
+
38
+ -- Employee: Read and update access (no delete)
39
+ ('550e8400-e29b-41d4-a716-446655440110'::uuid, '550e8400-e29b-41d4-a716-446655440002'::uuid, '550e8400-e29b-41d4-a716-446655440010'::uuid, true, false, true, true, false, NOW(), NOW()),
40
+ ('550e8400-e29b-41d4-a716-446655440111'::uuid, '550e8400-e29b-41d4-a716-446655440002'::uuid, '550e8400-e29b-41d4-a716-446655440011'::uuid, true, false, true, true, false, NOW(), NOW()),
41
+ ('550e8400-e29b-41d4-a716-446655440112'::uuid, '550e8400-e29b-41d4-a716-446655440002'::uuid, '550e8400-e29b-41d4-a716-446655440012'::uuid, true, true, true, true, false, NOW(), NOW()),
42
+ ('550e8400-e29b-41d4-a716-446655440113'::uuid, '550e8400-e29b-41d4-a716-446655440002'::uuid, '550e8400-e29b-41d4-a716-446655440013'::uuid, true, false, true, false, false, NOW(), NOW()),
43
+
44
+ -- Customer: Read-only access (create messages)
45
+ ('550e8400-e29b-41d4-a716-446655440120'::uuid, '550e8400-e29b-41d4-a716-446655440003'::uuid, '550e8400-e29b-41d4-a716-446655440010'::uuid, false, false, false, false, false, NOW(), NOW()),
46
+ ('550e8400-e29b-41d4-a716-446655440121'::uuid, '550e8400-e29b-41d4-a716-446655440003'::uuid, '550e8400-e29b-41d4-a716-446655440011'::uuid, false, false, false, false, false, NOW(), NOW()),
47
+ ('550e8400-e29b-41d4-a716-446655440122'::uuid, '550e8400-e29b-41d4-a716-446655440003'::uuid, '550e8400-e29b-41d4-a716-446655440012'::uuid, true, true, true, false, false, NOW(), NOW()),
48
+ ('550e8400-e29b-41d4-a716-446655440123'::uuid, '550e8400-e29b-41d4-a716-446655440003'::uuid, '550e8400-e29b-41d4-a716-446655440013'::uuid, true, false, true, false, false, NOW(), NOW());
49
+
50
+ -- ============================================
51
+ -- 4. PROFILES (Users - Apollo Astronauts)
52
+ -- ============================================
53
+
54
+ INSERT INTO public.profiles (id, email, name, role, created_at, updated_at) VALUES
55
+ -- Administrators
56
+ ('550e8400-e29b-41d4-a716-446655440200'::uuid, 'neil.armstrong@apollo.nasa.gov', 'Neil Armstrong', 'administrator', NOW(), NOW()),
57
+ ('550e8400-e29b-41d4-a716-446655440201'::uuid, 'buzz.aldrin@apollo.nasa.gov', 'Buzz Aldrin', 'administrator', NOW(), NOW()),
58
+
59
+ -- Employees
60
+ ('550e8400-e29b-41d4-a716-446655440210'::uuid, 'michael.collins@apollo.nasa.gov', 'Michael Collins', 'employee', NOW(), NOW()),
61
+ ('550e8400-e29b-41d4-a716-446655440211'::uuid, 'alan.bean@apollo.nasa.gov', 'Alan Bean', 'employee', NOW(), NOW()),
62
+ ('550e8400-e29b-41d4-a716-446655440212'::uuid, 'pete.conrad@apollo.nasa.gov', 'Pete Conrad', 'employee', NOW(), NOW()),
63
+
64
+ -- Customers
65
+ ('550e8400-e29b-41d4-a716-446655440220'::uuid, 'john.glenn@apollo.nasa.gov', 'John Glenn', 'customer', NOW(), NOW()),
66
+ ('550e8400-e29b-41d4-a716-446655440221'::uuid, 'alan.shepard@apollo.nasa.gov', 'Alan Shepard', 'customer', NOW(), NOW()),
67
+ ('550e8400-e29b-41d4-a716-446655440222'::uuid, 'gus.grissom@apollo.nasa.gov', 'Gus Grissom', 'customer', NOW(), NOW());
68
+
69
+ -- ============================================
70
+ -- 5. NOTIFICATION CATEGORIES
71
+ -- ============================================
72
+
73
+ INSERT INTO public.notification_categories (id, name, display_name, description, is_active, email_template_subject, email_template_body, created_at, updated_at) VALUES
74
+ ('550e8400-e29b-41d4-a716-446655440300'::uuid, 'message_received', 'Message Received', 'Notification when a new message is received', true, 'New message from {{sender}}', 'You have received a new message from {{sender}}: {{message}}', NOW(), NOW()),
75
+ ('550e8400-e29b-41d4-a716-446655440301'::uuid, 'message_updated', 'Message Updated', 'Notification when a message status is updated', true, 'Message status updated', 'Your message status has been updated to: {{status}}', NOW(), NOW()),
76
+ ('550e8400-e29b-41d4-a716-446655440302'::uuid, 'system_alert', 'System Alert', 'General system alerts and notifications', true, 'System Alert', 'System Alert: {{message}}', NOW(), NOW()),
77
+ ('550e8400-e29b-41d4-a716-446655440303'::uuid, 'support_ticket', 'Support Ticket', 'Support ticket related notifications', true, 'Support Ticket {{ticket_id}}', 'Your support ticket {{ticket_id}} has been updated', NOW(), NOW());
78
+
79
+ -- ============================================
80
+ -- 6. NOTIFICATION SETTINGS (User Preferences)
81
+ -- ============================================
82
+
83
+ INSERT INTO public.notification_settings (id, user_id, category_id, is_enabled, created_at, updated_at) VALUES
84
+ -- Neil Armstrong (Admin) - receives all notifications
85
+ ('550e8400-e29b-41d4-a716-446655440400'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, '550e8400-e29b-41d4-a716-446655440300'::uuid, true, NOW(), NOW()),
86
+ ('550e8400-e29b-41d4-a716-446655440401'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, '550e8400-e29b-41d4-a716-446655440301'::uuid, true, NOW(), NOW()),
87
+ ('550e8400-e29b-41d4-a716-446655440402'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, '550e8400-e29b-41d4-a716-446655440302'::uuid, true, NOW(), NOW()),
88
+ ('550e8400-e29b-41d4-a716-446655440403'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, '550e8400-e29b-41d4-a716-446655440303'::uuid, true, NOW(), NOW()),
89
+
90
+ -- Michael Collins (Employee) - selective notifications
91
+ ('550e8400-e29b-41d4-a716-446655440410'::uuid, '550e8400-e29b-41d4-a716-446655440210'::uuid, '550e8400-e29b-41d4-a716-446655440300'::uuid, true, NOW(), NOW()),
92
+ ('550e8400-e29b-41d4-a716-446655440411'::uuid, '550e8400-e29b-41d4-a716-446655440210'::uuid, '550e8400-e29b-41d4-a716-446655440301'::uuid, true, NOW(), NOW()),
93
+ ('550e8400-e29b-41d4-a716-446655440412'::uuid, '550e8400-e29b-41d4-a716-446655440210'::uuid, '550e8400-e29b-41d4-a716-446655440302'::uuid, false, NOW(), NOW()),
94
+ ('550e8400-e29b-41d4-a716-446655440413'::uuid, '550e8400-e29b-41d4-a716-446655440210'::uuid, '550e8400-e29b-41d4-a716-446655440303'::uuid, true, NOW(), NOW()),
95
+
96
+ -- John Glenn (Customer) - limited notifications
97
+ ('550e8400-e29b-41d4-a716-446655440420'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, '550e8400-e29b-41d4-a716-446655440300'::uuid, true, NOW(), NOW()),
98
+ ('550e8400-e29b-41d4-a716-446655440421'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, '550e8400-e29b-41d4-a716-446655440301'::uuid, true, NOW(), NOW()),
99
+ ('550e8400-e29b-41d4-a716-446655440422'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, '550e8400-e29b-41d4-a716-446655440302'::uuid, false, NOW(), NOW()),
100
+ ('550e8400-e29b-41d4-a716-446655440423'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, '550e8400-e29b-41d4-a716-446655440303'::uuid, true, NOW(), NOW());
101
+
102
+ -- ============================================
103
+ -- 7. MESSAGES (System Messages)
104
+ -- ============================================
105
+
106
+ INSERT INTO public.messages (id, user_id, name, email, phone, company_farm, message, status, created_at, updated_at) VALUES
107
+ -- From Neil Armstrong
108
+ ('550e8400-e29b-41d4-a716-446655440600'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, 'Neil Armstrong', 'neil.armstrong@apollo.nasa.gov', '+55 11 98765-4321', 'NASA - Apollo Mission', 'Requesting analysis of lunar region coverage', 'completed', NOW(), NOW()),
109
+
110
+ -- From John Glenn
111
+ ('550e8400-e29b-41d4-a716-446655440601'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, 'John Glenn', 'john.glenn@apollo.nasa.gov', '+55 21 99999-8888', 'NASA - Mercury Program', 'Question about coverage analysis', 'in_analysis', NOW(), NOW()),
112
+
113
+ -- From Alan Shepard
114
+ ('550e8400-e29b-41d4-a716-446655440602'::uuid, '550e8400-e29b-41d4-a716-446655440221'::uuid, 'Alan Shepard', 'alan.shepard@apollo.nasa.gov', '+55 85 97777-6666', 'NASA - Gemini Program', 'Feedback on previous analysis', 'pending', NOW(), NOW()),
115
+
116
+ -- Draft message
117
+ ('550e8400-e29b-41d4-a716-446655440603'::uuid, '550e8400-e29b-41d4-a716-446655440222'::uuid, 'Gus Grissom', 'gus.grissom@apollo.nasa.gov', '+55 31 98888-7777', 'NASA - Apollo Applications', 'Support request for system access', 'draft', NOW(), NOW());
118
+
119
+ -- ============================================
120
+ -- 8. NOTIFICATION LOGS (Notification History)
121
+ -- ============================================
122
+
123
+ INSERT INTO public.notification_logs (id, category_id, user_id, entity_type, entity_id, email_sent, email_error, sent_at, created_at) VALUES
124
+ ('550e8400-e29b-41d4-a716-446655440700'::uuid, '550e8400-e29b-41d4-a716-446655440300'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, 'messages', '550e8400-e29b-41d4-a716-446655440600'::uuid, true, null, NOW(), NOW()),
125
+ ('550e8400-e29b-41d4-a716-446655440701'::uuid, '550e8400-e29b-41d4-a716-446655440301'::uuid, '550e8400-e29b-41d4-a716-446655440200'::uuid, 'messages', '550e8400-e29b-41d4-a716-446655440600'::uuid, true, null, NOW(), NOW()),
126
+ ('550e8400-e29b-41d4-a716-446655440702'::uuid, '550e8400-e29b-41d4-a716-446655440300'::uuid, '550e8400-e29b-41d4-a716-446655440220'::uuid, 'messages', '550e8400-e29b-41d4-a716-446655440601'::uuid, false, 'User disabled email notifications', null, NOW());
package/dist/index.cjs CHANGED
@@ -4,8 +4,8 @@
4
4
  // src/cli/index.ts
5
5
  var import_commander = require("commander");
6
6
  var import_process = require("process");
7
- var import_path7 = require("path");
8
- var import_fs11 = require("fs");
7
+ var import_path8 = require("path");
8
+ var import_fs13 = require("fs");
9
9
 
10
10
  // src/cli/lib/detect.ts
11
11
  var import_fs = require("fs");
@@ -1626,9 +1626,13 @@ export type { UserPermission } from './getUserPermissions';
1626
1626
  }
1627
1627
  function updateEnvExample(projectDir) {
1628
1628
  const envExamplePath = (0, import_path6.join)(projectDir, ".env.example");
1629
- const envExampleContent = `# Supabase Configuration
1629
+ const envExampleContent = `# Supabase Configuration (Client-side)
1630
1630
  VITE_SUPABASE_URL=
1631
1631
  VITE_SUPABASE_ANON_KEY=
1632
+
1633
+ # Supabase Database Connection (Server-only, for seeding)
1634
+ # Get this from Supabase Dashboard \u2192 Settings \u2192 Database \u2192 Connection string (URI)
1635
+ SUPABASE_DB_URL=
1632
1636
  `;
1633
1637
  if ((0, import_fs9.existsSync)(envExamplePath)) {
1634
1638
  const existing = (0, import_fs9.readFileSync)(envExamplePath, "utf-8");
@@ -1808,9 +1812,173 @@ function updateAllSessionImports(gmooncDir) {
1808
1812
  }
1809
1813
  }
1810
1814
 
1815
+ // src/cli/lib/supabaseSeedVite.ts
1816
+ var import_path7 = require("path");
1817
+ var import_fs11 = require("fs");
1818
+ var import_pg = require("pg");
1819
+ var import_dotenv = require("dotenv");
1820
+ function getPackageRoot() {
1821
+ try {
1822
+ const currentDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
1823
+ return (0, import_path7.join)(currentDir, "../../..");
1824
+ } catch {
1825
+ return (0, import_path7.join)(process.cwd(), "node_modules", "gmoonc");
1826
+ }
1827
+ }
1828
+ var PACKAGE_ROOT = getPackageRoot();
1829
+ async function seedSupabase(options) {
1830
+ const { projectDir, dryRun } = options;
1831
+ try {
1832
+ (0, import_dotenv.config)({ path: (0, import_path7.join)(projectDir, ".env") });
1833
+ (0, import_dotenv.config)({ path: (0, import_path7.join)(projectDir, ".env.local") });
1834
+ const gmooncDir = (0, import_path7.join)(projectDir, "src/gmoonc");
1835
+ if (!(0, import_fs11.existsSync)(gmooncDir)) {
1836
+ logError('gmoonc is not installed. Run "npx gmoonc" first.');
1837
+ return { success: false, message: "gmoonc not installed" };
1838
+ }
1839
+ const supabaseDir = (0, import_path7.join)(gmooncDir, "supabase");
1840
+ if (!(0, import_fs11.existsSync)(supabaseDir)) {
1841
+ logError('Supabase integration not found. Run "npx gmoonc supabase --vite" first.');
1842
+ return { success: false, message: "Supabase not set up" };
1843
+ }
1844
+ const markerPath = (0, import_path7.join)(projectDir, ".gmoonc", "supabase-seed.json");
1845
+ if ((0, import_fs11.existsSync)(markerPath)) {
1846
+ logError("supabase-seed already executed in this project.");
1847
+ logError("To re-seed, delete the marker file: .gmoonc/supabase-seed.json");
1848
+ logError("Then manually clean the database in Supabase before re-running.");
1849
+ return { success: false, message: "Already seeded" };
1850
+ }
1851
+ const dbUrl = process.env.SUPABASE_DB_URL;
1852
+ if (!dbUrl) {
1853
+ logError("SUPABASE_DB_URL is not set in .env or .env.local");
1854
+ logError("");
1855
+ logError("To get the connection string:");
1856
+ logError("1. Go to your Supabase project dashboard");
1857
+ logError("2. Navigate to Settings \u2192 Database");
1858
+ logError('3. Copy the "Connection string (URI)"');
1859
+ logError("4. Add it to .env.local as:");
1860
+ logError(" SUPABASE_DB_URL=postgresql://postgres:[YOUR-PASSWORD]@[HOST]:5432/postgres");
1861
+ logError("");
1862
+ logError("\u26A0\uFE0F This is a server-only variable (no VITE_ prefix)");
1863
+ return { success: false, message: "SUPABASE_DB_URL not set" };
1864
+ }
1865
+ if (dryRun) {
1866
+ logInfo("\u{1F50D} Dry run mode - would execute SQL files");
1867
+ return { success: true };
1868
+ }
1869
+ const sqlFiles = [
1870
+ { name: "001_tables.sql", order: 1 },
1871
+ { name: "003_functions_triggers.sql", order: 2 },
1872
+ { name: "002_rls.sql", order: 3 },
1873
+ { name: "004_seed.sql", order: 4 }
1874
+ ];
1875
+ const projectSqlDir = (0, import_path7.join)(gmooncDir, "supabase", "sql");
1876
+ const packageSqlDir = (0, import_path7.join)(PACKAGE_ROOT, "assets", "supabase");
1877
+ if (!(0, import_fs11.existsSync)(projectSqlDir)) {
1878
+ ensureDirectoryExists((0, import_path7.join)(projectSqlDir, "dummy"));
1879
+ logInfo("\u{1F4CB} Copying SQL files to project...");
1880
+ for (const sqlFile of sqlFiles) {
1881
+ const packagePath = (0, import_path7.join)(packageSqlDir, sqlFile.name);
1882
+ const projectPath = (0, import_path7.join)(projectSqlDir, sqlFile.name);
1883
+ if ((0, import_fs11.existsSync)(packagePath)) {
1884
+ const content = (0, import_fs11.readFileSync)(packagePath, "utf-8");
1885
+ (0, import_fs11.writeFileSync)(projectPath, content, "utf-8");
1886
+ logSuccess(`Copied ${sqlFile.name} to src/gmoonc/supabase/sql/`);
1887
+ }
1888
+ }
1889
+ }
1890
+ logInfo("\n\u{1F50C} Connecting to Supabase database...");
1891
+ const client = new import_pg.Client({
1892
+ connectionString: dbUrl,
1893
+ ssl: { rejectUnauthorized: false }
1894
+ });
1895
+ await client.connect();
1896
+ logSuccess("Connected to database");
1897
+ const executedFiles = [];
1898
+ for (const sqlFile of sqlFiles) {
1899
+ logInfo(`
1900
+ \u{1F4DD} Applying ${sqlFile.name}...`);
1901
+ let sqlPath = (0, import_path7.join)(projectSqlDir, sqlFile.name);
1902
+ if (!(0, import_fs11.existsSync)(sqlPath)) {
1903
+ sqlPath = (0, import_path7.join)(packageSqlDir, sqlFile.name);
1904
+ }
1905
+ if (!(0, import_fs11.existsSync)(sqlPath)) {
1906
+ logError(`SQL file not found: ${sqlFile.name}`);
1907
+ await client.end();
1908
+ return { success: false, message: `SQL file not found: ${sqlFile.name}` };
1909
+ }
1910
+ const sql = (0, import_fs11.readFileSync)(sqlPath, "utf-8");
1911
+ try {
1912
+ await client.query("BEGIN");
1913
+ await client.query(sql);
1914
+ await client.query("COMMIT");
1915
+ executedFiles.push(sqlFile.name);
1916
+ logSuccess(`\u2713 Applied ${sqlFile.name}`);
1917
+ } catch (error) {
1918
+ await client.query("ROLLBACK");
1919
+ const errorMessage = error.message || "Unknown error";
1920
+ const errorPosition = error.position ? ` at position ${error.position}` : "";
1921
+ logError(`\u2717 Failed to apply ${sqlFile.name}${errorPosition}`);
1922
+ logError(`Error: ${errorMessage}`);
1923
+ if (error.position && sql) {
1924
+ const lines = sql.split("\n");
1925
+ const charPos = error.position;
1926
+ let currentPos = 0;
1927
+ let errorLine = 0;
1928
+ for (let i = 0; i < lines.length; i++) {
1929
+ currentPos += lines[i].length + 1;
1930
+ if (currentPos >= charPos) {
1931
+ errorLine = i + 1;
1932
+ break;
1933
+ }
1934
+ }
1935
+ if (errorLine > 0) {
1936
+ const start = Math.max(0, errorLine - 3);
1937
+ const end = Math.min(lines.length, errorLine + 2);
1938
+ logError("\nSQL context around error:");
1939
+ for (let i = start; i < end; i++) {
1940
+ const marker = i === errorLine - 1 ? ">>> " : " ";
1941
+ logError(`${marker}${i + 1}: ${lines[i]}`);
1942
+ }
1943
+ }
1944
+ }
1945
+ await client.end();
1946
+ return { success: false, message: `SQL execution failed: ${sqlFile.name}` };
1947
+ }
1948
+ }
1949
+ await client.end();
1950
+ logSuccess("\n\u2705 All SQL files applied successfully");
1951
+ const markerDir = (0, import_path7.join)(projectDir, ".gmoonc");
1952
+ ensureDirectoryExists((0, import_path7.join)(markerDir, "dummy"));
1953
+ const packageJsonPath = (0, import_path7.join)(PACKAGE_ROOT, "package.json");
1954
+ let version = "0.0.22";
1955
+ try {
1956
+ if ((0, import_fs11.existsSync)(packageJsonPath)) {
1957
+ const packageJson = JSON.parse((0, import_fs11.readFileSync)(packageJsonPath, "utf-8"));
1958
+ version = packageJson.version || version;
1959
+ }
1960
+ } catch {
1961
+ }
1962
+ const markerContent = JSON.stringify({
1963
+ version,
1964
+ executedAt: (/* @__PURE__ */ new Date()).toISOString(),
1965
+ files: executedFiles
1966
+ }, null, 2);
1967
+ (0, import_fs11.writeFileSync)(markerPath, markerContent, "utf-8");
1968
+ logSuccess("Created marker file: .gmoonc/supabase-seed.json");
1969
+ return { success: true };
1970
+ } catch (error) {
1971
+ logError(`Error: ${error.message}`);
1972
+ if (error.stack && process.env.DEBUG) {
1973
+ console.error(error.stack);
1974
+ }
1975
+ return { success: false, message: error.message };
1976
+ }
1977
+ }
1978
+
1811
1979
  // src/cli/index.ts
1812
1980
  var program = new import_commander.Command();
1813
- program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete dashboard into your React project").version("0.0.21").option("--base <path>", "Base path for dashboard routes", "/app").option("--skip-router-patch", "Skip automatic router integration (only copy files and inject CSS)").option("--dry-run", "Show what would be done without making changes").action(async (options) => {
1981
+ program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete dashboard into your React project").version("0.0.22").option("--base <path>", "Base path for dashboard routes", "/app").option("--skip-router-patch", "Skip automatic router integration (only copy files and inject CSS)").option("--dry-run", "Show what would be done without making changes").action(async (options) => {
1814
1982
  try {
1815
1983
  logInfo("\u{1F680} Starting gmoonc installer...");
1816
1984
  logInfo("\u{1F4E6} Installing complete dashboard into your React project\n");
@@ -1818,9 +1986,9 @@ program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete das
1818
1986
  const basePath = options.base || "/app";
1819
1987
  const dryRun = options.dryRun || false;
1820
1988
  const skipRouterPatch = options.skipRouterPatch || false;
1821
- const gmooncDir = (0, import_path7.join)(projectDir, "src/gmoonc");
1822
- const markerFile = (0, import_path7.join)(gmooncDir, ".gmoonc-installed.json");
1823
- if ((0, import_fs11.existsSync)(gmooncDir) || (0, import_fs11.existsSync)(markerFile)) {
1989
+ const gmooncDir = (0, import_path8.join)(projectDir, "src/gmoonc");
1990
+ const markerFile = (0, import_path8.join)(gmooncDir, ".gmoonc-installed.json");
1991
+ if ((0, import_fs13.existsSync)(gmooncDir) || (0, import_fs13.existsSync)(markerFile)) {
1824
1992
  logError("gmoonc already installed (src/gmoonc exists or marker file found).");
1825
1993
  logError("Remove src/gmoonc and restore backups to reinstall.");
1826
1994
  process.exit(1);
@@ -1861,7 +2029,7 @@ program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete das
1861
2029
  process.exit(1);
1862
2030
  }
1863
2031
  logInfo("\n\u{1F4DD} Injecting CSS imports...");
1864
- const entrypointPath = (0, import_path7.join)(projectDir, project.entrypoint);
2032
+ const entrypointPath = (0, import_path8.join)(projectDir, project.entrypoint);
1865
2033
  const cssResult = patchEntryCss(entrypointPath, dryRun);
1866
2034
  if (!cssResult.success && !dryRun) {
1867
2035
  logError("Failed to inject CSS");
@@ -1883,11 +2051,11 @@ program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete das
1883
2051
  }
1884
2052
  if (!dryRun) {
1885
2053
  ensureDirectoryExists(markerFile);
1886
- const packageJsonPath = (0, import_path7.join)(projectDir, "package.json");
2054
+ const packageJsonPath = (0, import_path8.join)(projectDir, "package.json");
1887
2055
  let version = "0.0.10";
1888
2056
  try {
1889
- if ((0, import_fs11.existsSync)(packageJsonPath)) {
1890
- const packageJson = JSON.parse((0, import_fs11.readFileSync)(packageJsonPath, "utf-8"));
2057
+ if ((0, import_fs13.existsSync)(packageJsonPath)) {
2058
+ const packageJson = JSON.parse((0, import_fs13.readFileSync)(packageJsonPath, "utf-8"));
1891
2059
  const gmooncVersion = packageJson.dependencies?.gmoonc || packageJson.devDependencies?.gmoonc;
1892
2060
  if (gmooncVersion) {
1893
2061
  version = gmooncVersion.replace(/^[\^~]/, "");
@@ -1899,7 +2067,7 @@ program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete das
1899
2067
  version,
1900
2068
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
1901
2069
  }, null, 2);
1902
- (0, import_fs11.writeFileSync)(markerFile, markerContent, "utf-8");
2070
+ (0, import_fs13.writeFileSync)(markerFile, markerContent, "utf-8");
1903
2071
  }
1904
2072
  logSuccess("\n\u2705 Installation complete!");
1905
2073
  logInfo("\nYour dashboard is now available at:");
@@ -1945,4 +2113,34 @@ program.command("supabase").description("Setup Supabase integration (Auth + RBAC
1945
2113
  process.exit(1);
1946
2114
  }
1947
2115
  });
2116
+ program.command("supabase-seed").description("Seed Supabase database with schema, RLS, functions, and initial data").option("--vite", "Seed for Vite projects").action(async (options) => {
2117
+ try {
2118
+ logInfo("\u{1F331} Starting Supabase database seeding...");
2119
+ const projectDir = (0, import_process.cwd)();
2120
+ const dryRun = false;
2121
+ if (!options.vite) {
2122
+ logError("Missing platform flag. Use: gmoonc supabase-seed --vite (Next will be added later).");
2123
+ process.exit(1);
2124
+ }
2125
+ const result = await seedSupabase({
2126
+ projectDir,
2127
+ dryRun
2128
+ });
2129
+ if (!result.success) {
2130
+ process.exit(1);
2131
+ }
2132
+ logSuccess("\n\u2705 Database seeding complete!");
2133
+ logInfo("\nYour Supabase database is now ready with:");
2134
+ logInfo(" - Tables (profiles, roles, modules, permissions, etc.)");
2135
+ logInfo(" - Functions and triggers");
2136
+ logInfo(" - Row Level Security (RLS) policies");
2137
+ logInfo(" - Initial seed data (Apollo user)");
2138
+ } catch (error) {
2139
+ logError(`Error: ${error.message}`);
2140
+ if (error.stack && process.env.DEBUG) {
2141
+ console.error(error.stack);
2142
+ }
2143
+ process.exit(1);
2144
+ }
2145
+ });
1948
2146
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gmoonc",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "Goalmoon Ctrl (gmoonc): Complete dashboard installer for React projects",
5
5
  "license": "MIT",
6
6
  "homepage": "https://gmoonc.com",
@@ -19,6 +19,7 @@
19
19
  "files": [
20
20
  "dist",
21
21
  "src/templates",
22
+ "assets",
22
23
  "scripts",
23
24
  "README.md",
24
25
  "LICENSE"
@@ -32,10 +33,13 @@
32
33
  "postinstall": "node scripts/block-global-install.cjs"
33
34
  },
34
35
  "dependencies": {
35
- "commander": "^12.0.0"
36
+ "commander": "^12.0.0",
37
+ "dotenv": "^16.4.5",
38
+ "pg": "^8.11.3"
36
39
  },
37
40
  "devDependencies": {
38
41
  "@types/node": "^20.0.0",
42
+ "@types/pg": "^8.10.9",
39
43
  "rimraf": "^6.0.0",
40
44
  "tsup": "^8.0.0",
41
45
  "typescript": "^5.0.0"