JP e0c1814cf1 Put images behind the session and make routes private by default
The /minio-images rewrite proxied straight onto the MinIO bucket with no
authentication, and the bucket carries an anonymous read policy. Verified
from the public internet: GET /minio-images?list-type=2 returned a full
ListBucketResult naming all 33 objects, and any key then fetched 200. Every
menu scan, drink photo and bar photo was enumerable and downloadable by
anyone. Replaced with a route handler that requires a session and streams
via the existing getImage(). The URL shape is unchanged, so stored
imageUrls, uploadImage/getImageUrl and every <img> keep working.

Nothing uses next/image and it must stay that way here: the optimizer
fetches server-side without the session cookie.

Route protection was an allowlist that had to be updated by hand for each
new page, and had already been missed for /bar, /bartender and /recommend,
which rendered to logged-out visitors. /recipes was in the middleware
matcher but not the authorized() list, so it fell through too. Inverted
both to a denylist so new pages are private by default. /api stays out of
the matcher because authorized() answers with an HTML redirect and API
clients need the JSON 401 those routes already return.

Also fixes a cross-user write: POST /api/recipes took sourceDrinkId from
the client with no ownership check, and the drink detail page loaded its
recipes relation unfiltered, so one user could attach an arbitrary recipe
to another user's drink where it rendered permanently and the owner could
not delete it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 20:20:39 +00:00

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

AI Gateway (Switchboard)

All AI features — menu scanning, label identification, drink search, the bartender and the recommendation engine — go through Switchboard, an OpenAI-compatible gateway that routes each request to the best available model. The app never pins a model id; it always sends switchboard/auto and lets the gateway choose, then logs which model answered and what it cost.

Setup:

  1. Set SWITCHBOARD_BASE_URL in your env file (defaults to http://192.168.2.11:8787/v1).
  2. Mint an API key in the Switchboard UI under Settings → API keys.
  3. Add that key in the app under Settings → AI Gateway.

Per-feature routing (cost/quality levers, token budgets, timeouts) lives in src/lib/ai/routing.ts. Note that a Switchboard key carries its own routing defaults, so the app sets category and prefer_free explicitly on every request rather than inheriting whatever the key was minted for.

Migrating from the old Claude/OpenAI integration

Earlier versions stored a per-user Anthropic or OpenAI key. Those rows are ignored at runtime and the Settings page offers to remove them, so no migration is required. To clear them in bulk instead:

DELETE FROM "UserApiKey"  WHERE provider IN ('claude','openai');
DELETE FROM "SearchCache" WHERE provider IN ('claude','openai');
UPDATE "UserPreference" SET "defaultProvider" = NULL;

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.

Description
No description provided
Readme 1.1 MiB
Languages
TypeScript 96.5%
Shell 2.9%
JavaScript 0.3%
CSS 0.2%
Dockerfile 0.1%