saltybytes-api

module
v0.0.0-...-df419cd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: AGPL-3.0

README

SaltyBytes API

Backend for SaltyBytes — a recipe app for iOS and Android. Search the web for recipes without the ads and life stories, import from any source, generate with AI, and cook hands-free with voice-guided cooking mode.

Built with Go, Gin, PostgreSQL + pgvector, and Claude AI.

See also: saltybytes-app — the Flutter iOS client | saltybytes-dashboard — the operational metrics dashboard.

Features

Recipe Search & Discovery — Search the web for recipes and get clean results — no ads, no SEO spam, no scrolling past someone's vacation story. Multi-tier pipeline: exact-match cache, pgvector semantic similarity, and Brave web search. Import any result directly into your collection.

Multi-Source Import — Import recipes from URLs (with JSON-LD extraction and Firecrawl fallback), photos (vision-based), freeform text, or manual entry. A canonical recipe cache deduplicates URL imports with automatic background refresh.

AI Recipe Generation — Create recipes through conversation with Claude when you can't find what you're looking for. Fork existing recipes into new variants, regenerate with feedback, and explore branching version history through a recipe tree.

Family Allergen Analysis — AI-powered ingredient analysis detects common allergens (dairy, nuts, shellfish, wheat, soy, sesame, etc.) with confidence scoring. Cross-reference results against family members' dietary profiles.

Real-Time Cooking Mode — WebSocket-based hands-free cooking. Voice commands are transcribed (Whisper), classified by intent (Claude), and answered contextually. Supports ephemeral recipe edits during cooking.

AI Dietary Interviews — Conversational dietary profiling for family members, covering allergies, intolerances, and preferences.

Architecture

Handlers → Services → Repositories → PostgreSQL (GORM)
Layer Purpose
internal/handlers/ HTTP request handling and validation
internal/service/ Business logic, AI orchestration
internal/repository/ Database access via interfaces (DI-friendly)
internal/models/ Data models and GORM schema
internal/ai/ Anthropic, OpenAI, and Brave Search providers
internal/ws/ WebSocket server for cooking mode
internal/middleware/ JWT auth, rate limiting, request context
configs/ AI prompt templates (YAML)
External Services
Service Used For
Anthropic Claude Recipe generation, allergen analysis, dietary interviews, voice intent classification, cooking Q&A
OpenAI DALL-E 3 (recipe images), Whisper (voice transcription), text-embedding-3-small (vector search)
Brave Search Web recipe discovery
S3-compatible object store Recipe image storage (Cloudflare R2 in production; AWS S3 or any S3 API works)
Amazon SES Signup verification email
PostgreSQL + pgvector Data persistence and semantic similarity search

Getting Started

Prerequisites
  • Go 1.24+
  • PostgreSQL 16+ with the pgvector extension
  • API keys for Anthropic, OpenAI, and an S3-compatible bucket for images (Cloudflare R2, AWS S3, MinIO, …)
Setup
  1. Clone the repository
git clone https://github.com/windoze95/saltybytes-api.git
cd saltybytes-api
  1. Configure environment variables
cp .env.example .env

See docs/env-setup.md for a detailed walkthrough of every variable, including how to create API keys and set up image storage.

  1. Run with Docker Compose (recommended)
docker compose up

This starts the API and a PostgreSQL instance. The database schema is auto-migrated on startup.

  1. Or run directly
go run ./cmd/api
Environment Variables
Variable Required Purpose
DATABASE_URL Yes PostgreSQL connection string
JWT_SECRET_KEY Yes Token signing secret
ANTHROPIC_API_KEY Yes Claude — recipe gen, allergens, voice, dietary
OPENAI_API_KEY Yes DALL-E, Whisper, embeddings
S3_BUCKET Yes Image storage bucket
AWS_REGION Yes Region for SES (and S3 when S3_ENDPOINT is empty)
ID_HEADER Yes Request validation header
S3_ENDPOINT No S3-compatible endpoint (Cloudflare R2, MinIO…); empty = AWS S3
S3_PUBLIC_URL No Public base URL images are served from (e.g. an R2 custom domain); empty = SDK object URL
S3_REGION / S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY No Image-store region + key pair; fall back to AWS_*
BRAVE_SEARCH_KEY No Web recipe search (gracefully disabled if absent)
AWS_ACCESS_KEY_ID No SES/S3 auth (falls back to IAM role)
AWS_SECRET_ACCESS_KEY No SES/S3 auth (falls back to IAM role)
PORT No Server port (default: 8080)
GIN_MODE No Set to release for production

API Overview

Authentication
  • POST /v1/users — Create account
  • POST /v1/auth/login — Login
  • POST /v1/auth/refresh — Refresh token
Recipes
  • POST /v1/recipes/chat — Generate recipe via conversation
  • PUT /v1/recipes/:id/chat — Regenerate with feedback
  • POST /v1/recipes/:id/fork — Fork into a new variant
  • GET /v1/recipes/:id/tree — Version history tree
  • GET /v1/recipes — List user's recipes
  • DELETE /v1/recipes/:id — Delete recipe
Import
  • POST /v1/recipes/import/url — Import from URL
  • POST /v1/recipes/import/photo — Import from photo
  • POST /v1/recipes/import/text — Import from text
  • POST /v1/recipes/import/manual — Manual entry
  • POST /v1/recipes/preview/url — Quick URL preview
  • GET /v1/recipes/search — Search recipes (semantic + web)
  • GET /v1/recipes/similar/:id — Find similar recipes
