Spaces:
danilonovais
/
Running on CPU Upgrade

google-labs-jules[bot] commited on
Commit
333834a
·
1 Parent(s): d33c618

feat: Comprehensive infrastructure audit and optimization

Browse files
.dockerignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .git
2
+ .github
3
+ .vscode
4
+ .DS_Store
5
+ README.md
6
+ LICENSE
7
+ SECURITY.md
8
+ knowledge/
9
+ node_modules
10
+ npm-debug.log
11
+ config/.env
.github/workflows/backup-workflows.yml CHANGED
@@ -8,14 +8,11 @@ on:
8
  jobs:
9
  backup:
10
  runs-on: ubuntu-latest
 
 
11
  steps:
12
  - uses: actions/checkout@v4
13
 
14
- - name: Install Postgres client
15
- run: |
16
- sudo apt-get update
17
- sudo apt-get install -y postgresql-client
18
-
19
  - name: Run backup script
20
  env:
21
  DB_HOST: ${{ secrets.DB_HOST }}
 
8
  jobs:
9
  backup:
10
  runs-on: ubuntu-latest
11
+ container:
12
+ image: postgres:15
13
  steps:
14
  - uses: actions/checkout@v4
15
 
 
 
 
 
 
16
  - name: Run backup script
17
  env:
18
  DB_HOST: ${{ secrets.DB_HOST }}
.github/workflows/sync-knowledge.yml CHANGED
@@ -15,9 +15,10 @@ jobs:
15
  uses: actions/setup-node@v4
16
  with:
17
  node-version: 20
 
18
 
19
- - name: Install deps
20
- run: npm ci || npm i
21
 
22
  - name: Run sync script
23
  env:
 
15
  uses: actions/setup-node@v4
16
  with:
17
  node-version: 20
18
+ cache: 'npm'
19
 
20
+ - name: Install dependencies
21
+ run: npm ci
22
 
23
  - name: Run sync script
24
  env:
