Files
yolkbook/README.md
2026-03-23 23:15:09 -07:00

10 KiB

🥚 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
  • Push notifications — optional ntfy alerts for security events: new registrations, admin logins, account lockouts, user changes, and impersonation

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:

    git clone https://git.chns.tech/CooperandGoodman/yolkbook.git
    cd yolkbook
    
  2. Copy .env.example to .env and fill in your values:

    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.
    NTFY_URL (empty) ntfy topic URL for push notifications (e.g. https://ntfy.sh/your-secret-topic). Leave empty to disable.
    NTFY_TOKEN (empty) Bearer token for authenticated ntfy topics. Leave empty if your topic is public or not needed.
  3. Start the stack:

    docker compose up -d --build
    
  4. Point your reverse proxy at port 8056 with HTTPS enabled.

  5. Open your browser at https://<your-domain>/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.

Push Notifications

Yolkbook can send alerts via ntfy for security-relevant events. Set NTFY_URL in .env to enable.

Event Priority
New user registered default
Admin login high
Account locked after failed attempts urgent
Login attempt on locked account high
User disabled high
User deleted urgent
Admin impersonation started high

Use https://ntfy.sh/your-secret-topic for the hosted service or a self-hosted ntfy URL. Set NTFY_TOKEN if your topic requires authentication. Notifications are fire-and-forget — a failed delivery is logged but never interrupts a request.

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 (nginx)
Login lockout Account locked for 15 minutes after 5 consecutive failed attempts
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

All authenticated pages include a footer with a Created by: CHNS.tech credit and a Buy Me a Coffee button linking to buymeacoffee.com/CHNS.

Migrating an Existing Install (pre-multi-user)

If you have an existing single-user install, run the migration script before rebuilding:

# 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