Skip to content

rdrkr/affilibuster

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

111 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Affilibuster Brand Icon

Affilibuster - A Basic Affiliation Platform

License: Proprietary Python 3.13+ Node.js 22+ TypeScript React Next.js 16+ FastAPI Strapi 5+ PostgreSQL Docker

A modern, production-ready affiliate platform with multi-language support, performance optimization, and clean architecture.

FeaturesArchitectureQuick StartProductionDevelopmentTesting


✨ Features

  • 🌍 Multi-Language Support: English (default), Italian, and Hebrew with automatic RTL layout
  • 💱 Dynamic Currency: Support for multiple currencies (USD, EUR, ILS, GBP, CAD, AUD, JPY, CNY) with user preferences
  • 🔍 SEO Optimized: Comprehensive hreflang tags, schema markup, sitemaps, and breadcrumbs
  • ⚡ High Performance: Static Site Generation (SSG) / Incremental Static Regeneration (ISR) with <3s load times and Lighthouse scores >90
  • 🏗️ Clean Architecture: Domain-driven design with clear separation of concerns and SOLID principles
  • 🧪 Test-First Development: Comprehensive testing infrastructure
  • 🔐 Secure: Affiliate link generation, GDPR compliance, secure credential management
  • 📱 Responsive Design: Mobile-first approach with Tailwind CSS
  • 🎨 Headless CMS: Strapi integration with full content management capabilities

🚀 Quick Start

Prerequisites

Required Software

Docker - Install for your platform:

  • macOS: Docker Desktop or brew install colima docker docker-compose docker-buildx
  • Linux: curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh
  • Windows: Download Docker Desktop

mkcert - For HTTPS development certificates:

  • macOS: brew install mkcert
  • Linux: sudo apt install mkcert or build from source
  • Windows: choco install mkcert or download from releases

One-Command Setup ⚡

# Clone and setup
git clone https://github.com/rdrkr/affilibuster.git
cd affilibuster

# Complete first-time setup (installs tools, dependencies, certificates, and hooks)
make setup

# Start all services
make dev

⏱️ Wait ~30 seconds for all services to be ready.

Access Your Applications

Service URL Notes
TheGreenBrother https://localhost:3001 Next.js Affiliate Site
Backend API https://localhost:8000 FastAPI REST API
API Docs https://localhost:8000/docs Swagger UI
CMS Admin https://localhost:1337/admin Strapi admin panel

Note: All services run on HTTPS with mkcert certificates. Your browser should trust them automatically after running mkcert -install.

Stop Services

make stop

🏗️ Architecture

System Design

Affilibuster follows a single source of truth architecture where all content originates from Strapi CMS and flows through the backend to the TheGreenBrother frontend:

TheGreenBrother (Next.js 16, React 19, TypeScript)
      ↓         (API calls only)
  Backend API   (FastAPI, Python 3.13)
      ↓         (syncs from)
  Strapi CMS    (Headless, PostgreSQL)

Key Rule: TheGreenBrother NEVER talks to Strapi directly. All content flows through the backend API.

Project Structure

