# ๐Ÿฅš Yolkbook A self-hosted, multi-user web app for backyard chicken keepers to track egg production, flock size, feed costs, and egg economics over time. ## Features - **Dashboard** โ€” at-a-glance stats: total eggs, 7/30-day totals, averages (green), flock size (orange), cost per egg and per dozen - **Daily log** โ€” record egg collections with one entry per day; includes full collection history with date filtering, edit, and delete below the form - **Flock management** โ€” track changes to your flock size over time so per-hen averages stay accurate - **Feed tracking** โ€” log feed purchases (bags + price per bag) - **Budget** โ€” cost per egg and cost per dozen, all-time and over the last 30 days - **Monthly summary** โ€” month-by-month breakdown of production, averages, feed cost, and cost per egg - **Multi-user** โ€” each user has their own isolated data; self-registration on the login page - **Admin panel** โ€” view all users, reset passwords, disable/enable accounts, delete accounts, and log in as any user - **Timezone support** โ€” each user sets their own timezone so dates and stat windows are always accurate ## Tech Stack | Layer | Technology | |----------|-------------------------| | Frontend | Vanilla HTML/CSS/JS | | Backend | FastAPI (Python) | | Database | MySQL 8.0 | | Server | Nginx (static + proxy) | | Runtime | Docker Compose | ## Getting Started ### Prerequisites - Docker and Docker Compose - A reverse proxy with HTTPS (e.g. Nginx Proxy Manager) โ€” required for secure cookie authentication ### Setup 1. Clone the repo: ```bash git clone https://git.chns.tech/CooperandGoodman/yolkbook.git cd yolkbook ``` 2. Copy `.env.example` to `.env` and fill in your values: ```bash cp .env.example .env ``` Required variables: | Variable | Description | |----------|-------------| | `MYSQL_ROOT_PASSWORD` | MySQL root password โ€” generate with `openssl rand -hex 16` | | `MYSQL_DATABASE` | Database name (default: `eggtracker`) | | `MYSQL_USER` | MySQL app username | | `MYSQL_PASSWORD` | MySQL app user password | | `ADMIN_USERNAME` | Username for the built-in admin account | | `ADMIN_PASSWORD` | Password for the built-in admin account | | `JWT_SECRET` | JWT signing secret โ€” generate with `openssl rand -hex 32` | Optional variables (with defaults): | Variable | Default | Description | |----------|---------|-------------| | `SECURE_COOKIES` | `true` | Set to `false` for local HTTP testing only; leave `true` when behind HTTPS | | `ALLOWED_ORIGINS` | *(empty)* | Comma-separated list of external origins allowed to call the API. Leave empty if accessed only through the bundled nginx frontend. | 3. Start the stack: ```bash docker compose up -d --build ``` 4. Point your reverse proxy at port `8056` with HTTPS enabled. 5. Open your browser at `https:///login` and sign in with the admin credentials you set in `.env`. The database schema is applied automatically on first start via `mysql/init.sql`. The admin user is created (or synced) automatically every time the API starts. ## Authentication - **Login / Register** โ€” the landing page (`/login`) has both a sign-in form and a self-registration link. - **Sessions** โ€” after login, a session cookie is set by the server. It is `HttpOnly` (inaccessible to JavaScript), `Secure` (HTTPS only), and `SameSite=Strict` (CSRF protection). Valid for 30 days. - **Logout** โ€” the `/api/auth/logout` endpoint clears the session cookie server-side. - **Admin password** โ€” always sourced from the `ADMIN_PASSWORD` env var. Changing it in `.env` and restarting updates the admin's password automatically. ## Admin Panel Accessible at `/admin` for admin accounts. Features: | Action | Description | |--------|-------------| | Reset password | Set a new password for any user | | Disable / Enable | Block or restore a user's access | | Delete | Permanently remove a user and all their data | | Login As | Impersonate a user to view or edit their data directly | When impersonating a user, an amber banner appears in the nav with a **Return to Admin** button. The original admin session is preserved server-side โ€” no admin credentials are stored in the browser during impersonation. ## User Settings The gear icon (โš™) in the top-right nav opens the Settings panel: - **Timezone** โ€” choose from a full list of IANA timezones or click *Detect automatically*. Affects what "today" is when pre-filling date fields and the 30-day/7-day windows on the dashboard and budget pages. - **Change Password** โ€” update your own password (requires current password). ## Security | Feature | Details | |---------|---------| | Authentication | HttpOnly + Secure + SameSite=Strict session cookie; no token in JS-accessible storage | | CSRF protection | SameSite=Strict cookie prevents cross-site request forgery without explicit tokens | | Password hashing | bcrypt | | CORS | Locked to same origin by default; configurable via `ALLOWED_ORIGINS` | | Rate limiting | Login: 5 req/min ยท Register: 3 req/min ยท Admin endpoints: 10 req/min | | Security headers | X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy, Content-Security-Policy | | Subresource Integrity | Chart.js CDN script pinned with SHA-384 hash | | Input validation | Server-side via Pydantic; all user-rendered content HTML-escaped | | SQL injection | SQLAlchemy ORM with parameterized queries throughout | | Container security | API runs as non-root user; all volume mounts read-only except database | ## Footer All authenticated pages include a footer with a **Created by: [CHNS.tech](https://chns.tech)** credit and a Buy Me a Coffee button linking to [buymeacoffee.com/CHNS](https://www.buymeacoffee.com/CHNS). ## Migrating an Existing Install (pre-multi-user) If you have an existing single-user install, run the migration script before rebuilding: ```bash # 1. Run the migration while the database is still running docker compose exec db mysql -u root -p"${MYSQL_ROOT_PASSWORD}" eggtracker < mysql/migrate_v2.sql # 2. Rebuild and restart docker compose up -d --build ``` All existing data will be automatically assigned to the admin account on first startup. ## API The FastAPI backend is available at `/api`. Interactive docs (Swagger UI) are at `/api/docs`. | Prefix | Description | |------------------|----------------------------------------------------| | `/api/auth` | Login, logout, register, change password, timezone | | `/api/admin` | User management (admin only) | | `/api/eggs` | Egg collection records | | `/api/flock` | Flock size history | | `/api/feed` | Feed purchase records | | `/api/other` | Other purchases (bedding, snacks, etc.) | | `/api/stats` | Dashboard, budget, and monthly summary | All data endpoints require an authenticated session cookie. Requests are automatically authenticated by the browser โ€” no `Authorization` header is needed. ## Project Structure ``` yolkbook/ โ”œโ”€โ”€ backend/ โ”‚ โ”œโ”€โ”€ main.py # FastAPI app entry point + startup seeding โ”‚ โ”œโ”€โ”€ auth.py # JWT utilities, password hashing, cookie helpers, auth dependencies โ”‚ โ”œโ”€โ”€ models.py # SQLAlchemy models โ”‚ โ”œโ”€โ”€ schemas.py # Pydantic schemas โ”‚ โ”œโ”€โ”€ database.py # DB connection โ”‚ โ”œโ”€โ”€ routers/ โ”‚ โ”‚ โ”œโ”€โ”€ auth_router.py # /api/auth โ€” login, logout, register, settings โ”‚ โ”‚ โ”œโ”€โ”€ admin.py # /api/admin โ€” user management + impersonation โ”‚ โ”‚ โ”œโ”€โ”€ eggs.py โ”‚ โ”‚ โ”œโ”€โ”€ flock.py โ”‚ โ”‚ โ”œโ”€โ”€ feed.py โ”‚ โ”‚ โ”œโ”€โ”€ other.py โ”‚ โ”‚ โ””โ”€โ”€ stats.py โ”‚ โ”œโ”€โ”€ requirements.txt โ”‚ โ””โ”€โ”€ Dockerfile โ”œโ”€โ”€ nginx/ โ”‚ โ”œโ”€โ”€ html/ # Frontend (HTML, CSS, JS) โ”‚ โ”‚ โ”œโ”€โ”€ index.html # Dashboard โ”‚ โ”‚ โ”œโ”€โ”€ log.html # Log Eggs + full collection history โ”‚ โ”‚ โ”œโ”€โ”€ flock.html # Flock management โ”‚ โ”‚ โ”œโ”€โ”€ budget.html # Budget / cost analysis โ”‚ โ”‚ โ”œโ”€โ”€ summary.html # Monthly summary โ”‚ โ”‚ โ”œโ”€โ”€ admin.html # Admin panel โ”‚ โ”‚ โ”œโ”€โ”€ login.html โ”‚ โ”‚ โ”œโ”€โ”€ 404.html โ”‚ โ”‚ โ”œโ”€โ”€ 50x.html โ”‚ โ”‚ โ”œโ”€โ”€ js/ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ api.js # Shared fetch helpers โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ auth.js # Auth utilities, nav, settings modal โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ login.js # Login/register page logic โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ dashboard.js โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ log.js # Egg logging interface โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ history.js # Collection history table (used on log page) โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ flock.js โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ budget.js โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ summary.js โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ admin.js # Admin panel โ”‚ โ”‚ โ””โ”€โ”€ css/style.css โ”‚ โ””โ”€โ”€ nginx.conf โ”œโ”€โ”€ mysql/ โ”‚ โ”œโ”€โ”€ init.sql # Schema for fresh installs โ”‚ โ””โ”€โ”€ migrate_v2.sql # Migration for pre-multi-user installs โ”œโ”€โ”€ .env.example # Template โ€” copy to .env and fill in values โ”œโ”€โ”€ docker-compose.yml โ””โ”€โ”€ .env # Secrets โ€” not committed ```