diff --git a/README.md b/README.md index 133d9f7..b6c552d 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,32 @@ # BTC Portfolio Tracker -A full-stack Bitcoin portfolio tracker with live EUR pricing, purchase history, and interactive charts. +A full-stack Bitcoin portfolio tracker with live EUR pricing, purchase/sell history, candlestick charts, and price predictions. --- ## 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 +- **Live BTC price** — fetched from CoinGecko in EUR, with cached fallback and stale warning +- **Purchase tracking** — log BTC buys with amount (EUR), price per BTC, and a custom date +- **Sell tracking** — log BTC sells with BTC amount, price per BTC, and a custom date +- **Portfolio stats** — total invested, current value, profit/loss, net BTC held +- **Price prediction** — enter a target BTC price to see projected portfolio value and P&L +- **Interactive charts** — portfolio value over time and BTC candlestick chart (OHLC stored locally) +- **Edit & delete** — inline editing and deletion for both purchases and sells +- **Admin panel** — admin users can create, list, and delete accounts - **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 | +| 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 + nginx | --- @@ -65,42 +68,55 @@ btc-portfolio/ ├── backend/ │ └── app/ │ ├── main.py # FastAPI app + CORS -│ ├── models.py # User & Purchase ORM models +│ ├── models.py # User, Purchase, Sell, OHLCCandle ORM models │ ├── auth.py # JWT + bcrypt │ ├── dependencies.py # Auth dependency injection │ ├── routes/ │ │ ├── users.py # POST /register, POST /login │ │ ├── purchases.py # CRUD /purchases +│ │ ├── sells.py # CRUD /sells │ │ ├── stats.py # GET /stats -│ │ └── history.py # GET /history (365-day BTC prices) +│ │ ├── history.py # GET /history (365-day BTC prices) +│ │ ├── candles.py # GET /candles (OHLC data + purchases overlay) +│ │ └── admin.py # GET/POST/DELETE /admin/users │ └── services/ │ └── btc.py # CoinGecko integration └── frontend/ └── src/ ├── App.js # Routing ├── pages/ - │ └── Dashboard.js # Main view + │ └── Dashboard.js # Main view: stats, predictions, charts, tables └── components/ - ├── AddPurchase.js # Purchase form - ├── PurchaseList.js # Purchase table (edit/delete) - ├── PortfolioChart.js # Invested vs current value - └── BTCHistoryChart.js # 1-year BTC price history + ├── AddPurchase.js # Purchase form (amount EUR, price, date) + ├── PurchaseList.js # Purchase table (inline edit/delete) + ├── AddSell.js # Sell form (BTC amount, price, date) + ├── SellList.js # Sell table (inline edit/delete) + ├── PortfolioChart.js # Invested vs current value over time + └── BTCCandlestickChart.js # OHLC candlestick chart with purchase markers ``` --- ## 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 | +| 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 | `/sells` | List user sells | Yes | +| POST | `/sells` | Add a sell | Yes | +| PUT | `/sells/{sell_id}` | Edit a sell | Yes | +| DELETE | `/sells/{sell_id}` | Delete a sell | Yes | +| GET | `/stats` | Portfolio stats (P&L, net BTC) | Yes | +| GET | `/history` | 365-day BTC price history | Yes | +| GET | `/candles` | OHLC candles + purchase overlay | Yes | +| GET | `/admin/users` | List all users (admin only) | Admin | +| POST | `/admin/users` | Create a user (admin only) | Admin | +| DELETE | `/admin/users/{id}` | Delete a user (admin only) | Admin | --- @@ -108,15 +124,19 @@ btc-portfolio/ 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) | +| Table | Columns | +|----------------|---------------------------------------------------------------| +| `users` | id, username (unique), password (bcrypt hash), is_admin | +| `purchases` | id, amount_eur, price_eur, created_at, user_id (FK) | +| `sells` | id, btc_amount, price_eur, created_at, user_id (FK) | +| `ohlc_candles` | id, date (unique, YYYY-MM-DD), open, high, low, close | --- ## Notes - The `SECRET_KEY` in `auth.py` is hardcoded — use an environment variable in production. -- CoinGecko requests are unauthenticated; failures return `0.0` gracefully. +- CoinGecko requests are unauthenticated; failures fall back to the last cached price with a UI warning. +- OHLC candle data is fetched from CoinGecko and stored locally to reduce API calls. - CORS is restricted to `localhost:3000` by default. +- The frontend is served via nginx in the Docker production setup.