Slower reading, on purpose.
Marginalia is a full-stack online bookstore built with Flask. Nine curated books, chosen rather than algorithmically recommended, across genres like Memoir, Fiction, Essays, and Nature. It features real user accounts, a persistent cart, order history, and a simulated checkout flow that validates payment details like a real gateway would, without ever contacting one.
- 📖 Browse a curated catalog, filterable by genre
- 🎨 CSS-gradient book covers — no image assets needed, each book's cover is generated from a two-color gradient stored in the database
- 🔐 User accounts — registration and login with hashed passwords (Werkzeug) and session management via Flask-Login
- 🛒 Persistent cart — add, increase/decrease quantity, or remove items, synced to your account
- 💳 Simulated checkout — validates card number (Luhn algorithm), expiry, and CVC like a real payment form, without ever contacting a real payment processor
- 🧾 Order history — past orders are saved with item snapshots (title, author, price at time of purchase), so catalog edits never affect historical orders
- 🚦 Flash messaging for errors, confirmations, and info across the app
⚠️ Custom error pages for 404 and 403
- Python 3 + Flask — routing and server-side logic
- Flask-SQLAlchemy — ORM and database models
- Flask-Login — session-based authentication
- Werkzeug Security — password hashing
- SQLite — database (
marginalia.db) - Jinja2 — server-side templating, with a reusable
cover()macro - HTML5 / CSS3 — custom-styled frontend, no CSS framework
- Google Fonts — Fraunces (headings) & Work Sans (body)
marginalia/
├── app.py # Routes and application setup
├── extensions.py # Shared Flask extension instances (db, login_manager)
├── models.py # SQLAlchemy models: User, Book, CartItem, Order, OrderItem
├── seed_data.py # Fixed catalog of 9 books, seeded on first run
├── templates/
│ ├── base.html # Shared layout, nav, and flash messages
│ ├── index.html # Catalog with genre filtering
│ ├── book_detail.html # Single book page
│ ├── cart.html # Cart contents and totals
│ ├── checkout.html # Simulated payment form
│ ├── success.html # Order confirmation
│ ├── orders.html # Order history
│ ├── login.html # Login form
│ ├── register.html # Registration form
│ ├── error.html # Shared 404 / 403 page
│ └── _macros.html # Reusable `cover()` gradient macro
├── static/
│ └── css/
│ └── style.css # Stylesheet
└── README.md
| Model | Key Fields |
|---|---|
User |
name, email (unique), password_hash, created_at |
Book |
title, author, genre, price_cents, description, stock, cover_from, cover_to |
CartItem |
user_id, book_id, quantity (unique per user/book pair) |
Order |
user_id, total_cents, status, card_last4, created_at |
OrderItem |
order_id, book_id, title, author, quantity, price_cents (snapshotted at purchase time) |
The catalog is seeded automatically from seed_data.py the first time the app runs, so marginalia.db doesn't need to exist beforehand.
pip install flask flask-sqlalchemy flask-login
git clone https://github.com/rhitamcoder/marginalia.git
cd marginalia
python app.py
The app will start in debug mode at http://127.0.0.1:5000/. On first run, the database and catalog are created automatically.
This project is a coursework / portfolio demonstration, not a production application. app.py uses os.environ.get("SECRET_KEY", "dev-secret-change-me"), a placeholder fallback intended only for local development, and no SECRET_KEY environment variable is configured for this repo.
Real user accounts should not be created on any public instance of this app, and it is not intended to be deployed for real-world use. The Flask-Login authentication and the checkout flow exist to demonstrate full-stack skills (auth, sessions, ORM relationships, server + client-side validation), not to handle real credentials or real payments.
This project doesn't integrate a real payment gateway. The checkout form validates card number (via the Luhn algorithm), expiry format, and CVC exactly like a real one would, but no card network is ever contacted and no money moves. On successful validation, it writes a real Order and OrderItem record, the same way a webhook from an actual processor would, so the cart, auth, and order history logic are all fully functional and wouldn't need to change if a real gateway were added later.
This project is licensed under the MIT License — see the LICENSE file for details.