vibecoder
·3 min read

Day 1 of the Inventory Brain: What actually got done

I planned to build a beautiful app. I ended up with a working database, one API endpoint, and a form that submits without breaking. That's it. That's the win.

inventoryday-1SQLiteFastAPI

I started at 9am with a list of things I wanted to build: barcode scanning, category management, photo uploads, a search bar, a mobile-friendly layout, export to CSV...

By noon I had a Python virtualenv and a SQLite schema.

That's fine. That's actually exactly right.

What Day 1 is actually for

The goal of Day 1 isn't to have something impressive. It's to have something running. A database that holds data. A server that starts without errors. A form that writes to the database when you submit it.

Those three things take longer than you think, and they're the foundation for everything else.

My Day 1 checklist had exactly:

[ ] Python venv set up and activated
[ ] SQLite schema written (items table, minimal columns)
[ ] FastAPI app starts on localhost:8080
[ ] POST /items works (via curl or Postman)
[ ] Basic HTML form submits and writes to DB
[ ] You can see the item in the DB with sqlite3 CLI

I finished all of them. The form was ugly. The schema had no indexes. The FastAPI routes had no error handling. All of that is Day 2's problem.

The schema I ended up with

CREATE TABLE items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    location TEXT,
    quantity INTEGER DEFAULT 1,
    notes TEXT,
    created_at TEXT DEFAULT (datetime('now'))
);

No categories. No barcodes. No photos. Just enough to prove the concept.

I'll add columns later. SQLite makes that easy. What I can't easily add later is "does the data model make sense for this problem" — so I spent 20 minutes just writing items on paper before touching the schema.

The FastAPI route that actually shipped

@app.post("/items", response_model=ItemOut)
async def create_item(item: ItemIn, db: AsyncConnection = Depends(get_db)):
    cursor = await db.execute(
        "INSERT INTO items (name, location, quantity, notes) VALUES (?, ?, ?, ?)",
        (item.name, item.location, item.quantity, item.notes),
    )
    await db.commit()
    return {**item.dict(), "id": cursor.lastrowid, "created_at": datetime.now().isoformat()}

That's it. No authentication. No pagination. No fancy error handling. It writes to SQLite and returns the created item.

What I skipped

  • Didn't set up any UI framework beyond a plain HTML file with a form
  • Didn't install Tailwind (Day 2)
  • Didn't think about mobile
  • Didn't add any tests (Day 3 maybe, realistically never for a local app)

The mindset that helps

On Day 1, every time you feel the urge to add something, write it on a sticky note instead. By end of day you'll have a pile of sticky notes and a working foundation. The sticky notes become Day 2's backlog.

The foundation is the thing. Everything else is optional.


Next: Day 2 — Adding search and a real UI →