Jonathan 672f5b74a4 Fix production deployment: replace serve with nginx reverse proxy
Frontend container now uses nginx to serve static files and proxy
/api/* requests to the backend container internally, eliminating
the hardcoded localhost:8000 build-time URL that caused "Network
error" on any non-local server. CORS origins are also configurable
via ALLOWED_ORIGINS env var.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:18:38 +02:00
2026-03-24 19:10:20 +01:00

BTC Portfolio Tracker

A full-stack Bitcoin portfolio tracker with live EUR pricing, purchase history, and interactive charts.


Features

  • Live BTC price — fetched from CoinGecko in EUR
  • Purchase tracking — log BTC buys with amount (EUR) and price per BTC
  • Portfolio stats — total invested, current value, profit/loss
  • Interactive charts — portfolio value over time and 1-year BTC price history
  • Edit & delete — manage purchases with inline editing
  • JWT authentication — secure per-user portfolios

Tech Stack

Layer Technology
Frontend React 18, Chart.js, dark theme
Backend FastAPI, SQLAlchemy, SQLite
Auth JWT (HS256, 24h expiry) + bcrypt
Pricing CoinGecko API (EUR)
Deploy Docker + Docker Compose

Getting Started

git clone <repo-url>
cd btc-portfolio
docker-compose up

Local Development

Backend

cd btc-portfolio/backend
pip install -r requirements.txt
uvicorn app.main:app --reload

Frontend

cd btc-portfolio/frontend
npm install
npm start

Project Structure

btc-portfolio/
├── backend/
│   └── app/
│       ├── main.py            # FastAPI app + CORS
│       ├── models.py          # User & Purchase ORM models
│       ├── auth.py            # JWT + bcrypt
│       ├── dependencies.py    # Auth dependency injection
│       ├── routes/
│       │   ├── users.py       # POST /register, POST /login
│       │   ├── purchases.py   # CRUD /purchases
│       │   ├── stats.py       # GET /stats
│       │   └── history.py     # GET /history (365-day BTC prices)
│       └── services/
│           └── btc.py         # CoinGecko integration
└── frontend/
    └── src/
        ├── App.js             # Routing
        ├── pages/
        │   └── Dashboard.js   # Main view
        └── components/
            ├── AddPurchase.js      # Purchase form
            ├── PurchaseList.js     # Purchase table (edit/delete)
            ├── PortfolioChart.js   # Invested vs current value
            └── BTCHistoryChart.js  # 1-year BTC price history

API Endpoints

Method Endpoint Description Auth
POST /register Create account No
POST /login Get JWT token No
GET /purchases List user purchases Yes
POST /purchases Add a purchase Yes
PUT /purchases/{id} Edit a purchase Yes
DELETE /purchases/{id} Delete a purchase Yes
GET /stats Portfolio stats (P&L) Yes
GET /history 365-day BTC price history Yes

Database

SQLite, stored at /app/data/btc_portfolio.db (persisted via Docker volume).

Table Columns
users id, username (unique), password (bcrypt hash)
purchases id, amount_eur, price_eur, created_at, user_id (FK)

Notes

  • The SECRET_KEY in auth.py is hardcoded — use an environment variable in production.
  • CoinGecko requests are unauthenticated; failures return 0.0 gracefully.
  • CORS is restricted to localhost:3000 by default.
S
Description
A portfolio of your BTC purchases, showing multiple stats and graphs
Readme 181 KiB
Languages
JavaScript 65.4%
Python 33.4%
Dockerfile 0.7%
HTML 0.5%