FlickVault is a personal movie and TV show journal built with FastAPI and a vanilla HTML/CSS/JavaScript frontend. It lets you keep a small local vault of media you have watched or want to watch, including IMDb IDs, posters, ratings, comments, and release years.
The app serves both a browser UI and an API from the same FastAPI server.
- Browse all saved movies and TV shows in a card-based vault
- Separate Watchlist and Watched views
- Search by title or IMDb ID
- Filter by year and sort by date added, rating, title, or release year
- Add new media with live preview
- Edit existing media
- Delete media with confirmation
- Mark watchlist items as watched
- Dashboard stats for total items, watched count, average rating, and completion rate
- Automatic API documentation through FastAPI at
/docs
- Backend: FastAPI, Pydantic
- Frontend: HTML, CSS, vanilla JavaScript
- Storage: PostgreSQL through SQLAlchemy, with a local SQLite fallback
- Auth: Supabase Auth JWTs verified by FastAPI
- Server: Uvicorn
FlickVault/
├─ app/
│ ├─ schema/
│ │ ├─ __init__.py
│ │ └─ validation.py
│ ├─ __init__.py
│ ├─ app.py
│ ├─ auth.py
│ └─ config.py
├─ data/
│ ├─ __init__.py
│ ├─ database.py
│ └─ helpers.py
├─ static/
│ ├─ app.js
│ ├─ index.html
│ └─ style.css
├─ .env.example
├─ .gitignore
├─ LICENSE
├─ README.md
├─ requirements.txt
└─ supabase_schema.sql
git clone https://github.com/ByteBard58/FlickVault.git
cd FlickVaultpython -m venv .venvsource .venv/bin/activateOn Windows:
.venv\Scripts\activatepip install -r requirements.txtFor local no-auth development, you can use the default SQLite database:
export AUTH_DISABLED=trueFor cloud deployment, copy .env.example into your hosting provider's environment variables and set:
DATABASE_URL: Supabase PostgreSQL connection stringSUPABASE_URL: Supabase project URLSUPABASE_ANON_KEY: Supabase public anon keySUPABASE_JWT_AUDIENCE: usuallyauthenticatedSUPABASE_JWT_ALGORITHMS: usuallyRS256,ES256
The app creates the required table on startup. You can also run supabase_schema.sql in the Supabase SQL editor.
uvicorn app.app:app --reloadThen open:
- App UI: http://127.0.0.1:8000
- API docs: http://127.0.0.1:8000/docs
GET /searchOptional query parameters:
imdb_id: IMDb title ID, such astt0407887name: partial title searchyear: release yearwatched:trueorfalse
Example:
curl "http://127.0.0.1:8000/search?name=arrival"GET /watchlistReturns all items where watched is false.
GET /watchedlistReturns all items where watched is true.
GET /item_uuid/{uuid}GET /item_id/{imdb_id}Example:
curl "http://127.0.0.1:8000/item_id/tt2543164"POST /add_itemExample:
curl -X POST "http://127.0.0.1:8000/add_item" \
-H "Content-Type: application/json" \
-d '{
"imdb_id": "tt2543164",
"title": "Arrival",
"year": 2016,
"end_year": null,
"poster_url": ["https://upload.wikimedia.org/wikipedia/en/d/df/Arrival%2C_Main_Poster.jpg"],
"watched": true,
"rating": 9.0,
"comment": "An incredibly smart and emotionally resonant sci-fi."
}'PUT /update_item/{imdb_id}Only include the fields you want to update.
Example:
curl -X PUT "http://127.0.0.1:8000/update_item/tt2543164" \
-H "Content-Type: application/json" \
-d '{
"watched": true,
"rating": 9.5,
"comment": "Even better on rewatch."
}'DELETE /delete_item/{imdb_id}Example:
curl -X DELETE "http://127.0.0.1:8000/delete_item/tt2543164"Each media item is stored as JSON with the following shape:
{
"uuid": "f8eac85e-6f90-4776-ade4-ca035afa0953",
"imdb_id": "tt0407887",
"title": "The Departed",
"year": 2006,
"end_year": null,
"poster_url": ["https://example.com/poster.jpg"],
"watched": true,
"rating": 8.5,
"comment": "One of the most complex plots I have ever seen in a movie.",
"date_added": "2026-05-24T05:27:02.275112Z"
}Validation rules:
imdb_idmust match the formatttfollowed by 7 to 10 digits.titlemust be 1 to 300 characters and cannot start or end with whitespace.yearandend_yearmust be between 1900 and 2050.rating, when provided, must be between 0 and 10.comment, when provided, must be between 5 and 1000 characters.- If
watchedisfalse,ratingandcommentmust benullor omitted.
The API also computes an imdb_link field from the IMDb ID when returning items.
- This project stores vault items in SQL and scopes every record by authenticated user ID.
data/db.jsonis kept only as legacy seed/reference data.- The frontend loads Lucide icons and Google Fonts from CDNs, so those assets require an internet connection.
- FastAPI exposes interactive API documentation at
/docsand OpenAPI JSON at/openapi.json.
- Create a Supabase project.
- Copy the pooled PostgreSQL connection string into
DATABASE_URL. - Copy the project URL into
SUPABASE_URL. - Copy the public anon key into
SUPABASE_ANON_KEY. - Run
supabase_schema.sqlin the SQL editor, or let the app create the table on first startup.
Create a Web Service with this build command:
pip install -r requirements.txtUse this start command:
uvicorn app.app:app --host 0.0.0.0 --port $PORTAdd the same environment variables from .env.example in Render's Environment tab.
This project is licensed under the MIT License.
Thank you for taking the time to assess my work. I hope you liked it and found it interesting. Please report any problems you notice in the Issues area.
Don't hesitate to contact me if you have any queries, recommendations, or topics you would want to talk about. My profile page has my contact details.
Have a great day!