394 lines
16 KiB
Markdown
394 lines
16 KiB
Markdown
# IGNY8 Phase 4: White-Label & Reporting (04B)
|
|
## Automated Reports, Agency Branding, Admin Dashboard, Client View
|
|
|
|
**Document Version:** 1.0
|
|
**Date:** 2026-03-23
|
|
**Phase:** IGNY8 Phase 4 — Business Layer
|
|
**Status:** Build Ready
|
|
**Source of Truth:** Codebase at `/data/app/igny8/`
|
|
**Audience:** Claude Code, Backend Developers, Frontend Developers, Architects
|
|
|
|
---
|
|
|
|
## 1. CURRENT STATE
|
|
|
|
### No Reporting Infrastructure
|
|
- Reports created manually by Alorig team via Google Docs/Sheets
|
|
- No automated metric collection across IGNY8 modules
|
|
- No PDF generation capability
|
|
- No scheduled report delivery
|
|
|
|
### No Agency/Reseller Model
|
|
- No white-label capability — all reports show IGNY8 branding
|
|
- No custom branding configuration
|
|
- No agency account structure
|
|
|
|
### Phase 4A Foundation Available (04A)
|
|
- `ManagedServiceSubscription` — client subscription data
|
|
- `BacklinkServiceOrder` — order tracking with margin
|
|
- `AhrefsDomainSnapshot` — DR, traffic, referring domains data
|
|
- `BacklinkIndexingRequest` — indexing status tracking
|
|
|
|
### Phase 2 Data Sources Available
|
|
- `Content` (writer app) — articles published, word counts
|
|
- `URLInspectionRecord` + `GSCMetricsCache` (02C) — indexing status, search performance
|
|
- `SAGBacklink` + `CampaignKPISnapshot` (02E) — backlink campaign metrics
|
|
- `SocialPost` + `SocialEngagement` (02H) — social media metrics
|
|
- `SAGBlueprint` health score (01G) — SAG completion and authority
|
|
- All IDs are integers (BigAutoField)
|
|
|
|
---
|
|
|
|
## 2. WHAT TO BUILD
|
|
|
|
### Overview
|
|
An automated report generation engine with 9 configurable sections, PDF output, white-label branding for agencies, an admin services dashboard for Alorig, and a client-facing read-only view for managed service subscribers.
|
|
|
|
### Report Generation Engine
|
|
|
|
**9 Configurable Report Sections** (each can be included/excluded per client):
|
|
|
|
| # | Section | Data Sources |
|
|
|---|---------|-------------|
|
|
| 1 | **Executive Summary** | AI-generated from all other sections — key wins, KPI highlights |
|
|
| 2 | **Content Performance** | `Content` model — articles published by type, word count, images created |
|
|
| 3 | **Indexing Status** | `URLInspectionRecord` + `GSCMetricsCache` (02C) — indexed/pending/error trend |
|
|
| 4 | **Keyword Rankings** | `GSCMetricsCache` (02C) + `AhrefsDomainSnapshot` (04A) — top 10/20/50, movers |
|
|
| 5 | **Organic Traffic** | `GSCMetricsCache` (02C) — clicks, impressions, CTR, avg position, MoM change |
|
|
| 6 | **Backlink Campaign** | `SAGBacklink` (02E) + `BacklinkServiceOrder` (04A) + `AhrefsDomainSnapshot` (04A) — links built, DR dist, budget, quality, referring domain growth |
|
|
| 7 | **Social Media** | `SocialPost` + `SocialEngagement` (02H) — posts by platform, engagement, top performers |
|
|
| 8 | **SAG Health** | `SAGBlueprint` (01G) — completion %, cluster status, authority score (0-100), content gaps |
|
|
| 9 | **Next Month Plan** | `SAGCampaign` (02E) + automation queue — upcoming content topics, backlink targets, action items |
|
|
|
|
### PDF Report Generation
|
|
|
|
| Component | Choice | Rationale |
|
|
|-----------|--------|-----------|
|
|
| Template engine | WeasyPrint (HTML → PDF) | CSS-based layout, full typography control |
|
|
| Charts | matplotlib (server-side rendering) | SVG/PNG charts embedded in HTML |
|
|
| Storage | S3/media storage | URL saved in `ServiceReport.report_pdf_url` |
|
|
| Themes | Light + Dark | Configurable per template |
|
|
|
|
**Report Flow:**
|
|
```
|
|
Celery task triggers → Collect metrics from all sources →
|
|
Render section HTML per included sections →
|
|
Generate charts via matplotlib → Merge into base template →
|
|
WeasyPrint converts HTML → PDF → Upload to storage →
|
|
Save ServiceReport with PDF URL → Email to recipients if configured
|
|
```
|
|
|
|
### White-Label Branding (Agency Play)
|
|
|
|
For agencies reselling IGNY8 services:
|
|
|
|
**`AgencyBranding` provides:**
|
|
- Agency name (replaces "IGNY8" / "Alorig" throughout PDF)
|
|
- Logo URL (replaces IGNY8 logo in header)
|
|
- Primary + secondary colors (brand color scheme)
|
|
- Contact email + phone + website URL
|
|
- Footer text
|
|
|
|
**When `ServiceReport.is_white_label = True`:**
|
|
- All "IGNY8" and "Alorig" text replaced with `brand_name`
|
|
- Logo swapped to `brand_logo_url`
|
|
- Footer shows agency contact info
|
|
- Color scheme uses agency brand colors
|
|
- Report URL domain can be custom (via Caddy subdomain routing)
|
|
|
|
### Admin Services Dashboard (Alorig Team Only)
|
|
|
|
**Frontend Pages (.tsx + Zustand):**
|
|
|
|
```
|
|
frontend/src/pages/Services/
|
|
├── ServicesDashboard.tsx # Overview: all managed clients, MRR, revenue
|
|
│ ├── ClientList.tsx # All subscriptions with status, tier, articles count
|
|
│ ├── RevenueSummary.tsx # MRR total, margin total, trend chart
|
|
│ └── UpcomingActions.tsx # Overdue: reports, content, renewals
|
|
├── ClientDetail.tsx # Single client management
|
|
│ ├── ClientConfig.tsx # Service config editor (JSON form)
|
|
│ ├── ContentTracker.tsx # Articles published this month vs target
|
|
│ ├── BacklinkTracker.tsx # Links ordered vs delivered vs live vs indexed
|
|
│ ├── AhrefsMetrics.tsx # DR history, referring domains, top pages
|
|
│ ├── ReportHistory.tsx # Past reports with resend option
|
|
│ └── BillingHistory.tsx # Invoices, payments, margin per order
|
|
├── BacklinkOrders.tsx # All orders across clients
|
|
│ ├── OrderList.tsx # Filterable by client, status, package
|
|
│ └── OrderDetail.tsx # Individual order with link-by-link tracking
|
|
├── IndexingDashboard.tsx # Backlink indexing status across all clients
|
|
└── ReportGenerator.tsx # Generate report for any client + period
|
|
```
|
|
|
|
**Sidebar addition** (admin-only, behind `managed_services_enabled` feature flag):
|
|
```
|
|
ADMIN
|
|
├── Sector Templates
|
|
└── Managed Services (NEW)
|
|
```
|
|
|
|
### Client-Facing View (Managed Service Subscribers)
|
|
|
|
For managed clients who also have IGNY8 SaaS access:
|
|
|
|
**Frontend Pages (.tsx + Zustand):**
|
|
```
|
|
frontend/src/pages/ManagedService/
|
|
├── ServiceOverview.tsx # What's included, current month progress
|
|
├── ReportViewer.tsx # View/download past reports
|
|
└── ApprovalQueue.tsx # Approve blueprint, review content (if review_required)
|
|
```
|
|
|
|
**Sidebar addition** (only shows if `ManagedServiceSubscription` exists for account):
|
|
```
|
|
ACCOUNT
|
|
├── Account Settings
|
|
├── Plans & Billing
|
|
├── Managed Service (NEW — conditional)
|
|
├── Usage
|
|
└── AI Models
|
|
```
|
|
|
|
---
|
|
|
|
## 3. DATA MODELS & APIS
|
|
|
|
### New Models (in `services` app)
|
|
|
|
**`ServiceReport`** (extends `AccountBaseModel`)
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `site` | ForeignKey(Site) | Report target site |
|
|
| `managed_subscription` | ForeignKey(ManagedServiceSubscription, null=True) | Linked subscription |
|
|
| `report_type` | CharField(max_length=20) | `weekly` / `monthly` / `quarterly` |
|
|
| `period_start` | DateField | Report period start |
|
|
| `period_end` | DateField | Report period end |
|
|
| `report_data` | JSONField | All metrics for period (structured by section) |
|
|
| `report_pdf_url` | URLField(blank=True) | Generated PDF in S3 |
|
|
| `is_white_label` | BooleanField(default=False) | Use agency branding |
|
|
| `branding` | ForeignKey(AgencyBranding, null=True) | Agency branding reference |
|
|
| `sections_included` | JSONField | List of included section keys |
|
|
| `generated_at` | DateTimeField(auto_now_add=True) | Generation timestamp |
|
|
| `sent_at` | DateTimeField(null=True) | Email sent timestamp |
|
|
| `sent_to` | JSONField(default=list) | List of recipient emails |
|
|
|
|
Table: `igny8_service_reports`
|
|
|
|
**`AgencyBranding`** (extends `AccountBaseModel`)
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `brand_name` | CharField(max_length=200) | Agency name |
|
|
| `brand_logo_url` | URLField(blank=True) | Logo URL |
|
|
| `primary_color` | CharField(max_length=7) | Hex color code |
|
|
| `secondary_color` | CharField(max_length=7) | Hex color code |
|
|
| `contact_email` | EmailField(blank=True) | Agency contact email |
|
|
| `contact_phone` | CharField(blank=True) | Agency phone |
|
|
| `website_url` | URLField(blank=True) | Agency website |
|
|
| `footer_text` | TextField(blank=True) | Custom footer text |
|
|
| `is_active` | BooleanField(default=True) | Active flag |
|
|
|
|
Table: `igny8_agency_branding`
|
|
|
|
**`ReportTemplate`** (extends `AccountBaseModel`)
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `name` | CharField(max_length=200) | Template name |
|
|
| `template_html` | TextField | Base HTML template |
|
|
| `template_css` | TextField | Custom CSS |
|
|
| `is_default` | BooleanField(default=False) | System default |
|
|
| `branding` | ForeignKey(AgencyBranding, null=True) | Agency-specific template |
|
|
|
|
Table: `igny8_report_templates`
|
|
|
|
### API Endpoints
|
|
|
|
All under `/api/v1/`:
|
|
|
|
**Service Reports:**
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| GET | `/services/reports/` | List (admin + client's own) |
|
|
| POST | `/services/reports/generate/` | Generate report for site + period |
|
|
| GET | `/services/reports/{id}/` | Detail + PDF URL |
|
|
| POST | `/services/reports/{id}/send/` | Email to recipients |
|
|
| POST | `/services/reports/{id}/regenerate/` | Regenerate PDF |
|
|
| GET | `/services/reports/preview/` | Preview with data (no save) |
|
|
|
|
**Agency Branding:**
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| GET | `/services/branding/` | List brandings |
|
|
| POST | `/services/branding/` | Create branding |
|
|
| GET | `/services/branding/{id}/` | Detail |
|
|
| PUT | `/services/branding/{id}/` | Update |
|
|
| DELETE | `/services/branding/{id}/` | Delete |
|
|
|
|
**Report Templates:**
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| GET | `/services/report-templates/` | List templates |
|
|
| POST | `/services/report-templates/` | Create custom template |
|
|
| PUT | `/services/report-templates/{id}/` | Update template |
|
|
|
|
**Dashboard (Admin):**
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| GET | `/services/dashboard/` | Revenue, clients, MRR |
|
|
| GET | `/services/dashboard/overdue/` | Overdue deliverables |
|
|
| GET | `/services/dashboard/margin/` | Margin tracking |
|
|
| GET | `/services/dashboard/clients/` | Client list with status summary |
|
|
|
|
### Celery Tasks
|
|
|
|
| Task | Schedule | Purpose |
|
|
|------|----------|---------|
|
|
| `generate_weekly_reports` | Every Monday 6am | Generate for all Pro clients |
|
|
| `generate_monthly_reports` | 1st of month | Generate for all Lite + Pro clients |
|
|
| `send_pending_reports` | Daily | Email any generated but unsent reports |
|
|
| `check_overdue_deliverables` | Daily | Flag clients behind on content/links |
|
|
| `collect_report_metrics` | Nightly | Pre-aggregate metrics for faster generation |
|
|
|
|
### Services
|
|
|
|
| Service | Purpose |
|
|
|---------|---------|
|
|
| `ReportService` | `generate_report()` — collect metrics, render PDF |
|
|
| `ReportEmailService` | Send report emails with PDF attachment or link |
|
|
|
|
### New Python Dependencies
|
|
- `weasyprint` — HTML → PDF rendering
|
|
- `matplotlib` — chart generation (server-side SVG/PNG)
|
|
|
|
---
|
|
|
|
## 4. IMPLEMENTATION STEPS
|
|
|
|
### Build Sequence
|
|
|
|
**Week 1: Models + Report Engine**
|
|
1. Create `ServiceReport`, `AgencyBranding`, `ReportTemplate` models + migration
|
|
2. Create serializers + viewsets
|
|
3. Build `ReportService` — metric collection from all 9 data sources
|
|
4. Build PDF template (base HTML + CSS) with section rendering
|
|
5. Integrate WeasyPrint for HTML → PDF conversion
|
|
6. Build chart generation via matplotlib (DR trend, traffic chart, etc.)
|
|
|
|
**Week 2: White-Label + Dashboard**
|
|
1. Build `AgencyBranding` CRUD endpoints
|
|
2. Implement branding injection in report templates
|
|
3. Build admin dashboard API endpoints
|
|
4. Build Celery tasks for scheduled report generation
|
|
|
|
**Week 3: Frontend**
|
|
1. Build `ServicesDashboard.tsx` + child components
|
|
2. Build `ClientDetail.tsx` + child components
|
|
3. Build `BacklinkOrders.tsx` + `IndexingDashboard.tsx`
|
|
4. Build `ReportGenerator.tsx`
|
|
5. Build client-facing `ManagedService/` pages
|
|
6. Add sidebar items (admin + client conditional)
|
|
|
|
### Zustand Stores
|
|
|
|
```typescript
|
|
// frontend/src/stores/servicesStore.ts
|
|
interface ServicesState {
|
|
subscriptions: ManagedServiceSubscription[]
|
|
reports: ServiceReport[]
|
|
orders: BacklinkServiceOrder[]
|
|
dashboard: DashboardSummary | null
|
|
loading: boolean
|
|
fetchSubscriptions: () => Promise<void>
|
|
fetchReports: (siteId: number) => Promise<void>
|
|
generateReport: (params: ReportParams) => Promise<void>
|
|
fetchDashboard: () => Promise<void>
|
|
}
|
|
|
|
// frontend/src/stores/brandingStore.ts
|
|
interface BrandingState {
|
|
brandings: AgencyBranding[]
|
|
templates: ReportTemplate[]
|
|
fetchBrandings: () => Promise<void>
|
|
createBranding: (data: AgencyBrandingInput) => Promise<void>
|
|
updateBranding: (id: number, data: AgencyBrandingInput) => Promise<void>
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. ACCEPTANCE CRITERIA
|
|
|
|
### Report Generation
|
|
- [ ] Reports generate with data from all 9 sections when data available
|
|
- [ ] Sections configurable per client — excluded sections omitted from PDF
|
|
- [ ] PDF renders correctly with charts, tables, and branding
|
|
- [ ] WeasyPrint produces valid PDF files uploadable to S3
|
|
- [ ] Charts render via matplotlib (DR trend, traffic chart, ranking distribution)
|
|
- [ ] Generated PDF URL saved in `ServiceReport.report_pdf_url`
|
|
|
|
### Scheduled Reports
|
|
- [ ] Weekly reports auto-generate on Monday 6am for all Pro clients
|
|
- [ ] Monthly reports auto-generate on 1st for all Lite + Pro clients
|
|
- [ ] `send_pending_reports` emails generated-but-unsent reports
|
|
- [ ] Pre-aggregation task collects metrics nightly for faster generation
|
|
|
|
### White-Label Branding
|
|
- [ ] `AgencyBranding` stores name, logo, colors, contact info
|
|
- [ ] When `is_white_label = True`, "IGNY8"/"Alorig" replaced with `brand_name`
|
|
- [ ] Logo, colors, and footer text swapped in PDF output
|
|
- [ ] Multiple brandings supported per account
|
|
|
|
### Admin Dashboard
|
|
- [ ] `ServicesDashboard.tsx` shows all managed clients, MRR, revenue
|
|
- [ ] `ClientDetail.tsx` shows config, content tracker, backlink tracker, reports, billing
|
|
- [ ] `BacklinkOrders.tsx` lists all orders filterable by client, status, package
|
|
- [ ] `IndexingDashboard.tsx` shows indexing status across all clients
|
|
- [ ] `ReportGenerator.tsx` generates on-demand report for any client + period
|
|
- [ ] Sidebar shows "Managed Services" link only for admin users
|
|
|
|
### Client-Facing View
|
|
- [ ] `ServiceOverview.tsx` shows tier, articles progress, current month status
|
|
- [ ] `ReportViewer.tsx` lists past reports with download links
|
|
- [ ] `ApprovalQueue.tsx` shows pending blueprint/content approvals
|
|
- [ ] Sidebar shows "Managed Service" only when subscription exists
|
|
|
|
---
|
|
|
|
## 6. CLAUDE CODE INSTRUCTIONS
|
|
|
|
### Context Requirements
|
|
1. Read 04A (Managed Services) — subscription, order, Ahrefs, indexing models
|
|
2. Read 02C (GSC Integration) — GSCMetricsCache, URLInspectionRecord for report sections
|
|
3. Read 02E (Linker External) — SAGBacklink, CampaignKPISnapshot for backlink section
|
|
4. Read 02H (Socializer) — SocialPost, SocialEngagement for social section
|
|
5. Read 01G (SAG Health Monitoring) — health score for SAG section
|
|
6. Read existing billing app — understand existing admin sidebar structure
|
|
|
|
### Execution Order
|
|
```
|
|
Models + migrations → ReportService → PDF template + WeasyPrint →
|
|
AgencyBranding CRUD → Celery tasks → Admin dashboard frontend → Client frontend
|
|
```
|
|
|
|
### Critical Rules
|
|
1. **All IDs are integers** — BigAutoField PKs
|
|
2. **Model names PLURAL** — Clusters, Keywords, etc.
|
|
3. **Table prefix** — `igny8_` for all tables
|
|
4. **App** — models go in `services` app (same as 04A)
|
|
5. **Frontend** — `.tsx` files, Zustand stores, in `frontend/src/pages/Services/` and `frontend/src/pages/ManagedService/`
|
|
6. **Feature flag** — admin dashboard behind `managed_services_enabled` flag
|
|
7. **Report data** — always query by site + date range, never expose cross-account data
|
|
8. **PDF security** — generated PDFs accessible only to account owner or admin
|
|
9. **Celery app** — `igny8_core` for all tasks
|
|
10. **New dependencies** — `weasyprint`, `matplotlib` added to `requirements.txt`
|
|
|
|
### Cross-References
|
|
|
|
| Doc | Relationship |
|
|
|-----|-------------|
|
|
| 04A Managed Services | Subscription + order data feeds all reports |
|
|
| 02C GSC Integration | GSCMetricsCache → sections 3 (Indexing), 4 (Rankings), 5 (Traffic) |
|
|
| 02E Linker External | SAGBacklink + CampaignKPISnapshot → section 6 (Backlinks) |
|
|
| 02H Socializer | SocialPost + SocialEngagement → section 7 (Social Media) |
|
|
| 01G SAG Health Monitoring | Health score → section 8 (SAG Health) |
|
|
| 04C Pricing Launch | Feature gates control who can access reports + white-label |
|