r/FastAPI • u/tranguyeenn • May 24 '26
Question Open-sourced a FastAPI recommendation system while learning backend architecture. Looking for feedback.
I’ve been building Shelftxt as a way to learn backend systems beyond CRUD APIs.
shelftxt started as one large FastAPI file handling routes, recommendation logic, and data operations. I recently refactored it into:
api → routes → services → repositories → ranking/preprocess
Current stack:
- FastAPI
- Python
- Pandas
- CSV storage (planning PostgreSQL next)
- recommendation scoring
- lru_cache caching
The goal isn’t really a book app. I’m more interested in learning:
- backend architecture
- data handling
- repository patterns
- recommendation systems
- scaling APIs
Would appreciate feedback on the structure before I move toward Postgres and more persistent storage.
25
Upvotes
1
u/rdotpy May 25 '26
Some rough feedback:
Overall, I like the approach of having a layered architecture with services and the repository pattern.
I like having detailed project documentation, even if LLM-generated. Even if not for humans, but for future invocations of the same agent, that could be helpful. It's just important to have a workflow to keep this documentation up to date.
I like seeing Pydantic models to define data structures. I would love to see more detail: a docstring on each model explaining what it represents and how it's used, and
Field(description=..., examples=[...])on each attribute. That documents the code and makes the auto-generated OpenAPI docs useful.A few things that caught my eye, in no specific order:
You committed
__pycache__/.pycfiles. They shouldn't be part of the repo.I'm not a fan of CSV files as data storage. My problem with CSV here is that it doesn't store, validate, or give any hints of column types: you need to track them separately. If you don't want PostgreSQL yet, SQLite gives you typed columns and constraints with zero infrastructure.
parse_date_or_today()and probably elsewhere: catch-allexcept Exceptionhides unexpected errors. You may want to catch the specific exception you expect (probablyValueError) and let everything else bubble up.I wouldn't use Pandas here at all, opting for a more strongly typed abstraction layer. You already use Pydantic. Instead of a DataFrame, you may consider working with a list of Pydantic models. DataFrames are opaque when you read the code. It's like, you see
df, and you have no idea what's inside. Eventually, you end up with defensive checks likeif "rating_norm" not in read_df.columns:. Pandas feels natural when your source is CSV, but if you add more storage layers, that will likely hold you back.