···1+# Arabica - Coffee Brew Tracker
2+3+A self-hosted web application for tracking your coffee brewing journey. Built with Go, Templ, and SQLite.
4+5+## Features
6+7+- 📝 Quick entry of brew data (temperature, time, method, flexible grind size entry, etc.)
8+- ☕ Organize beans by origin and roaster with quick-select dropdowns
9+- 📱 Mobile-first PWA design for on-the-go tracking
10+- 📊 Rating system and tasting notes
11+- 📥 Export your data as JSON
12+- 🔄 CRUD operations for all brew entries
13+- 🗄️ SQLite database with abstraction layer for easy migration
14+15+## Tech Stack
16+17+- **Backend**: Go 1.22+ (using stdlib router)
18+- **Database**: SQLite (via modernc.org/sqlite - pure Go, no CGO)
19+- **Templates**: Templ (type-safe HTML templates)
20+- **Frontend**: HTMX + Alpine.js
21+- **CSS**: Tailwind CSS
22+- **PWA**: Service Worker for offline support
23+24+## Project Structure
25+26+```
27+arabica/
28+├── cmd/server/ # Application entry point
29+├── internal/
30+│ ├── database/ # Database interface & SQLite implementation
31+│ ├── models/ # Data models
32+│ ├── handlers/ # HTTP handlers
33+│ └── templates/ # Templ templates
34+├── web/static/ # Static assets (CSS, JS, PWA files)
35+├── migrations/ # Database migrations
36+└── Makefile # Build commands
37+```
38+39+## Getting Started
40+41+### Prerequisites
42+43+- Go 1.22+
44+- Templ CLI
45+- Tailwind CSS CLI
46+- (Optional) Air for hot reload
47+48+Or use Nix:
49+50+```bash
51+nix develop
52+```
53+54+### Installation
55+56+1. Clone the repository:
57+```bash
58+cd arabica-site
59+```
60+61+2. Install dependencies:
62+```bash
63+make install-deps
64+```
65+66+3. Build the application:
67+```bash
68+make build
69+```
70+71+4. Run the server:
72+```bash
73+make run
74+```
75+76+The application will be available at `http://localhost:8080`
77+78+### Development
79+80+For hot reload during development:
81+82+```bash
83+make dev
84+```
85+86+This uses Air to automatically rebuild when you change Go files or templates.
87+88+### Building Assets
89+90+```bash
91+# Generate templ files
92+make templ
93+94+# Build Tailwind CSS
95+make css
96+97+# Or build everything
98+make build
99+```
100+101+## Usage
102+103+### Adding a Brew
104+105+1. Navigate to "New Brew" from the home page
106+2. Select a bean (or add a new one with the "+ New" button)
107+ - When adding a new bean, provide a **Name** (required) like "Morning Blend" or "House Espresso"
108+ - Optionally add Origin, Roast Level, and Description
109+3. Select a roaster (or add a new one)
110+4. Fill in brewing details:
111+ - Method (Pour Over, French Press, etc.)
112+ - Temperature (°C)
113+ - Brew time (seconds)
114+ - Grind size (free text - enter numbers like "18" or "3.5" for grinder settings, or descriptions like "Medium" or "Fine")
115+ - Grinder (optional)
116+ - Tasting notes
117+ - Rating (1-10)
118+5. Click "Save Brew"
119+120+### Viewing Brews
121+122+Navigate to the "Brews" page to see all your entries in a table format with:
123+- Date
124+- Bean details
125+- Roaster
126+- Method and parameters
127+- Rating
128+- Actions (View, Delete)
129+130+### Exporting Data
131+132+Click "Export JSON" on the brews page to download all your data as JSON.
133+134+## Configuration
135+136+Environment variables:
137+138+- `DB_PATH`: Path to SQLite database (default: `./arabica.db`)
139+- `PORT`: Server port (default: `8080`)
140+141+## Database Abstraction
142+143+The application uses an interface-based approach for database operations, making it easy to swap SQLite for PostgreSQL or another database later. See `internal/database/store.go` for the interface definition.
144+145+## PWA Support
146+147+The application includes:
148+- Web App Manifest for "Add to Home Screen"
149+- Service Worker for offline caching
150+- Mobile-optimized UI with large touch targets
151+152+## Future Enhancements (Not in MVP)
153+154+- Statistics and analytics page
155+- CSV export
156+- Multi-user support (database already has user_id column)
157+- Search and filtering
158+- Photo uploads for beans/brews
159+- Brew recipes and sharing
160+161+## Development Notes
162+163+### Why These Choices?
164+165+- **Go**: Fast compilation, single binary deployment, excellent stdlib
166+- **modernc.org/sqlite**: Pure Go SQLite (no CGO), easy cross-compilation
167+- **Templ**: Type-safe templates, better than text/template for HTML
168+- **HTMX**: Progressive enhancement without heavy JS framework
169+- **Nix**: Reproducible builds across environments
170+171+### Database Schema
172+173+See `migrations/001_initial.sql` for the complete schema.
174+175+Key tables:
176+- `users`: Future multi-user support
177+- `beans`: Coffee bean information
178+- `roasters`: Roaster information
179+- `brews`: Individual brew records with all parameters
180+181+## License
182+183+MIT
184+185+## Contributing
186+187+This is a personal project, but suggestions and improvements are welcome!
+22
build.sh
···0000000000000000000000
···1+#!/usr/bin/env bash
2+set -e
3+4+echo "🔧 Building Arabica..."
5+6+# Generate templ files
7+echo "📝 Generating templates..."
8+templ generate
9+10+# Build CSS
11+echo "🎨 Building CSS..."
12+tailwindcss -i web/static/css/style.css -o web/static/css/output.css --minify
13+14+# Build Go binary
15+echo "🚀 Building Go application..."
16+mkdir -p bin
17+go build -o bin/arabica cmd/server/main.go
18+19+echo "✅ Build complete!"
20+echo ""
21+echo "Run './bin/arabica' to start the server"
22+echo "Or run 'make dev' for hot reload development mode"
···1+-- Initial schema for Arabica coffee tracking
2+3+CREATE TABLE IF NOT EXISTS users (
4+ id INTEGER PRIMARY KEY AUTOINCREMENT,
5+ username TEXT UNIQUE NOT NULL,
6+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
7+);
8+9+CREATE TABLE IF NOT EXISTS beans (
10+ id INTEGER PRIMARY KEY AUTOINCREMENT,
11+ name TEXT,
12+ origin TEXT NOT NULL,
13+ roast_level TEXT,
14+ description TEXT,
15+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
16+);
17+18+CREATE TABLE IF NOT EXISTS roasters (
19+ id INTEGER PRIMARY KEY AUTOINCREMENT,
20+ name TEXT UNIQUE NOT NULL,
21+ location TEXT,
22+ website TEXT,
23+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
24+);
25+26+CREATE TABLE IF NOT EXISTS grinders (
27+ id INTEGER PRIMARY KEY AUTOINCREMENT,
28+ name TEXT UNIQUE NOT NULL,
29+ type TEXT,
30+ notes TEXT,
31+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
32+);
33+34+CREATE TABLE IF NOT EXISTS brews (
35+ id INTEGER PRIMARY KEY AUTOINCREMENT,
36+ user_id INTEGER NOT NULL DEFAULT 1,
37+ bean_id INTEGER NOT NULL,
38+ roaster_id INTEGER NOT NULL,
39+ method TEXT NOT NULL,
40+ temperature REAL,
41+ time_seconds INTEGER,
42+ grind_size TEXT,
43+ grinder TEXT,
44+ tasting_notes TEXT,
45+ rating INTEGER CHECK(rating >= 1 AND rating <= 10),
46+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
47+ FOREIGN KEY (user_id) REFERENCES users(id),
48+ FOREIGN KEY (bean_id) REFERENCES beans(id),
49+ FOREIGN KEY (roaster_id) REFERENCES roasters(id)
50+);
51+52+-- Insert default user for single-user mode (ignore if exists)
53+INSERT OR IGNORE INTO users (username) VALUES ('default');
54+55+-- Create indexes for common queries
56+CREATE INDEX IF NOT EXISTS idx_brews_user_id ON brews(user_id);
57+CREATE INDEX IF NOT EXISTS idx_brews_bean_id ON brews(bean_id);
58+CREATE INDEX IF NOT EXISTS idx_brews_roaster_id ON brews(roaster_id);
59+CREATE INDEX IF NOT EXISTS idx_brews_created_at ON brews(created_at DESC);