affilibuster/                        # Monorepo root
├── backend/                         # FastAPI backend
│ ├── src/affilibuster_backend/
│ │ ├── config/                      # Configuration & settings
│ │ ├── domain/                      # Business logic (Clean Architecture)
│ │ │ ├── entities/                  # Domain models
│ │ │ ├── repositories/              # Repository interfaces
│ │ │ ├── services/                  # Domain services
│ │ │ └── use_cases/                 # Business logic
│ │ ├── infrastructure/              # External integrations
│ │ │ ├── api/                       # FastAPI routes, models, middleware
│ │ │ │ └── routes/                  # API endpoints
│ │ │ ├── cache/                     # Redis implementation
│ │ │ ├── cms/                       # Strapi HTTP client
│ │ │ ├── database/                  # SQLAlchemy setup & models
│ │ │ │ ├── alembic/                 # Database migrations
│ │ │ │ ├── models/                  # Database models
│ │ │ │ └── repositories/            # Repository implementations
│ │ │ ├── email/                     # Email service integration
│ │ │ ├── middleware/                # Custom middleware
│ │ │ └── dependencies.py            # Dependency injection
│ │ └── main.py                      # Application entry point
│ └── tests/
│ ├── fixtures/                      # Test data and helpers
│ ├── integration/                   # Integration tests
│ │ └── infrastructure/              # Infrastructure integration tests
│ └── unit/                          # Unit tests
│ ├── config/                        # Configuration tests
│ ├── domain/                        # Domain layer tests
│ └── infrastructure/                # Infrastructure layer tests
│
├── the-green-brother/               # Next.js 16 affiliate site (TheGreenBrother)
│ ├── src/
│ │ ├── app/                         # Next.js App Router pages
│ │ ├── components/                  # React components
│ │ │ ├── about/                     # About page components
│ │ │ ├── call-to-actions/           # CTA components (Newsletter, etc.)
│ │ │ ├── elements/                  # Shared UI elements (Header, Label, TextBlock, etc.)
│ │ │ ├── footer/                    # Footer components
│ │ │ ├── homepage/                  # Homepage composition (HomeSections)
│ │ │ ├── layout/                    # Layout components
│ │ │ ├── menus/                     # Menu components (Language, Search, Theme)
│ │ │ ├── navigation/                # Navigation (Navbar, MobileMenu)
│ │ │ └── sections/                  # Reusable section components (Hero, FeaturedProducts, etc.)
│ │ ├── lib/                         # Utilities, API clients, hooks (feature-based subdirs)
│ │ ├── i18n/                        # Internationalization configuration
│ │ └── styles/                      # Global styles and theme
│ ├── Dockerfile                     # TheGreenBrother dev server container
│ ├── Dockerfile.prod                # Production 3-stage build (standalone Next.js)
│ └── Dockerfile.test-runner         # Lightweight Playwright test container
│
├── cms/                             # Strapi 5 headless CMS
│ ├── config/                        # Strapi configuration files
│ ├── src/
│ │ ├── api/                         # Content types (25+ types including:)
│ │ │ ├── about/                     # About page content
│ │ │ ├── author/                    # Blog authors
│ │ │ ├── blog/                      # Blog listing page
│ │ │ ├── blog-post/                 # Blog posts
│ │ │ ├── blog-post-tag/             # Blog post tags
│ │ │ ├── contact-us/                # Contact page content
│ │ │ ├── currency/                  # Currency configuration
│ │ │ ├── footer/                    # Footer content
│ │ │ ├── homepage/                  # Homepage content
│ │ │ ├── navigation/                # Navigation structure
│ │ │ ├── product/                   # Product content type
│ │ │ ├── product-category/          # Product categories
│ │ │ ├── product-tag/               # Product tags
│ │ │ └── [+11 more types]           # FAQ, Privacy, Terms, Error pages, etc.
│ │ ├── components/                  # UI component schemas
│ │ ├── plugins/                     # Custom Strapi plugins
│ │ │ ├── strapi-plugin-nested-populator/  # Deep nested content population via REST API
│ │ │ └── strapi-plugin-relation-filter/   # Admin panel relation dropdown filtering
│ │ ├── index.ts                     # Strapi entry point
│ │ └── utils/                       # Utility functions
│ └── scripts/                       # Build and utility scripts
│
├── contracts/                       # OpenAPI specifications (source of truth)
│ └── template.openapi.yaml          # Backend API specification (version controlled)
│                                    # Note: strapi.openapi.yaml and affilibuster.openapi.yaml are
│                                    # generated at runtime by CMS and Backend respectively
│
├── specs/                           # Feature specifications & designs
├── scripts/                         # Development & deployment scripts
│ ├── audit.sh                       # Security audit
│ ├── backup-db.sh                   # Production PostgreSQL backup (30-day retention)
│ ├── build.sh                       # Build all services
│ ├── clean.sh                       # Clean build artifacts
│ ├── format.sh                      # Format code
│ ├── lint.sh                        # Lint code
│ ├── setup.sh                       # Development setup
│ └── test.sh                        # Run tests
│
├── .github/
│ └── workflows/
│   ├── ci.yaml                      # CI pipeline (tests, lint, type-check)
│   └── deploy.yaml                  # CD pipeline (SSH deploy to Hetzner VPS)
│
├── .specify/                        # SpecKit project configuration
│ ├── memory/constitution.md         # Project constitution & principles
│ ├── scripts/                       # SpecKit automation scripts
│ └── templates/                     # Documentation templates
│
├── .claude/                         # Claude AI configuration
│ └── commands/                      # Custom AI commands
│
├── data/                            # Static data files
│ ├── assets/                        # Uploaded media assets
│ ├── backend-seed.jsonl             # Backend seed data
│ ├── configuration/                 # Configuration exports
│ ├── entities/                      # Entity data exports
│ └── links/                         # Link data
│
├── docs/                            # Project documentation
│ ├── eco-friendly-affiliate-website-prd.md
│ └── specs/
│
├── Caddyfile                        # Production reverse proxy (auto SSL, routing, security headers)
├── Caddyfile.remote                 # Local proxy for remote-backend development
├── docker-compose.yaml              # Local development environment (all services)
├── docker-compose.remote.yaml       # Remote-backend development (local frontend → prod backend)
└── docker-compose.prod.yaml         # Production environment (Hetzner VPS)

