Day 76 of 100 Days Coding Challenge: Python
Civilization Time Builder (Day 76 – Day 96)
When AI first suggested this project, I hesitated. The generated project plan was full of terms I barely understood. Take “Poetry,” for example. At first, it sounded like something Shakespeare might dabble in—but in reality, it’s a tool for managing Python dependencies. Once I looked it up and understood what it did, I decided to give it a try.
Environment management had been a thorn in my side during the Stock Tracker App Project. A single update to Python or one of its libraries could break everything I had built. I had already watched my programs collapse because of an accidental update. It was clear: if I wanted to build something more complex, I needed to learn a tool like Poetry.
The theme of this project also pulled me in. It was all about history—a subject I’ve loved since childhood. I can still remember sitting in my parents’ library, leafing through their history books for hours. In that sense, this project felt tailor-made for me.
What excites me most is how expandable this program can be. I could easily adapt it into something larger, like mapping the timelines of Asimov’s Foundation series, Sanderson’s Stormlight Archive, or other Cosmere-related books.
That said, this was one of the toughest challenges I’ve faced so far. Some days I spent five or six hours just trying to fix problems. At one point, I almost quit altogether. But I kept going. Looking back, I’m glad I didn’t give up. Yes, I made plenty of mistakes—but each one taught me something valuable. If nothing else, I learned the importance of patience—with my code and with myself.
Experience
Today marked Day 1 of my shiny new project: the Civilization Timeline Builder. Finally, a project that ties together two of my favorite things—coding and history. The idea is to build an app that makes exploring history feel a little less like flipping through a dusty textbook and a little more like discovering buried treasure.
This project feels bigger than anything I’ve tackled before. Bigger data, bigger scope, bigger headaches. To avoid drowning in dependency drama, I brought in Poetry, my new virtual assistant. Poetry takes charge of libraries, versions, and packaging so I don’t end up in dependency jail. Think of it as a backstage manager who makes sure the actors (libraries) show up on time and don’t fight with each other.
The process, however, wasn’t like my earlier, simpler projects where I just spun up a virtual environment and carried on. Right away, I could sense something different. I usually code at an unholy hour of the morning, fueled by post-exercise clarity, but even then I had to stop and double-check every step. I even started a day early just to reread the instructions, as if I were reviewing the rules of an unfamiliar board game before play.
Today’s Motivation / Challenge
Why bother with all this fuss? Because Poetry is the difference between a messy desk covered in loose papers and a neat binder where everything is tabbed, labeled, and ready to go. Dependency management sounds boring—until it breaks. Then it’s all you think about. This project matters because it forces me to upgrade my tools and habits, making me a more organized (and hopefully less panicked) developer.
Purpose of the Code (Object)
The code for today doesn’t build empires or conquer continents just yet. Instead, it sets up a tiny FastAPI server with a health check and a stub of civilization data. It’s the scaffolding—the skeleton—upon which everything else will hang. Think of it as the tent poles before the circus begins.
Functions & Features
- Start a FastAPI server with a health check endpoint.
- Return a couple of sample civilizations from in-memory data.
- Filter civilizations by region and year range.
Requirements / Setup
- Python 3.13
- Poetry (dependency management)
- FastAPI, Streamlit, Uvicorn
Install Poetry’s deps via:
poetry install
Run the API:
poetry run uvicorn app.main:api –reload
Minimal Code Sample
from fastapi import FastAPI, Query
from typing import List, Optional
api = FastAPI(title=”CivTimeline API”)
@api.get(“/health”)
def health():
return {“ok”: True}
CIVS = [
{“id”: 1, “name”: “Roman Republic/Empire”, “region”: “Europe”, “start_year”: -509, “end_year”: 476},
{“id”: 2, “name”: “Han Dynasty”, “region”: “East Asia”, “start_year”: -206, “end_year”: 220},
]
@api.get(“/civs”)
def list_civs(region: Optional[List[str]] = Query(None), start: int = -3000, end: int = 2000):
# Filter civs by year and region
return {“items”: [c for c in CIVS if c[“start_year”] <= end and c[“end_year”] >= start
and (not region or c[“region”] in region)]}
A small API stub with civilizations you can query.
The Civilization Timeline Builder
Notes / Lessons Learned
This project began with a repo scaffold: Poetry + FastAPI + Streamlit. It quickly proved to be a different animal than the smaller projects I’d done before. Installing Poetry felt like watching paint dry—it took so long I thought I had failed. But once I checked, it was there, quietly waiting for me to notice.
Next came the .env and .env.example files, along with .gitignore. These guardrails saved me from committing private config files to git. I learned this lesson the hard way in a previous project, where I nearly exposed secrets before catching myself. A README was also added, though I’ll admit I skipped it at first and paid the price in confusion later.
Booting up the FastAPI and Streamlit stubs worked, but the process felt chaotic. Nothing was “normal” compared to my earlier projects. To cope, I broke the steps into tiny pieces and forced myself to ask “why” at each step. The trick is not to stay in “why mode” too long—you’ll skip something important. Next time, I’m making a checklist before indulging my curiosity.
Optional Ideas for Expansion
- Add a proper database instead of temporary in-memory data.
- Build a simple UI filter in Streamlit for regions and years.
- Visualize civilizations on a timeline chart.

