Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ curl -LsSf https://astral.sh/uv/install.sh | sh

# Install all dependencies
uv sync --all-extras

# Copy the example env file and fill in values
cp apps/kitchen_mate/.env.example apps/kitchen_mate/.env
```

### Running the CLI
Expand All @@ -46,35 +49,59 @@ uv run --directory packages/recipe_clipper recipe-clipper <URL>
### Running the Backend

```bash
# Run database migrations
uv run --directory apps/kitchen_mate alembic upgrade head

# Development server
uv run --directory apps/kitchen_mate uvicorn kitchen_mate.main:app --reload

# Using Docker
# Using Docker (runs migrations automatically)
docker compose up --build
```

By default, migrations create `kitchenmate.db` in the current directory. Set `CACHE_DB_PATH` to override the location.

### Running the Frontend

```bash
# Install dependencies (first time only)
npm install --prefix apps/kitchen_mate/frontend

# Start development server (port 5173)
npm run dev --prefix apps/kitchen_mate/frontend
```

The Vite dev server proxies API requests to the backend at `http://localhost:8000`, so the backend must be running.

## Deployment Modes

Kitchen Mate supports two deployment modes:

### Single-Tenant (Self-Hosted)

Run your own instance with no authentication required. All features are available to anyone with access.
Run your own instance with no authentication required. All features are available to anyone with access. No Supabase configuration needed.

```bash
# No Supabase configuration needed - just run the app
docker compose up --build
# Run database migrations
uv run --directory apps/kitchen_mate alembic upgrade head

# Start backend (optional: set ANTHROPIC_API_KEY for LLM-based extraction)
uv run --directory apps/kitchen_mate uvicorn kitchen_mate.main:app --reload

# Start frontend (in a separate terminal)
npm run dev --prefix apps/kitchen_mate/frontend
```

### Multi-Tenant (SaaS)

Deploy as a multi-tenant service with Supabase authentication. Public features (clip, export) work for everyone; user-specific features require sign-in.

Set the following in `apps/kitchen_mate/.env` (see `.env.example`):

```bash
# Set Supabase environment variables
export SUPABASE_JWT_SECRET="your-jwt-secret"
export VITE_SUPABASE_URL="https://your-project.supabase.co"
export VITE_SUPABASE_ANON_KEY="your-anon-key"
SUPABASE_JWT_SECRET="your-jwt-secret"
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_ANON_KEY="your-anon-key"
```

The mode is determined automatically by whether `SUPABASE_JWT_SECRET` is set.
Expand Down
37 changes: 23 additions & 14 deletions apps/kitchen_mate/.env.example
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
# Kitchen Mate Environment Configuration
# Copy this file to .env and fill in your values
# LLM-based recipe extraction (optional in single-tenant mode)
ANTHROPIC_API_KEY=

# LLM fallback for unsupported recipe sites (optional)
ANTHROPIC_API_KEY=your-api-key-here
# Multi-tenant mode (leave unset for single-tenant/self-hosted)
SUPABASE_JWT_SECRET=
SUPABASE_URL=
SUPABASE_ANON_KEY=

# Pro user IDs for tier-based authorization (comma-separated Supabase user IDs)
# Users in this list get Pro tier with access to LLM features
# In single-tenant mode (no Supabase), all users automatically get Pro tier
# PRO_USER_IDS=uuid-1,uuid-2,uuid-3
# Pro tier access (comma-separated Supabase user IDs)
PRO_USER_IDS=

# CORS origins (comma-separated, optional)
# CORS_ORIGINS=http://localhost:5173,https://yourdomain.com
# CORS (comma-separated origins)
CORS_ORIGINS=http://localhost:5173

# Multi-tenant mode: Uncomment these to enable Supabase authentication
# SUPABASE_URL is used by both backend (JWKS verification) and frontend (auth client)
# SUPABASE_URL=https://your-project.supabase.co
# SUPABASE_ANON_KEY=your-anon-key
# Database
CACHE_DB_PATH=kitchenmate.db

# File storage ("local" or "s3")
STORAGE_BACKEND=local
STORAGE_LOCAL_PATH=uploads

# S3 storage (required when STORAGE_BACKEND=s3)
S3_BUCKET=
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_REGION=us-east-1
S3_ENDPOINT_URL=
2 changes: 2 additions & 0 deletions apps/kitchen_mate/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ RUN uv sync --frozen --no-dev

# Default port (Render sets PORT environment variable)
ENV PORT=8000
# Default local storage path to persistent disk; overridden in production by STORAGE_BACKEND=s3
ENV STORAGE_LOCAL_PATH=/data/uploads
EXPOSE $PORT

# Run migrations and start the application (shell form to expand $PORT)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Add source_file_key and thumbnail_key to user_recipes

Revision ID: a1b2c3d4e5f6
Revises: ede6c69f37ad
Create Date: 2026-04-11 00:00:00.000000

"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision: str = "a1b2c3d4e5f6"
down_revision: Union[str, Sequence[str], None] = "ede6c69f37ad"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
"""Add file storage key columns to user_recipes."""
op.add_column("user_recipes", sa.Column("source_file_key", sa.Text(), nullable=True))
op.add_column("user_recipes", sa.Column("thumbnail_key", sa.Text(), nullable=True))


def downgrade() -> None:
"""Remove file storage key columns from user_recipes."""
op.drop_column("user_recipes", "thumbnail_key")
op.drop_column("user_recipes", "source_file_key")
Loading
Loading