An interactive market intelligence dashboard built on top of public WLCB (Washington State Liquor and Cannabis Board) production and licensing data. Explore production trends across licensed breweries, wineries, cideries, and distilleries in Washington State, ask natural-language questions about the data, and find producers near you.
| Tool | Version | Install |
|---|---|---|
| Python | ≥ 3.11 | python.org |
| uv | latest | curl -LsSf https://astral.sh/uv/install.sh | sh |
| Node.js | ≥ 20 | nodejs.org |
| pnpm | latest | npm install -g pnpm |
| Ollama | latest | ollama.ai (required for the Ask feature) |
git clone https://github.com/your-username/craft-brewing-production.git
cd craft-brewing-productioncd backend
cp .env.example .env # copy default config
uv sync # install Python dependencies
uv run alembic upgrade head # apply database migrations
uv run fastapi dev # starts at http://localhost:8000The API will be available at http://localhost:8000. Interactive docs at http://localhost:8000/docs.
cd frontend
pnpm install
pnpm dev # starts at http://localhost:5173Open http://localhost:5173 in your browser.
Place WLCB source files (.txt, .docx, .csv, .pdf, .xlsx) in a local data directory, then run:
cd backend
uv run python scripts/run_ingestion.py --data-dir /path/to/wlcb-files
uv run python scripts/run_geocoding.py --limit 500 # geocode producer addressesIngestion is idempotent — re-running skips already-processed files by SHA-256 hash. Geocoding uses Nominatim (OpenStreetMap) and rate-limits itself to 1 request per 1.1 seconds.
ollama pull llama3.2
# Ollama must be running (it starts automatically on most installs)The assistant will activate automatically once Ollama is reachable at http://localhost:11434.
| Command | Description |
|---|---|
uv sync |
Install / sync dependencies from lockfile |
uv run fastapi dev |
Start API server with hot reload |
uv run pytest |
Run tests and generate coverage report |
uv run mypy app |
Type-check the backend |
uv run ruff check . |
Lint |
uv run ruff format . |
Format |
uv run alembic upgrade head |
Apply pending migrations |
uv run alembic revision --autogenerate -m "desc" |
Generate a new migration |
| Command | Description |
|---|---|
pnpm dev |
Start Vite dev server |
pnpm build |
Production build (TypeScript + Vite) |
pnpm test |
Run unit tests (Vitest) |
pnpm test:coverage |
Run tests and generate HTML coverage report |
pnpm type-check |
TypeScript compiler check |
pnpm lint |
ESLint |
Both layers generate HTML coverage reports that you can open in your browser.
Backend — after running uv run pytest:
open backend/htmlcov/index.html
Frontend — after running pnpm test:coverage from frontend/:
open frontend/coverage/index.html
pnpm testruns tests only and produces no report. Usepnpm test:coverageto get the HTML output.
Copy backend/.env.example to backend/.env and adjust as needed.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite+aiosqlite:///./data/app.db |
SQLite connection string |
DUCKDB_PATH |
./data/analytics.duckdb |
DuckDB analytics database path |
DATA_DIR |
./data |
Directory for raw and processed data files |
CORS_ORIGINS |
http://localhost:5173 |
Allowed frontend origins |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama API endpoint |
OLLAMA_MODEL |
llama3.2 |
Model used for natural-language queries |
GEOCODING_USER_AGENT |
wa-beverage-explorer |
User-agent for Nominatim requests |
GEOCODING_RATE_LIMIT_SECONDS |
1.1 |
Delay between geocoding requests |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, WARNING, ERROR) |
Browser (React 18 + Vite)
↕ REST (proxied via Vite dev server)
FastAPI (Python 3.11)
├── SQLite — producers, production records, ingestion runs (via SQLAlchemy)
└── DuckDB — analytics views attached to SQLite (read-only for API)
ETL Pipeline (run manually or via cron)
WLCB files → parsers → normalizers → SQLite → DuckDB views refreshed
- Backend: Python 3.11 · FastAPI · SQLAlchemy · Alembic · DuckDB · Pandas
- Frontend: React 18 · TypeScript · Vite · TanStack Query · Recharts · Leaflet
- LLM: Ollama (
llama3.2) — fully local, no external API calls - Geocoding: Nominatim / OpenStreetMap via
geopy— no API key required
MIT — see LICENSE for details.