Spaces:
Sleeping
Sleeping
google-labs-jules[bot]
commited on
Commit
·
333834a
1
Parent(s):
d33c618
feat: Comprehensive infrastructure audit and optimization
Browse files- .dockerignore +11 -0
- .github/workflows/backup-workflows.yml +2 -5
- .github/workflows/sync-knowledge.yml +3 -2
- .gitignore +35 -0
- README.md +83 -413
- config/{.env → .env.example} +31 -29
- docker/Dockerfile +7 -0
- docker/docker-compose.yml +13 -0
- scripts/backup.sh +26 -4
- scripts/restore.sh +61 -5
- scripts/sync-knowledge.mjs +47 -17
- scripts/test-infrastructure.sh +12 -27
- supabase/schema.sql +14 -0
- test_output.log +3 -0
.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
|
| 20 |
-
run: npm ci
|
| 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 |
-
- **
|
| 10 |
-
- **
|
| 11 |
-
- **
|
| 12 |
-
- **ChromaDB**: Vector store for embeddings and AI-powered search
|
| 13 |
|
| 14 |
### AI & Automation
|
| 15 |
-
|
| 16 |
-
- **
|
| 17 |
-
- **
|
| 18 |
-
- **
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
- **
|
| 24 |
-
- **
|
| 25 |
-
- **Knowledge Sync**: Multi-repository content synchronization
|
| 26 |
-
- **Health Monitoring**: Container health checks and alerting
|
| 27 |
|
| 28 |
## 📋 Prerequisites
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 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
|
| 75 |
-
|
|
|
|
|
|
|
| 76 |
```
|
| 77 |
|
| 78 |
### 2. Local Development
|
| 79 |
-
|
| 80 |
```bash
|
| 81 |
# Start the full stack locally
|
| 82 |
-
docker
|
| 83 |
|
| 84 |
# Check service status
|
| 85 |
-
docker
|
| 86 |
|
| 87 |
# View logs
|
| 88 |
-
docker
|
| 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 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
- Knowledge base content
|
| 238 |
-
- Vector embeddings
|
| 239 |
|
| 240 |
-
###
|
|
|
|
| 241 |
|
| 242 |
-
|
| 243 |
-
# Create full backup
|
| 244 |
-
./scripts/backup.sh custom-backup-name
|
| 245 |
|
| 246 |
-
|
| 247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
|
| 249 |
-
#
|
| 250 |
-
./scripts/restore.sh
|
| 251 |
-
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
|
| 253 |
-
|
|
|
|
| 254 |
|
| 255 |
-
- **
|
| 256 |
-
- **
|
| 257 |
-
- **
|
|
|
|
| 258 |
|
| 259 |
## 🔧 Maintenance
|
| 260 |
|
| 261 |
### Health Monitoring
|
| 262 |
-
|
| 263 |
```bash
|
| 264 |
-
# Check container health
|
| 265 |
-
docker
|
| 266 |
|
| 267 |
# View application logs
|
| 268 |
-
docker
|
| 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 |
-
|
| 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 |
-
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
| 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://
|
| 18 |
|
| 19 |
-
# ===== DATABASE CONFIGURATION =====
|
|
|
|
| 20 |
DB_TYPE=postgresdb
|
| 21 |
-
DB_POSTGRESDB_HOST=
|
| 22 |
DB_POSTGRESDB_PORT=6543
|
| 23 |
DB_POSTGRESDB_DATABASE=postgres
|
| 24 |
-
DB_POSTGRESDB_USER=postgres
|
| 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 |
-
|
| 33 |
HF_TOKEN=
|
| 34 |
-
HF_SPACE_NAME=
|
| 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 |
-
|
| 46 |
-
|
|
|
|
|
|
|
| 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 |
-
|
| 57 |
-
|
| 58 |
-
KB_PATH_MIDJOURNEY=projects/midjorney-prompt
|
| 59 |
|
| 60 |
# ===== MONITORING AND LOGGING =====
|
| 61 |
-
|
| 62 |
-
N8N_METRICS=true
|
| 63 |
-
SENTRY_DSN=your-sentry-dsn (optional)
|
| 64 |
|
| 65 |
# ===== BACKUP CONFIGURATION =====
|
| 66 |
-
|
| 67 |
-
|
| 68 |
BACKUP_ENCRYPTION_PASSWORD=
|
| 69 |
|
| 70 |
# ===== SECURITY =====
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
| 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}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
echo "==> Done.
|
|
|
|
| 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 |
-
: "${
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 {
|
| 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 |
-
|
| 34 |
} else {
|
| 35 |
console.log('Pulling KB repo...');
|
| 36 |
-
|
| 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('
|
| 50 |
-
.upsert({ path: pth, title, content, hash }, { onConflict: 'path' })
|
| 51 |
-
.select()
|
| 52 |
.single();
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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('
|
| 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 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
}
|
| 91 |
}
|
| 92 |
-
console.log(
|
|
|
|
|
|
|
|
|
|
| 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"
|
| 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
|
| 58 |
-
run_test "Dockerfile syntax" "
|
| 59 |
-
run_test "Docker Compose syntax" "docker
|
| 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
|
| 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
|
| 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
|
| 139 |
sleep 30
|
| 140 |
|
| 141 |
-
run_test "n8n health endpoint" "curl -f http://localhost:
|
| 142 |
-
run_test "Vector store endpoint" "curl -f http://localhost:8000/api/v1/heartbeat"
|
| 143 |
|
| 144 |
# Cleanup
|
| 145 |
-
docker
|
| 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 |
+
[0;32m[INFO][0m 🧪 Starting n8n Infrastructure Test Suite
|
| 2 |
+
================================================
|
| 3 |
+
[0;32m[INFO][0m Testing Docker configuration...
|