Introduction
Why I Built MyChronicle 2.0
MyChronicle started as a personal solution to a simple problem: keeping track of different types of media across multiple platforms.
The first version allowed users to search, track, and review movies, TV shows, anime, and manga in one place. However, as the application evolved, I began to recognize a significant architectural limitation: MyChronicle relied too heavily on third-party APIs to function.
Most media data was fetched directly from AniList and TMDB, meaning MyChronicle essentially acted as a wrapper around external services. I had ownership of user data, but very little ownership of the actual media data powering the application.
I wanted to change that.
2.0 is a major architectural improvement focused on building an independent media data layer, reducing external API dependencies, and making the application more scalable and maintainable.
It is also an opportunity to challenge myself, explore new concepts, and gain experience building a more realistic, data-driven application.
What It Does
MyChronicle provides a centralized platform for tracking different types of media.
Users can:
- Search and discover movies, TV shows, anime, and manga.
- Browse popular and trending media.
- View detailed information enriched from multiple metadata providers.
- Maintain a personal media library.
- Write personal notes and reviews for tracked media.
Unlike the previous version, 2.0 maintains its own media records and internal identifiers. Third-party APIs are used as metadata providers rather than being the foundation of the application's data model.
What's Different in 2.0?
The biggest change is how MyChronicle handles media data.
Instead of simply forwarding requests to third-party APIs, 2.0 introduces an internal media model with its own identifiers. External API identifiers are maintained separately and associated with the corresponding internal media record.
API responses are stored in MongoDB with TTL-based expiration, reducing repeated requests while allowing metadata to be refreshed.
Additionally, multiple APIs are used to enrich media records with information that may be missing from individual providers.
The goal is to move from an API-dependent application to an application that owns and manages its own media data.
Architecture & Tech Highlights
Internal Media Data Layer
One of the most important architectural changes in 2.0 is the introduction of an internal media model.
In 2.0, user library entries and reviews referenced media using identifiers provided by third-party APIs. This created a strong dependency on external data providers.
In 2.0, each media record has its own internal identity. External provider identifiers are maintained separately as references associated with that record.
For example, a movie can have a TMDB ID and an IMDb ID while maintaining a single internal MyChronicle ID.
The data model distinguishes between:
- Primary ID: Identifies the primary external media record.
- Primary Source: Identifies the provider associated with that primary ID.
- External IDs: Maintains identifiers from other providers.
- Internal ID: Identifies the media record within MyChronicle itself.
This allows user data to reference MyChronicle's own media records rather than depending directly on external providers.
Media Synchronization & External Data Management
V2 introduces a synchronization process that retrieves metadata from external providers, stores their responses, and creates or reuses internal media records.
When a user requests detailed information about a media item, the backend performs the following operations:
- Fetches the primary media details from TMDB or AniList.
- Identifies additional metadata providers using available external identifiers.
- Retrieves enrichment data from OMDb or MyAnimeList when applicable.
- Stores the external API responses in MongoDB with TTL-based expiration.
- Checks whether the corresponding internal media record already exists.
- If it doesn't exist, creates a new internal media record using the available metadata.
- Combines the relevant data into a unified response for the frontend.
For example, when synchronizing an anime from AniList, the backend checks whether a MAL identifier is available. If it is, the corresponding MAL data is retrieved and used to enrich the media information.
Alongside this synchronization process, V2 introduces persistent storage for external API responses. Rather than treating provider responses as temporary data that only exists during a request, they are stored in MongoDB with TTL-based expiration.
This provides several benefits:
- Avoids repeatedly requesting the same metadata from external APIs.
- Reduces unnecessary API calls and helps prevent rate limits.
- Allows previously retrieved responses to be reused.
- Provides a controlled expiration mechanism so metadata can be refreshed.
The expiration time is calculated based on the media data being synchronized rather than treating every response as permanently valid.
It is important to distinguish between external API response storage and internal media records: TTL expiration applies only to the stored external API responses, not to the core media records or user data.
This approach allows multiple providers to contribute metadata to a single internal media record while reducing repeated requests to external services.
Media Discovery & Redis Caching
Media discovery introduces a different challenge from retrieving individual media details.
With multiple filters and potentially large result sets, directly querying external APIs for every pagination request could lead to unnecessary API calls, rate limits, and slow responses.
To address this, popular and trending media results are stored in Redis.
When users browse discovery pages, the backend can reuse these stored results instead of repeatedly requesting the same data from external providers.
This provides a more efficient foundation for infinite scrolling and reduces the number of requests made to third-party APIs.
Third-Party API Integration
2.0 uses four external APIs to retrieve and enrich media metadata:
- TMDB: Primary source for movie and TV show information.
- AniList: Primary source for anime and manga information.
- OMDb: Enriches movie records with additional information that may not be available through TMDB.
- MyAnimeList (MAL): Enriches anime and manga records with additional metadata.
Each provider has its own response structure and available fields. I use separate Pydantic models and normalization logic to handle these differences and combine the information consistently.
Backend
- FastAPI handles backend endpoints and third-party API communication.
- Pydantic is used for data validation, serialization, and response modeling.
- MongoDB stores user information, internal media records, external API responses, and reviews.
- TTL-based expiration manages the lifecycle of stored external API responses.
- Redis stores popular and trending discovery results.
- Asynchronous requests handle communication with multiple external providers.
- Structured logging with structlog helps monitor backend operations.
- FastAPI dependency injection manages shared dependencies.
Frontend
The frontend is being redesigned alongside the backend improvements.
Although the previous version was functional, I wanted to improve its visual design and overall user experience.
The new frontend is being built with React, TypeScript, and Vite, with TanStack Query handling server state and Tailwind CSS for styling.
The redesign focuses on providing a cleaner, more intuitive interface for searching, discovering, and managing media.
Tech Stack
Backend
Frontend
Third-Party APIs
Architecture
Infrastructure
Challenges & Engineering Decisions
Migrating from External IDs to Internal IDs
One of the biggest challenges was migrating existing user data.
In 2.0, user library entries and reviews referenced media using identifiers provided by third-party APIs.
Since 2.0 introduces its own internal media identifiers, existing user records needed to be migrated to reference the new IDs.
This required:
- Retrieving the existing external media identifiers from user records.
- Creating or identifying the corresponding internal media records.
- Mapping external identifiers to the newly created internal records.
- Updating user library entries and reviews to reference the internal IDs.
The main challenge was ensuring that existing user data remained associated with the correct media records throughout the migration.
This was an important step toward decoupling user data from external API providers.
Redesigning the Backend Data Flow
Introducing persistent API response storage fundamentally changed how the backend operates.
The previous implementation primarily fetched data from external providers and returned it to the frontend.
2.0 required a more structured approach involving additional database models, storage and retrieval logic, TTL management, synchronization services, and response composition.
This meant rewriting significant parts of the backend rather than simply adding caching to the existing implementation.
Integrating Multiple Metadata Providers
Adding OMDb and MyAnimeList introduced another layer of complexity.
Each API provides different metadata, uses different response structures, and has its own limitations.
I needed to handle the relationships between providers using identifiers such as IMDb IDs and MAL IDs, retrieve additional metadata when available, and associate it with the correct internal media record.
This required additional Pydantic models and normalization logic to ensure that information from different providers could be combined consistently.
Efficient Media Discovery & Pagination
Supporting multiple discovery filters while providing infinite scrolling introduced another challenge.
Repeatedly querying external APIs for every pagination request could result in unnecessary network traffic and rate-limit issues.
I addressed this by storing popular and trending media results in Redis, allowing the backend to reuse previously retrieved discovery results.
This reduces repeated external requests and provides a more efficient approach to media discovery.
Infrastructure & Deployment
2.0 is being developed with the same deployment architecture established in the first version.
The intended setup uses Docker and Google Cloud Run for the backend, with Cloudflare hosting the frontend.
The existing CI/CD workflow using GitHub Actions and Workload Identity Federation will also be retained.
Planned Deployment Architecture
- Docker: Containerizes the backend application.
- Google Artifact Registry: Stores Docker images.
- Google Cloud Run: Hosts the backend with automatic scaling.
- GitHub Actions: Automates testing, building, and deployment.
- Workload Identity Federation: Provides keyless authentication between GitHub Actions and Google Cloud.
- Cloudflare: Hosts the frontend.
CI/CD Pipeline
The existing deployment workflow will be reused and adapted for 2.0:
- Runs automated tests before deployment.
- Authenticates to Google Cloud through Workload Identity Federation.
- Builds a Docker image tagged with the Git commit SHA.
- Pushes the image to Artifact Registry.
- Deploys the updated application to Cloud Run.
- Cleans up older images to manage storage usage.
The deployment configuration will continue to use Cloud Run's scaling capabilities to keep resource usage and hosting costs under control.
2.0 deployment and infrastructure configuration are not yet completed.
Demo & Project Status
MyChronicle 2.0 is currently under active development.
The backend architecture is being refactored to support internal media identifiers, persistent API response storage, and metadata enrichment from multiple providers.
The frontend is also being redesigned to provide a better user experience and complement the updated backend architecture.
Once development is complete, 2.0 will replace the original implementation.
Current Development Status
- Backend architecture
- Frontend redesign
- Docker and Google Cloud deployment
The goal is not just to build another media tracker, but to build a platform that owns its data model, manages its own media records, and is less dependent on external services.