🛠️ Technology Stack

  • TheGreenBrother: Next.js 16, React 19, TypeScript 5.7+, Tailwind CSS 4, next-intl
  • Backend: FastAPI 0.120+, Python 3.13+, PostgreSQL 15+, Redis, Alembic
  • CMS: Strapi 5+, PostgreSQL 15+, i18n plugin
  • Infrastructure: Docker & Docker Compose, Caddy (production reverse proxy + auto SSL)

🎯 Design Principles

  • Clean Architecture: Business logic isolated from framework dependencies
  • SOLID Principles: Single responsibility, open/closed, Liskov substitution, interface segregation, dependency inversion
  • Test-First Development: Tests written before implementation (TDD)
  • API-First Design: OpenAPI specifications as source of truth
  • Modular Architecture: Reusable components across affiliate sites
  • Performance & SEO Standards: <3s load times, Lighthouse scores >90
  • Strong Typing: Strict type safety with explicit annotations and generated model usage

Clean Architecture Layers

Affilibuster implements Clean Architecture with strict dependency rules to ensure business logic remains isolated from external concerns:

┌─────────────────────────────────────────────────┐
│              Frameworks & Drivers               │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │   Next.js   │ │   FastAPI   │ │   Strapi    │ │
│ │    React    │ │ PostgreSQL  │ │    Redis    │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────┐
│               Interface Adapters                │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │   Routes    │ │ Controllers │ │Repositories │ │
│ │   Views     │ │ Presenters  │ │ Gateways    │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────┐
│                    Use Cases                    │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │   Business  │ │ Application │ │   Domain    │ │
│ │    Rules    │ │  Services   │ │   Logic     │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────┐
│                     Entities                    │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │   Product   │ │     User    │ │  Language   │ │
│ │   Currency  │ │    Locale   │ │   Config    │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────┘

Layer Responsibilities

Entities (Innermost Circle)
  • Core business objects and enterprise-wide business rules
  • Pure domain models with no framework dependencies
  • Examples: Product, User, Language, Currency entities
Use Cases
  • Application-specific business rules
  • Orchestrate data flow between entities and interface adapters
  • Contain the application's use case logic
Interface Adapters
  • Convert data from/to external formats
  • Presenters, controllers, repositories, gateways
  • Interface between use cases and frameworks
  • Examples: FastAPI routes, React components, repository implementations
Frameworks & Drivers (Outermost Circle)
  • UI frameworks, databases, external APIs
  • All technical infrastructure details
  • Examples: Next.js, FastAPI, PostgreSQL, Strapi, Redis

Dependency Flow

Critical Rule: Dependencies point inward only - outer layers depend on inner layers, never the reverse:

Frameworks → Interface Adapters → Use Cases → Entities

This ensures:

  • Business logic isolation - no framework dependencies in domain layer
  • Testability - inner layers can be tested independently
  • Flexibility - frameworks can be replaced without affecting business logic
  • Maintainability - clear separation of concerns

🚢 Production Deployment (Hetzner VPS)

Affilibuster runs on a self-hosted Hetzner VPS with Docker, Caddy for automatic SSL, and GitHub Actions for continuous deployment.

Production Architecture

Internet
  │
  ▼