Allergens
  • POST /v1/recipes/:id/allergens/analyze — Run allergen analysis
  • GET /v1/recipes/:id/allergens — Get analysis results
  • POST /v1/recipes/:id/allergens/check-family — Cross-reference family dietary profiles
Family & Dietary
  • POST /v1/family — Create family
  • POST /v1/family/members — Add member
  • PUT /v1/family/members/:id/dietary — Update dietary profile
  • POST /v1/family/members/:id/dietary/interview — AI dietary interview
Cooking Mode
  • GET /v1/ws/cook/:id — WebSocket connection for hands-free cooking

Testing

All tests run offline — no database, network, or external services required. Services accept repository interfaces for dependency injection.

# Run all tests
go test ./... -count=1

# Verbose
go test ./... -v -count=1

# Specific package
go test ./internal/service/ -v

# Lint
go vet ./...

Deployment

The CI/CD pipeline runs automatically via GitHub Actions:

  • On PR to main — vet, test, build validation
  • On merge to main — vet, test, Docker build, push to GHCR (ghcr.io/windoze95/saltybytes-api), then deploy to the target selected by the DEPLOY_TARGET repository variable: droplet (single-host docker-compose stack, see deploy/README.md) or ecs (AWS Fargate, the original target)
Manual deployment
docker build --platform linux/amd64 -t saltybytes-api .

The Dockerfile uses a multi-stage build (Go 1.25 builder → debian:12-slim runtime with ffmpeg for video import).

Tech Stack

  • Language: Go 1.24
  • Framework: Gin
  • ORM: GORM
  • Database: PostgreSQL 17 + pgvector
  • AI: Anthropic Claude, OpenAI (DALL-E, Whisper, Embeddings)
  • Search: Brave Search API
  • Storage: S3-compatible object store (Cloudflare R2 in production)
  • Auth: JWT (golang-jwt)
  • WebSocket: gorilla/websocket
  • Logging: zap
  • Container: Docker (debian:12-slim + ffmpeg)
  • CI/CD: GitHub Actions → GHCR → docker-compose on a DigitalOcean droplet (or ECS Fargate)

License

This project is dual-licensed:

  • Open Source: GNU Affero General Public License v3.0 (AGPL-3.0) — you are free to use, modify, and distribute this software, provided that any derivative work or network service built with it is also released under the AGPL-3.0.
  • Commercial: If you wish to use this software in proprietary/closed-source applications without the AGPL-3.0 obligations, a commercial license is available. Contact the maintainer for details.

Directories

Path Synopsis
cmd
api command
sitepreview command
Command sitepreview serves the public website (internal/web) with canned fixture data on localhost — no database, no network.
Command sitepreview serves the public website (internal/web) with canned fixture data on localhost — no database, no network.
internal
ai
db
email
Package email sends transactional email (signup verification codes) through Amazon SES.
Package email sends transactional email (signup verification codes) through Amazon SES.
iap
Package iap implements store-side purchase verification for the App Store (StoreKit 2 signed JWS, verified locally against Apple's pinned root CA) and Google Play (Android Publisher API), plus the account-token scheme that ties store purchases back to SaltyBytes users.
Package iap implements store-side purchase verification for the App Store (StoreKit 2 signed JWS, verified locally against Apple's pinned root CA) and Google Play (Android Publisher API), plus the account-token scheme that ties store purchases back to SaltyBytes users.
mcpserver
Package mcpserver exposes SaltyBytes as a remote MCP server: OAuth-protected tools over Streamable HTTP at /mcp, with MCP Apps widgets rendered in-chat by hosts like Claude and ChatGPT.
Package mcpserver exposes SaltyBytes as a remote MCP server: OAuth-protected tools over Streamable HTTP at /mcp, with MCP Apps widgets rendered in-chat by hosts like Claude and ChatGPT.
notify
Package notify pushes operational alerts to an ntfy topic so the operator hears about problems (budget trips, provider failures) from their phone, with a tap-through link to the place where the problem gets fixed.
Package notify pushes operational alerts to an ntfy topic so the operator hears about problems (budget trips, provider failures) from their phone, with a tap-through link to the place where the problem gets fixed.
s3
Package s3 stores recipe images in an S3-compatible object store: AWS S3 by default, or any store reachable through S3_ENDPOINT (Cloudflare R2, DigitalOcean Spaces, MinIO).
Package s3 stores recipe images in an S3-compatible object store: AWS S3 by default, or any store reachable through S3_ENDPOINT (Cloudflare R2, DigitalOcean Spaces, MinIO).
units
Package units is the single source of truth for SaltyBytes' unit handling: canonical unit metadata (dimension, measurement system, factor to a base unit), measure-kind classification, base-quantity normalization, and deterministic display conversion.
Package units is the single source of truth for SaltyBytes' unit handling: canonical unit metadata (dimension, measurement system, factor to a base unit), measure-kind classification, base-quantity normalization, and deterministic display conversion.
video
Package video handles importing recipes from social/video links by acquiring the video's caption, transcript, and downloadable media via the ScrapeCreators API, then (in later layers) sampling frames and extracting the recipe.
Package video handles importing recipes from social/video links by acquiring the video's caption, transcript, and downloadable media via the ScrapeCreators API, then (in later layers) sampling frames and extracting the recipe.
web
Package web serves the public marketing site and shareable recipe pages at the apex domain (saltybytes.ai).
Package web serves the public marketing site and shareable recipe pages at the apex domain (saltybytes.ai).
ws

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL