A beer inventory and trading platform — beercellar.io
- Framework — TanStack Start (React 19, Vite)
- Database — PostgreSQL 16 via Drizzle ORM
- UI — Radix UI + Tailwind CSS v4
- Auth — Untappd OAuth
- Testing — Vitest + Playwright
# 1. Install dependencies
pnpm install
# 2. Set up environment variables
cp .env.example .env
# Edit .env with your Untappd OAuth credentials (optional for basic dev)
# 3. Start PostgreSQL
pnpm docker:up
# 4. Run migrations and seed the database
pnpm db:migrate && pnpm db:seed
# 5. Start the dev server
pnpm devThe app is available at http://localhost:3000.
| Script | Description |
|---|---|
pnpm dev |
Start Vite dev server with HMR |
pnpm build |
Production build |
pnpm start |
Serve the production build |
pnpm test |
Run unit tests (Vitest) |
pnpm test:watch |
Run tests in watch mode |
pnpm test:e2e |
Run E2E tests (Playwright) |
pnpm docker:up |
Start PostgreSQL container |
pnpm docker:down |
Stop PostgreSQL container |
pnpm docker:dev |
Run Postgres + app in Docker |
pnpm docker:prod |
Build and run production Docker stack |
pnpm db:generate |
Generate Drizzle migration files |
pnpm db:migrate |
Apply pending migrations |
pnpm db:seed |
Seed the database |
pnpm db:reset |
Drop, recreate, migrate, and seed the DB |
pnpm db:shell |
Open a psql shell to the dev database |
src/
routes/ # File-based routing (TanStack Router)
__root.tsx # Root layout
index.tsx # Landing page
dashboard.tsx # User dashboard
auth/ # OAuth callback routes
beers/ # Beer detail/list pages
breweries/ # Brewery pages
search/ # Search pages
users/ # User profile pages
settings.tsx # User settings
server/
auth/ # Untappd OAuth + session handling
db/ # Drizzle schema, migrations, seed
functions/ # Server functions (RPC-style)
components/
ui/ # Radix-based primitives (button, card, dialog, etc.)
nav/ # Navigation components
inventory/ # Inventory management components
notifications/ # Toast/notification components
lib/ # Shared utilities
styles/ # Global Tailwind styles
See .env.example for all variables. Key ones:
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
SESSION_SECRET |
Server-side session encryption key |
UNTAPPD_CLIENT_ID |
Untappd OAuth app client ID |
UNTAPPD_CLIENT_SECRET |
Untappd OAuth app client secret |
UNTAPPD_CALLBACK_URL |
OAuth redirect URL |
VITE_UNTAPPD_CLIENT_ID |
Client-side Untappd client ID |
VITE_UNTAPPD_CALLBACK_URL |
Client-side OAuth redirect URL |
Development — By default, Docker only runs PostgreSQL. The app runs natively via pnpm dev:
pnpm docker:up # Postgres only
pnpm dev # App on hostTo run everything in Docker: pnpm docker:dev
Production — Uses a multi-stage Dockerfile with a separate compose file:
cp .env.production.example .env.production
# Edit with real credentials
pnpm docker:prodpnpm test # Unit tests with Vitest
pnpm test:e2e # E2E tests with Playwright (requires running app + DB)Tests are co-located with source files as *.test.ts(x).
Authentication uses Untappd OAuth. To enable login locally:
- Create an app at untappd.com/api/register
- Set the callback URL to
http://localhost:3000/auth/oauth/untappd - Add the client ID and secret to your
.envfile