Environment-driven provider selection
The application treats AI vendor choice as configuration rather than code-level branching, which keeps the system extensible and allows switching among OpenAI, Gemini, Claude, or mock mode without code changes.
Built a FastAPI-based backend that automates end-to-end marketing campaign generation, scheduling, and dispatch using AI-generated text and image assets, with a resilient provider abstraction, SQLAlchemy persistence, and background processing. The system implements a domain-driven campaign workflow, runtime provider switching, deterministic fallback behavior, and containerized deployment for a single-process asynchronous scheduler.
01Context
The project is a backend service for creating marketing campaigns, generating campaign copy and visuals from a prompt, scheduling delivery, and dispatching a simulated SMS at the target time.
Marketing teams need a repeatable way to turn a campaign brief into text, image, and delivery logic without manual coordination across separate AI and messaging workflows.
Deliver an automated campaign lifecycle from prompt intake to scheduled execution while keeping the system resilient when AI providers are unavailable and easy to configure through environment variables.
The application centers a Campaign model and a scheduling workflow that validate inputs, persist campaign records, invoke the selected AI provider, generate local image assets, and dispatch due campaigns through a bounded asynchronous polling loop.
02Ownership
The areas I owned end to end as Backend Engineer.
Designed and implemented a REST API for campaign creation and retrieval with Pydantic validation, status tracking, and SQLite persistence using SQLAlchemy models and session management.
Implemented a background scheduler that polls due campaigns every 10 seconds, generates copy and promotional images, records results to the campaign record, and simulates SMS dispatch without blocking on external AI failures.
Built a pluggable AI provider system for text and image generation with runtime configuration via environment variables, supporting OpenAI, Google Gemini, and Anthropic Claude with deterministic mock fallback when credentials or APIs are unavailable.
Structured the project around service-oriented modules for text generation, image generation, SMS simulation, and scheduling to keep business logic readable, extensible, and isolated from the FastAPI app layer.
Containerized the application with Docker and docker-compose, mounted persistent storage for the SQLite database and generated images, and exposed health checks and Swagger documentation for local and production deployment workflows.
03System design
Layer 01
The FastAPI app exposes a small campaign API at /campaigns, validates inbound payloads with Pydantic schemas, and uses SQLAlchemy sessions to persist and fetch Campaign records while keeping request handlers thin and focused on transport concerns.
Layer 02
The scheduler coordinates text generation, image generation, and SMS simulation through dedicated service classes, creating a clear separation between orchestration logic and vendor-specific provider implementations.
Layer 03
Text and image providers are selected at runtime from configuration and wrapped in factory functions; when a provider is missing, misconfigured, or errors, the system falls back to deterministic mock implementations rather than failing campaign dispatch.
Layer 04
Generated images are written to a local directory and served through a FastAPI static mount, while Docker volume configuration ensures the SQLite database and generated images persist across container restarts.
04Engineering judgment
The application treats AI vendor choice as configuration rather than code-level branching, which keeps the system extensible and allows switching among OpenAI, Gemini, Claude, or mock mode without code changes.
The project explicitly enforces one running scheduler instance in production because the same due campaign should not be dispatched multiple times; the README documents this constraint and the Docker setup is built around a single worker process.
Generated image bytes are saved to disk and exposed through a static route so the backend can return a stable URL even when the underlying AI SDK returns raw binary output rather than a remote hosted image URL.
Fail-safe logic in the text and image generator services ensures a campaign still completes with fallback content and a placeholder image if an AI API is unavailable, which is important for maintaining automation continuity.
05Toolbox
06Capabilities
The API supports creating campaigns with name, prompt, phone number, and scheduled time, persists them in a Campaign model with status transitions, and exposes endpoints to list all campaigns or fetch a single campaign record.
The text generator service delegates to the configured provider and formats a short SMS-appropriate marketing message using a shared system prompt, with response validation and fallback output when generation fails.
The image generation pipeline creates a visual asset from the campaign prompt, stores it locally, and returns a URL for a static endpoint so the final message includes a generated image reference.
A background asyncio loop checks for pending campaigns whose schedule_time is due, generates content, updates the campaign status to sent, and triggers the SMS simulation for the target number.
The app exposes a /health endpoint and structured logging for campaign creation, scheduler runs, provider calls, and dispatch operations, making it easier to monitor the service in Docker and containerized environments.
07Problem solving
Challenge 01
External API failures, empty responses, or absent keys could block campaign execution and break the full dispatch flow.
The factory and service layers validate configuration, catch provider initialization or runtime errors, and route to deterministic mock providers so scheduling remains operational without manual intervention.
Challenge 02
In a polling background scheduler, duplicate execution across workers or repeated process instances can trigger the same campaign multiple times.
The project documents the requirement for only one scheduler process and configures the production Docker setup to run a single worker, reducing the risk of multiple dispatches.
Challenge 03
Different providers return different formats and delivery mechanisms for image generation, including raw bytes and temporary URLs.
A shared local storage helper converts raw image bytes to files and returns a servable URL, while the image provider interface normalizes this behavior across providers.
Challenge 04
A clean development setup should not require external account credentials or service quotas for basic execution.
Default configuration selects the mock provider and the code explicitly falls back to deterministic outputs when no provider is configured or when a real provider fails.
08Result
Built a modular backend workflow for campaign automation that separates API, persistence, provider logic, and background execution.
Achieved resilient AI execution by defaulting to deterministic mock providers when credentials or external APIs are unavailable.
Created a deployment-ready service with Docker configuration, persistent storage for the database and generated images, and a clear production single-worker constraint.
Produced a maintainable architecture where provider implementations are isolated behind factories and shared interfaces, allowing new AI vendors to be added without rewriting core orchestration.
09Reflection
AI-first backends need explicit failure handling and fallback behavior to remain operational when third-party services are unavailable or misconfigured.
Background processing is most reliable when orchestration and execution boundaries are clear, especially when there is a risk of duplicate dispatches in distributed or multi-worker environments.
Local asset persistence is a practical solution when AI-generated media is returned as raw bytes rather than hosted URLs, reducing dependency on external storage during early-stage deployment.
Next step
I take on backend, API, and DevOps work — from data modelling and REST design through containerization and production deployment.
A project case study by Md Fahad Mir — Backend & DevOps Engineer, Dhaka, Bangladesh.