A multi-location marketing operations platform for retail chains to centrally manage location-specific marketing campaigns with AI-powered content generation and sophisticated approval workflows.
Important
This project is one of my experiments with Claude Code! It's still needs polishing. It's currently a work in progress.
Retail chains with multiple locations face significant challenges in marketing operations:
- Inconsistent Messaging: Each store creates its own marketing content, leading to brand inconsistency
- Manual Processes: Campaign creation, approval, and deployment are time-consuming manual tasks
- No Visibility: Corporate has limited visibility into what marketing is being used at each location
- Scalability Issues: As the number of locations grows, managing campaigns becomes exponentially harder
- Content Quality: Not every location has skilled marketers to create compelling content
StoreSync provides a centralized platform where:
- Corporate teams create reusable campaign templates with brand guidelines
- Location managers customize campaigns for their specific stores
- Brand managers review and approve campaigns before they go live
- AI assists in generating high-quality, on-brand content
- Everyone has visibility into campaign status across all locations
- Create reusable templates with Jinja2-style variables (
{{location_name}},{{discount_percentage}}) - Customize campaigns per location while maintaining brand consistency
- Schedule campaigns for future activation
- Track campaign status across all locations
Complete 7-stage workflow with full audit trail:
Draft → Pending Review → Approved → Scheduled → Active → Completed
↘ Rejected → (back to Draft)
- Role-based permissions (Admin, Brand Manager, Location Manager, Viewer)
- Required comments for rejections
- Complete history of all approval decisions
- Template Rendering: Automatically populate templates with location-specific data
- AI-Enhanced Content: Generate creative marketing copy using GPT-4
- RAG (Retrieval-Augmented Generation): Uses successful past campaigns as context for better results
- Semantic Search: Find similar campaigns using vector embeddings
- HTML Email Generation: AI converts plain text campaigns into responsive, brand-styled HTML emails
- Campaign-Aware Styling: Email colors and mood automatically match campaign type (seasonal, clearance, grand opening, etc.)
- Email Preview: Desktop/mobile preview with regeneration capability
- Recipient Management: Add recipients via bulk input, track delivery status
- Batch Sending: Rate-limited email delivery with status tracking (pending, sent, failed)
- Test Emails: Send preview emails before full campaign delivery
- Manage multiple brands from a single platform
- Brand-specific templates and settings
- Location hierarchies under each brand
- Bulk import locations via CSV/Excel
| Technology | Purpose |
|---|---|
| Django 5.0 | Web framework |
| Django REST Framework | REST API |
| PostgreSQL + pgvector | Database with vector search |
| Celery + Redis | Background task processing |
| LangChain + OpenAI | AI content generation |
| django-fsm | Workflow state machine |
| Technology | Purpose |
|---|---|
| Next.js 14 | React framework |
| TypeScript | Type safety |
| Tailwind CSS | Styling |
| Zustand | State management |
| React Query | Server state & caching |
| React Hook Form + Zod | Form handling & validation |
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (Next.js) │
│ localhost:3000 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Django REST API │
│ localhost:8000 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Auth │ │ Brands │ │ Campaigns │ │
│ │ (JWT) │ │ Locations │ │ Templates, Approvals │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ PostgreSQL │ │ Redis │ │ OpenAI │
│ + pgvector │ │ (Task Broker) │ │ (LLM + RAG) │
└─────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Celery Workers │
│ - Content Gen │
│ - Scheduling │
│ - Notifications│
└─────────────────┘
┌──────────────────────────────────────────────────────────────────────────┐
│ MODELS │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ │
│ │ User │ │ Brand │ │ CampaignTemplate │ │
│ ├─────────────┤ ├─────────────┤ ├──────────────────┤ │
│ │ id (BigInt) │ │ id (UUID) │ │ id (UUID) │ │
│ │ email │ │ name │ │ brand_id → Brand │ │
│ │ role │ │ slug │ │ name │ │
│ │ preferences │ │ logo │ │ content_template │ │
│ │ brands (M2M)│───►│ settings │◄───│ campaign_type │ │
│ └─────────────┘ └─────────────┘ └──────────────────┘ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Location │ │ │
│ │ ├─────────────┤ │ │
│ │ │ id (UUID) │ │ │
│ │ │ brand_id ───┼─► Brand │ │
│ │ │ name │ │ │
│ │ │ store_number│ │ │
│ │ │ address │ │ │
│ │ │ attributes │ │ │
│ │ └──────┬──────┘ │ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌───────────────────────────────────┐ │
│ │ │ LocationCampaign │ │
│ │ ├───────────────────────────────────┤ │
│ │ │ id (UUID) │ │
│ │ │ location_id ──────► Location │ │
│ │ │ template_id ──────► CampaignTemplate │
│ └───────►│ created_by_id ────► User │ │
│ │ status (FSM) │ │
│ │ generated_content │ │
│ │ generated_html_email │ │
│ │ content_embedding (Vector 1536) │ │
│ │ scheduled_start / scheduled_end │ │
│ └───────────────┬───────────────────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ ApprovalStep │ │ EmailRecipient │ │
│ ├─────────────────┤ ├─────────────────┤ │
│ │ id (UUID) │ │ id (UUID) │ │
│ │ campaign_id ────┼─► │ campaign_id ────┼─► LocationCampaign│
│ │ approver_id ────┼─► User │ │
│ │ decision │ │ email │ │
│ │ comments │ │ name │ │
│ │ previous_status │ │ status │ │
│ │ new_status │ │ sent_at │ │
│ └─────────────────┘ │ error_message │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
| Relationship | Type | Description |
|---|---|---|
| Brand → Locations | 1:N | A brand has many store locations |
| Brand → CampaignTemplates | 1:N | A brand has many reusable templates |
| User ↔ Brands | M:N | Users can manage multiple brands (via junction table) |
| Location → Campaigns | 1:N | A location has many campaigns |
| Template → Campaigns | 1:N | A template is used by many campaigns |
| User → Campaigns | 1:N | A user creates many campaigns (created_by) |
| Campaign → ApprovalSteps | 1:N | A campaign has an audit trail of approvals |
| User → ApprovalSteps | 1:N | A user makes many approval decisions (approver) |
| Campaign → EmailRecipients | 1:N | A campaign has many email recipients |
- Docker and Docker Compose
- Node.js 18+ (for local frontend development)
- OpenAI API key (for AI features)
-
Clone the repository
git clone <repository-url> cd storesync
-
Set up environment variables
cp .env.example .env # Edit .env and add your OPENAI_API_KEY -
Start all services
docker compose up -d
-
Run database migrations
docker compose exec backend python manage.py migrate -
Create a superuser
docker compose exec backend python manage.py createsuperuser -
Access the application
- Frontend: http://localhost:3000
- API: http://localhost:8000/api/v1/
- API Docs: http://localhost:8000/api/docs/
- Celery Flower: http://localhost:5555
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements/local.txt
# Set environment variables
export DATABASE_URL=postgres://storesync:storesync@localhost:5432/storesync
export REDIS_URL=redis://localhost:6379/0
export OPENAI_API_KEY=your-key-here
# Run migrations
python manage.py migrate
# Start development server
python manage.py runservercd frontend
# Install dependencies
npm install
# Start development server
npm run devPOST /api/v1/auth/token/ # Login (returns JWT tokens)
POST /api/v1/auth/token/refresh/ # Refresh access token
POST /api/v1/auth/register/ # Register new user
GET /api/v1/auth/me/ # Get current user
GET/POST /api/v1/brands/
GET/PATCH /api/v1/brands/{id}/
GET/POST /api/v1/brands/{id}/locations/
POST /api/v1/brands/{id}/locations/bulk_import/
GET/POST /api/v1/campaigns/templates/
GET/PATCH /api/v1/campaigns/templates/{id}/
GET/POST /api/v1/campaigns/
GET/PATCH /api/v1/campaigns/{id}/
# Workflow Actions
POST /api/v1/campaigns/{id}/submit/
POST /api/v1/campaigns/{id}/approve/
POST /api/v1/campaigns/{id}/reject/
POST /api/v1/campaigns/{id}/schedule/
# AI Features
POST /api/v1/campaigns/{id}/generate_content/
POST /api/v1/campaigns/similar/
# HTML Email
POST /api/v1/campaigns/{id}/generate_html_email/
GET /api/v1/campaigns/{id}/email_preview/
POST /api/v1/campaigns/{id}/add_recipients/
GET /api/v1/campaigns/{id}/recipients/
POST /api/v1/campaigns/{id}/send_emails/
POST /api/v1/campaigns/{id}/send_test_email/
GET /api/v1/campaigns/{id}/email_status/
DELETE /api/v1/campaigns/{id}/clear_recipients/
Full API documentation available at /api/docs/ (Swagger UI) or /api/redoc/.
storesync/
├── apps/
│ ├── users/ # User authentication & roles
│ ├── brands/ # Brand & location management
│ ├── campaigns/ # Templates, campaigns, approvals
│ │ └── services/ # AI content generation, similarity search
│ └── core/ # Shared utilities
├── config/ # Django settings & URLs
├── frontend/
│ ├── src/
│ │ ├── app/ # Next.js pages (App Router)
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom React hooks
│ │ ├── lib/ # API client, utilities
│ │ ├── stores/ # Zustand stores
│ │ └── types/ # TypeScript types
│ └── e2e/ # Playwright tests
├── requirements/ # Python dependencies
└── docker-compose.yml # Docker services
# Run all tests
docker compose exec backend pytest
# Run with coverage
docker compose exec backend pytest --cov=apps --cov-report=htmlcd frontend
# Unit tests
npm test
# Unit tests with coverage
npm run test:coverage
# E2E tests (requires running application)
npm run test:e2e| Variable | Description | Required |
|---|---|---|
SECRET_KEY |
Django secret key | Yes |
DEBUG |
Enable debug mode | No (default: False) |
DATABASE_URL |
PostgreSQL connection URL | Yes |
REDIS_URL |
Redis connection URL | Yes |
OPENAI_API_KEY |
OpenAI API key for AI features | No* |
ALLOWED_HOSTS |
Allowed host headers | Yes (production) |
CORS_ALLOWED_ORIGINS |
Allowed CORS origins | Yes |
EMAIL_HOST |
SMTP server hostname | No** |
EMAIL_PORT |
SMTP server port | No (default: 587) |
EMAIL_HOST_USER |
SMTP username | No** |
EMAIL_HOST_PASSWORD |
SMTP password | No** |
EMAIL_USE_TLS |
Use TLS for SMTP | No (default: True) |
DEFAULT_FROM_EMAIL |
Default sender address | No |
*AI features will be disabled without an OpenAI API key
**Email sending features require SMTP configuration
| Role | Permissions |
|---|---|
| Admin | Full system access |
| Brand Manager | Approve/reject campaigns, manage templates |
| Location Manager | Create and submit campaigns |
| Viewer | Read-only access |
StoreSync uses Celery for background processing:
- Content Generation: Async AI content generation with retries
- HTML Email Generation: Convert plain text to responsive HTML emails
- Email Batch Sending: Rate-limited email delivery (5 emails/second)
- Test Email: Send preview emails to verify content
- Embedding Computation: Batch vector embedding generation
| Task | Schedule | Description |
|---|---|---|
| Activate Campaigns | Every 5 min | Transition scheduled → active |
| Complete Campaigns | Every 5 min | Transition active → completed (past end date) |
| Approval Digest | Daily 9 AM | Email summary of pending approvals |
| Data Cleanup | Weekly (Sun 2 AM) | Remove old approval history (>1 year) |
Monitor tasks at http://localhost:5555 (Celery Flower).
This project is proprietary software. All rights reserved.
