# User Guide This guide walks you through using WineBox to manage your wine cellar. ## Dashboard Overview When you log in, the **Dashboard** shows you: - **Total Bottles** - All bottles currently in your cellar - **Unique Wines** - Number of different wines - **Wines Tracked** - Total wines you've ever recorded Below the statistics, you'll see breakdowns by country, grape variety, and vintage, plus your recent activity. ## Checking In Wine Adding wine to your cellar is easy with WineBox's AI-powered label scanning. ### Step-by-Step 1. **Click Check In** in the navigation menu 2. **Upload the front label photo** (required) - Click "Choose file" or drag and drop an image - Supported formats: JPG, PNG, GIF, WebP 3. **Wait for scanning** - the form populates automatically - A notification tells you which scanner was used (Claude Vision or Tesseract OCR) 4. **Upload back label** (optional) - adds more details 5. **Use autocomplete** (optional) - Type at least 2 characters in the Wine Name field - Select a wine to auto-fill winery, country, and ABV 6. **Review the details** - edit anything that looks incorrect 7. **Set quantity** - how many bottles you're adding 8. **Add notes** (optional) - where you bought it, price, occasion 9. **Click Check In Wine** 10. **Confirm** in the dialog that appears ### What Gets Detected The AI scanner looks for: - Wine name - Vintage year - Winery/producer - Grape variety - Region and country - Sub-region (e.g., Côte de Nuits, Médoc) - Appellation (e.g., Nuits-St-Georges, Pomerol) - Alcohol percentage - Classification (Grand Cru, DOCG, Reserve, etc.) ### Using Wine Autocomplete The autocomplete feature searches over 100,000 wines from the X-Wines dataset: - Start typing a wine name (minimum 2 characters) - Results show wine name, winery, type, country, and community ratings - Use arrow keys to navigate, Enter to select - Selecting a wine fills in: name, winery, country, and ABV **Note**: Autocomplete requires the X-Wines database to be installed. See the "For Developers" section below for setup instructions. ## Viewing Your Cellar The **Cellar** page displays all your wines as cards. ### Filters Use the dropdown to show: - **All Wines** - everything you've tracked - **In Stock Only** - wines with bottles available - **Out of Stock** - wines you've finished ### Quick Search Type in the search box to filter by name or winery. ### Wine Cards Each card shows: - Label image - Wine name and vintage - Region and country - Appellation and classification tags (when available) - Current bottle count - **Check Out** button Click anywhere on the card to see full details. ## Wine Details Clicking a wine opens the detail modal showing: - **Label image** - the photo you uploaded - **Full wine info** - name, vintage, region, sub-region, appellation, country, classification, alcohol % - **Stock status** - how many bottles you have - **Raw label text** - expand to see what the scanner detected - **Transaction history** - every check-in and check-out - **Actions** - Check Out and Delete buttons ## Checking Out Wine Remove bottles when you drink or sell them: 1. Go to the **Cellar** page 2. Find the wine (use search if needed) 3. Click **Check Out** on the card, or open details first 4. Enter the quantity to remove 5. Add notes (optional) - occasion, tasting notes, who you shared it with 6. Click **Check Out** The transaction is recorded in your history. ## Searching Your Cellar The **Search** page offers advanced filtering beyond the cellar's quick search. ### Available Filters | Filter | Description | |--------|-------------| | Text Search | Searches name, winery, region, sub-region, appellation, and label text | | Vintage | Filter by year | | Grape Variety | e.g., "Cabernet", "Merlot" | | Winery | Filter by producer | | Region | e.g., "Napa Valley", "Bordeaux" | | Country | e.g., "France", "Italy" | | Wine Type | Red, White, Rosé, Sparkling, Fortified, Dessert | | Price Tier | Budget through Ultra Premium | | In Stock Only | Only wines with bottles available | ### Search Tips - Partial matches work: "Cab" finds "Cabernet Sauvignon" - Searches are case-insensitive - Combine multiple filters for precise results - Click **Clear** to reset all filters ## Transaction History The **History** page shows a chronological log of all activity. ### What's Recorded - **Check In** (green "IN" badge) - bottles added - **Check Out** (red "OUT" badge) - bottles removed Each entry shows: - Transaction type - Wine name and vintage - Quantity - Date and time ### Filtering History Use the dropdown to show: - All transactions - Check-ins only - Check-outs only ## Importing from Spreadsheets The **Import** page lets you bulk-add wines from CSV or XLSX files. ### Import Workflow 1. **Click Import** in the navigation menu 2. **Upload your spreadsheet** (CSV or XLSX, max 10 MB) 3. **Review the column mapping** - WineBox suggests which spreadsheet columns map to wine fields 4. **Adjust the mapping** as needed: - Map columns to standard wine fields (name, country, vintage, etc.) - Map extra columns to **custom fields** (e.g., "Purchase Price", "Cellar Location") - Set columns to "skip" if they're not needed 5. **Process the import** - wines are created in your cellar ### Custom Fields Columns that don't map to standard wine fields can be stored as custom fields. These are preserved on each wine and displayed in the detail modal as a 2-column grid of label/value cards. Custom field names use the `custom:FieldName` mapping syntax (e.g., `custom:Purchase Price`). ## Exporting Your Collection Export your wine collection from the **Cellar** or **History** pages using the **Export** dropdown. ### Supported Formats | Format | Description | |--------|-------------| | CSV | Comma-separated values, opens in any spreadsheet app | | XLSX | Excel format with styled headers and auto-sized columns | | JSON | Structured data with export metadata | | YAML | Human-readable structured data | ### Custom Fields in Exports When exporting to CSV or XLSX, custom fields are expanded into individual columns rather than being serialized as a single JSON blob. This means: - Each custom field gets its own column header (e.g., "Purchase Price", "Cellar Location") - Custom field columns are sorted alphabetically and appended after the standard columns - If different wines have different custom fields, all unique field names appear as columns, with empty values where a wine doesn't have that field - This preserves the original spreadsheet layout when you import and then re-export ### Export via API You can also export programmatically: ```bash # Export as CSV curl -H "Authorization: Bearer " \ "http://localhost:8000/api/export/wines?format=csv" -o wines.csv # Export as XLSX curl -H "Authorization: Bearer " \ "http://localhost:8000/api/export/wines?format=xlsx" -o wines.xlsx # Export with filters curl -H "Authorization: Bearer " \ "http://localhost:8000/api/export/wines?format=csv&country=France&in_stock=true" ``` ## Tips for Best Results ### Taking Great Label Photos For best AI scanning: 1. **Good lighting** - natural light or well-lit room 2. **Sharp focus** - ensure text is readable 3. **Full label** - capture the entire label 4. **Flat angle** - photograph straight-on, not at an angle 5. **High resolution** - more pixels = better accuracy ### AI Scanning Options WineBox uses two scanning engines: 1. **Claude Vision AI** (recommended) - More accurate label interpretation - Requires Anthropic API key - Add to `secrets.env`: `WINEBOX_ANTHROPIC_API_KEY=your-key` - Or set in `config.toml`: `[ocr] use_claude_vision = true` 2. **Tesseract OCR** (fallback) - Works without API key - Basic text extraction - Install: `brew install tesseract` (macOS) or `apt-get install tesseract-ocr` (Linux) - To force Tesseract only: set `[ocr] use_claude_vision = false` in config.toml ### Keeping Your Cellar Organized - Use consistent naming when editing wine names - Always include vintage when known - Use standard grape variety names (Cabernet Sauvignon, not "Cab") - Include region and country for better searching - Add notes about where you purchased wines ### Data Backup Your cellar data is stored in MongoDB and the filesystem: | Location | Contents | |----------|----------| | MongoDB `winebox` database | All wines, transactions, and users | | `data/images/` | Label photos you've uploaded | **Back up regularly** to preserve your collection records: ```bash # Backup MongoDB mongodump --db winebox --out backups/ # Backup images tar -czf backups/images.tar.gz data/images/ ``` --- # For Developers This section covers development setup, testing, and API documentation for contributors. ## Project Structure ``` winebox/ ├── winebox/ # Main application package │ ├── main.py # FastAPI application │ ├── config/ # Configuration module │ │ ├── schema.py # Pydantic config models │ │ ├── loader.py # TOML loading logic │ │ └── settings.py # Global settings instance │ ├── database.py # MongoDB/PyMongo setup │ ├── models/ # MongoDB document models │ ├── schemas/ # Pydantic API schemas │ ├── routers/ # API endpoints │ ├── services/ # Business logic (OCR, etc.) │ ├── auth/ # Authentication (fastapi-users) │ └── static/ # Web interface (HTML, JS, CSS) ├── config/ # Configuration templates │ ├── config.toml.example │ └── secrets.env.example ├── deploy/ # Deployment module │ ├── __init__.py # Package exports │ ├── common.py # Shared utilities │ ├── app.py # Deploy application │ ├── setup.py # Initial server setup │ ├── xwines.py # Deploy X-Wines dataset │ ├── winebox.service # systemd service │ └── nginx-winebox.conf # nginx config ├── scripts/ # Utility scripts │ ├── seed_reference_data.py # Reference data seeding │ └── migrations/ # Database migration scripts ├── tests/ # Test suite ├── docs/ # Sphinx documentation ├── data/ # Images and local data └── tasks.py # Invoke tasks ``` ## Development Setup ```bash # Clone and install with uv git clone https://github.com/jdrumgoole/winebox.git cd winebox uv sync --all-extras # Start MongoDB (using Docker) docker run -d -p 27017:27017 --name mongodb mongo:7 # Or install locally: # macOS: brew tap mongodb/brew && brew install mongodb-community # Ubuntu: see https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/ # Set up configuration cp config/config.toml.example config.toml cp config/secrets.env.example secrets.env # Edit secrets.env and add your API key (optional) # WINEBOX_ANTHROPIC_API_KEY=your-key # Install Tesseract OCR fallback brew install tesseract # macOS # or: sudo apt-get install tesseract-ocr # Ubuntu/Debian # Initialize database uv run python -m invoke init-db # Start development server with auto-reload uv run python -m invoke start --reload ``` ## Installing the X-Wines Database The wine autocomplete feature requires the X-Wines dataset. This is only available when running from source. ### Test Dataset (Development) For development with 100 sample wines: ```bash uv run python deploy/import_xwines_mongo.py --version test ``` ### Full Dataset (100K+ Wines) For the complete database with community ratings: ```bash # Install download tool uv pip install gdown # Download dataset from Google Drive mkdir -p data/xwines uv run gdown --folder "https://drive.google.com/drive/folders/1LqguJNV-aKh1PuWMVx5ELA61LPfGfuu_?usp=sharing" -O data/xwines/ # Copy files to expected location cp data/xwines/X-Wines_Official_Repository/last/XWines_Full_100K_wines.csv data/xwines/ cp data/xwines/X-Wines_Official_Repository/last/XWines_Full_21M_ratings.csv data/xwines/ # Import (takes a few minutes) uv run python deploy/import_xwines_mongo.py --version full --force ``` ### Verify Import ```bash curl http://localhost:8000/api/xwines/stats ``` You should see `wine_count: 100646` for the full dataset. ## Running Tests ```bash # Run all tests (unit + a core E2E subset) uv run python -m invoke test # Run only unit tests (fast, no server required) uv run python -m invoke test-unit # Run a small subset of fast unit tests for rapid feedback (~2s, no DB) uv run python -m invoke test-quick # Run core Playwright E2E smoke tests (requires running server) uv run python -m invoke start-background uv run python -m invoke test-e2e-fast # Run full Playwright E2E suite (includes slow big CSV imports) uv run python -m invoke start-background uv run python -m invoke test-e2e-full # Run with verbose output uv run python -m invoke test --verbose # Run with coverage uv run python -m invoke test --coverage ``` **Note**: E2E tests use Playwright for browser automation. Install browsers with: ```bash uv run playwright install ``` ## Invoke Tasks Reference ### Server Management ```bash uv run python -m invoke start # Start foreground uv run python -m invoke start --reload # Start with auto-reload uv run python -m invoke start-background # Start in background uv run python -m invoke stop # Stop server uv run python -m invoke restart # Restart server uv run python -m invoke status # Check status uv run python -m invoke logs # View logs ``` ### Database Management ```bash uv run python -m invoke init-db # Initialize uv run python -m invoke purge --force # Delete all data uv run python -m invoke purge-wines --force # Delete wines only ``` ### Database Migrations ```bash uv run python -m scripts.migrations.runner status # Show version uv run python -m scripts.migrations.runner up # Migrate to latest uv run python -m scripts.migrations.runner down --to 0 # Revert uv run python -m scripts.migrations.runner history # Show history ``` ### User Management (Development) ```bash uv run python -m invoke add-user EMAIL --password PASS uv run python -m invoke remove-user EMAIL --force uv run python -m invoke list-users uv run python -m invoke disable-user EMAIL uv run python -m invoke enable-user EMAIL uv run python -m invoke passwd EMAIL --password NEWPASS ``` ### Documentation ```bash uv run python -m invoke docs-build # Build Sphinx docs uv run python -m invoke docs-serve # Build and serve locally ``` ## API Reference Full API documentation is available at http://localhost:8000/docs when the server is running. ### Authentication All API endpoints (except `/health`) require JWT authentication. ```bash # Get token (note: OAuth2 spec uses 'username' field, but WineBox expects email) curl -X POST http://localhost:8000/api/auth/token \ -d "username=myemail@example.com&password=mypass" # Use token in requests curl -H "Authorization: Bearer " http://localhost:8000/api/wines ``` ### Wine Management | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/wines/record` | Add wine(s) to cellar | | POST | `/api/wines/{id}/checkout` | Remove wine(s) from cellar | | GET | `/api/wines` | List all wines | | GET | `/api/wines/{id}` | Get wine details | | PUT | `/api/wines/{id}` | Update wine metadata | | DELETE | `/api/wines/{id}` | Delete wine | ### Cellar & History | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/cellar` | Current cellar inventory | | GET | `/api/cellar/summary` | Summary statistics | | GET | `/api/transactions` | Full transaction history | | GET | `/api/transactions/{id}` | Single transaction | ### Search | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/search` | Search wines by criteria | ### X-Wines Dataset | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/xwines/search?q=` | Autocomplete wine search | | GET | `/api/xwines/wines/{id}` | Get X-Wines wine details | | GET | `/api/xwines/stats` | Dataset statistics | | GET | `/api/xwines/types` | List wine types | | GET | `/api/xwines/countries` | List countries | ### Example: Check In via API ```bash curl -X POST http://localhost:8000/api/wines/record \ -H "Authorization: Bearer " \ -F "front_label=@wine_front.jpg" \ -F "back_label=@wine_back.jpg" \ -F "name=Chateau Margaux" \ -F "vintage=2016" \ -F "region=Bordeaux" \ -F "sub_region=Médoc" \ -F "appellation=Margaux" \ -F "classification=Premier Grand Cru Classé" \ -F "quantity=6" ``` ### Example: Search via API ```bash curl -H "Authorization: Bearer " \ "http://localhost:8000/api/search?country=France&wine_type=Red&in_stock=true" ``` ## Building Documentation ```bash # Build HTML docs uv run python -m invoke docs-build # Serve docs locally uv run python -m invoke docs-serve ``` Documentation is built to `docs/_build/html/`.