.gitignore ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # Dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.js
7
+
8
+ # Testing
9
+ /coverage
10
+
11
+ # Local-first knowledge base
12
+ /knowledge
13
+
14
+ # Backups (store off-site)
15
+ /workflows/backup/*
16
+ !/workflows/backup/.keep
17
+
18
+ # Environment variables
19
+ .env
20
+ .env.*
21
+ !.env.example
22
+
23
+ # OS-specific
24
+ .DS_Store
25
+ *.swo
26
+ *~
27
+ *.swp
28
+
29
+ # Logs
30
+ npm-debug.log*
31
+ yarn-debug.log*
32
+ yarn-error.log*
33
+
34
+ # VSCode
35
+ .vscode/
README.md CHANGED
@@ -1,95 +1,67 @@
1
  # n8n Infrastructure Repository
2
 
 
 
 
3
  A comprehensive, production-ready infrastructure setup for deploying n8n automation platform on Hugging Face Spaces with AI integrations and automated knowledge management.
4
 
5
  ## 🚀 Features
6
 
7
  ### Core Platform
8
-
9
- - **n8n v1.17.1**: Self-hosted workflow automation platform
10
- - **Hugging Face Spaces**: Docker-based deployment with automatic scaling
11
- - **Supabase PostgreSQL**: SSL-encrypted database with pgvector extension
12
- - **ChromaDB**: Vector store for embeddings and AI-powered search
13
 
14
  ### AI & Automation
15
-
16
- - **LangChain Integration**: Advanced AI workflow capabilities
17
- - **Multi-Model Support**: OpenAI GPT, Anthropic Claude, Google Vertex AI
18
- - **Vector Knowledge Base**: Automated content ingestion with embeddings
19
- - **Community Nodes**: Extended functionality with custom AI nodes
20
-
21
- ### DevOps & Monitoring
22
-
23
- - **GitHub Actions CI/CD**: Automated deployment and maintenance
24
- - **Automated Backups**: Daily workflow and configuration backups
25
- - **Knowledge Sync**: Multi-repository content synchronization
26
- - **Health Monitoring**: Container health checks and alerting
27
 
28
  ## 📋 Prerequisites
29
 
30
- Before setting up the infrastructure, ensure you have:
31
-
32
- 1. **GitHub Account** with repository access
33
- 2. **Hugging Face Account** with Spaces access
34
- 3. **Supabase Account** with PostgreSQL database
35
- 4. **Git** and **Docker** installed locally
36
-
37
- ### Required Secrets
38
-
39
- Configure these secrets in your GitHub repository settings:
40
-
41
- ```bash
42
- # Hugging Face
43
- HF_USERNAME=your-huggingface-username
44
- HF_TOKEN=your-hf-token
45
- HF_SPACE_NAME=n8n-automation
46
-
47
- # Database
48
- DB_POSTGRESDB_HOST=your-project.supabase.co
49
- DB_POSTGRESDB_USER=postgres
50
- DB_POSTGRESDB_PASSWORD=your-database-password
51
- DB_POSTGRESDB_DATABASE=postgres
52
-
53
- # n8n Configuration
54
- N8N_ENCRYPTION_KEY=your-32-character-encryption-key
55
- N8N_USER_MANAGEMENT_JWT_SECRET=your-jwt-secret
56
- WEBHOOK_URL=https://your-username-n8n-automation.hf.space
57
-
58
- # AI Services (Optional)
59
- OPENAI_API_KEY=sk-your-openai-key
60
- ANTHROPIC_API_KEY=sk-ant-your-anthropic-key
61
- GOOGLE_PROJECT_ID=your-gcp-project
62
- ```
63
 
64
  ## 🛠️ Quick Start
65
 
66
  ### 1. Repository Setup
67
-
68
  ```bash
69
  # Clone the repository
70
  git clone https://github.com/your-username/n8n-infra.git
71
  cd n8n-infra
72
 
73
- # Create environment configuration
74
- cp config/.env.example .env
75
- # Edit .env with your actual values
 
 
76
  ```
77
 
78
  ### 2. Local Development
79
-
80
  ```bash
81
  # Start the full stack locally
82
- docker-compose -f docker/docker-compose.yml up -d
83
 
84
  # Check service status
85
- docker-compose -f docker/docker-compose.yml ps
86
 
87
  # View logs
88
- docker-compose -f docker/docker-compose.yml logs -f n8n
89
  ```
90
 
91
  ### 3. Hugging Face Deployment
92
-
93
  ```bash
94
  # Trigger deployment via GitHub Actions
95
  git push origin main
@@ -99,196 +71,77 @@ gh workflow run deploy-to-hf.yml
99
  ```
100
 
101
  ## 📊 Database Setup
 
102
 
103
- ### Supabase Configuration
104
-
105
- 1. **Create Supabase Project**:
106
-
107
- ```sql
108
- -- Enable pgvector extension
109
- CREATE EXTENSION IF NOT EXISTS vector;
110
-
111
- -- Create knowledge base schema
112
- CREATE SCHEMA IF NOT EXISTS knowledge;
113
-
114
- -- Create embeddings table
115
- CREATE TABLE knowledge.embeddings (
116
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
117
- content_id TEXT NOT NULL,
118
- collection_name TEXT NOT NULL,
119
- content TEXT NOT NULL,
120
- embedding VECTOR(384),
121
- metadata JSONB DEFAULT '{}',
122
- created_at TIMESTAMPTZ DEFAULT NOW(),
123
- updated_at TIMESTAMPTZ DEFAULT NOW()
124
- );
125
-
126
- -- Create indexes for performance
127
- CREATE INDEX IF NOT EXISTS idx_embeddings_collection ON knowledge.embeddings(collection_name);
128
- CREATE INDEX IF NOT EXISTS idx_embeddings_content_id ON knowledge.embeddings(content_id);
129
- CREATE INDEX IF NOT EXISTS idx_embeddings_vector ON knowledge.embeddings
130
- USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
131
- ```
132
-
133
- 2. **Configure Row Level Security**:
134
-
135
- ```sql
136
- -- Enable RLS
137
- ALTER TABLE knowledge.embeddings ENABLE ROW LEVEL SECURITY;
138
-
139
- -- Allow authenticated users to read embeddings
140
- CREATE POLICY "Users can read embeddings" ON knowledge.embeddings
141
- FOR SELECT TO authenticated USING (true);
142
-
143
- -- Allow service role to manage embeddings
144
- CREATE POLICY "Service role can manage embeddings" ON knowledge.embeddings
145
- FOR ALL TO service_role USING (true);
146
- ```
147
-
148
- ## 🤖 AI Integration Guide
149
-
150
- ### LangChain Workflows
151
-
152
- The platform supports advanced LangChain workflows:
153
-
154
- ```javascript
155
- // Example: Knowledge-based Q&A workflow
156
- {
157
- "nodes": [
158
- {
159
- "name": "Vector Search",
160
- "type": "n8n-nodes-vector-store",
161
- "parameters": {
162
- "operation": "similarity_search",
163
- "query": "{{ $json.question }}",
164
- "collection": "n8n",
165
- "top_k": 5
166
- }
167
- },
168
- {
169
- "name": "LangChain QA",
170
- "type": "@n8n/n8n-nodes-langchain",
171
- "parameters": {
172
- "chain_type": "question_answering",
173
- "context": "{{ $json.vector_results }}",
174
- "question": "{{ $json.question }}"
175
- }
176
- }
177
- ]
178
- }
179
- ```
180
-
181
- ### Custom AI Nodes
182
-
183
- Install additional AI nodes:
184
-
185
- ```bash
186
- # Install in running container
187
- docker exec n8n-automation npm install n8n-nodes-google-vertex-ai
188
- docker exec n8n-automation npm install n8n-nodes-openai-advanced
189
-
190
- # Restart to load new nodes
191
- docker-compose -f docker/docker-compose.yml restart n8n
192
- ```
193
-
194
- ## 🗄️ Knowledge Management
195
-
196
- ### Automated Synchronization
197
-
198
- The system automatically syncs content from these repositories:
199
-
200
- - **n8n Knowledge**: `/projects/n8n` - Workflow examples and best practices
201
- - **Video & Animation**: `/projects/videos-e-animacoes` - Multimedia processing guides
202
- - **Midjourney Prompts**: `/projects/midjorney-prompt` - AI art generation prompts
203
-
204
- ### Manual Knowledge Sync
205
-
206
- ```bash
207
- # Sync specific collection
208
- ./scripts/sync-knowledge.sh
209
-
210
- # Or trigger via GitHub Actions
211
- gh workflow run sync-knowledge.yml -f collections=n8n,midjourney-prompt
212
- ```
213
-
214
- ### Vector Search Setup
215
-
216
- Query the knowledge base in n8n workflows:
217
-
218
- ```javascript
219
- // Vector similarity search node configuration
220
- {
221
- "collection": "n8n",
222
- "query": "How to create webhook workflows",
223
- "top_k": 3,
224
- "score_threshold": 0.7
225
- }
226
- ```
227
 
228
  ## 💾 Backup & Recovery
229
 
230
  ### Automated Backups
 
 
 
 
231
 
232
- Daily backups include:
 
 
 
 
233
 
234
- - All n8n workflows (exported as JSON)
235
- - Encrypted credentials
236
- - Database schema
237
- - Knowledge base content
238
- - Vector embeddings
239
 
240
- ### Manual Backup
 
241
 
242
- ```bash
243
- # Create full backup
244
- ./scripts/backup.sh custom-backup-name
245
 
246
- # List available backups
247
- ls workflows/backup/
 
 
 
 
 
 
248
 
249
- # Restore from backup
250
- ./scripts/restore.sh n8n_backup_20240115_140230
251
- ```
 
 
 
 
 
 
252
 
253
- ### Backup Schedule
 
254
 
255
- - **Daily**: Automated workflow backup at 2 AM UTC
256
- - **Weekly**: Full system backup including database
257
- - **On-demand**: Manual backups via GitHub Actions
 
258
 
259
  ## 🔧 Maintenance
260
 
261
  ### Health Monitoring
262
-
263
  ```bash
264
- # Check container health
265
- docker-compose -f docker/docker-compose.yml ps
266
 
267
  # View application logs
268
- docker-compose -f docker/docker-compose.yml logs -f n8n
269
-
270
- # Monitor vector store
271
- curl http://localhost:8000/api/v1/heartbeat
272
  ```
273
 
274
  ### Performance Tuning
275
-
276
- **Database Optimization**:
277
-
278
- ```sql
279
- -- Monitor query performance
280
- SELECT query, mean_exec_time, calls
281
- FROM pg_stat_statements
282
- WHERE query LIKE '%n8n%'
283
- ORDER BY mean_exec_time DESC
284
- LIMIT 10;
285
-
286
- -- Optimize vector searches
287
- SET ivfflat.probes = 10;
288
- ```
289
-
290
- **Container Resources**:
291
-
292
  ```yaml
293
  # docker-compose.yml resource limits
294
  services:
@@ -303,193 +156,10 @@ services:
303
  memory: 2G
304
  ```
305
 
306
- ## 🔒 Security
307
-
308
- ### SSL Configuration
309
-
310
- - All database connections use SSL encryption
311
- - Webhook URLs must use HTTPS
312
- - Container communication over encrypted networks
313
-
314
- ### Credential Management
315
-
316
- ```bash
317
- # Credentials are encrypted by n8n
318
- # Store sensitive files in config/credentials/
319
- mkdir -p config/credentials
320
- echo '{}' > config/credentials/google-service-account.json
321
-
322
- # Set proper permissions
323
- chmod 600 config/credentials/*
324
- ```
325
-
326
- ### Environment Security
327
-
328
- - Never commit `.env` files
329
- - Use GitHub Secrets for sensitive data
330
- - Rotate encryption keys regularly
331
- - Enable Supabase RLS policies
332
-
333
- ## 🚨 Troubleshooting
334
-
335
- ### Common Issues
336
-
337
- **Connection Problems**:
338
-
339
- ```bash
340
- # Test database connection
341
- docker exec n8n-automation psql "$DB_POSTGRESDB_HOST" -U "$DB_POSTGRESDB_USER" -c "\l"
342
-
343
- # Check n8n logs
344
- docker logs n8n-automation --tail 50
345
-
346
- # Verify webhook connectivity
347
- curl -I "$WEBHOOK_URL/healthz"
348
- ```
349
-
350
- **Deployment Issues**:
351
-
352
- ```bash
353
- # Check Hugging Face Space status
354
- curl -I "https://huggingface.co/spaces/$HF_USERNAME/$HF_SPACE_NAME"
355
-
356
- # View GitHub Actions logs
357
- gh run list --workflow=deploy-to-hf.yml
358
- gh run view [run-id] --log
359
- ```
360
-
361
- **Knowledge Sync Problems**:
362
-
363
- ```bash
364
- # Manual knowledge sync debug
365
- ./scripts/sync-knowledge.sh
366
- echo $? # Should return 0 for success
367
-
368
- # Check embedding generation
369
- python3 -c "
370
- import json
371
- with open('knowledge/n8n/n8n_embeddings.json') as f:
372
- data = json.load(f)
373
- print(f'Embeddings loaded: {len(data)} documents')
374
- "
375
- ```
376
-
377
- ### Recovery Procedures
378
-
379
- **Emergency Restore**:
380
-
381
- 1. Stop all services: `docker-compose down`
382
- 2. Restore from latest backup: `./scripts/restore.sh [backup-name]`
383
- 3. Restart services: `docker-compose up -d`
384
- 4. Verify functionality: Access web interface
385
-
386
- **Database Recovery**:
387
-
388
- ```sql
389
- -- Check database integrity
390
- SELECT schemaname, tablename, n_tup_ins, n_tup_upd, n_tup_del
391
- FROM pg_stat_user_tables
392
- WHERE schemaname = 'public';
393
-
394
- -- Rebuild vector indexes if needed
395
- REINDEX INDEX idx_embeddings_vector;
396
- ```
397
-
398
- ## 📈 Scaling
399
-
400
- ### Horizontal Scaling
401
-
402
- - Multiple n8n instances with queue mode
403
- - Load balancer configuration
404
- - Distributed vector store
405
-
406
- ### Performance Monitoring
407
-
408
- - Enable n8n metrics: `N8N_METRICS=true`
409
- - Database query monitoring
410
- - Vector search performance tracking
411
- - Container resource utilization
412
-
413
  ## 🔄 CI/CD Pipeline
414
-
415
- ### Workflow Triggers
416
-
417
- - **Push to main**: Automatic deployment
418
- - **Scheduled**: Daily backups and knowledge sync
419
- - **Manual**: On-demand operations via GitHub Actions
420
-
421
- ### Pipeline Stages
422
-
423
- 1. **Build**: Docker image creation and testing
424
- 2. **Test**: Health checks and validation
425
- 3. **Deploy**: Hugging Face Spaces deployment
426
- 4. **Monitor**: Post-deployment verification
427
-
428
- ## 📝 Contributing
429
-
430
- 1. Fork the repository
431
- 2. Create feature branch: `git checkout -b feature/new-capability`
432
- 3. Commit changes: `git commit -am 'Add new capability'`
433
- 4. Push branch: `git push origin feature/new-capability`
434
- 5. Submit pull request
435
-
436
- ### Development Workflow
437
-
438
- ```bash
439
- # Local development
440
- docker-compose -f docker/docker-compose.yml up --build
441
-
442
- # Run tests
443
- ./scripts/test-infrastructure.sh
444
-
445
- # Deploy to staging
446
- gh workflow run deploy-to-hf.yml -f force_deploy=true
447
- ```
448
-
449
- ## 📞 Support
450
-
451
- - **Issues**: GitHub Issues
452
- - **Documentation**: [n8n Documentation](https://docs.n8n.io)
453
- - **Community**: [n8n Community](https://community.n8n.io)
454
-
455
- ## 📄 License
456
-
457
- This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
458
-
459
- ---
460
-
461
- **⚡ Pro Tips**:
462
-
463
- 1. **Performance**: Use queue mode for high-volume workflows
464
- 2. **Security**: Regular credential rotation and access reviews
465
- 3. **Monitoring**: Set up alerts for failed workflows and system health
466
- 4. **Backup**: Test restore procedures regularly
467
- 5. **Knowledge**: Keep your knowledge base updated with latest best practices
468
 
469
  ---
470
-
471
- _Built with ❤️ for the n8n automation community_
472
-
473
- ### ChromaDB
474
-
475
- ChromaDB é utilizado como vector store para armazenar embeddings e permitir buscas semânticas avançadas nos fluxos de trabalho do n8n.
476
-
477
- #### Configuração
478
-
479
- 1. **Obtenha seu token de autenticação (API Key) no painel do Chroma Cloud**.
480
- 2. No arquivo `.env`, adicione as variáveis:
481
-
482
- ```dotenv
483
- CHROMA_AUTH_TOKEN=ck-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
484
- CHROMA_HOST=api.chroma.com
485
- CHROMA_PORT=443
486
- ```
487
-
488
- 3. Certifique-se de que o serviço Chroma está acessível e que o token está correto.
489
-
490
- 4. Para uso local, ajuste `CHROMA_HOST` para `localhost` e `CHROMA_PORT` para a porta configurada.
491
-
492
- #### Referências
493
-
494
- - [Documentação ChromaDB](https://docs.trychroma.com/)
495
- - [Como gerar API Key no Chroma Cloud](https://docs.trychroma.com/cloud)
 
1
  # n8n Infrastructure Repository
2
 
3
+ > **⚠️ Security Warning**
4
+ > A `.env` file with sensitive credentials was previously committed to this repository. Although the file has been removed, the credentials may still be present in the Git history. **It is crucial that you scrub the Git history of this repository and rotate all exposed secrets (API keys, database passwords, etc.) immediately.** Tools like [bfg-repo-cleaner](https://rtyley.github.io/bfg-repo-cleaner/) can help with this process.
5
+
6
  A comprehensive, production-ready infrastructure setup for deploying n8n automation platform on Hugging Face Spaces with AI integrations and automated knowledge management.
7
 
8
  ## 🚀 Features
9
 
10
  ### Core Platform
11
+ - **n8n**: Self-hosted workflow automation platform.
12
+ - **Hugging Face Spaces**: Docker-based deployment with automatic scaling.
13
+ - **Supabase PostgreSQL**: SSL-encrypted database with pgvector extension.
14
+ - **ChromaDB**: Vector store for embeddings and AI-powered search.
 
15
 
16
  ### AI & Automation
17
+ - **LangChain Integration**: Advanced AI workflow capabilities.
18
+ - **Multi-Model Support**: OpenAI GPT, Anthropic Claude, Google Vertex AI.
19
+ - **Vector Knowledge Base**: Automated content ingestion with embeddings.
20
+ - **Community Nodes**: Extended functionality with custom AI nodes.
21
+
22
+ ### DevOps & Security
23
+ - **GitHub Actions CI/CD**: Automated deployment and maintenance.
24
+ - **Optimized Docker Setup**: Non-root user and healthchecks for enhanced security and reliability.
25
+ - **Automated Full Backups**: Daily backups of database, workflows, and credentials.
26
+ - **Database Security**: Row Level Security (RLS) enabled by default.
27
+ - **Knowledge Sync**: Multi-repository content synchronization.
 
28
 
29
  ## 📋 Prerequisites
30
 
31
+ - **GitHub Account**
32
+ - **Hugging Face Account**
33
+ - **Supabase Account**
34
+ - **Git** and **Docker** installed locally
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  ## 🛠️ Quick Start
37
 
38
  ### 1. Repository Setup
 
39
  ```bash
40
  # Clone the repository
41
  git clone https://github.com/your-username/n8n-infra.git
42
  cd n8n-infra
43
 
44
+ # Create your local environment configuration from the example
45
+ cp config/.env.example config/.env
46
+
47
+ # Edit config/.env with your actual values.
48
+ # NEVER commit this file to Git.
49
  ```
50
 
51
  ### 2. Local Development
 
52
  ```bash
53
  # Start the full stack locally
54
+ docker compose -f docker/docker-compose.yml up -d
55
 
56
  # Check service status
57
+ docker compose -f docker/docker-compose.yml ps
58
 
59
  # View logs
60
+ docker compose -f docker/docker-compose.yml logs -f n8n
61
  ```
62
 
63
  ### 3. Hugging Face Deployment
64
+ The repository is configured to automatically deploy to a Hugging Face Space on every push to the `main` branch.
65
  ```bash
66
  # Trigger deployment via GitHub Actions
67
  git push origin main
 
71
  ```
72
 
73
  ## 📊 Database Setup
74
+ The authoritative schema is defined in `supabase/schema.sql`. It is recommended to apply this schema to your Supabase project via the Supabase UI SQL Editor or by using Supabase migrations.
75
 
76
+ Key features of the schema include:
77
+ - A `knowledge` schema to encapsulate all knowledge base tables.
78
+ - `documents` and `embeddings` tables for storing content and its vector embeddings.
79
+ - A `vector_l2_ops` index on the `embeddings` table for efficient similarity search.
80
+ - **Row Level Security (RLS)** enabled on all tables to control data access. By default, data is public for reading, but only the `service_role` can write data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  ## 💾 Backup & Recovery
83
 
84
  ### Automated Backups
85
+ The `.github/workflows/backup-workflows.yml` GitHub Action runs nightly to create a full backup of your n8n instance. Each backup is a `.tar.gz` archive that includes:
86
+ - A full dump of the PostgreSQL database.
87
+ - A JSON export of all your n8n workflows.
88
+ - A copy of your `config` directory, which contains n8n credentials and settings.
89
 
90
+ ### Manual Backup
91
+ To create a backup manually, you can run the `backup.sh` script. This requires you to have the necessary environment variables set (see `config/.env.example`).
92
+ ```bash
93
+ # Make sure the script is executable
94
+ chmod +x scripts/backup.sh
95
 
96
+ # Run the script
97
+ ./scripts/backup.sh
98
+ ```
 
 
99
 
100
+ ### Restore from Backup
101
+ To restore your n8n instance from a backup, use the `restore.sh` script.
102
 
103
+ **Warning:** This process will overwrite your existing database and configuration.
 
 
104
 
105
+ 1. **Stop your n8n container** to prevent data corruption.
106
+ ```bash
107
+ docker compose -f docker/docker-compose.yml stop n8n
108
+ ```
109
+ 2. Run the `restore.sh` script, providing the path to your backup file.
110
+ ```bash
111
+ # Make sure the script is executable
112
+ chmod +x scripts/restore.sh
113
 
114
+ # Run the restore script
115
+ BACKUP_FILE=workflows/backup/n8n-backup-YYYYMMDD-HHMMSS.tar.gz ./scripts/restore.sh
116
+ ```
117
+ 3. The script will guide you through the process. It will restore the database and the `config` directory.
118
+ 4. For workflows, the script will provide a `restored_workflows_*.json` file. You will need to import this file manually via the n8n UI or by using the `n8n-cli`.
119
+ 5. **Restart your n8n container.**
120
+ ```bash
121
+ docker compose -f docker/docker-compose.yml start n8n
122
+ ```
123
 
124
+ ## 🔒 Security
125
+ This repository has been optimized with security in mind.
126
 
127
+ - **Credential Management**: A `.gitignore` file is included to prevent committing sensitive files like `.env`. An example file `config/.env.example` is provided.
128
+ - **Container Security**: The `Dockerfile` is configured to run n8n as a non-root user, reducing the container's attack surface.
129
+ - **Database Security**: Row Level Security is enabled in the database schema (`supabase/schema.sql`).
130
+ - **Secret Rotation**: As mentioned in the security warning, it is critical to rotate any secrets that may have been exposed in the Git history.
131
 
132
  ## 🔧 Maintenance
133
 
134
  ### Health Monitoring
 
135
  ```bash
136
+ # Check container health (includes a healthcheck)
137
+ docker compose -f docker/docker-compose.yml ps
138
 
139
  # View application logs
140
+ docker compose -f docker/docker-compose.yml logs -f n8n
 
 
 
141
  ```
142
 
143
  ### Performance Tuning
144
+ **Container Resources**: Resource limits are defined in `docker-compose.yml` to prevent resource exhaustion during local development.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  ```yaml
146
  # docker-compose.yml resource limits
147
  services:
 
156
  memory: 2G
157
  ```
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  ## 🔄 CI/CD Pipeline
160
+ The CI/CD pipelines are defined in the `.github/workflows` directory and are optimized for:
161
+ - **Efficiency**: The backup workflow uses a pre-built Docker container, and the knowledge sync workflow uses dependency caching to speed up execution.
162
+ - **Reliability**: The knowledge sync workflow uses `npm ci` for deterministic builds.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
  ---
165
+ _This README has been updated to reflect the infrastructure audit and optimization._
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/{.env → .env.example} RENAMED
@@ -1,10 +1,13 @@
1
  # n8n Infrastructure Environment Configuration
2
- # Copy this file to .env and fill in your actual values
 
3
 
4
  # ===== CORE N8N CONFIGURATION =====
5
- N8N_ENCRYPTION_KEY=wzU4MDO5k77AsKSU10gZILj7qkxQzoYD
6
- N8N_USER_MANAGEMENT_JWT_SECRET=rwTS25Uo0hKYcArORBS7mIMYXyo4A3av
7
- N8N_HOST=danilonovais-n8n-dan.hf.space
 
 
8
  N8N_PUBLIC_API_DISABLED=false
9
  N8N_LOG_LEVEL=info
10
  N8N_METRICS=true
@@ -14,61 +17,60 @@ EXECUTIONS_DATA_SAVE_ON_ERROR=all
14
  EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
15
  EXECUTIONS_DATA_PRUNE=true
16
  EXECUTIONS_DATA_MAX_AGE=336
17
- WEBHOOK_URL=https://danilonovais-n8n-dan.hf.space/
18
 
19
- # ===== DATABASE CONFIGURATION =====
 
20
  DB_TYPE=postgresdb
21
- DB_POSTGRESDB_HOST=aws-1-sa-east-1.pooler.supabase.com
22
  DB_POSTGRESDB_PORT=6543
23
  DB_POSTGRESDB_DATABASE=postgres
24
- DB_POSTGRESDB_USER=postgres.vkgwjmvekrlrjybbmtks
25
  DB_POSTGRESDB_SCHEMA=public
26
- # NOTE: Keep DB password only in HF Space Secrets (runtime)
27
  DB_POSTGRESDB_PASSWORD=
28
  DB_POSTGRESDB_SSL=true
29
  DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false
30
 
31
  # ===== DEPLOYMENT CONFIGURATION =====
32
- # NOTE: Move HF_TOKEN to GitHub Actions Secrets (not used by runtime container)
33
  HF_TOKEN=
34
- HF_SPACE_NAME=danilonovais/n8n-dan
35
- # NOTE: Move GITHUB_TOKEN to GitHub Actions Secrets (not used by runtime container)
36
  GITHUB_TOKEN=
37
 
38
  # ===== AI INTEGRATIONS =====
39
- GOOGLE_PROJECT_ID=peppy-flame-468203-e0
40
- GOOGLE_CREDENTIALS_PATH=/home/node/.n8n/credentials/google-service-account.json
41
- GOOGLE_APPLICATION_CREDENTIALS=/home/node/.n8n/credentials/google-service-account.json
42
  # NOTE: Keep AI/API keys in HF Space Secrets (runtime) and/or GitHub Actions Secrets
43
  OPENAI_API_KEY=
44
  ANTHROPIC_API_KEY=
45
- VERTEX_AI_PROJECT=n8n-workflows
46
- VERTEX_AI_LOCATION=us-central1
 
 
47
 
48
- # ===== VECTOR STORE CONFIGURATION =====
49
  CHROMA_AUTH_TOKEN=
50
  CHROMA_HOST=api.chroma.com
51
  CHROMA_PORT=443
52
 
53
  # ===== KNOWLEDGE BASE SYNC =====
 
54
  KB_REPO_N8N=https://github.com/danilonovaisv/CHATGPT-knowledge-base.git
55
  KB_BRANCH_N8N=main
56
- KB_PATH_N8N=projects/n8n
57
- KB_PATH_VIDEOS=projects/videos-e-animacoes
58
- KB_PATH_MIDJOURNEY=projects/midjorney-prompt
59
 
60
  # ===== MONITORING AND LOGGING =====
61
- N8N_LOG_LEVEL=info
62
- N8N_METRICS=true
63
- SENTRY_DSN=your-sentry-dsn (optional)
64
 
65
  # ===== BACKUP CONFIGURATION =====
66
- BACKUP_SCHEDULE=0 2 * * *
67
- BACKUP_RETENTION_DAYS=30
68
  BACKUP_ENCRYPTION_PASSWORD=
69
 
70
  # ===== SECURITY =====
71
- ALLOWED_ORIGINS=https://danilonovais-n8n-dan.hf.space
72
- CSRF_SECRET=REPLACE_WITH_RANDOM_32_64_CHAR_STRING
 
 
73
  RATE_LIMIT_WINDOW=15
74
- RATE_LIMIT_MAX=100
 
1
  # n8n Infrastructure Environment Configuration
2
+ # Copy this file to .env and fill in your actual values.
3
+ # NEVER commit the .env file to version control.
4
 
5
  # ===== CORE N8N CONFIGURATION =====
6
+ # Generate with `openssl rand -hex 32`
7
+ N8N_ENCRYPTION_KEY=
8
+ # Generate with `openssl rand -hex 32`
9
+ N8N_USER_MANAGEMENT_JWT_SECRET=
10
+ N8N_HOST=your-n8n-host.hf.space
11
  N8N_PUBLIC_API_DISABLED=false
12
  N8N_LOG_LEVEL=info
13
  N8N_METRICS=true
 
17
  EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
18
  EXECUTIONS_DATA_PRUNE=true
19
  EXECUTIONS_DATA_MAX_AGE=336
20
+ WEBHOOK_URL=https://your-n8n-host.hf.space/
21
 
22
+ # ===== DATABASE CONFIGURATION (SUPABASE) =====
23
+ # Find these in your Supabase project settings
24
  DB_TYPE=postgresdb
25
+ DB_POSTGRESDB_HOST=
26
  DB_POSTGRESDB_PORT=6543
27
  DB_POSTGRESDB_DATABASE=postgres
28
+ DB_POSTGRESDB_USER=postgres
29
  DB_POSTGRESDB_SCHEMA=public
30
+ # NOTE: Keep DB password only in HF Space Secrets (runtime) or a local .env file.
31
  DB_POSTGRESDB_PASSWORD=
32
  DB_POSTGRESDB_SSL=true
33
  DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false
34
 
35
  # ===== DEPLOYMENT CONFIGURATION =====
36
+ # NOTE: These should be GitHub Actions Secrets, not used by the runtime container.
37
  HF_TOKEN=
38
+ HF_SPACE_NAME=your-username/your-space-name
 
39
  GITHUB_TOKEN=
40
 
41
  # ===== AI INTEGRATIONS =====
 
 
 
42
  # NOTE: Keep AI/API keys in HF Space Secrets (runtime) and/or GitHub Actions Secrets
43
  OPENAI_API_KEY=
44
  ANTHROPIC_API_KEY=
45
+ GOOGLE_PROJECT_ID=
46
+ # The following are used if you mount a service account key file
47
+ GOOGLE_CREDENTIALS_PATH=/home/node/.n8n/credentials/google-service-account.json
48
+ GOOGLE_APPLICATION_CREDENTIALS=/home/node/.n8n/credentials/google-service-account.json
49
 
50
+ # ===== VECTOR STORE CONFIGURATION (CHROMA) =====
51
  CHROMA_AUTH_TOKEN=
52
  CHROMA_HOST=api.chroma.com
53
  CHROMA_PORT=443
54
 
55
  # ===== KNOWLEDGE BASE SYNC =====
56
+ # The repository to sync knowledge from
57
  KB_REPO_N8N=https://github.com/danilonovaisv/CHATGPT-knowledge-base.git
58
  KB_BRANCH_N8N=main
59
+ # Comma-separated list of directories inside the repo to sync
60
+ KB_PATH_N8N=projects/n8n,projects/videos-e-animacoes,projects/midjorney-prompt
 
61
 
62
  # ===== MONITORING AND LOGGING =====
63
+ SENTRY_DSN=
 
 
64
 
65
  # ===== BACKUP CONFIGURATION =====
66
+ # API key for the backup script to access n8n
67
+ N8N_API_KEY=
68
  BACKUP_ENCRYPTION_PASSWORD=
69
 
70
  # ===== SECURITY =====
71
+ # A comma-separated list of allowed origins for the n8n UI
72
+ ALLOWED_ORIGINS=https://your-n8n-host.hf.space
73
+ # Generate with `openssl rand -hex 32`
74
+ CSRF_SECRET=
75
  RATE_LIMIT_WINDOW=15
76
+ RATE_LIMIT_MAX=100
docker/Dockerfile CHANGED
@@ -19,6 +19,13 @@ ENV QUEUE_BULL_REDIS_DISABLED=true
19
  ENV N8N_METRICS=true
20
  ENV QUEUE_HEALTH_CHECK_ACTIVE=true
21
 
 
 
 
 
 
 
 
22
  # Database (set via Secrets in HF Space)
23
  # ENV DB_TYPE=postgresdb
24
  # ENV DB_POSTGRESDB_HOST=
 
19
  ENV N8N_METRICS=true
20
  ENV QUEUE_HEALTH_CHECK_ACTIVE=true
21
 
22
+ # Add healthcheck
23
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
24
+ CMD curl -f "http://localhost:${N8N_PORT:-5678}/healthz" || exit 1
25
+
26
+ # Switch to non-root user for security
27
+ USER node
28
+
29
  # Database (set via Secrets in HF Space)
30
  # ENV DB_TYPE=postgresdb
31
  # ENV DB_POSTGRESDB_HOST=
docker/docker-compose.yml CHANGED
@@ -31,3 +31,16 @@ services:
31
  - ./config:/config
32
  - ./workflows:/workflows
33
  restart: unless-stopped
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  - ./config:/config
32
  - ./workflows:/workflows
33
  restart: unless-stopped
34
+ deploy:
35
+ resources:
36
+ limits:
37
+ cpus: "2.0"
38
+ memory: 4G
39
+ reservations:
40
+ cpus: "1.0"
41
+ memory: 2G
42
+ healthcheck:
43
+ test: ["CMD-SHELL", "curl -f http://localhost:5678/healthz"]
44
+ interval: 30s
45
+ timeout: 10s
46
+ retries: 3
scripts/backup.sh CHANGED
@@ -10,14 +10,36 @@ set -euo pipefail
10
  : "${N8N_API_KEY?Missing N8N_API_KEY}"
11
 
12
  TS=$(date +%Y%m%d-%H%M%S)
13
- OUTDIR="workflows/backup/${TS}"
 
14
  mkdir -p "$OUTDIR"
15
 
 
 
 
 
 
 
 
16
  echo "==> Dumping Postgres (Supabase) ..."
17
- export PGPASSWORD="${DB_PASSWORD}"
18
  pg_dump -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" -F c -Z 5 -f "${OUTDIR}/db.dump"
19
 
20
  echo "==> Exporting n8n workflows ..."
21
- curl -sS -H "X-N8N-API-KEY: ${N8N_API_KEY}" "${N8N_BASE_URL}/rest/workflows" > "${OUTDIR}/workflows.json"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- echo "==> Done. Artifacts at ${OUTDIR}"
 
10
  : "${N8N_API_KEY?Missing N8N_API_KEY}"
11
 
12
  TS=$(date +%Y%m%d-%H%M%S)
13
+ BACKUP_NAME="n8n-backup-${TS}"
14
+ OUTDIR="workflows/backup/${BACKUP_NAME}"
15
  mkdir -p "$OUTDIR"
16
 
17
+ # Use .pgpass for security
18
+ PGPASS_FILE=$(mktemp)
19
+ trap 'rm -f "$PGPASS_FILE"' EXIT # Ensure cleanup
20
+ echo "${DB_HOST}:${DB_PORT}:${DB_NAME}:${DB_USER}:${DB_PASSWORD}" > "${PGPASS_FILE}"
21
+ chmod 600 "${PGPASS_FILE}"
22
+ export PGPASSFILE="${PGPASS_FILE}"
23
+
24
  echo "==> Dumping Postgres (Supabase) ..."
 
25
  pg_dump -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" -F c -Z 5 -f "${OUTDIR}/db.dump"
26
 
27
  echo "==> Exporting n8n workflows ..."
28
+ curl -sS -H "X-N8N-API-KEY: ${N8N_API_KEY}" "${N8N_BASE_URL}/rest/workflows" > "${OUTDIR}/workflows.json"
29
+
30
+ echo "==> Backing up n8n config and credentials ..."
31
+ # We assume the script is run from the repo root, and config is in ./config
32
+ if [ -d "config" ]; then
33
+ # Exclude .env if it exists, as it's for local dev
34
+ rsync -av --exclude '.env' config/ "${OUTDIR}/config/"
35
+ else
36
+ echo "Warning: 'config' directory not found. Skipping credentials backup."
37
+ fi
38
+
39
+ echo "==> Creating backup archive ..."
40
+ tar -czf "workflows/backup/${BACKUP_NAME}.tar.gz" -C "workflows/backup" "${BACKUP_NAME}"
41
+
42
+ # Clean up temporary directory
43
+ rm -rf "${OUTDIR}"
44
 
45
+ echo "==> Done. Backup created at workflows/backup/${BACKUP_NAME}.tar.gz"
scripts/restore.sh CHANGED
@@ -6,9 +6,65 @@ set -euo pipefail
6
  : "${DB_NAME?Missing DB_NAME}"
7
  : "${DB_USER?Missing DB_USER}"
8
  : "${DB_PASSWORD?Missing DB_PASSWORD}"
9
- : "${DUMP_PATH?Usage: DUMP_PATH=/path/to/db.dump ./scripts/restore.sh}"
10
 
11
- echo "==> Restoring Postgres from ${DUMP_PATH} ..."
12
- export PGPASSWORD="${DB_PASSWORD}"
13
- pg_restore -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" --clean --if-exists "${DUMP_PATH}"
14
- echo "==> Done."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  : "${DB_NAME?Missing DB_NAME}"
7
  : "${DB_USER?Missing DB_USER}"
8
  : "${DB_PASSWORD?Missing DB_PASSWORD}"
9
+ : "${BACKUP_FILE?Usage: BACKUP_FILE=/path/to/backup.tar.gz ./scripts/restore.sh}"
10
 
11
+ if [ ! -f "${BACKUP_FILE}" ]; then
12
+ echo "Error: Backup file not found at ${BACKUP_FILE}"
13
+ exit 1
14
+ fi
15
+
16
+ # Extract backup name from file path
17
+ BACKUP_NAME=$(basename "${BACKUP_FILE}" .tar.gz)
18
+ TMP_DIR="workflows/backup/${BACKUP_NAME}"
19
+
20
+ # 1. Extract backup
21
+ echo "==> Extracting backup archive ..."
22
+ mkdir -p "${TMP_DIR}"
23
+ tar -xzf "${BACKUP_FILE}" -C "workflows/backup"
24
+
25
+ DUMP_FILE="${TMP_DIR}/db.dump"
26
+ if [ ! -f "${DUMP_FILE}" ]; then
27
+ echo "Error: db.dump not found in backup archive."
28
+ rm -rf "${TMP_DIR}"
29
+ exit 1
30
+ fi
31
+
32
+ # 2. Restore Database
33
+ # Use .pgpass for security
34
+ PGPASS_FILE=$(mktemp)
35
+ trap 'rm -f "$PGPASS_FILE" "$TMP_DIR"' EXIT # Ensure cleanup
36
+ echo "${DB_HOST}:${DB_PORT}:${DB_NAME}:${DB_USER}:${DB_PASSWORD}" > "${PGPASS_FILE}"
37
+ chmod 600 "${PGPASS_FILE}"
38
+ export PGPASSFILE="${PGPASS_FILE}"
39
+
40
+ echo "==> Restoring Postgres database ..."
41
+ pg_restore -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" --clean --if-exists "${DUMP_FILE}"
42
+
43
+ # 3. Restore Config
44
+ echo "==> Restoring n8n config and credentials ..."
45
+ if [ -d "${TMP_DIR}/config" ]; then
46
+ # Important: Stop n8n before replacing config files to avoid corruption
47
+ echo "Make sure the n8n container is stopped before proceeding."
48
+ read -p "Press enter to continue"
49
+
50
+ rsync -av --delete "${TMP_DIR}/config/" "config/"
51
+ echo "Config restored. Please restart the n8n container."
52
+ else
53
+ echo "Warning: 'config' directory not found in backup. Skipping."
54
+ fi
55
+
56
+ # 4. Restore Workflows
57
+ echo "==> Restoring n8n workflows ..."
58
+ if [ -f "${TMP_DIR}/workflows.json" ]; then
59
+ # n8n can automatically load workflows from the /workflows directory
60
+ # We need to split the JSON array into individual files
61
+ # This is complex in bash, so we'll provide the file for manual import
62
+ # and add instructions in the README
63
+ cp "${TMP_DIR}/workflows.json" "workflows/restored_workflows_${BACKUP_NAME}.json"
64
+ echo "Workflows JSON saved to workflows/restored_workflows_${BACKUP_NAME}.json"
65
+ echo "Please import them manually via the n8n UI or use the n8n-cli."
66
+ else
67
+ echo "Warning: 'workflows.json' not found in backup. Skipping."
68
+ fi
69
+
70
+ echo "==> Restore complete."
scripts/sync-knowledge.mjs CHANGED
@@ -2,7 +2,7 @@
2
  // Requires: OPENAI_API_KEY, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, KNOWLEDGE_REPO_URL, KNOWLEDGE_DIRS
3
  import { createClient } from '@supabase/supabase-js';
4
  import crypto from 'node:crypto';
5
- import { execSync } from 'node:child_process';
6
  import fs from 'node:fs';
7
  import path from 'node:path';
8
  import process from 'node:process';
@@ -27,13 +27,23 @@ const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);
27
  const workdir = path.resolve('knowledge');
28
  if (!fs.existsSync(workdir)) fs.mkdirSync(workdir, { recursive: true });
29
 
 
 
 
 
 
 
 
 
 
 
30
  const repoDir = path.join(workdir, 'CHATGPT-knowledge-base');
31
  if (!fs.existsSync(repoDir)) {
32
  console.log('Cloning KB repo...');
33
- execSync(`git clone --depth 1 ${KNOWLEDGE_REPO_URL} ${repoDir}`, { stdio: 'inherit' });
34
  } else {
35
  console.log('Pulling KB repo...');
36
- execSync(`git -C ${repoDir} pull`, { stdio: 'inherit' });
37
  }
38
 
39
  const dirs = KNOWLEDGE_DIRS.split(',').map(s => s.trim());
@@ -46,11 +56,19 @@ async function upsertDoc(pth, content) {
46
 
47
  // Upsert document
48
  const { data: doc, error: docErr } = await supabase
49
- .from('knowledge.documents')
50
- .upsert({ path: pth, title, content, hash }, { onConflict: 'path' })
51
- .select()
52
  .single();
53
- if (docErr) throw docErr;
 
 
 
 
 
 
 
 
54
 
55
  if (openai) {
56
  // Embedding
@@ -62,15 +80,18 @@ async function upsertDoc(pth, content) {
62
  const vector = emb.data[0].embedding;
63
 
64
  const { error: embErr } = await supabase
65
- .from('knowledge.embeddings')
66
- .upsert({ doc_id: doc.id, embedding: vector, model: 'text-embedding-3-large' });
67
- if (embErr) throw embErr;
68
  } else {
69
  console.warn('OPENAI_API_KEY not set, skipping embeddings for', pth);
70
  }
71
  }
72
 
73
  async function main() {
 
 
 
74
  for (const rel of dirs) {
75
  const abs = path.join(repoDir, rel);
76
  if (!fs.existsSync(abs)) {
@@ -79,17 +100,26 @@ async function main() {
79
  }
80
  const entries = await fs.promises.readdir(abs, { withFileTypes: true });
81
  for (const ent of entries) {
 
 
 
82
  const full = path.join(abs, ent.name);
83
- if (ent.isDirectory()) continue;
84
- if (!/\.(md|markdown|json|txt)$/i.test(ent.name)) continue;
85
-
86
- const content = await fs.promises.readFile(full, 'utf8');
87
  const repoRelPath = path.relative(repoDir, full);
88
- console.log('Ingest:', repoRelPath);
89
- await upsertDoc(repoRelPath, content);
 
 
 
 
 
 
 
90
  }
91
  }
92
- console.log('Sync complete');
 
 
 
93
  }
94
 
95
  main().catch(err => { console.error(err); process.exit(1); });
 
2
  // Requires: OPENAI_API_KEY, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, KNOWLEDGE_REPO_URL, KNOWLEDGE_DIRS
3
  import { createClient } from '@supabase/supabase-js';
4
  import crypto from 'node:crypto';
5
+ import { spawnSync } from 'node:child_process';
6
  import fs from 'node:fs';
7
  import path from 'node:path';
8
  import process from 'node:process';
 
27
  const workdir = path.resolve('knowledge');
28
  if (!fs.existsSync(workdir)) fs.mkdirSync(workdir, { recursive: true });
29
 
30
+ function runCommand(command, args, options = {}) {
31
+ const result = spawnSync(command, args, { stdio: 'inherit', ...options });
32
+ if (result.error) {
33
+ throw result.error;
34
+ }
35
+ if (result.status !== 0) {
36
+ throw new Error(`Command failed: ${command} ${args.join(' ')}`);
37
+ }
38
+ }
39
+
40
  const repoDir = path.join(workdir, 'CHATGPT-knowledge-base');
41
  if (!fs.existsSync(repoDir)) {
42
  console.log('Cloning KB repo...');
43
+ runCommand('git', ['clone', '--depth', '1', KNOWLEDGE_REPO_URL, repoDir]);
44
  } else {
45
  console.log('Pulling KB repo...');
46
+ runCommand('git', ['pull'], { cwd: repoDir });
47
  }
48
 
49
  const dirs = KNOWLEDGE_DIRS.split(',').map(s => s.trim());
 
56
 
57
  // Upsert document
58
  const { data: doc, error: docErr } = await supabase
59
+ .from('documents')
60
+ .upsert({ path: pth, title, content, hash, updated_at: new Date() }, { onConflict: 'path' })
61
+ .select('id, hash')
62
  .single();
63
+
64
+ if (docErr) throw new Error(`Supabase doc upsert error: ${docErr.message}`);
65
+ if (!doc) throw new Error('Upsert did not return a document.');
66
+
67
+ // If hash is the same, skip embedding
68
+ if (doc.hash === hash && !process.env.FORCE_REEMBED) {
69
+ console.log(`Skipping ${pth} (content unchanged)`);
70
+ return;
71
+ }
72
 
73
  if (openai) {
74
  // Embedding
 
80
  const vector = emb.data[0].embedding;
81
 
82
  const { error: embErr } = await supabase
83
+ .from('embeddings')
84
+ .upsert({ doc_id: doc.id, embedding: vector, model: 'text-embedding-3-large' }, { onConflict: 'doc_id' });
85
+ if (embErr) throw new Error(`Supabase embedding upsert error: ${embErr.message}`);
86
  } else {
87
  console.warn('OPENAI_API_KEY not set, skipping embeddings for', pth);
88
  }
89
  }
90
 
91
  async function main() {
92
+ let successCount = 0;
93
+ let errorCount = 0;
94
+
95
  for (const rel of dirs) {
96
  const abs = path.join(repoDir, rel);
97
  if (!fs.existsSync(abs)) {
 
100
  }
101
  const entries = await fs.promises.readdir(abs, { withFileTypes: true });
102
  for (const ent of entries) {
103
+ if (ent.isDirectory() || !/\.(md|markdown|json|txt)$/i.test(ent.name)) {
104
+ continue;
105
+ }
106
  const full = path.join(abs, ent.name);
 
 
 
 
107
  const repoRelPath = path.relative(repoDir, full);
108
+ try {
109
+ const content = await fs.promises.readFile(full, 'utf8');
110
+ console.log('Ingesting:', repoRelPath);
111
+ await upsertDoc(repoRelPath, content);
112
+ successCount++;
113
+ } catch (err) {
114
+ console.error(`Failed to process ${repoRelPath}: ${err.message}`);
115
+ errorCount++;
116
+ }
117
  }
118
  }
119
+ console.log(`\nSync complete. ${successCount} processed, ${errorCount} errors.`);
120
+ if (errorCount > 0) {
121
+ process.exit(1);
122
+ }
123
  }
124
 
125
  main().catch(err => { console.error(err); process.exit(1); });
scripts/test-infrastructure.sh CHANGED
@@ -32,8 +32,9 @@ run_test() {
32
 
33
  ((TESTS_TOTAL++))
34
  log_test "Running: $test_name"
 
35
 
36
- if eval "$test_command" > /dev/null 2>&1; then
37
  echo " ✅ PASSED"
38
  ((TESTS_PASSED++))
39
  return 0
@@ -53,10 +54,10 @@ fi
53
  test_docker() {
54
  log_info "Testing Docker configuration..."
55
 
56
- run_test "Docker daemon accessible" "docker --version"
57
- run_test "Docker Compose available" "docker-compose --version"
58
- run_test "Dockerfile syntax" "docker build -f docker/Dockerfile --dry-run . 2>/dev/null || docker build -f docker/Dockerfile -t n8n-test . --dry-run"
59
- run_test "Docker Compose syntax" "docker-compose -f docker/docker-compose.yml config"
60
  }
61
 
62
  # Test environment configuration
@@ -64,7 +65,7 @@ test_environment() {
64
  log_info "Testing environment configuration..."
65
 
66
  run_test "Environment example exists" "[[ -f config/.env.example ]]"
67
- run_test "Required directories exist" "[[ -d workflows && -d knowledge && -d scripts ]]"
68
 
69
  if [[ -f .env ]]; then
70
  run_test "Environment file loaded" "[[ -n \${N8N_ENCRYPTION_KEY:-} ]]"
@@ -80,10 +81,9 @@ test_scripts() {
80
 
81
  run_test "Backup script executable" "[[ -x scripts/backup.sh ]]"
82
  run_test "Restore script executable" "[[ -x scripts/restore.sh ]]"
83
- run_test "Sync script executable" "[[ -x scripts/sync-knowledge.sh ]]"
84
  run_test "Backup script syntax" "bash -n scripts/backup.sh"
85
  run_test "Restore script syntax" "bash -n scripts/restore.sh"
86
- run_test "Sync script syntax" "bash -n scripts/sync-knowledge.sh"
87
  }
88
 
89
  # Test GitHub Actions
@@ -117,32 +117,18 @@ test_database() {
117
  fi
118
  }
119
 
120
- # Test knowledge base
121
- test_knowledge() {
122
- log_info "Testing knowledge base configuration..."
123
-
124
- run_test "Knowledge directories exist" "[[ -d knowledge/n8n && -d knowledge/videos-e-animacoes && -d knowledge/midjourney-prompt ]]"
125
-
126
- # Test Python dependencies for embedding generation
127
- if command -v python3 > /dev/null; then
128
- run_test "Python available" "python3 --version"
129
- run_test "Required Python packages" "python3 -c 'import sentence_transformers, json, hashlib'"
130
- fi
131
- }
132
-
133
  # Integration tests
134
  test_integration() {
135
  log_info "Running integration tests..."
136
 
137
  # Test if we can start services locally
138
- if run_test "Start services locally" "docker-compose -f docker/docker-compose.yml up -d --build"; then
139
  sleep 30
140
 
141
- run_test "n8n health endpoint" "curl -f http://localhost:7860/healthz"
142
- run_test "Vector store endpoint" "curl -f http://localhost:8000/api/v1/heartbeat"
143
 
144
  # Cleanup
145
- docker-compose -f docker/docker-compose.yml down > /dev/null 2>&1
146
  else
147
  log_error "Failed to start services - skipping integration tests"
148
  fi
@@ -161,10 +147,9 @@ main() {
161
  test_scripts
162
  test_github_actions
163
  test_database
164
- test_knowledge
165
 
166
  # Skip integration tests if Docker unavailable
167
- if docker --version > /dev/null 2>&1; then
168
  test_integration
169
  else
170
  log_warn "Docker not available - skipping integration tests"
 
32
 
33
  ((TESTS_TOTAL++))
34
  log_test "Running: $test_name"
35
+ echo " Executing: $test_command"
36
 
37
+ if eval "$test_command"; then
38
  echo " ✅ PASSED"
39
  ((TESTS_PASSED++))
40
  return 0
 
54
  test_docker() {
55
  log_info "Testing Docker configuration..."
56
 
57
+ run_test "Docker daemon accessible" "sudo docker --version"
58
+ run_test "Docker Compose available" "sudo docker compose version"
59
+ run_test "Dockerfile syntax" "sudo docker build -f docker/Dockerfile -t n8n-test-build ."
60
+ run_test "Docker Compose syntax" "sudo docker compose -f docker/docker-compose.yml config"
61
  }
62
 
63
  # Test environment configuration
 
65
  log_info "Testing environment configuration..."
66
 
67
  run_test "Environment example exists" "[[ -f config/.env.example ]]"
68
+ run_test "Required directories exist" "[[ -d workflows && -d scripts ]]"
69
 
70
  if [[ -f .env ]]; then
71
  run_test "Environment file loaded" "[[ -n \${N8N_ENCRYPTION_KEY:-} ]]"
 
81
 
82
  run_test "Backup script executable" "[[ -x scripts/backup.sh ]]"
83
  run_test "Restore script executable" "[[ -x scripts/restore.sh ]]"
84
+ run_test "Sync script syntax" "bash -n scripts/sync-knowledge.sh"
85
  run_test "Backup script syntax" "bash -n scripts/backup.sh"
86
  run_test "Restore script syntax" "bash -n scripts/restore.sh"
 
87
  }
88
 
89
  # Test GitHub Actions
 
117
  fi
118
  }
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  # Integration tests
121
  test_integration() {
122
  log_info "Running integration tests..."
123
 
124
  # Test if we can start services locally
125
+ if run_test "Start services locally" "sudo docker compose -f docker/docker-compose.yml up -d --build"; then
126
  sleep 30
127
 
128
+ run_test "n8n health endpoint" "curl -f http://localhost:5678/healthz"
 
129
 
130
  # Cleanup
131
+ sudo docker compose -f docker/docker-compose.yml down > /dev/null 2>&1
132
  else
133
  log_error "Failed to start services - skipping integration tests"
134
  fi
 
147
  test_scripts
148
  test_github_actions
149
  test_database
 
150
 
151
  # Skip integration tests if Docker unavailable
152
+ if sudo docker --version > /dev/null 2>&1; then
153
  test_integration
154
  else
155
  log_warn "Docker not available - skipping integration tests"
supabase/schema.sql CHANGED
@@ -30,3 +30,17 @@ create or replace view knowledge.searchable as
30
  select d.id, d.title, d.path, d.source_url, d.updated_at
31
  from knowledge.documents d
32
  order by d.updated_at desc;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  select d.id, d.title, d.path, d.source_url, d.updated_at
31
  from knowledge.documents d
32
  order by d.updated_at desc;
33
+
34
+ -- ==> RLS (Row Level Security)
35
+ -- 1. Enable RLS
36
+ alter table knowledge.documents enable row level security;
37
+ alter table knowledge.embeddings enable row level security;
38
+
39
+ -- 2. Create policies
40
+ -- Allow public read access to all
41
+ create policy "Allow public read access" on knowledge.documents for select using (true);
42
+ create policy "Allow public read access" on knowledge.embeddings for select using (true);
43
+
44
+ -- Allow service_role (server-side) to perform all actions
45
+ create policy "Allow all for service_role" on knowledge.documents for all to service_role with check (true);
46
+ create policy "Allow all for service_role" on knowledge.embeddings for all to service_role with check (true);
test_output.log ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [INFO] 🧪 Starting n8n Infrastructure Test Suite
2
+ ================================================
3
+ [INFO] Testing Docker configuration...