# How MVC Architecture Is Implemented in MoneyPrinterTurbo: FastAPI Structure Explained

> Explore how MoneyPrinterTurbo implements MVC architecture with FastAPI. Learn about Pydantic models, controller modules, and FastAPI's view layer for efficient data and media delivery.

- Repository: [Harry/MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo)
- Tags: architecture
- Published: 2026-03-23

---

**MoneyPrinterTurbo implements a clean MVC architecture using FastAPI, where Pydantic models handle data validation and state management, controller modules manage HTTP routing and orchestration, and FastAPI's response handling combined with static file mounts serve as the view layer for JSON and media delivery.**

MoneyPrinterTurbo is an AI-powered video generation application built on FastAPI that leverages a structured MVC (Model-View-Controller) pattern to separate concerns between data management, business logic, and presentation. This architectural approach makes the codebase modular, testable, and extensible for adding new AI-driven media generation features.

## MVC Architecture Overview in MoneyPrinterTurbo

The project adapts classic MVC principles to the asynchronous, HTTP-centric world of FastAPI. Each layer has distinct responsibilities and implementation files:

| MVC Layer | Responsibility | Primary Implementation | Key Example |
|-----------|----------------|------------------------|-------------|
| **Model** | Defines data structures, validation rules, constants, and state-management logic | Pydantic schemas ([`app/models/schema.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/models/schema.py)), constants ([`app/models/const.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/models/const.py)), state services ([`app/services/state.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/services/state.py)) | `VideoParams`, `TASK_STATE_PROCESSING`, `MemoryState` |
| **View** | Serializes model data into HTTP responses and serves static files | FastAPI response models, `utils.get_response`, `StaticFiles` mounts in [`app/asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/asgi.py) | `utils.get_response(200, data)`, video file serving |
| **Controller** | Handles HTTP requests, orchestrates service calls, and maps URLs to functions | Router modules in `app/controllers/v1/` ([`video.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/video.py), [`llm.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/llm.py)), root router ([`app/router.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/router.py)) | `@router.post("/videos")` → `create_video` |

## The Model Layer: Data Validation and State Management

The Model layer in MoneyPrinterTurbo is responsible for data integrity, validation, and persistence. It uses Pydantic for schema definition and custom state classes for runtime data storage.

### Pydantic Schemas for Request Validation

All request and response bodies are defined using **Pydantic** models in [`app/models/schema.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/models/schema.py), guaranteeing type safety and automatic OpenAPI documentation generation.

```python

# app/models/schema.py

class VideoParams(BaseModel):
    """Parameters supplied when creating a video task."""
    video_subject: str
    video_script: str = ""          # optional script supplied by the user

    video_aspect: Optional[VideoAspect] = VideoAspect.portrait.value
    # … other fields omitted for brevity

```

### Constants and Enums

Shared constants such as task states and supported file types live in [`app/models/const.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/models/const.py). These enums are reused across schemas and services to maintain consistency.

```python

# app/models/const.py

TASK_STATE_PROCESSING = 4
FILE_TYPE_VIDEOS = ["mp4", "mov", "mkv", "webm"]

```

### State Management with MemoryState and RedisState

The Model layer also encapsulates runtime task state through the `BaseState` abstraction. The implementation chooses between **in-memory** (`MemoryState`) and **Redis** (`RedisState`) based on configuration.

```python

# app/services/state.py

class MemoryState(BaseState):
    def __init__(self):
        self._tasks = {}

    def update_task(self, task_id: str, state: int = const.TASK_STATE_PROCESSING, progress: int = 0, **kwargs):
        self._tasks[task_id] = {"task_id": task_id, "state": state, "progress": progress, **kwargs}

```

## The View Layer: JSON Responses and Static Media

In MoneyPrinterTurbo, the View layer is responsible for serializing Model data into HTTP responses. FastAPI handles much of this automatically, but the project adds standardization through utility functions and static file mounts.

### Standardized JSON Response Envelopes

The [`app/utils/utils.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/utils/utils.py) file provides a helper function to ensure all API responses follow a consistent envelope structure.

```python

# app/utils/utils.py

def get_response(status: int, data: Any = None, message: str = "success"):
    return {"status": status, "message": message, "data": data}

```

### Serving Generated Videos via StaticFiles

The View layer also serves generated media directly. In [`app/asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/asgi.py), `StaticFiles` mounts act as the view for video resources, making completed tasks downloadable or streamable.

```python

# app/asgi.py

task_dir = utils.task_dir()
app.mount("/tasks", StaticFiles(directory=task_dir, html=True, follow_symlink=True), name="")
public_dir = utils.public_dir()
app.mount("/", StaticFiles(directory=public_dir, html=True), name="")

```

## The Controller Layer: Routing and Business Logic

Controllers in MoneyPrinterTurbo handle HTTP request validation, orchestrate service calls, and return view responses. They are organized under `app/controllers/v1/` and aggregated by a root router.

### Video Generation Endpoints

The [`app/controllers/v1/video.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/controllers/v1/video.py) module defines endpoints for creating and managing video tasks. It validates incoming `TaskVideoRequest` models and delegates processing to the task manager.

```python

# app/controllers/v1/video.py

@router.post("/videos", response_model=TaskResponse, summary="Generate a short video")
def create_video(background_tasks: BackgroundTasks, request: Request, body: TaskVideoRequest):
    return create_task(request, body, stop_at="video")

```

The `create_task` helper function demonstrates the controller's orchestration role:

```python
def create_task(request: Request, body: Union[TaskVideoRequest, SubtitleRequest, AudioRequest], stop_at: str):
    task_id = utils.get_uuid()
    request_id = base.get_task_id(request)
    task = {"task_id": task_id, "request_id": request_id, "params": body.model_dump()}
    sm.state.update_task(task_id)                     # Model update

    task_manager.add_task(tm.start, task_id=task_id, params=body, stop_at=stop_at)   # Service call

    return utils.get_response(200, task)              # View response

```

### LLM Script Generation Endpoints

The [`app/controllers/v1/llm.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/controllers/v1/llm.py) module handles AI-driven content creation, following the same pattern of validating models and returning standardized responses.

```python

# app/controllers/v1/llm.py

@router.post("/scripts", response_model=VideoScriptResponse, summary="Create a script for the video")
def generate_video_script(request: Request, body: VideoScriptRequest):
    video_script = llm.generate_script(
        video_subject=body.video_subject,
        language=body.video_language,
        paragraph_number=body.paragraph_number,
    )
    return utils.get_response(200, {"video_script": video_script})

```

### Router Aggregation

The root router in [`app/router.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/router.py) collects all version-specific controllers, forming the complete API surface.

```python

# app/router.py

root_api_router = APIRouter()
root_api_router.include_router(video.router)   # Controller → View

root_api_router.include_router(llm.router)

```

## Wiring the Application Together

The [`app/asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/asgi.py) file serves as the application bootstrap, mounting the root router and initializing the view layer's static file handling. This completes the MVC pipeline by connecting controllers to the FastAPI application instance and configuring the view components for media delivery.

## Summary

MoneyPrinterTurbo demonstrates a clean implementation of MVC architecture within the FastAPI ecosystem:

- **Models** define data structures using Pydantic schemas, manage constants in [`const.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/const.py), and handle runtime state through `MemoryState` or `RedisState` implementations.
- **Views** serialize data through standardized JSON envelopes in `utils.get_response` and serve generated media via `StaticFiles` mounts in [`asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/asgi.py).
- **Controllers** in `app/controllers/v1/` handle HTTP routing, validate incoming models, orchestrate service calls, and return consistent view responses through the root router aggregation.

## Frequently Asked Questions

### How does MoneyPrinterTurbo handle state management within the MVC pattern?

MoneyPrinterTurbo implements state management in the Model layer through the `BaseState` abstraction defined in [`app/services/state.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/services/state.py). The system supports both `MemoryState` for in-memory storage during development and `RedisState` for production persistence, allowing controllers to update task progress via `sm.state.update_task()` while remaining agnostic to the underlying storage mechanism.

### What serves as the View layer in this FastAPI implementation?

The View layer consists of two primary components: standardized JSON response envelopes generated by `utils.get_response()` in [`app/utils/utils.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/utils/utils.py), and static file mounts configured in [`app/asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/asgi.py) using FastAPI's `StaticFiles`. Together, these components handle both API data serialization and direct media delivery for generated video files.

### Where are the Controller endpoints defined in the project?

Controller endpoints are organized under `app/controllers/v1/`, with specific modules like [`video.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/video.py) handling video generation routes and [`llm.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/llm.py) managing AI script creation. These are aggregated into the root API router in [`app/router.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/router.py) using `root_api_router.include_router()`, creating a centralized routing structure that connects to the FastAPI application instance in [`app/asgi.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/asgi.py).

### How does the Model layer validate incoming API requests?

The Model layer uses Pydantic schemas defined in [`app/models/schema.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/models/schema.py) to enforce data validation automatically. When a controller receives a request, FastAPI validates the payload against these schemas—such as `VideoParams` or `TaskVideoRequest`—ensuring type safety and generating OpenAPI documentation before the controller logic executes.