temproary docs uplaoded
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# Migration Notes
|
||||
|
||||
## Purpose
|
||||
Track significant schema or data migrations, with references to the scripts present in the repo that have been used to adjust data or structure.
|
||||
|
||||
## Code Locations (exact paths)
|
||||
- Migration/utility scripts (repo root `backend/`):
|
||||
- `verify_migrations.py`, `verify_status_fixes.py`, `verify_taxonomy.py`
|
||||
- `fix_*` scripts (e.g., `fix_cluster_status.py`, `fix_content_types.py`, `fix_integration_site_url.py`, `fix_sync.py`, `fix_taxonomy_relationships.py`)
|
||||
- `rename_fields_migration.sql`
|
||||
- `inject_test_data.py`, `sync_idea_status.py`, `check_recent_keywords.py`, `check_api_response.py`, `diagnose_generate_content.py`
|
||||
- Django migrations: `backend/igny8_core/**/migrations/` (per app)
|
||||
|
||||
## High-Level Responsibilities
|
||||
- Capture when ad-hoc fixes or manual SQL were required so future migrations can account for existing state.
|
||||
- Provide guidance on verifying migrations after code changes.
|
||||
|
||||
## Detailed Behavior
|
||||
- Python fix/verify scripts operate against live DBs to patch or validate data (names indicate target domain: clusters/content/integration/taxonomy).
|
||||
- `rename_fields_migration.sql` suggests a manual SQL rename was performed; ensure corresponding Django migration exists or is applied.
|
||||
- `verify_*` scripts check consistency after migrations or data changes.
|
||||
- These scripts are not automatically executed; they are run manually as needed.
|
||||
|
||||
## Execution Flow (Recommended)
|
||||
- Prefer standard Django migrations first: `python manage.py makemigrations && python manage.py migrate`.
|
||||
- For data issues covered by fix scripts:
|
||||
- Review script purpose and run in controlled environment (staging) before production.
|
||||
- Take DB backup before executing manual SQL or fix scripts.
|
||||
- After applying migrations/fixes, run verify scripts to confirm expected state.
|
||||
|
||||
## Cross-Module Interactions
|
||||
- Scripts touch planner/writer/integration data; impacts automation and billing indirectly if content/status changes alter usage.
|
||||
|
||||
## State Transitions (if applicable)
|
||||
- DB schema changes via migrations; data patches via scripts.
|
||||
|
||||
## Error Handling
|
||||
- Scripts log/print outputs; failures will surface during execution; no centralized handler.
|
||||
|
||||
## Tenancy Rules
|
||||
- All scripts should respect account/site scoping; review code before running to ensure filters exist or add them.
|
||||
|
||||
## Billing Rules (if applicable)
|
||||
- None directly; data corrections may affect content/automation counts but not credit logs.
|
||||
|
||||
## Background Tasks / Schedulers (if applicable)
|
||||
- None; scripts are on-demand.
|
||||
|
||||
## Key Design Considerations
|
||||
- Keep fix/verify scripts version-controlled but treat them as one-off tools; remove or archive obsolete scripts.
|
||||
- Ensure Django migrations are the source of truth for schema; manual SQL should be mirrored in migrations.
|
||||
|
||||
## How Developers Should Work With This Module
|
||||
- Before running any fix/verify script, read it and constrain to target account/site if possible.
|
||||
- Add notes here when new manual interventions occur, including date/purpose and scripts used.
|
||||
|
||||
## Recent Hardening (Dec 2025)
|
||||
- Throttling bypass for authenticated users to prevent user-facing 429s.
|
||||
- AI keys fallback: OpenAI/Runware pulled from system account (`aws-admin`/`default-account`/`default`) or Django settings if tenant key absent.
|
||||
- Integration settings restricted to system account or developer (`IsSystemAccountOrDeveloper` backend guard, `AdminGuard` frontend).
|
||||
- DRF default permissions tightened to authenticated + tenant access (`IsAuthenticatedAndActive`, `HasTenantAccess`); public endpoints must override explicitly (e.g., AuthViewSet).
|
||||
@@ -0,0 +1,303 @@
|
||||
# DevOps Operations Guide
|
||||
|
||||
**Purpose:** Complete operational procedures for managing IGNY8 in production
|
||||
**Version:** 1.0
|
||||
**Last Updated:** January 20, 2026
|
||||
|
||||
---
|
||||
|
||||
## 📋 Executive Summary
|
||||
|
||||
This document provides a complete structure for:
|
||||
1. **Automated Backups** - Regular database + config backups
|
||||
2. **Environment Management** - Dev vs Staging vs Production
|
||||
3. **Health Monitoring** - Automated health checks & alerts
|
||||
4. **Disaster Recovery** - Quick recovery procedures
|
||||
5. **Change Management** - Safe deployment workflow
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Directory Structure (To Be Implemented)
|
||||
|
||||
```
|
||||
/data/
|
||||
├── app/
|
||||
│ └── igny8/ # Application code
|
||||
│ ├── docker-compose.app.yml # Production compose ✅
|
||||
│ ├── docker-compose.staging.yml # Staging compose ⚠️ TO CREATE
|
||||
│ ├── .env # Production env
|
||||
│ ├── .env.staging # Staging env ⚠️ TO CREATE
|
||||
│ └── scripts/
|
||||
│ └── ops/ # ⚠️ TO CREATE
|
||||
│ ├── backup-db.sh # Database backup
|
||||
│ ├── backup-full.sh # Full backup (db + code + config)
|
||||
│ ├── restore-db.sh # Database restore
|
||||
│ ├── deploy-staging.sh # Deploy to staging
|
||||
│ ├── deploy-production.sh# Deploy to production
|
||||
│ ├── rollback.sh # Rollback deployment
|
||||
│ ├── health-check.sh # System health check
|
||||
│ ├── sync-prod-to-staging.sh # Sync data
|
||||
│ └── log-rotate.sh # Log rotation
|
||||
│
|
||||
├── backups/ # Backup storage
|
||||
│ ├── daily/ # Daily automated backups
|
||||
│ │ └── YYYYMMDD/
|
||||
│ │ ├── db_igny8_YYYYMMDD_HHMMSS.sql.gz
|
||||
│ │ └── config_YYYYMMDD.tar.gz
|
||||
│ ├── weekly/ # Weekly backups (kept 4 weeks)
|
||||
│ ├── monthly/ # Monthly backups (kept 12 months)
|
||||
│ └── pre-deploy/ # Pre-deployment snapshots
|
||||
│ └── YYYYMMDD_HHMMSS/
|
||||
│
|
||||
├── logs/ # Centralized logs
|
||||
│ ├── production/
|
||||
│ │ ├── backend.log
|
||||
│ │ ├── celery-worker.log
|
||||
│ │ ├── celery-beat.log
|
||||
│ │ └── access.log
|
||||
│ ├── staging/
|
||||
│ └── caddy/
|
||||
│
|
||||
└── stack/ # Infrastructure stack
|
||||
└── igny8-stack/ # (Future - not yet separated)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Automated Backup System
|
||||
|
||||
### Backup Strategy
|
||||
|
||||
| Type | Frequency | Retention | Content |
|
||||
|------|-----------|-----------|---------|
|
||||
| **Daily** | 1:00 AM | 7 days | Database + configs |
|
||||
| **Weekly** | Sunday 2:00 AM | 4 weeks | Full backup |
|
||||
| **Monthly** | 1st of month | 12 months | Full backup |
|
||||
| **Pre-Deploy** | Before each deploy | 5 most recent | Database snapshot |
|
||||
|
||||
### Cron Schedule
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/igny8-backup
|
||||
|
||||
# Daily database backup at 1:00 AM
|
||||
0 1 * * * root /data/app/igny8/scripts/ops/backup-db.sh daily >> /data/logs/backup.log 2>&1
|
||||
|
||||
# Weekly full backup on Sunday at 2:00 AM
|
||||
0 2 * * 0 root /data/app/igny8/scripts/ops/backup-full.sh weekly >> /data/logs/backup.log 2>&1
|
||||
|
||||
# Monthly full backup on 1st at 3:00 AM
|
||||
0 3 1 * * root /data/app/igny8/scripts/ops/backup-full.sh monthly >> /data/logs/backup.log 2>&1
|
||||
|
||||
# Health check every 5 minutes
|
||||
*/5 * * * * root /data/app/igny8/scripts/ops/health-check.sh >> /data/logs/health.log 2>&1
|
||||
|
||||
# Log rotation daily at midnight
|
||||
0 0 * * * root /data/app/igny8/scripts/ops/log-rotate.sh >> /data/logs/maintenance.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Environment Management
|
||||
|
||||
### Environment Comparison
|
||||
|
||||
| Aspect | Development | Staging | Production |
|
||||
|--------|-------------|---------|------------|
|
||||
| **Domain** | localhost:5173 | staging.igny8.com | app.igny8.com |
|
||||
| **API** | localhost:8010 | staging-api.igny8.com | api.igny8.com |
|
||||
| **Database** | igny8_dev_db | igny8_staging_db | igny8_db |
|
||||
| **Redis DB** | 2 | 1 | 0 |
|
||||
| **Debug** | True | False | False |
|
||||
| **AI Keys** | Test/Limited | Test/Limited | Production |
|
||||
| **Payments** | Sandbox | Sandbox | Live |
|
||||
| **Compose File** | docker-compose.dev.yml | docker-compose.staging.yml | docker-compose.app.yml |
|
||||
| **Project Name** | igny8-dev | igny8-staging | igny8-app |
|
||||
|
||||
### Port Allocation
|
||||
|
||||
| Service | Dev | Staging | Production |
|
||||
|---------|-----|---------|------------|
|
||||
| Backend | 8010 | 8012 | 8011 |
|
||||
| Frontend | 5173 | 8024 | 8021 |
|
||||
| Marketing | 5174 | 8026 | 8023 |
|
||||
| Flower | - | 5556 | 5555 |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Deployment Workflow
|
||||
|
||||
### Safe Deployment Checklist
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DEPLOYMENT CHECKLIST │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ PRE-DEPLOYMENT │
|
||||
│ □ All tests passing on staging? │
|
||||
│ □ Database migrations reviewed? │
|
||||
│ □ Backup created? │
|
||||
│ □ Rollback plan ready? │
|
||||
│ □ Team notified? │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ DEPLOYMENT │
|
||||
│ □ Create pre-deploy backup │
|
||||
│ □ Tag current images for rollback │
|
||||
│ □ Pull latest code │
|
||||
│ □ Build new images │
|
||||
│ □ Apply migrations │
|
||||
│ □ Restart containers │
|
||||
│ □ Verify health check │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ POST-DEPLOYMENT │
|
||||
│ □ Monitor logs for 10 minutes │
|
||||
│ □ Test critical paths (login, API, AI functions) │
|
||||
│ □ Check error rates │
|
||||
│ □ If issues → ROLLBACK │
|
||||
│ □ Update changelog │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Git Branch Strategy
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
│ main │ ← Production deployments
|
||||
└────▲─────┘
|
||||
│ merge (after staging approval)
|
||||
┌────┴─────┐
|
||||
│ staging │ ← Staging deployments
|
||||
└────▲─────┘
|
||||
│ merge
|
||||
┌────────────────┼────────────────┐
|
||||
│ │ │
|
||||
┌───────┴───────┐ ┌──────┴──────┐ ┌───────┴───────┐
|
||||
│feature/xyz │ │feature/abc │ │hotfix/urgent │
|
||||
└───────────────┘ └─────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏥 Health Monitoring
|
||||
|
||||
### Health Check Endpoints
|
||||
|
||||
| Endpoint | Purpose | Expected Response |
|
||||
|----------|---------|-------------------|
|
||||
| `/api/v1/system/status/` | Overall system status | `{"status": "healthy"}` |
|
||||
| `/api/v1/system/health/` | Detailed component health | JSON with all components |
|
||||
|
||||
### Monitoring Targets
|
||||
|
||||
1. **Backend API** - Response time < 500ms
|
||||
2. **Database** - Connection pool healthy
|
||||
3. **Redis** - Connection alive
|
||||
4. **Celery Workers** - Queue length < 100
|
||||
5. **Celery Beat** - Scheduler running
|
||||
6. **Disk Space** - > 20% free
|
||||
7. **Memory** - < 80% used
|
||||
|
||||
### Alert Thresholds
|
||||
|
||||
| Metric | Warning | Critical |
|
||||
|--------|---------|----------|
|
||||
| API Response Time | > 1s | > 5s |
|
||||
| Error Rate | > 1% | > 5% |
|
||||
| CPU Usage | > 70% | > 90% |
|
||||
| Memory Usage | > 70% | > 90% |
|
||||
| Disk Usage | > 70% | > 90% |
|
||||
| Celery Queue | > 50 | > 200 |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Common Operations
|
||||
|
||||
### Daily Operations
|
||||
|
||||
```bash
|
||||
# Check system health
|
||||
/data/app/igny8/scripts/ops/health-check.sh
|
||||
|
||||
# View logs
|
||||
tail -f /data/logs/production/backend.log
|
||||
|
||||
# Check container status
|
||||
docker compose -f /data/app/igny8/docker-compose.app.yml -p igny8-app ps
|
||||
```
|
||||
|
||||
### Weekly Operations
|
||||
|
||||
```bash
|
||||
# Review backup status
|
||||
ls -la /data/backups/daily/
|
||||
du -sh /data/backups/*
|
||||
|
||||
# Check disk space
|
||||
df -h
|
||||
|
||||
# Review error logs
|
||||
grep -i error /data/logs/production/backend.log | tail -50
|
||||
```
|
||||
|
||||
### Emergency Procedures
|
||||
|
||||
```bash
|
||||
# Immediate rollback
|
||||
/data/app/igny8/scripts/ops/rollback.sh
|
||||
|
||||
# Emergency restart
|
||||
docker compose -f /data/app/igny8/docker-compose.app.yml -p igny8-app restart
|
||||
|
||||
# Emergency database restore
|
||||
/data/app/igny8/scripts/ops/restore-db.sh /data/backups/latest.sql.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 What's Missing (Action Items)
|
||||
|
||||
### Priority 1 - Critical (Before Go-Live)
|
||||
|
||||
| Item | Status | Action |
|
||||
|------|--------|--------|
|
||||
| `docker-compose.staging.yml` | ❌ Missing | Create from documentation |
|
||||
| `.env.staging` | ❌ Missing | Create from example |
|
||||
| Deployment scripts | ❌ Missing | Create all ops scripts |
|
||||
| Automated backup cron | ❌ Missing | Set up cron jobs |
|
||||
| Pre-deploy backup | ❌ Missing | Add to deploy script |
|
||||
|
||||
### Priority 2 - Important (First Week)
|
||||
|
||||
| Item | Status | Action |
|
||||
|------|--------|--------|
|
||||
| Health check automation | ❌ Missing | Create monitoring |
|
||||
| Log rotation | ❌ Missing | Set up logrotate |
|
||||
| Staging DNS | ❌ Unknown | Configure if needed |
|
||||
| Caddyfile staging routes | ❌ Unknown | Add staging domains |
|
||||
|
||||
### Priority 3 - Nice to Have (First Month)
|
||||
|
||||
| Item | Status | Action |
|
||||
|------|--------|--------|
|
||||
| CI/CD pipeline | ❌ Not set | Optional automation |
|
||||
| External monitoring | ❌ Not set | UptimeRobot/Datadog |
|
||||
| Alerting system | ❌ Not set | Email/Slack alerts |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Create ops scripts directory**: `/data/app/igny8/scripts/ops/`
|
||||
2. **Create all deployment scripts** (see STAGING-SETUP-GUIDE.md)
|
||||
3. **Create staging compose file** (copy from documentation)
|
||||
4. **Set up automated backups**
|
||||
5. **Test complete deployment cycle** on staging
|
||||
6. **Go live with confidence**
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [STAGING-SETUP-GUIDE.md](final-clean-best-deployment-plan/STAGING-SETUP-GUIDE.md) - Detailed staging setup
|
||||
- [TWO-REPO-ARCHITECTURE.md](final-clean-best-deployment-plan/TWO-REPO-ARCHITECTURE.md) - Architecture overview
|
||||
- [INFRASTRUCTURE-STACK.md](final-clean-best-deployment-plan/INFRASTRUCTURE-STACK.md) - Stack details
|
||||
@@ -0,0 +1,74 @@
|
||||
# Deployment Guide
|
||||
|
||||
## Purpose
|
||||
Describe how to deploy the IGNY8 stack using the provided Dockerfiles and `docker-compose.app.yml`, including service wiring and required external dependencies.
|
||||
|
||||
## Code Locations (exact paths)
|
||||
- App compose stack: `docker-compose.app.yml`
|
||||
- Backend image: `backend/Dockerfile`
|
||||
- Frontend image: `frontend/Dockerfile`
|
||||
- Backend settings/env: `backend/igny8_core/settings.py`
|
||||
|
||||
## High-Level Responsibilities
|
||||
- Build images for backend, frontend, marketing, and sites renderer.
|
||||
- Bring up the app stack (backend, frontend, marketing, sites, Celery worker, Celery beat) on the shared external network.
|
||||
- Rely on external infra services (Postgres, Redis) defined outside this repo (referenced in compose comments).
|
||||
|
||||
## Detailed Behavior
|
||||
- Backend container:
|
||||
- Image `igny8-backend:latest` from `backend/Dockerfile` (Python 3.11 slim, installs `requirements.txt`, runs Gunicorn on 8010).
|
||||
- Mounted volumes: `/data/app/igny8/backend` (code), `/data/app/igny8` (shared), `/data/app/logs` (logs).
|
||||
- Env vars for DB/Redis and security flags (USE_SECURE_COOKIES/PROXY, DEBUG, SECRET_KEY).
|
||||
- Healthcheck hits `http://localhost:8010/api/v1/system/status/`.
|
||||
- Frontend container:
|
||||
- Image `igny8-frontend-dev:latest` from `frontend/Dockerfile.dev` (built separately; serves via Vite dev server on 5173 exposed as 8021).
|
||||
- Env `VITE_BACKEND_URL`.
|
||||
- Marketing dev and Sites renderer containers: images `igny8-marketing-dev:latest` and `igny8-sites-dev:latest`, ports 8023→5174 and 8024→5176; Sites mounts `/data/app/igny8/sites` and `/data/app/sites-data`.
|
||||
- Celery worker/beat:
|
||||
- Use `igny8-backend:latest`, commands `celery -A igny8_core worker` and `celery -A igny8_core beat`.
|
||||
- Share same DB/Redis env and code volumes.
|
||||
- Network: `igny8_net` marked `external: true`; compose expects Postgres and Redis running in another stack (`/data/app/docker-compose.yml` per comment).
|
||||
- Ports: backend 8011→8010, frontend 8021→5173, marketing 8023→5174, sites 8024→5176.
|
||||
|
||||
## Data Structures / Models Involved (no code)
|
||||
- Not model-specific; relies on runtime env (Postgres DB, Redis broker).
|
||||
|
||||
## Execution Flow
|
||||
- Build images:
|
||||
- `docker build -t igny8-backend:latest -f backend/Dockerfile backend`
|
||||
- `docker build -t igny8-frontend-dev:latest -f frontend/Dockerfile.dev frontend`
|
||||
- `docker build -t igny8-marketing-dev:latest -f frontend/Dockerfile.marketing.dev frontend`
|
||||
- `docker build -t igny8-sites-dev:latest -f sites/Dockerfile.dev sites`
|
||||
- Ensure external infra stack (Postgres, Redis, network `igny8_net`) is up.
|
||||
- Run: `docker compose -f docker-compose.app.yml -p igny8-app up -d`.
|
||||
- Healthcheck will mark backend healthy before frontend depends_on proceeds.
|
||||
|
||||
## Cross-Module Interactions
|
||||
- Backend depends on Postgres/Redis; Celery worker/beat rely on same env to process automation/AI tasks.
|
||||
- Frontend depends on backend health; sites renderer reads deployed sites from `/data/app/sites-data`.
|
||||
|
||||
## State Transitions (if applicable)
|
||||
- Container lifecycle managed by Docker restart policy (`restart: always`).
|
||||
|
||||
## Error Handling
|
||||
- Backend healthcheck fails if status endpoint not reachable; container marked unhealthy causing depends_on wait.
|
||||
- Gunicorn exit surfaces via Docker logs; no auto-restart beyond Docker restart policy.
|
||||
|
||||
## Tenancy Rules
|
||||
- Enforced in application layer via middleware; deployment does not alter tenancy.
|
||||
|
||||
## Billing Rules (if applicable)
|
||||
- None at deployment layer.
|
||||
|
||||
## Background Tasks / Schedulers (if applicable)
|
||||
- Celery beat runs schedules (e.g., automation scheduler) using same image and env.
|
||||
|
||||
## Key Design Considerations
|
||||
- Compose uses images (not builds) to avoid accidental rebuilds in Portainer; images must exist beforehand.
|
||||
- External network requirement means infra stack must pre-create `igny8_net` and services.
|
||||
- Backend served by Gunicorn with 4 workers per compose command; adjust via compose if scaling container horizontally.
|
||||
|
||||
## How Developers Should Work With This Module
|
||||
- When changing env vars, update `docker-compose.app.yml` and keep parity with `settings.py`.
|
||||
- For new services (e.g., monitoring), add to compose and attach to `igny8_net`.
|
||||
- Keep healthcheck endpoint stable (`/api/v1/system/status/`) or update compose accordingly.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Environment Setup
|
||||
|
||||
## Purpose
|
||||
Outline required runtime dependencies, environment variables, and local setup steps derived from the codebase configuration.
|
||||
|
||||
## Code Locations (exact paths)
|
||||
- Django settings/env: `backend/igny8_core/settings.py`
|
||||
- Backend dependencies: `backend/requirements.txt`
|
||||
- Backend image provisioning: `backend/Dockerfile`
|
||||
- Frontend env/build: `frontend/Dockerfile`, `frontend/package.json`, `frontend/vite.config.ts`
|
||||
- Compose stack env: `docker-compose.app.yml`
|
||||
|
||||
## High-Level Responsibilities
|
||||
- Provide prerequisites for backend (Python 3.11, Postgres, Redis) and frontend (Node 18).
|
||||
- Enumerate environment variables consumed by backend and compose files.
|
||||
- Describe local or containerized setup flows.
|
||||
|
||||
## Detailed Behavior
|
||||
- Backend settings require:
|
||||
- `SECRET_KEY`, `DEBUG`, `USE_SECURE_COOKIES`, `USE_SECURE_PROXY_HEADER`.
|
||||
- Database: `DATABASE_URL` or `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_PORT`; falls back to SQLite in DEBUG if none provided.
|
||||
- Redis/Celery: `CELERY_BROKER_URL`, `CELERY_RESULT_BACKEND` default to `redis://{REDIS_HOST}:{REDIS_PORT}/0`.
|
||||
- JWT: `JWT_SECRET_KEY`, expiry defaults (15m access, 30d refresh).
|
||||
- CORS: allowed origins include local ports (5173/5174/5176/8024) and `app.igny8.com`.
|
||||
- Stripe/PayPal keys optional (`STRIPE_PUBLIC_KEY`, `STRIPE_SECRET_KEY`, `PAYPAL_*`).
|
||||
- Backend Dockerfile installs system deps (gcc, libpq-dev) and pip installs `requirements.txt`; runs `collectstatic` (best-effort).
|
||||
- Frontend expects `VITE_BACKEND_URL` (compose sets to `https://api.igny8.com/api`); build via `npm install` then `npm run build` (Dockerfile).
|
||||
- Compose injects DB/Redis env to backend/worker/beat and secure cookie/proxy flags for production use.
|
||||
|
||||
## Data Structures / Models Involved (no code)
|
||||
- Not model-specific; environment affects DB connections, auth, CORS, Celery, billing keys.
|
||||
|
||||
## Execution Flow
|
||||
- Local (backend):
|
||||
- `python -m venv .venv && source .venv/bin/activate`
|
||||
- `pip install -r backend/requirements.txt`
|
||||
- Set env vars (DB/REDIS/JWT/CORS/SECRET_KEY).
|
||||
- `python backend/manage.py migrate` then `python backend/manage.py runserver 8010`.
|
||||
- Local (frontend):
|
||||
- `npm install` in `frontend/`
|
||||
- Set `VITE_BACKEND_URL`
|
||||
- `npm run dev -- --host --port 5173`
|
||||
- Containerized:
|
||||
- Build images per Dockerfiles; run `docker compose -f docker-compose.app.yml up -d` with external Postgres/Redis and network `igny8_net`.
|
||||
|
||||
## Cross-Module Interactions
|
||||
- Celery uses same Redis host/port as defined in env; automation tasks rely on this.
|
||||
- CORS/secure cookie flags must align with frontend host to allow auth.
|
||||
|
||||
## State Transitions (if applicable)
|
||||
- `DEBUG` toggles throttling bypass (`IGNY8_DEBUG_THROTTLE`) and SQLite fallback.
|
||||
|
||||
## Error Handling
|
||||
- Missing DB env → falls back to SQLite in DEBUG; in prod must set Postgres vars.
|
||||
- Healthcheck in compose will fail if env misconfigured and backend cannot start.
|
||||
|
||||
## Tenancy Rules
|
||||
- Unchanged by env; account context enforced in middleware once app runs.
|
||||
|
||||
## Billing Rules (if applicable)
|
||||
- Stripe/PayPal keys optional; without them payment flows are disabled/pending.
|
||||
|
||||
## Background Tasks / Schedulers (if applicable)
|
||||
- Celery broker/backend must be reachable; worker/beat require the same env set.
|
||||
|
||||
## Key Design Considerations
|
||||
- Prefer Postgres in all shared/test/prod; SQLite only for local development.
|
||||
- Keep SECRET_KEY/JWT keys distinct and secret in production.
|
||||
|
||||
## How Developers Should Work With This Module
|
||||
- Add new env variables in `settings.py` with safe defaults; document in this file.
|
||||
- Mirror envs in compose and deployment systems (Portainer/CI) to avoid drift.
|
||||
@@ -0,0 +1,974 @@
|
||||
# WordPress Integration & Publishing Flow - Complete Technical Documentation
|
||||
|
||||
**Last Updated:** January 20, 2026
|
||||
**Version:** 1.8.4
|
||||
**Status:** Production Active
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [System Overview](#1-system-overview)
|
||||
2. [Integration Setup Flow](#2-integration-setup-flow)
|
||||
3. [Manual Publishing Flow](#3-manual-publishing-flow)
|
||||
4. [Automation Publishing Flow](#4-automation-publishing-flow)
|
||||
5. [Webhook Sync Flow (WordPress → IGNY8)](#5-webhook-sync-flow-wordpress--igny8)
|
||||
6. [Metadata Sync Flow](#6-metadata-sync-flow)
|
||||
7. [Data Models & Storage](#7-data-models--storage)
|
||||
8. [Plugin Distribution System](#8-plugin-distribution-system)
|
||||
9. [Current Implementation](#9-current-implementation)
|
||||
10. [Flow Diagrams](#10-flow-diagrams)
|
||||
|
||||
---
|
||||
|
||||
## 1. System Overview
|
||||
|
||||
### Architecture Summary
|
||||
|
||||
IGNY8 integrates with WordPress sites through a **custom WordPress plugin** (`igny8-wp-bridge`) that:
|
||||
- Receives content from IGNY8 via a custom REST endpoint (`/wp-json/igny8/v1/publish`)
|
||||
- Sends status updates back to IGNY8 via webhooks
|
||||
- **Authenticates using API key ONLY** (stored in Site.wp_api_key - single source of truth)
|
||||
- Auto-updates via IGNY8 plugin distribution system (v1.7.0+)
|
||||
- Supports advanced template rendering with image layouts
|
||||
- **No WordPress admin credentials required** (username/password authentication deprecated)
|
||||
|
||||
### Communication Pattern
|
||||
|
||||
```
|
||||
IGNY8 App ←→ WordPress Site
|
||||
│ │
|
||||
│ HTTP POST │
|
||||
├─────────────→│ Publish content via /wp-json/igny8/v1/publish
|
||||
│ │
|
||||
│ HTTP POST │
|
||||
│←─────────────┤ Webhook status updates via /api/v1/integration/webhooks/wordpress/status/
|
||||
│ │
|
||||
│ HTTP GET │
|
||||
├─────────────→│ Check plugin updates via /wp-json/igny8/v1/check-update
|
||||
│ │
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
| Component | Location | Purpose |
|
||||
|-----------|----------|---------|
|
||||
| SiteIntegration Model | `business/integration/models.py` | Stores WordPress credentials & config |
|
||||
| SyncEvent Model | `business/integration/models.py` | Logs all sync operations |
|
||||
| Plugin Models | `plugins/models.py` | Plugin versioning and distribution |
|
||||
| Celery Task | `tasks/wordpress_publishing.py` | Background publishing worker |
|
||||
| Webhook Handler | `modules/integration/webhooks.py` | Receives WordPress status updates |
|
||||
| Frontend Form | `components/sites/WordPressIntegrationForm.tsx` | User setup UI |
|
||||
|
||||
### Recent Updates (v1.7.0)
|
||||
|
||||
**Plugin Distribution System:**
|
||||
- ✅ Automated plugin distribution and updates
|
||||
- ✅ WordPress plugin v1.3.3 with template improvements
|
||||
- ✅ Image layout fixes (square/landscape positioning)
|
||||
- ✅ Auto-update mechanism via WordPress hooks
|
||||
- ✅ Health check and monitoring endpoints
|
||||
|
||||
---
|
||||
|
||||
## 2. Integration Setup Flow
|
||||
|
||||
### 2.1 Pre-requisites (WordPress Side)
|
||||
|
||||
1. WordPress 5.6+ with REST API enabled
|
||||
2. Pretty permalinks enabled (Settings → Permalinks)
|
||||
3. IGNY8 WordPress Bridge plugin v1.3.0+ installed and activated
|
||||
4. No security plugins blocking REST API
|
||||
|
||||
### 2.2 Plugin Installation (Updated v1.7.0)
|
||||
|
||||
**Option 1: Manual Download & Install**
|
||||
- User downloads latest plugin from IGNY8 app
|
||||
- Frontend: Site Settings → WordPress Integration → Download Plugin
|
||||
- Download endpoint: `https://api.igny8.com/api/plugins/igny8-wp-bridge/download/`
|
||||
- Installs in WordPress: Plugins → Add New → Upload ZIP
|
||||
|
||||
**Option 2: Direct URL Install**
|
||||
- WordPress admin → Plugins → Add New → Upload Plugin
|
||||
- Paste ZIP URL with signed download token
|
||||
- Plugin installs and auto-registers with IGNY8
|
||||
|
||||
**Plugin Auto-Update:**
|
||||
- WordPress checks for updates every 12 hours
|
||||
- Plugin hooks into `pre_set_site_transient_update_plugins`
|
||||
- Compares current version with latest from IGNY8 API
|
||||
- Notifies admin if update available
|
||||
- Can be updated via WordPress admin (one-click)
|
||||
|
||||
### 2.3 Setup Steps (User Flow)
|
||||
|
||||
**Step 1: User navigates to Site Settings**
|
||||
- Frontend: `/sites/{id}/settings` → WordPress Integration section
|
||||
- Component: `WordPressIntegrationForm.tsx`
|
||||
|
||||
**Step 2: User clicks "Generate API Key"**
|
||||
- Frontend calls: `POST /v1/integration/integrations/generate-api-key/`
|
||||
- Body: `{ "site_id": 123 }`
|
||||
- Backend stores API key in `Site.wp_api_key` field (SINGLE source of truth)
|
||||
- Creates/updates `SiteIntegration` record with empty credentials_json
|
||||
|
||||
**Step 3: User configures WordPress plugin**
|
||||
- Configures plugin with:
|
||||
- IGNY8 API URL: `https://api.igny8.com`
|
||||
- Site API Key: (copied from IGNY8)
|
||||
- Site ID: (shown in IGNY8)
|
||||
- **Note:** No WordPress admin credentials needed
|
||||
|
||||
**Step 4: Test Connection**
|
||||
- Plugin calls: `POST https://api.igny8.com/api/v1/integration/integrations/test-connection/`
|
||||
- Headers: `Authorization: Bearer {api_key}`
|
||||
- Body: `{ "site_id": 123, "api_key": "...", "site_url": "https://..." }`
|
||||
- Backend validates API key against `Site.wp_api_key`
|
||||
- Success: SiteIntegration created with empty credentials_json, plugin registers installation
|
||||
- Failure: Error message displayed
|
||||
|
||||
### 2.4 Data Created During Setup
|
||||
|
||||
**SiteIntegration Record:**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"site_id": 123,
|
||||
"account_id": 456,
|
||||
"platform": "wordpress",
|
||||
"platform_type": "cms",
|
||||
"config_json": {
|
||||
"site_url": "https://example.com"
|
||||
},
|
||||
"credentials_json": {
|
||||
"plugin_version": "1.3.4",
|
||||
"debug_enabled": false
|
||||
},
|
||||
"is_active": true,
|
||||
"sync_enabled": true,
|
||||
"sync_status": "pending",
|
||||
"_note": "API key stored in Site.wp_api_key, not in credentials_json"
|
||||
}
|
||||
```
|
||||
|
||||
**Site Model (API Key Storage):**
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"name": "Example Site",
|
||||
"url": "https://example.com",
|
||||
"wp_api_key": "igny8_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"hosting_type": "wordpress"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2.5 Authentication Architecture (v1.3.4+)
|
||||
|
||||
### API Key as Single Source of Truth
|
||||
|
||||
**Storage:**
|
||||
- API key stored in `Site.wp_api_key` field (Django backend)
|
||||
- Plugin stores same API key in WordPress options table: `igny8_api_key`
|
||||
- SiteIntegration.credentials_json does NOT contain API key
|
||||
|
||||
**Authentication Flow (IGNY8 → WordPress):**
|
||||
```python
|
||||
# Backend: publisher_service.py
|
||||
destination_config = {
|
||||
'site_url': integration.config_json.get('site_url'),
|
||||
'api_key': integration.site.wp_api_key # From Site model
|
||||
}
|
||||
|
||||
# WordPress Adapter: wordpress_adapter.py
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
requests.post(f"{site_url}/wp-json/igny8/v1/publish", headers=headers, json=payload)
|
||||
```
|
||||
|
||||
**Authentication Flow (WordPress → IGNY8):**
|
||||
```php
|
||||
// Plugin: class-igny8-api.php
|
||||
$api_key = get_option('igny8_api_key');
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $api_key,
|
||||
'Content-Type' => 'application/json'
|
||||
);
|
||||
wp_remote_post('https://api.igny8.com/api/v1/...', array('headers' => $headers));
|
||||
```
|
||||
|
||||
**Validation (WordPress Side):**
|
||||
```php
|
||||
// Plugin: class-igny8-rest-api.php
|
||||
public function check_permission($request) {
|
||||
// Check X-IGNY8-API-KEY header
|
||||
$header_api_key = $request->get_header('x-igny8-api-key');
|
||||
|
||||
// Check Authorization Bearer header
|
||||
$auth_header = $request->get_header('Authorization');
|
||||
|
||||
$stored_api_key = get_option('igny8_api_key');
|
||||
|
||||
if (hash_equals($stored_api_key, $header_api_key) ||
|
||||
strpos($auth_header, 'Bearer ' . $stored_api_key) !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return new WP_Error('rest_forbidden', 'Invalid API key', array('status' => 401));
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecated Authentication Methods
|
||||
|
||||
**No Longer Supported (removed in v1.3.4):**
|
||||
- ❌ Username/password authentication
|
||||
- ❌ App passwords via WordPress REST API
|
||||
- ❌ OAuth/token exchange
|
||||
- ❌ Webhook signature validation (webhooks deprecated)
|
||||
- ❌ Storing API key in SiteIntegration.credentials_json
|
||||
|
||||
**Legacy Fields (do not use):**
|
||||
- `Site.wp_username` - deprecated
|
||||
- `Site.wp_app_password` - deprecated
|
||||
- `Site.wp_url` - deprecated (use SiteIntegration.config_json.site_url)
|
||||
|
||||
---
|
||||
|
||||
## 3. Manual Publishing Flow
|
||||
|
||||
### 3.1 Trigger Points
|
||||
|
||||
1. **Content Review Page** - "Publish to WordPress" button
|
||||
2. **Content Approved Page** - Publish action in context menu
|
||||
3. **Bulk Actions** - Select multiple, publish all
|
||||
|
||||
### 3.2 Detailed Flow
|
||||
|
||||
**Step 1: User clicks "Publish to WordPress"**
|
||||
- Frontend: `ContentViewSet.publish` action called
|
||||
- Endpoint: `POST /api/v1/writer/content/{id}/publish/`
|
||||
- Optional body: `{ "site_integration_id": 123 }`
|
||||
|
||||
**Step 2: Backend validates content**
|
||||
- Checks content exists and belongs to user's site
|
||||
- Checks content not already published (`external_id` must be null)
|
||||
- Finds active WordPress integration for the site
|
||||
- Error if no integration found
|
||||
|
||||
**Step 3: Optimistic status update**
|
||||
- Content status changed to `published` immediately
|
||||
- User sees success message
|
||||
- Actual WordPress publishing happens async
|
||||
|
||||
**Step 4: Celery task queued**
|
||||
- Task: `publish_content_to_wordpress.delay(content_id, site_integration_id)`
|
||||
- Task name: `igny8_core.tasks.wordpress_publishing`
|
||||
|
||||
**Step 5: Celery task execution (Background)**
|
||||
|
||||
The task performs these steps:
|
||||
|
||||
1. **Load data** - Get Content and SiteIntegration from database
|
||||
2. **Check if already published** - Skip if `external_id` exists
|
||||
3. **Generate excerpt** - Strip HTML, take first 150 chars
|
||||
4. **Load taxonomy terms** - Categories from `taxonomy_terms` M2M field, fallback to cluster name
|
||||
5. **Load tags** - From `taxonomy_terms` + primary/secondary keywords
|
||||
6. **Load images** - Featured image and gallery images, convert paths to URLs
|
||||
7. **Build payload:**
|
||||
```json
|
||||
{
|
||||
"content_id": 123,
|
||||
"title": "Post Title",
|
||||
"content_html": "<p>Full HTML content...</p>",
|
||||
"excerpt": "Short excerpt...",
|
||||
"status": "publish",
|
||||
"seo_title": "SEO Title",
|
||||
"seo_description": "Meta description",
|
||||
"primary_keyword": "main keyword",
|
||||
"secondary_keywords": ["kw1", "kw2"],
|
||||
"featured_image_url": "https://app.igny8.com/images/...",
|
||||
"gallery_images": [{ "url": "...", "alt": "", "caption": "" }],
|
||||
"categories": ["Category Name"],
|
||||
"tags": ["tag1", "tag2"]
|
||||
}
|
||||
```
|
||||
8. **Send to WordPress:**
|
||||
- URL: `{site_url}/wp-json/igny8/v1/publish`
|
||||
- Headers: `X-IGNY8-API-Key: {api_key}`
|
||||
- Method: POST
|
||||
- Timeout: 30 seconds
|
||||
|
||||
**Step 6: Process WordPress response**
|
||||
|
||||
| HTTP Code | Meaning | Action |
|
||||
|-----------|---------|--------|
|
||||
| 201 | Created | Update content with `external_id`, `external_url`, log success |
|
||||
| 409 | Already exists | Update content with existing WordPress post data |
|
||||
| 4xx/5xx | Error | Log failure, retry up to 3 times with exponential backoff |
|
||||
|
||||
**Step 7: Update IGNY8 content record**
|
||||
```python
|
||||
content.external_id = str(wp_post_id)
|
||||
content.external_url = wp_post_url
|
||||
content.status = 'published'
|
||||
content.metadata['wordpress_status'] = 'publish'
|
||||
content.save()
|
||||
```
|
||||
|
||||
**Step 8: Create SyncEvent record**
|
||||
```python
|
||||
SyncEvent.objects.create(
|
||||
integration=site_integration,
|
||||
site=content.site,
|
||||
account=content.account,
|
||||
event_type='publish',
|
||||
action='content_publish',
|
||||
description=f"Published content '{title}' to WordPress",
|
||||
success=True,
|
||||
content_id=content.id,
|
||||
external_id=external_id,
|
||||
details={...}
|
||||
)
|
||||
```
|
||||
|
||||
### 3.3 Error Handling
|
||||
|
||||
- **Timeout**: Retry after 60 seconds (first attempt), then exponentially
|
||||
- **Connection Error**: Same retry logic
|
||||
- **Max Retries**: 3 attempts total
|
||||
- **Final Failure**: SyncEvent created with `success=False`, error logged
|
||||
|
||||
---
|
||||
|
||||
## 4. Automation Publishing Flow
|
||||
|
||||
### 4.1 Automation Stage 7: Review → Published
|
||||
|
||||
Automation Stage 7 handles auto-approval and publishing:
|
||||
|
||||
**Current Implementation:**
|
||||
- Content in `review` status is changed to `published` status
|
||||
- Status change only - **NO automatic WordPress push currently implemented**
|
||||
- Lock released, automation run marked complete
|
||||
|
||||
**What DOES NOT happen automatically:**
|
||||
- No `publish_content_to_wordpress` task is triggered
|
||||
- Content sits in `published` status waiting for manual publish or scheduled task
|
||||
|
||||
### 4.2 Scheduled Publishing Task (NOT CURRENTLY SCHEDULED)
|
||||
|
||||
There exists a task `process_pending_wordpress_publications()` that:
|
||||
- Finds content with `status='published'` and `external_id=NULL`
|
||||
- Queues each item to `publish_content_to_wordpress` task
|
||||
- Processes max 50 items per run
|
||||
|
||||
**CURRENT STATUS: This task is NOT in Celery Beat schedule!**
|
||||
|
||||
Looking at `celery.py`, the beat schedule includes:
|
||||
- `check-scheduled-automations` (hourly)
|
||||
- `replenish-monthly-credits` (monthly)
|
||||
- Various maintenance tasks
|
||||
|
||||
**Missing:**
|
||||
- `process_pending_wordpress_publications` is NOT scheduled
|
||||
|
||||
### 4.3 To Enable Auto-Publishing After Automation
|
||||
|
||||
Two options:
|
||||
|
||||
**Option A: Add to Celery Beat Schedule**
|
||||
```python
|
||||
'process-pending-wordpress-publications': {
|
||||
'task': 'igny8_core.tasks.wordpress_publishing.process_pending_wordpress_publications',
|
||||
'schedule': crontab(minute='*/5'), # Every 5 minutes
|
||||
},
|
||||
```
|
||||
|
||||
**Option B: Call directly from Stage 7**
|
||||
Modify `run_stage_7()` to queue publish tasks for each approved content item.
|
||||
|
||||
---
|
||||
|
||||
## 5. Webhook Sync Flow (WordPress → IGNY8)
|
||||
|
||||
### 5.1 Purpose
|
||||
|
||||
Keeps IGNY8 in sync when content is modified directly in WordPress:
|
||||
- Post status changed (published → draft, etc.)
|
||||
- Post deleted/trashed
|
||||
- Post metadata updated
|
||||
|
||||
### 5.2 Webhook Endpoints
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `POST /api/v1/integration/webhooks/wordpress/status/` | Status changes |
|
||||
| `POST /api/v1/integration/webhooks/wordpress/metadata/` | Metadata updates |
|
||||
|
||||
### 5.3 Status Webhook Flow
|
||||
|
||||
**Step 1: WordPress plugin detects status change**
|
||||
- Hooks into `transition_post_status` action
|
||||
- Collects: post_id, content_id, new_status, post_url
|
||||
|
||||
**Step 2: Plugin sends webhook to IGNY8**
|
||||
```
|
||||
POST https://app.igny8.com/api/v1/integration/webhooks/wordpress/status/
|
||||
|
||||
Headers:
|
||||
X-IGNY8-API-KEY: {api_key}
|
||||
|
||||
Body:
|
||||
{
|
||||
"post_id": 123,
|
||||
"content_id": 456,
|
||||
"post_status": "publish",
|
||||
"post_url": "https://example.com/my-post/",
|
||||
"post_title": "My Post Title",
|
||||
"site_url": "https://example.com"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: IGNY8 validates and processes**
|
||||
|
||||
1. Extract API key from header
|
||||
2. Find Content by `content_id`
|
||||
3. Find SiteIntegration by site_url + platform
|
||||
4. Verify API key matches stored key
|
||||
5. Map WordPress status to IGNY8 status:
|
||||
| WordPress | IGNY8 |
|
||||
|-----------|-------|
|
||||
| publish | published |
|
||||
| draft | draft |
|
||||
| pending | review |
|
||||
| private | published |
|
||||
| trash | draft |
|
||||
| future | review |
|
||||
6. Update Content record:
|
||||
```python
|
||||
content.external_id = str(post_id)
|
||||
content.external_url = post_url
|
||||
content.status = mapped_status
|
||||
content.metadata['wordpress_status'] = post_status
|
||||
content.metadata['last_wp_sync'] = now
|
||||
content.save()
|
||||
```
|
||||
7. Create SyncEvent log
|
||||
|
||||
### 5.4 Metadata Webhook Flow
|
||||
|
||||
Similar to status webhook but updates `content.metadata['wp_metadata']` with:
|
||||
- Categories
|
||||
- Tags
|
||||
- Author info
|
||||
- Modified date
|
||||
|
||||
---
|
||||
|
||||
## 6. Metadata Sync Flow
|
||||
|
||||
### 6.1 Manual Sync (User-Initiated)
|
||||
|
||||
**Trigger:** User clicks "Sync Now" in Site Settings
|
||||
|
||||
**Endpoint:** `POST /api/v1/integration/integrations/{id}/sync/`
|
||||
|
||||
**What it does:**
|
||||
- Calls `SyncMetadataService.sync_wordpress_structure()`
|
||||
- Fetches from WordPress:
|
||||
- Post types and counts
|
||||
- Categories list
|
||||
- Tags list
|
||||
- Site metadata
|
||||
- Updates integration's `last_sync_at`
|
||||
- Does NOT push/pull content
|
||||
|
||||
### 6.2 Structure Update
|
||||
|
||||
**Endpoint:** `POST /api/v1/integration/integrations/{id}/update_structure/`
|
||||
|
||||
Refreshes understanding of WordPress site:
|
||||
- Available post types
|
||||
- Taxonomy structures
|
||||
- Capabilities
|
||||
|
||||
---
|
||||
|
||||
## 7. Data Models & Storage
|
||||
|
||||
### 7.1 SiteIntegration
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| id | AutoField | Primary key |
|
||||
| account | FK(Account) | Owner account |
|
||||
| site | FK(Site) | IGNY8 site (contains wp_api_key) |
|
||||
| platform | CharField | 'wordpress' |
|
||||
| platform_type | CharField | 'cms' |
|
||||
| config_json | JSONField | `{ "site_url": "https://..." }` |
|
||||
| credentials_json | JSONField | `{ "plugin_version": "1.3.4", "debug_enabled": false }` |
|
||||
| is_active | Boolean | Connection enabled |
|
||||
| sync_enabled | Boolean | Two-way sync enabled |
|
||||
| last_sync_at | DateTime | Last successful sync |
|
||||
| sync_status | CharField | pending/success/failed/syncing |
|
||||
| sync_error | TextField | Last error message |
|
||||
|
||||
**Note:** `credentials_json` no longer stores API key. API key is stored in `Site.wp_api_key` (single source of truth).
|
||||
|
||||
### 7.1a Site Model (API Key Storage)
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| account | FK(Account) | Owner account |
|
||||
| name | CharField | Site display name |
|
||||
| url | URLField | WordPress site URL |
|
||||
| wp_api_key | CharField | **API key for WordPress integration (SINGLE source of truth)** |
|
||||
| wp_url | URLField | Legacy field (deprecated) |
|
||||
| wp_username | CharField | Legacy field (deprecated) |
|
||||
| wp_app_password | CharField | Legacy field (deprecated) |
|
||||
| hosting_type | CharField | 'wordpress', 'shopify', 'igny8_sites', 'multi' |
|
||||
|
||||
### 7.2 Plugin Models
|
||||
|
||||
#### Plugin
|
||||
|
||||
Core plugin registry (platform-agnostic).
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| name | CharField | Plugin display name (e.g., "IGNY8 WordPress Bridge") |
|
||||
| slug | SlugField | URL-safe identifier (e.g., "igny8-wp-bridge") |
|
||||
| platform | CharField | Target platform ('wordpress', 'shopify', etc.) |
|
||||
| description | TextField | Plugin description |
|
||||
| author | CharField | Plugin author |
|
||||
| author_url | URLField | Author website |
|
||||
| plugin_url | URLField | Plugin homepage |
|
||||
| icon_url | URLField | Plugin icon (256x256) |
|
||||
| banner_url | URLField | Plugin banner (772x250) |
|
||||
| is_active | Boolean | Whether plugin is available for download |
|
||||
| created_at | DateTime | Record creation |
|
||||
| updated_at | DateTime | Last modified |
|
||||
|
||||
**Current WordPress Plugin:**
|
||||
- Name: "IGNY8 WordPress Bridge"
|
||||
- Slug: "igny8-wp-bridge"
|
||||
- Platform: "wordpress"
|
||||
- Description: "Connect your WordPress site to IGNY8 for AI-powered content publishing, SEO optimization, and seamless automation."
|
||||
- Author: "IGNY8 Team"
|
||||
|
||||
#### PluginVersion
|
||||
|
||||
Version tracking with distribution files.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| plugin | FK(Plugin) | Parent plugin |
|
||||
| version | CharField | Semantic version (e.g., "1.3.4") |
|
||||
| status | CharField | 'development', 'beta', 'released', 'deprecated' |
|
||||
| release_notes | TextField | Changelog/release notes |
|
||||
| file_path | CharField | Path to ZIP file in /plugins/{platform}/dist/ |
|
||||
| file_size | BigInteger | ZIP file size in bytes |
|
||||
| checksum_md5 | CharField | MD5 hash for verification |
|
||||
| checksum_sha256 | CharField | SHA256 hash for verification |
|
||||
| requires_version | CharField | Minimum platform version (e.g., WP 5.6+) |
|
||||
| tested_version | CharField | Tested up to version |
|
||||
| is_latest | Boolean | Whether this is the latest stable version |
|
||||
| download_count | Integer | Number of downloads |
|
||||
| released_at | DateTime | Public release date |
|
||||
| created_at | DateTime | Record creation |
|
||||
|
||||
**Current Latest Version (1.3.4):**
|
||||
- Status: "released"
|
||||
- File: `/plugins/wordpress/dist/igny8-wp-bridge-1.3.4.zip`
|
||||
- Requires: WordPress 5.6+
|
||||
- Tested: WordPress 6.4
|
||||
- Features: API key authentication only, template improvements, image layout fixes
|
||||
|
||||
#### PluginInstallation
|
||||
|
||||
Tracks plugin installations per site.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| site | FK(Site) | Site where plugin is installed |
|
||||
| plugin_version | FK(PluginVersion) | Installed version |
|
||||
| installed_at | DateTime | Installation timestamp |
|
||||
| last_seen | DateTime | Last health check |
|
||||
| status | CharField | 'active', 'inactive', 'error' |
|
||||
| metadata | JSONField | Installation-specific data (PHP version, WP version, etc.) |
|
||||
|
||||
#### PluginDownload
|
||||
|
||||
Download analytics.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| plugin_version | FK(PluginVersion) | Downloaded version |
|
||||
| site | FK(Site, null=True) | Site that downloaded (if authenticated) |
|
||||
| ip_address | GenericIPAddressField | Downloader IP |
|
||||
| user_agent | TextField | Browser/client info |
|
||||
| downloaded_at | DateTime | Download timestamp |
|
||||
|
||||
### 7.3 SyncEvent
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| id | AutoField | Primary key |
|
||||
| integration | FK(SiteIntegration) | Parent integration |
|
||||
| site | FK(Site) | Related site |
|
||||
| account | FK(Account) | Owner account |
|
||||
| event_type | CharField | publish/sync/error/webhook/metadata_sync |
|
||||
| action | CharField | content_publish/status_update/etc |
|
||||
| description | TextField | Human-readable event description |
|
||||
| success | Boolean | Event outcome |
|
||||
| content_id | Integer | IGNY8 content ID |
|
||||
| external_id | CharField | WordPress post ID |
|
||||
| error_message | TextField | Error details if failed |
|
||||
| details | JSONField | Additional event data |
|
||||
| duration_ms | Integer | Operation duration |
|
||||
| created_at | DateTime | Event timestamp |
|
||||
|
||||
### 7.3 Content Fields (Publishing Related)
|
||||
|
||||
| Field | Purpose |
|
||||
|-------|---------|
|
||||
| external_id | WordPress post ID (string) |
|
||||
| external_url | WordPress post URL |
|
||||
| status | IGNY8 status (draft/review/published) |
|
||||
| metadata['wordpress_status'] | WordPress status (publish/draft/etc) |
|
||||
| metadata['last_wp_sync'] | Last webhook sync timestamp |
|
||||
|
||||
---
|
||||
|
||||
## 8. Current Implementation Gaps
|
||||
|
||||
### 8.1 Missing: Scheduled Auto-Publishing
|
||||
|
||||
**Problem:** Content approved by Automation Stage 7 is not automatically pushed to WordPress.
|
||||
|
||||
**Current State:**
|
||||
- `process_pending_wordpress_publications()` task exists
|
||||
- Task is NOT in Celery Beat schedule
|
||||
- Content remains in `published` status with `external_id=NULL`
|
||||
|
||||
**Impact:** Users must manually publish each content item even after automation completes.
|
||||
|
||||
### 8.2 Missing: Pull Sync (WordPress → IGNY8 Content)
|
||||
|
||||
**Problem:** No way to import existing WordPress posts into IGNY8.
|
||||
|
||||
**Current State:**
|
||||
- Webhooks only handle status updates for content that originated from IGNY8
|
||||
- No "Import from WordPress" feature
|
||||
- No scheduled pull sync
|
||||
|
||||
### 8.3 Missing: Content Update Sync
|
||||
|
||||
**Problem:** Editing content in IGNY8 after publishing doesn't update WordPress.
|
||||
|
||||
**Current State:**
|
||||
- Only initial publish is supported
|
||||
- No "republish" or "update" functionality
|
||||
- `external_id` check prevents re-publishing
|
||||
|
||||
### 8.4 Missing: Image Upload to WordPress
|
||||
|
||||
**Problem:** Featured images are passed as URLs, not uploaded to WordPress media library.
|
||||
|
||||
**Current State:**
|
||||
- Image URL is sent in payload
|
||||
- WordPress plugin must download and create attachment
|
||||
- If plugin doesn't handle this, no featured image
|
||||
|
||||
---
|
||||
|
||||
## 8. Plugin Distribution System
|
||||
|
||||
### 8.1 Architecture (v1.7.0)
|
||||
|
||||
**Plugin Distribution Components:**
|
||||
- `Plugin` model - Multi-platform plugin registry
|
||||
- `PluginVersion` model - Version tracking with files and checksums
|
||||
- `PluginInstallation` model - Installation tracking per site
|
||||
- `PluginDownload` model - Download analytics
|
||||
|
||||
**Distribution Endpoints:**
|
||||
```
|
||||
GET /api/plugins/igny8-wp-bridge/download/ - Download latest ZIP
|
||||
POST /api/plugins/igny8-wp-bridge/check-update/ - Check for updates
|
||||
GET /api/plugins/igny8-wp-bridge/info/ - Plugin metadata
|
||||
POST /api/plugins/igny8-wp-bridge/register/ - Register installation
|
||||
POST /api/plugins/igny8-wp-bridge/health-check/ - Health monitoring
|
||||
```
|
||||
|
||||
### 8.2 Auto-Update Mechanism
|
||||
|
||||
**WordPress Side:**
|
||||
1. Plugin hooks into `pre_set_site_transient_update_plugins`
|
||||
2. Calls `/api/plugins/igny8-wp-bridge/check-update/` with current version
|
||||
3. Receives update info if newer version available
|
||||
4. WordPress displays update notification
|
||||
5. User clicks "Update Now" (or auto-update runs)
|
||||
6. WordPress downloads ZIP from `/download/` endpoint
|
||||
7. Installs and activates new version
|
||||
|
||||
**IGNY8 Side:**
|
||||
1. Developer updates plugin source code
|
||||
2. Creates new `PluginVersion` in Django admin
|
||||
3. Changes status to "released"
|
||||
4. Signal automatically builds ZIP with checksums
|
||||
5. Files stored in `/plugins/wordpress/dist/`
|
||||
6. WordPress sites can now download/update
|
||||
|
||||
### 8.3 Version History (Recent)
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|| 1.3.4 | Jan 12, 2026 | **API key authentication only** (removed username/password support), webhooks deprecated, Bearer token auth, simplified integration || 1.3.3 | Jan 10, 2026 | Template design: Square image grid fixes, landscape positioning, direct styling for images without captions |
|
||||
| 1.3.2 | Jan 9, 2026 | Template rendering improvements, image layout enhancements |
|
||||
| 1.3.1 | Jan 9, 2026 | Plugin versioning updates |
|
||||
| 1.3.0 | Jan 8, 2026 | Distribution system release, auto-update mechanism |
|
||||
|
||||
### 8.4 Security Features
|
||||
|
||||
- **Signed URLs:** Download links expire after configurable time
|
||||
- **Checksums:** MD5 and SHA256 verification
|
||||
- **Rate Limiting:** Per IP/site download limits
|
||||
- **API Authentication:** Required for sensitive operations
|
||||
- **Version Verification:** WordPress validates plugin before update
|
||||
|
||||
### 8.5 Monitoring
|
||||
|
||||
**Installation Tracking:**
|
||||
- Total installations per version
|
||||
- Active installations by site
|
||||
- Version distribution analytics
|
||||
|
||||
**Download Analytics:**
|
||||
- Download counts per version
|
||||
- Geographic distribution
|
||||
- Failed download attempts
|
||||
|
||||
**Health Checks:**
|
||||
- Plugin health status per installation
|
||||
- Error reporting from WordPress sites
|
||||
- Version compatibility tracking
|
||||
|
||||
---
|
||||
|
||||
## 9. Current Implementation
|
||||
|
||||
### 9.1 Production Status (v1.7.0)
|
||||
|
||||
**✅ Fully Operational:**
|
||||
- WordPress plugin distribution system
|
||||
- Auto-update mechanism
|
||||
- Template rendering with advanced layouts
|
||||
- Image positioning (square/landscape)
|
||||
- Content publishing (manual + automation)
|
||||
- Webhook status sync
|
||||
- API authentication
|
||||
- Health monitoring
|
||||
|
||||
**✅ Template Features (v1.3.3):**
|
||||
- Square images: Side-by-side layout (left/right aligned)
|
||||
- Landscape images: Full-width with max 1024px
|
||||
- Images appear after first paragraph in sections
|
||||
- Direct border-radius/shadow on images without captions
|
||||
- Responsive design for mobile/tablet
|
||||
|
||||
### 9.2 Known Limitations
|
||||
|
||||
**Missing Features:**
|
||||
- Bi-directional content sync (WordPress → IGNY8 editing)
|
||||
- Conflict resolution for dual edits
|
||||
- Advanced metadata sync beyond basics
|
||||
- Multi-site WordPress network support
|
||||
- Custom post type publishing
|
||||
|
||||
### 9.3 Future Enhancements
|
||||
|
||||
**Planned:**
|
||||
- Image regeneration feature (Phase 9)
|
||||
- Advanced template customization
|
||||
- Custom field mapping
|
||||
- Bulk publishing operations
|
||||
- Real-time sync notifications
|
||||
|
||||
---
|
||||
|
||||
## 10. Flow Diagrams
|
||||
|
||||
### 10.1 Integration Setup (API Key Authentication)
|
||||
|
||||
```
|
||||
┌──────────┐ ┌─────────────────┐ ┌───────────────┐
|
||||
│ User │ │ IGNY8 API │ │ WordPress │
|
||||
│ │ │ (Backend) │ │ Site │
|
||||
└────┬─────┘ └────────┬────────┘ └───────┬───────┘
|
||||
│ │ │
|
||||
│ 1. Generate API Key (Site Settings) │
|
||||
├───────────────────>│ │
|
||||
│ │ Store in Site.wp_api_key
|
||||
│<───────────────────┤ (SINGLE source) │
|
||||
│ 2. API Key: igny8_live_xxxxx │
|
||||
│ │ │
|
||||
│ 3. Download Plugin ZIP │
|
||||
├───────────────────>│ │
|
||||
│ │ GET /api/plugins/ │
|
||||
│ │ igny8-wp-bridge/ │
|
||||
│ │ download/ │
|
||||
│<───────────────────┤ │
|
||||
│ 4. igny8-wp-bridge-1.3.4.zip │
|
||||
│ │ │
|
||||
│ 5. Install & Activate Plugin──────────────┼────────>
|
||||
│ │ │
|
||||
│ 6. Enter API Key + Site ID in WP Settings─┼────────>
|
||||
│ │ │
|
||||
│ 7. Click "Test Connection" in Plugin──────┼────────>
|
||||
│ │ │
|
||||
│ │ 8. POST /api/v1/ │
|
||||
│ │ integration/ │
|
||||
│ │ integrations/ │
|
||||
│ │ test-connection/ │
|
||||
│ │<─────────────────────┤
|
||||
│ │ Headers: │
|
||||
│ │ Authorization: │
|
||||
│ │ Bearer {api_key} │
|
||||
│ │ │
|
||||
│ │ Validate against │
|
||||
│ │ Site.wp_api_key │
|
||||
│ │ │
|
||||
│ │ Create/Update │
|
||||
│ │ SiteIntegration │
|
||||
│ │ (credentials_json={})│
|
||||
│ │ │
|
||||
│ │ 9. 200 OK │
|
||||
│ ├─────────────────────>│
|
||||
│ │ {success: true} │
|
||||
│ │ │
|
||||
│ 10. Success Message in Plugin─────────────┼────────>
|
||||
│ │ │
|
||||
│ │ 11. POST /register/ │
|
||||
│ │<─────────────────────┤
|
||||
│ │ Store PluginInstallation
|
||||
│ │ │
|
||||
```
|
||||
|
||||
**Key Changes in v1.3.4:**
|
||||
- ✅ API key stored in `Site.wp_api_key` (not in SiteIntegration)
|
||||
- ✅ `credentials_json` is empty (only stores plugin_version, debug_enabled)
|
||||
- ✅ Authentication via `Authorization: Bearer {api_key}` header
|
||||
- ✅ No WordPress admin username/password needed
|
||||
- ✅ Simplified setup - single API key for all communication
|
||||
|
||||
### 10.2 Manual Publishing
|
||||
|
||||
```
|
||||
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌───────────────┐
|
||||
│ User │ │ IGNY8 API │ │ Celery │ │ WordPress │
|
||||
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └───────┬───────┘
|
||||
│ │ │ │
|
||||
│ 1. Click Publish │ │ │
|
||||
├─────────────────>│ │ │
|
||||
│ │ │ │
|
||||
│ │ 2. Validate │ │
|
||||
│ │ 3. Update status │ │
|
||||
│ │ 4. Queue task │ │
|
||||
│ ├─────────────────>│ │
|
||||
│<─────────────────┤ │ │
|
||||
│ 5. "Publishing..." │ │
|
||||
│ │ │ │
|
||||
│ │ │ 6. POST /publish │
|
||||
│ │ ├──────────────────>│
|
||||
│ │ │ │
|
||||
│ │ │<──────────────────┤
|
||||
│ │ │ 7. 201 Created │
|
||||
│ │ │ │
|
||||
│ │ 8. Update Content│ │
|
||||
│ │<─────────────────┤ │
|
||||
│ │ 9. Create SyncEvent │
|
||||
│ │ │ │
|
||||
```
|
||||
|
||||
### 10.3 Plugin Auto-Update Flow
|
||||
|
||||
```
|
||||
┌───────────────┐ ┌──────────────┐
|
||||
│ WordPress │ │ IGNY8 API │
|
||||
└───────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ 1. Check for updates (cron)
|
||||
│ POST /check-update/│
|
||||
├───────────────────>│
|
||||
│ (current: 1.3.2) │
|
||||
│ │
|
||||
│<───────────────────┤
|
||||
│ 2. Update available│
|
||||
│ (latest: 1.3.3) │
|
||||
│ │
|
||||
│ 3. User clicks │
|
||||
│ "Update Now" │
|
||||
│ │
|
||||
│ GET /download/ │
|
||||
├───────────────────>│
|
||||
│ │
|
||||
│<───────────────────┤
|
||||
│ 4. ZIP file │
|
||||
│ │
|
||||
│ 5. Install & Activate
|
||||
│ │
|
||||
│ POST /register/ │
|
||||
├───────────────────>│
|
||||
│ (new version info) │
|
||||
│ │
|
||||
│<───────────────────┤
|
||||
│ 6. Registration OK │
|
||||
│ │
|
||||
```
|
||||
|
||||
### 10.4 Webhook Status Sync
|
||||
|
||||
```
|
||||
┌───────────────┐ ┌──────────────┐
|
||||
│ WordPress │ │ IGNY8 API │
|
||||
└───────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
│ 1. User changes status in WP
|
||||
│ │
|
||||
│ 2. POST /webhooks/wordpress/status/
|
||||
├───────────────────>│
|
||||
│ │
|
||||
│ │ 3. Validate API key
|
||||
│ │ 4. Find Content
|
||||
│ │ 5. Map status
|
||||
│ │ 6. Update Content
|
||||
│ │ 7. Create SyncEvent
|
||||
│ │
|
||||
│<───────────────────┤
|
||||
│ 8. 200 OK │
|
||||
│ │
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Flow | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Integration Setup | ✅ Working | API key based |
|
||||
| Manual Publish | ✅ Working | Via Celery task |
|
||||
| Automation Publish | ⚠️ Partial | Stage 7 sets status but doesn't trigger WordPress push |
|
||||
| Webhook Status Sync | ✅ Working | WordPress → IGNY8 status updates |
|
||||
| Webhook Metadata Sync | ✅ Working | WordPress → IGNY8 metadata |
|
||||
| Scheduled Auto-Publish | ❌ Not Active | Task exists but not scheduled |
|
||||
| Content Pull Sync | ❌ Not Implemented | No import from WordPress |
|
||||
| Content Update Sync | ❌ Not Implemented | No republish capability |
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
# IGNY8 Application Repository
|
||||
|
||||
**Repository Name:** `igny8-app`
|
||||
**Purpose:** Custom application code for the IGNY8 Content AI Platform
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This repository contains ONLY the custom business logic for IGNY8. It does not contain:
|
||||
- Dockerfiles (in stack repo)
|
||||
- package.json / requirements.txt (in stack repo)
|
||||
- Vite/TypeScript configs (in stack repo)
|
||||
- Docker compose files (in stack repo)
|
||||
|
||||
---
|
||||
|
||||
## Complete Folder Structure
|
||||
|
||||
```
|
||||
igny8-app/
|
||||
│
|
||||
├── README.md # App overview
|
||||
├── CHANGELOG.md # Version history
|
||||
├── .gitignore # Git ignore rules
|
||||
├── .env.example # Environment template
|
||||
│
|
||||
├── backend/
|
||||
│ └── igny8_core/ # Django application
|
||||
│ ├── __init__.py
|
||||
│ ├── settings.py # Django settings
|
||||
│ ├── urls.py # Root URL routing
|
||||
│ ├── celery.py # Celery configuration
|
||||
│ ├── wsgi.py # WSGI entry point
|
||||
│ ├── asgi.py # ASGI entry point
|
||||
│ ├── tasks.py # Root Celery tasks
|
||||
│ │
|
||||
│ ├── auth/ # Authentication module
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── models.py # User, Account, Site, Sector, Plan
|
||||
│ │ ├── views.py # Login, register, password reset
|
||||
│ │ ├── serializers.py # DRF serializers
|
||||
│ │ ├── middleware.py # AccountContextMiddleware
|
||||
│ │ ├── urls.py # Auth URL routes
|
||||
│ │ └── migrations/ # Database migrations
|
||||
│ │
|
||||
│ ├── api/ # API infrastructure
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py # Base ViewSets (AccountModelViewSet)
|
||||
│ │ ├── authentication.py # JWT, API key auth
|
||||
│ │ ├── pagination.py # Unified pagination
|
||||
│ │ └── tests/ # API tests
|
||||
│ │
|
||||
│ ├── ai/ # AI engine
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── engine.py # AIEngine orchestrator
|
||||
│ │ ├── registry.py # Function registry
|
||||
│ │ ├── model_registry.py # AI model configuration
|
||||
│ │ ├── progress.py # Progress tracking
|
||||
│ │ └── functions/ # AI function implementations
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── auto_cluster.py
|
||||
│ │ ├── generate_ideas.py
|
||||
│ │ ├── generate_content.py
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── modules/ # Feature modules (API layer)
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── planner/ # Keywords, Clusters, Ideas
|
||||
│ │ │ ├── models.py
|
||||
│ │ │ ├── views.py
|
||||
│ │ │ ├── serializers.py
|
||||
│ │ │ ├── urls.py
|
||||
│ │ │ └── migrations/
|
||||
│ │ ├── writer/ # Tasks, Content, Images
|
||||
│ │ ├── billing/ # Credits, usage, transactions
|
||||
│ │ ├── integration/ # WordPress integration
|
||||
│ │ ├── system/ # Settings, prompts, AI config
|
||||
│ │ ├── linker/ # Internal linking
|
||||
│ │ ├── optimizer/ # Content optimization
|
||||
│ │ └── publisher/ # Publishing pipeline
|
||||
│ │
|
||||
│ ├── business/ # Business logic (services)
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── automation/ # 7-stage automation pipeline
|
||||
│ │ ├── billing/ # Credit service
|
||||
│ │ ├── content/ # Content generation
|
||||
│ │ ├── integration/ # Sync services
|
||||
│ │ ├── linking/ # Link processing
|
||||
│ │ ├── notifications/ # Notification system
|
||||
│ │ ├── optimization/ # Content optimization
|
||||
│ │ ├── planning/ # Clustering, ideas
|
||||
│ │ └── publishing/ # Publishing orchestration
|
||||
│ │
|
||||
│ ├── middleware/ # Custom middleware
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── request_id.py # X-Request-ID header
|
||||
│ │ └── resource_tracker.py # Resource tracking
|
||||
│ │
|
||||
│ ├── tasks/ # Celery background tasks
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── *.py
|
||||
│ │
|
||||
│ ├── admin/ # Django admin customization
|
||||
│ ├── common/ # Shared utilities
|
||||
│ ├── management/ # Django management commands
|
||||
│ │ └── commands/
|
||||
│ ├── utils/ # Helper functions
|
||||
│ ├── urls/ # URL routing modules
|
||||
│ ├── static/ # App static files
|
||||
│ └── templates/ # Django templates
|
||||
│
|
||||
├── frontend/
|
||||
│ └── src/ # React application
|
||||
│ ├── main.tsx # Entry point
|
||||
│ ├── App.tsx # Root component, routing
|
||||
│ ├── index.css # Global styles, Tailwind
|
||||
│ ├── vite-env.d.ts # Vite type definitions
|
||||
│ ├── svg.d.ts # SVG type definitions
|
||||
│ │
|
||||
│ ├── api/ # API client modules
|
||||
│ │ ├── linker.api.ts
|
||||
│ │ ├── optimizer.api.ts
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── services/ # Core services
|
||||
│ │ ├── api.ts # Main API service
|
||||
│ │ └── notifications.api.ts # Notification API
|
||||
│ │
|
||||
│ ├── store/ # Zustand state stores
|
||||
│ │ ├── authStore.ts # Authentication state
|
||||
│ │ ├── siteStore.ts # Active site
|
||||
│ │ ├── sectorStore.ts # Active sector
|
||||
│ │ ├── billingStore.ts # Billing state
|
||||
│ │ ├── moduleStore.ts # Module enable/disable
|
||||
│ │ ├── notificationStore.ts # Notifications
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── pages/ # Route pages
|
||||
│ │ ├── Dashboard/
|
||||
│ │ ├── Planner/
|
||||
│ │ ├── Writer/
|
||||
│ │ ├── Automation/
|
||||
│ │ ├── Linker/
|
||||
│ │ ├── Optimizer/
|
||||
│ │ ├── Settings/
|
||||
│ │ ├── Billing/
|
||||
│ │ └── Auth/
|
||||
│ │
|
||||
│ ├── components/ # Reusable components
|
||||
│ │ ├── common/ # Shared UI components
|
||||
│ │ ├── dashboard/ # Dashboard widgets
|
||||
│ │ ├── header/ # Header components
|
||||
│ │ └── shared/ # Cross-feature components
|
||||
│ │
|
||||
│ ├── layout/ # Layout components
|
||||
│ │ ├── AppLayout.tsx
|
||||
│ │ ├── AppHeader.tsx
|
||||
│ │ └── AppSidebar.tsx
|
||||
│ │
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ ├── context/ # React contexts
|
||||
│ ├── config/ # App configuration
|
||||
│ ├── icons/ # Icon components
|
||||
│ ├── styles/ # CSS modules/styles
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── types/ # TypeScript types
|
||||
│ ├── templates/ # Content templates
|
||||
│ ├── modules/ # Feature modules
|
||||
│ ├── marketing/ # Marketing site
|
||||
│ │ ├── index.tsx
|
||||
│ │ ├── MarketingApp.tsx
|
||||
│ │ ├── config/
|
||||
│ │ ├── components/
|
||||
│ │ ├── layout/
|
||||
│ │ ├── pages/
|
||||
│ │ ├── images/
|
||||
│ │ └── styles/
|
||||
│ │
|
||||
│ └── __tests__/ # Test files
|
||||
│
|
||||
├── public/ # Public static assets
|
||||
│ ├── favicon.ico
|
||||
│ ├── logo.svg
|
||||
│ └── images/
|
||||
│
|
||||
└── docs/ # Documentation
|
||||
├── 00-SYSTEM/
|
||||
│ └── ARCHITECTURE.md
|
||||
├── 10-MODULES/
|
||||
├── 20-API/
|
||||
├── 30-FRONTEND/
|
||||
├── 40-WORKFLOWS/
|
||||
├── 50-DEPLOYMENT/
|
||||
│ ├── TWO-REPO-ARCHITECTURE.md
|
||||
│ ├── INFRASTRUCTURE-STACK.md
|
||||
│ ├── IGNY8-APP-STRUCTURE.md # This file
|
||||
│ ├── DOCKER-DEPLOYMENT.md
|
||||
│ └── ENVIRONMENT-SETUP.md
|
||||
├── 90-REFERENCE/
|
||||
└── plans/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment to New Server
|
||||
|
||||
### Prerequisites
|
||||
- Stack already installed (see INFRASTRUCTURE-STACK.md)
|
||||
- Server has `/data/stack/igny8-stack/` ready
|
||||
- Docker network `igny8_net` exists
|
||||
|
||||
### Step-by-Step Deployment
|
||||
|
||||
```
|
||||
1. Copy app code to server
|
||||
|
||||
Option A: Git clone
|
||||
cd /data/app
|
||||
git clone https://github.com/yourorg/igny8-app.git igny8
|
||||
|
||||
Option B: Rsync from existing server
|
||||
rsync -avz --exclude='.git' \
|
||||
--exclude='node_modules' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='staticfiles' \
|
||||
--exclude='dist' \
|
||||
old-server:/data/app/igny8/ /data/app/igny8/
|
||||
|
||||
2. Create symlinks to stack
|
||||
cd /data/stack/igny8-stack
|
||||
./scripts/link-app.sh igny8
|
||||
|
||||
3. Configure environment
|
||||
cd /data/app/igny8
|
||||
cp .env.example .env
|
||||
nano .env # Set your secrets
|
||||
|
||||
4. Install frontend dependencies
|
||||
docker exec igny8_frontend npm install
|
||||
|
||||
5. Run database migrations
|
||||
docker exec igny8_backend python manage.py migrate
|
||||
|
||||
6. Create superuser (first time only)
|
||||
docker exec -it igny8_backend python manage.py createsuperuser
|
||||
|
||||
7. Collect static files
|
||||
docker exec igny8_backend python manage.py collectstatic --noinput
|
||||
|
||||
8. Start all services
|
||||
docker compose -f docker-compose.app.yml up -d
|
||||
|
||||
9. Verify
|
||||
curl https://api.igny8.com/api/v1/system/status/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Gets Copied vs Symlinked
|
||||
|
||||
### Copied (Your Code)
|
||||
|
||||
| Path | Content |
|
||||
|------|---------|
|
||||
| `backend/igny8_core/` | All Django app code |
|
||||
| `frontend/src/` | All React code |
|
||||
| `public/` | Static assets |
|
||||
| `docs/` | Documentation |
|
||||
| `.env` | Environment config |
|
||||
|
||||
### Symlinked (From Stack)
|
||||
|
||||
| App Path | Stack Path |
|
||||
|----------|------------|
|
||||
| `backend/Dockerfile` | `stack/backend/Dockerfile` |
|
||||
| `backend/requirements.txt` | `stack/backend/requirements.txt` |
|
||||
| `backend/manage.py` | `stack/backend/manage.py` |
|
||||
| `frontend/Dockerfile.dev` | `stack/frontend/Dockerfile.dev` |
|
||||
| `frontend/package.json` | `stack/frontend/package.json` |
|
||||
| `frontend/vite.config.ts` | `stack/frontend/vite.config.ts` |
|
||||
| `frontend/tsconfig*.json` | `stack/frontend/tsconfig*.json` |
|
||||
| `docker-compose.app.yml` | `stack/docker/docker-compose.app.yml` |
|
||||
|
||||
---
|
||||
|
||||
## Updating App on Existing Server
|
||||
|
||||
### Code Update (Most Common)
|
||||
|
||||
```
|
||||
cd /data/app/igny8
|
||||
git pull # Get latest code
|
||||
|
||||
# If migrations changed:
|
||||
docker exec igny8_backend python manage.py migrate
|
||||
|
||||
# If frontend deps changed:
|
||||
docker exec igny8_frontend npm install
|
||||
|
||||
# Restart to apply:
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### Full Rebuild (After Major Changes)
|
||||
|
||||
```
|
||||
cd /data/app/igny8
|
||||
docker compose down
|
||||
docker compose build --no-cache
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Before Migration
|
||||
|
||||
### What to Backup
|
||||
|
||||
| Item | Command/Method |
|
||||
|------|----------------|
|
||||
| Database | `pg_dump igny8_db > backup.sql` |
|
||||
| App code | `git push` or `rsync` |
|
||||
| Uploads | Copy `/data/app/igny8/backend/media/` |
|
||||
| Environment | Copy `.env` file |
|
||||
|
||||
### Full Backup Script
|
||||
|
||||
```
|
||||
# On old server
|
||||
DATE=$(date +%Y%m%d)
|
||||
mkdir -p /data/backups/$DATE
|
||||
|
||||
# Database
|
||||
docker exec igny8_postgres pg_dump -U igny8 igny8_db > /data/backups/$DATE/db.sql
|
||||
|
||||
# App code (excluding generated files)
|
||||
tar -czf /data/backups/$DATE/app.tar.gz \
|
||||
--exclude='node_modules' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='staticfiles' \
|
||||
--exclude='dist' \
|
||||
--exclude='.git' \
|
||||
/data/app/igny8/
|
||||
|
||||
# Environment
|
||||
cp /data/app/igny8/.env /data/backups/$DATE/
|
||||
|
||||
echo "Backup complete: /data/backups/$DATE/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [TWO-REPO-ARCHITECTURE.md](TWO-REPO-ARCHITECTURE.md) - Why this structure
|
||||
- [INFRASTRUCTURE-STACK.md](INFRASTRUCTURE-STACK.md) - Stack repo details
|
||||
- [DOCKER-DEPLOYMENT.md](DOCKER-DEPLOYMENT.md) - Container details
|
||||
- [ARCHITECTURE.md](../00-SYSTEM/ARCHITECTURE.md) - System architecture
|
||||
@@ -0,0 +1,219 @@
|
||||
# Infrastructure Stack Repository
|
||||
|
||||
**Repository Name:** `igny8-stack`
|
||||
**Purpose:** Reusable tech stack for Django + React applications
|
||||
|
||||
---
|
||||
|
||||
## Complete Folder Structure
|
||||
|
||||
```
|
||||
igny8-stack/
|
||||
│
|
||||
├── README.md # Stack overview and quick start
|
||||
├── install.sh # Main installation script
|
||||
├── uninstall.sh # Cleanup script
|
||||
│
|
||||
├── config/
|
||||
│ ├── .env.example # Environment variables template
|
||||
│ │
|
||||
│ └── caddy/
|
||||
│ └── Caddyfile # Reverse proxy configuration
|
||||
│
|
||||
├── docker/
|
||||
│ ├── docker-compose.infra.yml # Shared services (Postgres, Redis, Caddy)
|
||||
│ └── docker-compose.app.yml # App services template
|
||||
│
|
||||
├── backend/
|
||||
│ ├── Dockerfile # Python 3.11 slim + dependencies
|
||||
│ ├── requirements.txt # Django, DRF, Celery, Gunicorn, etc.
|
||||
│ ├── manage.py # Django CLI entry point
|
||||
│ ├── container_startup.sh # Container entrypoint script
|
||||
│ └── create_groups.py # Initial permission groups setup
|
||||
│
|
||||
├── frontend/
|
||||
│ ├── Dockerfile.dev # Vite dev server with HMR
|
||||
│ ├── Dockerfile.prod # Production build with Caddy
|
||||
│ ├── Dockerfile.marketing.dev # Marketing site dev server
|
||||
│ ├── package.json # React, Vite, Tailwind, Zustand, etc.
|
||||
│ ├── package-lock.json # Locked dependency versions
|
||||
│ ├── vite.config.ts # Vite configuration
|
||||
│ ├── tsconfig.json # TypeScript base config
|
||||
│ ├── tsconfig.app.json # App TypeScript config
|
||||
│ ├── tsconfig.node.json # Node TypeScript config
|
||||
│ ├── postcss.config.js # PostCSS for Tailwind
|
||||
│ ├── eslint.config.js # ESLint rules
|
||||
│ ├── index.html # Main app HTML template
|
||||
│ └── marketing.html # Marketing site HTML template
|
||||
│
|
||||
└── scripts/
|
||||
├── build-images.sh # Build all Docker images
|
||||
├── migrate.sh # Run Django migrations
|
||||
├── backup-db.sh # Database backup utility
|
||||
├── restore-db.sh # Database restore utility
|
||||
└── health-check.sh # System health check
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Purposes
|
||||
|
||||
### Root Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `install.sh` | Creates directories, symlinks, builds images, sets up network |
|
||||
| `uninstall.sh` | Removes symlinks and cleans up (keeps data) |
|
||||
|
||||
### Config Folder
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `.env.example` | Template for environment variables (DB passwords, secrets, domains) |
|
||||
| `caddy/Caddyfile` | Routes domains to containers, handles SSL, WebSocket proxying |
|
||||
|
||||
### Docker Folder
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `docker-compose.infra.yml` | Postgres, Redis, Caddy, PgAdmin, FileBrowser, Portainer |
|
||||
| `docker-compose.app.yml` | Backend, Frontend, Celery Worker, Celery Beat, Flower |
|
||||
|
||||
### Backend Folder
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `Dockerfile` | Python 3.11 slim, installs requirements, runs Gunicorn |
|
||||
| `requirements.txt` | All Python dependencies (Django 5.x, DRF, Celery, etc.) |
|
||||
| `manage.py` | Django management command entry point |
|
||||
| `container_startup.sh` | Logs startup, runs migrations if needed |
|
||||
| `create_groups.py` | Creates initial Django permission groups |
|
||||
|
||||
### Frontend Folder
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `Dockerfile.dev` | Node 18, Vite dev server with hot reload |
|
||||
| `Dockerfile.prod` | Multi-stage build, Caddy serves static files |
|
||||
| `Dockerfile.marketing.dev` | Marketing site dev server (port 5174) |
|
||||
| `package.json` | All npm dependencies |
|
||||
| `vite.config.ts` | Build config, HMR settings, code splitting |
|
||||
| `tsconfig*.json` | TypeScript compiler settings |
|
||||
| `postcss.config.js` | Tailwind CSS processing |
|
||||
| `eslint.config.js` | Code linting rules |
|
||||
| `index.html` | Main app entry HTML |
|
||||
| `marketing.html` | Marketing site entry HTML |
|
||||
|
||||
### Scripts Folder
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `build-images.sh` | Builds all Docker images with proper tags |
|
||||
| `migrate.sh` | Runs Django migrations inside container |
|
||||
| `backup-db.sh` | Dumps PostgreSQL database to backup file |
|
||||
| `restore-db.sh` | Restores database from backup file |
|
||||
| `health-check.sh` | Checks all services are running |
|
||||
|
||||
---
|
||||
|
||||
## New Server Installation
|
||||
|
||||
### Prerequisites
|
||||
- Ubuntu 22.04+ or Debian 12+
|
||||
- Docker and Docker Compose installed
|
||||
- Git installed
|
||||
- Domain DNS pointing to server IP
|
||||
|
||||
### Step-by-Step Installation
|
||||
|
||||
```
|
||||
1. Create directories
|
||||
mkdir -p /data/stack /data/app /data/logs
|
||||
|
||||
2. Clone stack repository
|
||||
cd /data/stack
|
||||
git clone https://github.com/yourorg/igny8-stack.git
|
||||
|
||||
3. Run installation script
|
||||
cd igny8-stack
|
||||
chmod +x install.sh
|
||||
./install.sh
|
||||
|
||||
4. Verify installation
|
||||
docker images # Should show app-backend, app-frontend images
|
||||
docker network ls # Should show igny8_net
|
||||
ls -la /data/app/ # Should show prepared structure
|
||||
```
|
||||
|
||||
### What install.sh Does
|
||||
|
||||
1. Creates Docker network (`igny8_net`)
|
||||
2. Creates directory structure under `/data/app/`
|
||||
3. Builds Docker images:
|
||||
- `app-backend:latest`
|
||||
- `app-frontend-dev:latest`
|
||||
- `app-marketing-dev:latest`
|
||||
4. Starts infrastructure services (Postgres, Redis, Caddy)
|
||||
5. Creates symlinks for app folder structure
|
||||
6. Prints next steps
|
||||
|
||||
---
|
||||
|
||||
## Updating Stack on Existing Server
|
||||
|
||||
```
|
||||
1. Pull latest changes
|
||||
cd /data/stack/igny8-stack
|
||||
git pull
|
||||
|
||||
2. Rebuild images if Dockerfile changed
|
||||
./scripts/build-images.sh
|
||||
|
||||
3. Restart containers to use new images
|
||||
cd /data/app/igny8
|
||||
docker compose -f docker-compose.app.yml down
|
||||
docker compose -f docker-compose.app.yml up -d
|
||||
|
||||
4. Verify
|
||||
docker ps
|
||||
./scripts/health-check.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Customizing for Different Apps
|
||||
|
||||
The stack is designed to run any Django + React application. To use it for a different app (not igny8):
|
||||
|
||||
1. Clone stack to new server
|
||||
2. Run `install.sh`
|
||||
3. Clone your app repo to `/data/app/yourapp/`
|
||||
4. Update `.env` with your app's settings
|
||||
5. Update Caddyfile with your domains
|
||||
6. Start containers
|
||||
|
||||
The stack doesn't contain any igny8-specific logic - it's a generic Django+React runtime environment.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Key variables to set in `.env`:
|
||||
|
||||
| Variable | Purpose | Example |
|
||||
|----------|---------|---------|
|
||||
| `DB_HOST` | PostgreSQL host | `postgres` |
|
||||
| `DB_NAME` | Database name | `igny8_db` |
|
||||
| `DB_USER` | Database user | `igny8` |
|
||||
| `DB_PASSWORD` | Database password | `secure_password` |
|
||||
| `REDIS_HOST` | Redis host | `redis` |
|
||||
| `SECRET_KEY` | Django secret key | `random_50_char_string` |
|
||||
| `DOMAIN` | Primary domain | `igny8.com` |
|
||||
| `DEBUG` | Debug mode | `False` |
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [TWO-REPO-ARCHITECTURE.md](TWO-REPO-ARCHITECTURE.md) - Why two repos
|
||||
- [IGNY8-APP-STRUCTURE.md](IGNY8-APP-STRUCTURE.md) - App-specific code structure
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,150 @@
|
||||
# Two-Repository Architecture
|
||||
|
||||
**Purpose:** Separate tech stack infrastructure from custom application code for easy server migration and deployment.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Instead of one monolithic repository, split into two:
|
||||
|
||||
| Repository | Contains | Changes | Deployment |
|
||||
|------------|----------|---------|------------|
|
||||
| `igny8-stack` | Docker, configs, dependencies | Rarely | Clone once per server |
|
||||
| `igny8-app` | Your custom business logic | Frequently | Copy to deploy |
|
||||
|
||||
---
|
||||
|
||||
## Why This Architecture?
|
||||
|
||||
### Current Problem
|
||||
- Everything mixed together (Dockerfiles, configs, your code)
|
||||
- To deploy to new server, must copy everything
|
||||
- Hard to distinguish "what's mine" vs "what's framework"
|
||||
|
||||
### Solution Benefits
|
||||
- **Clean separation**: Stack vs App code
|
||||
- **Easy migration**: Just copy app folder after stack is installed
|
||||
- **Version independence**: Update stack without touching app
|
||||
- **Reusable stack**: Same stack can run different apps on different servers
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
### Server Structure After Setup
|
||||
|
||||
```
|
||||
/data/
|
||||
├── stack/
|
||||
│ └── igny8-stack/ # Cloned from stack repo (read-only)
|
||||
│
|
||||
├── app/
|
||||
│ └── igny8/ # Your app code + symlinks to stack
|
||||
│ ├── backend/
|
||||
│ │ ├── Dockerfile → symlink to stack
|
||||
│ │ ├── requirements.txt → symlink to stack
|
||||
│ │ ├── manage.py → symlink to stack
|
||||
│ │ └── igny8_core/ # YOUR CODE
|
||||
│ │
|
||||
│ └── frontend/
|
||||
│ ├── package.json → symlink to stack
|
||||
│ ├── vite.config.ts → symlink to stack
|
||||
│ └── src/ # YOUR CODE
|
||||
│
|
||||
└── logs/
|
||||
```
|
||||
|
||||
### Symlinks Explained
|
||||
|
||||
The `install.sh` script creates symbolic links from your app folder to the stack folder. This means:
|
||||
- Stack files (Dockerfile, package.json, etc.) live in one place
|
||||
- Your app folder references them via symlinks
|
||||
- Docker sees a complete project structure
|
||||
- You only manage your custom code
|
||||
|
||||
---
|
||||
|
||||
## Migration Workflow
|
||||
|
||||
### On New Server
|
||||
|
||||
```
|
||||
Step 1: Install Stack (one-time)
|
||||
────────────────────────────────
|
||||
cd /data/stack
|
||||
git clone https://your-repo/igny8-stack.git
|
||||
cd igny8-stack
|
||||
./install.sh
|
||||
|
||||
Step 2: Deploy Your App
|
||||
────────────────────────────────
|
||||
cd /data/app
|
||||
git clone https://your-repo/igny8-app.git igny8
|
||||
# OR: rsync/scp from old server
|
||||
|
||||
Step 3: Configure
|
||||
────────────────────────────────
|
||||
cp .env.example .env
|
||||
nano .env # Set secrets, domains
|
||||
|
||||
Step 4: Start
|
||||
────────────────────────────────
|
||||
docker compose -f docker-compose.app.yml up -d
|
||||
```
|
||||
|
||||
### Updating Existing Server
|
||||
|
||||
**Update app code only:**
|
||||
```
|
||||
cd /data/app/igny8
|
||||
git pull
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
**Update stack (rare):**
|
||||
```
|
||||
cd /data/stack/igny8-stack
|
||||
git pull
|
||||
./scripts/build-images.sh
|
||||
docker compose -f /data/app/igny8/docker-compose.app.yml up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Goes Where?
|
||||
|
||||
### Stack Repo (igny8-stack)
|
||||
|
||||
Things that are **same for any Django+React app**:
|
||||
- Dockerfiles
|
||||
- Base requirements.txt / package.json
|
||||
- Vite config, TypeScript config
|
||||
- Docker compose templates
|
||||
- Caddy config templates
|
||||
- Utility scripts
|
||||
|
||||
### App Repo (igny8-app)
|
||||
|
||||
Things that are **specific to your application**:
|
||||
- Django app code (models, views, serializers, business logic)
|
||||
- React components, pages, stores
|
||||
- App-specific static assets
|
||||
- Documentation
|
||||
- Environment config templates
|
||||
|
||||
---
|
||||
|
||||
## Key Principle
|
||||
|
||||
> If you deleted your app code and replaced it with a different Django+React app,
|
||||
> would this file still make sense?
|
||||
> - YES → Stack repo
|
||||
> - NO → App repo
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [INFRASTRUCTURE-STACK.md](INFRASTRUCTURE-STACK.md) - Complete stack repo structure
|
||||
- [IGNY8-APP-STRUCTURE.md](IGNY8-APP-STRUCTURE.md) - App repo structure
|
||||
Reference in New Issue
Block a user