Caddy (ports 80/443) ── automatic Let's Encrypt SSL
  ├── thegreenbrother.com       → the-green-brother:3000 (Next.js standalone)
  ├── thegreenbrother.com/api/* → backend:8000 (FastAPI, /api prefix stripped)
  └── cms.thegreenbrother.com   → strapi:1337 (Strapi CMS)

Internal Docker network (HTTP only):
  ├── postgres:5432
  ├── redis:6379
  ├── strapi:1337
  ├── backend:8000
  └── the-green-brother:3000

All inter-service communication is plain HTTP inside Docker. Caddy terminates SSL at the edge.

Production Files

File Purpose
docker-compose.prod.yaml Caddy, resource limits, restart policies, log rotation
docker-compose.remote.yaml Local frontend + Caddy proxy → production backend
Caddyfile Auto SSL, path-based routing, security headers
Caddyfile.remote Local proxy: /api/* → prod, rest → local frontend
cms/Dockerfile.prod Multi-stage Strapi (node:22-alpine, non-root)
backend/Dockerfile.prod Multi-stage FastAPI (python:3.13-slim, non-root)
backend/docker-entrypoint.prod.sh Wait for PG, alembic migrate, uvicorn
the-green-brother/Dockerfile.prod 3-stage Next.js standalone (non-root)
.env.prod.example Production env template
.github/workflows/deploy.yaml CD: SSH deploy, health checks, image prune
scripts/setup-vps.sh Server hardening + Docker installation
scripts/generate-env.sh Interactive .env.prod generator with auto secrets
scripts/backup-db.sh Daily pg_dump, 30-day retention

Build & Deploy

# On the VPS:

# 1. Setup environment (install Docker, etc.)
make setup-vps

# 2. Generate production secrets
make generate-env

# 3. Build and Start
make build-prod
make start-prod

# View logs
make logs-prod

# Stop services
make stop-prod

# Check service health
curl -sf https://thegreenbrother.com
curl -sf https://thegreenbrother.com/api/v1/health
curl -sf https://cms.thegreenbrother.com/api/health

Automated Deployment (CI/CD)

Pushing to main triggers:

  1. CI (.github/workflows/ci.yaml): Tests, lint, type-check
  2. CD (.github/workflows/deploy.yaml): SSH into VPS, pull, build, deploy, health check, prune old images

Required GitHub secrets: VPS_HOST, VPS_USER, VPS_SSH_KEY, VPS_SSH_KNOWN_HOSTS.

Backup Strategy

  • Daily DB backups: scripts/backup-db.sh via cron at 3 AM UTC to Hetzner Cloud Volume (/mnt/backups/)
  • 30-day retention with automatic cleanup
  • Hetzner server snapshots: Built-in full server backup

📊 Monitoring (Uptime Kuma)

Affilibuster uses Uptime Kuma for self-hosted monitoring of all services.

  • URL: https://uptime.thegreenbrother.com
  • Configuration: Defined in code at uptime-kuma-monitors.yaml
  • Auto-Provisioning: Monitors are automatically synced on every deployment via scripts/provision_uptime.py.

adding New Monitors

  1. Edit uptime-kuma-monitors.yaml in the root directory.
  2. Commit and push your changes.
  3. The deployment pipeline will automatically update Uptime Kuma.

Manual Provisioning

If you need to sync monitors manually without a full deployment:

# SSH into VPS
make ssh

# Run provisioning script
docker compose -f docker-compose.prod.yaml exec backend /app/.venv/bin/python scripts/provision_uptime.py

🛠️ Development

Getting Started

# Show all available commands
make help

# Complete first-time setup
make setup

# Start all services (Docker + TheGreenBrother + Backend + CMS)
make dev

# Start only Docker services
make start

# Stop services
make stop

# Restart services
make restart

# View logs
make logs                # All services
make logs-backend        # Backend only
make logs-the-green-brother       # TheGreenBrother only

# Check service status
make ps
make health

Remote-Backend Development

Develop the frontend locally while using the production backend and CMS. A local Caddy proxy mirrors the production routing pattern (/api/* → production backend), eliminating CORS issues.

# Start frontend against production backend & CMS
make start-remote

# Start with log tailing
make dev-remote

# View logs
make logs-remote

# Stop
make stop-remote

# Rebuild frontend image
make build-remote

How it works: A local Caddy reverse proxy listens on localhost:3000 and routes /api/* requests to thegreenbrother.com (production), while all other requests go to the local Next.js dev server with hot reload.

File Purpose
docker-compose.remote.yaml Frontend + local Caddy proxy
Caddyfile.remote Routes /api/* to prod, rest to local frontend

Development Workflow

  1. Environment Setup: make setup handles all prerequisites
  2. Start Development: make dev starts everything you need
  3. Code Changes: Edit files in your preferred editor
  4. Testing: Run make test to ensure quality
  5. Code Quality: Use make lint and make format to maintain standards
  6. Deployment: Use make build for production builds

Database Migrations

Affilibuster uses Alembic for database schema migrations in the backend.

Migration Commands

# Run migrations (apply pending migrations)
cd backend
uv run task migrate

# Create a new migration (auto-generate from model changes)
uv run task migrate-create "description of changes"

# View migration history
uv run task migrate-history

# Check current migration version
uv run task migrate-current

# Rollback one migration
uv run task migrate-downgrade

How It Works

  • Models First: Define your SQLAlchemy models in backend/src/affilibuster_backend/infrastructure/database/models/
  • Auto-Generate: Alembic detects model changes and generates migration files
  • Version Control: Migration files in backend/alembic/versions/ are committed to git
  • Docker Integration: Migrations run automatically on make dev via docker-entrypoint.sh

Configuration

  • Migration Config: backend/alembic.ini (required by Alembic)
  • Task Commands: Defined in backend/pyproject.toml under [tool.taskipy.tasks]
  • Database URL: Loaded from affilibuster_backend.config.settings in alembic/env.py

Important Notes

  • Never delete migrations - they're part of your schema history
  • Always test migrations before committing (up and down)
  • Review auto-generated migrations - Alembic may miss some changes
  • Docker handles migrations - no manual migrate needed when using make dev

🧪 Testing

Test Philosophy

Affilibuster tests are divided into two distinct categories with different purposes:

E2E Tests (Correctness)

  • Purpose: Verify that features work correctly
  • NO explicit timeouts - tests use global timeout (5 minutes)
  • NO waitForTimeout() calls - wait for elements/states, not arbitrary time
  • Tests should pass regardless of system load
  • Focus on "Does it work?" not "Is it fast?"

Performance Tests (Timing)

  • Purpose: Verify performance requirements are met
  • Production builds only - skip on development builds
  • Strict timing thresholds - defined in tests/config/performance-thresholds.ts
  • Network throttling - simulate real-world conditions (3G)
  • Focus on "Is it fast enough?"

Test Architecture

Affilibuster uses a dedicated test-runner container for all Playwright E2E and performance tests, providing:

  • Lightweight Container: Uses Dockerfile.test-runner - only Playwright dependencies, no Next.js build
  • Resource Isolation: Tests run in a separate container from the dev server, eliminating resource contention
  • Dedicated Resources: 4 CPU cores and 4GB RAM allocated specifically for test execution
  • Improved Stability: Webkit tests no longer timeout due to system load from dev server hot-reload/compilation
  • Better Performance: Tests can run in parallel without degrading the dev server
  • Persistent Browser Cache: Playwright browsers are installed once and cached across test runs

Architecture:

┌─────────────────┐     ┌───────────────────┐     ┌─────────────┐
│   test-runner   │────▶│ the-green-brother │────▶│   backend   │
│   (Playwright)  │     │   (Dev Server)    │     │  (FastAPI)  │
│   4 CPU / 4GB   │     │      1 CPU        │     │             │
└─────────────────┘     └───────────────────┘     └─────────────┘

Tests execute in test-runner, hitting the the-green-brother dev server, which calls the backend API.

Quick Commands

# Run all tests with coverage
make test

# Run tests in parallel (faster)
make test-parallel

# Individual modules
make test-backend          # Backend (pytest)
make test-the-green-brother         # TheGreenBrother (Jest)
make test-cms              # CMS (when custom code added)

# E2E tests with specific browser
make test-the-green-brother-integration BROWSER=webkit
make test-the-green-brother-integration BROWSER=chromium
make test-the-green-brother-integration BROWSER=firefox

# Performance tests
make test-performance BROWSER=chromium

# Coverage reports
make coverage-merge        # Merge all module reports
make coverage-view         # Open merged HTML report

🎨 Code Quality

Quick Commands

# Check code style
make lint              # Check all code style
make lint-fix          # Auto-fix linting issues

# Format code
make format            # Format all code
make format-check      # Check formatting without changes

# Specific modules
make lint-python            # Check Python code
make lint-typescript        # Check TypeScript/JavaScript
make lint-openapi           # Validate OpenAPI specs

Tools & Standards

  • Python: Ruff (linter/formatter), MyPy (type checker)
  • TypeScript: ESLint (linter), Prettier (formatter)
  • OpenAPI: Redocly (validation)
  • Pre-commit hooks: Automatically installed with make setup

📡 API Documentation

OpenAPI Architecture

Affilibuster uses a layered OpenAPI architecture with auto-generated types for type safety across all services.

Layered Specification System

┌──────────────────────────────────────────────────────────┐
│ OpenAPI Specifications                                   │
├──────────────────────────┬───────────────────────────────┤
│ Layer 1: Strapi Content  │ Layer 2: Backend Services     │
├──────────────────────────┼───────────────────────────────┤
│ • Product                │ • Currencies API              │
│ • Homepage               │ • Preferences API             │
│ • Navigation             │ • Language Detection          │
│ • Pages                  │ • Content Proxy Endpoints     │
│ (i18n, rich fields)      │ (extends Strapi types)        │
└──────────────────────────┴───────────────────────────────┘
            │                             │
            │     references via $ref     │
            └─────────────────────────────┘
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
       Code Generators            Code Generators
     @hey-api/openapi-ts       datamodel-code-generator
              │                         │
              ▼                         ▼
      TypeScript Types         Python Pydantic Models
          generated/                backend/src/
                            infrastructure/api/generated/

Specification Files

  • Template (Backend API): contracts/template.openapi.yaml - Defines all backend endpoints and types
  • Strapi Content: contracts/strapi.openapi.yaml - Auto-generated content schemas (generated by CMS during startup)
  • Merged Specification: contracts/affilibuster.openapi.yaml - Merged spec (generated by Backend during startup)
  • Backend references Strapi via external $ref for clean separation of concerns

Interactive Documentation

Key Commands

# Validate OpenAPI specifications
make lint-openapi

# Regenerate Strapi OpenAPI (when content types change)
cd cms && npm run openapi:generate

🌐 Content Architecture

Single Source of Truth: Strapi CMS

All user-facing content originates from Strapi CMS, ensuring consistency and scalability.

Content Types

  • Collection Types: Products, languages, currencies, locales
  • Single Types: Navigation, footer, homepage, about, contact, legal pages

Adding New Languages

  1. Add new locale in Strapi admin panel
  2. Update backend/scripts/seed.py with new language seeding data
  3. Run make seed or let it happen automatically on startup
  4. Zero backend code changes required

Custom CMS Plugins

Affilibuster includes two custom Strapi plugins managed in-house under cms/src/plugins/:

strapi-plugin-nested-populator

Automatically populates deeply nested content structures in Strapi REST API responses. When a query includes customPopulate=nested, the plugin intercepts the request via a Document Service middleware and recursively builds a full populate tree for all components, dynamic zones, relations, and media fields. Supports configurable maximum depth (defaultDepth), field ignore lists, and automatic circular reference prevention. Creator fields (admin::user) are skipped by default to reduce response size.

strapi-plugin-relation-filter

Filters relation dropdowns in the Strapi admin panel based on pluginOptions configuration defined in content type schemas. When editing content in the admin panel, relation fields normally show all available entries. This plugin overrides the findAvailable handler on the content-manager's relations controller to automatically apply filters defined in each attribute's pluginOptions, restricting which related entries appear in the dropdown.


⚡ Performance & SEO

Performance Targets

  • Page load <3s on 3G connections
  • Lighthouse scores >90
  • LCP <2.5s, FCP <1.8s, TTFB <600ms

SEO Features

  • Comprehensive hreflang tags for multi-language support
  • Schema markup (Product, BreadcrumbList, Organization)
  • Sitemaps for each language
  • Meta tags, OG tags, image optimization
  • Critical CSS inlined, pagination instead of infinite scroll

📚 Acknowledgments

Affilibuster is built on the shoulders of giants. We are deeply grateful to the open-source community and the maintainers of the following projects:

Core Frameworks

Databases & Infrastructure

Backend Dependencies (Python)

TheGreenBrother Dependencies (TypeScript/JavaScript)

Development & Testing Tools

Code Generation & API Tools

Security & Quality

GitHub Actions

Additional Libraries

For a complete list of all dependencies, please see:

We are grateful to all the maintainers and contributors of these projects. Without their dedication and hard work, Affilibuster would not be possible. Thank you! 🙏


Made with ❤️ by the Affilibuster Team