Commit Graph

22 Commits

Author SHA1 Message Date
Alexander 096d6e2868 feat(rezepte)!: liturgical-aware seasonality via date ranges
CI / update (push) Successful in 3m31s
Replace season: number[] (months 1-12) on Recipe with seasonRanges, a
list of date ranges where each endpoint is either a fixed MM-DD or a
movable liturgical anchor (Easter, Ash Wednesday, Palm Sunday,
Pentecost, Advent I) plus a day offset. The old month list couldn't
express liturgical seasons whose boundaries shift each year (Advent,
Lent, Easter Octave, Christmas Octave) nor sub-month windows.

The shared evaluator resolves anchors against [Y-1, Y, Y+1] so spans
that wrap the calendar year boundary (e.g. christmas + 0 to
christmas + 7) match correctly on both sides. SeasonSelect was
rewritten as a controlled bind:ranges editor with a
fixed/liturgical kind toggle, anchor + offset inputs, per-row
resolved-this-year preview, and preset chips.

Run the one-time migration before deploying:
  pnpm exec vite-node scripts/migrate-season-to-ranges.ts

It coalesces contiguous month runs into single fixed ranges and
merges Dec/Jan wrap into one wrapping range; the new code does not
read the legacy season field, so order matters.
2026-05-02 17:53:27 +02:00
Alexander 1e23ed02c2 feat: add "round off this day" nutrition suggestions
Suggest optimal 1-3 food combinations to fill remaining macro budget using
weighted least-squares solver over a curated pantry (~55 foods) plus user
favorites/recents. Recipes scored individually (no combining). Features:

- Combinatorial solver (singles, pairs, triples) with macro-weighted scoring
- MealTypePicker component (extracted from quick-log, shared)
- Hero card with fit%, macro delta icons (Beef/Droplet/Wheat), ingredient
  cards, animated +/X toggle for logging
- Responsive layout: sidebar on mobile, center column on desktop
- MongoDB cache with ±5% tolerance, SSR on cache hit, TTL auto-expiry
- Cache invalidation on food-log/favorites/custom-meals CRUD
- Recipe per100g backfill admin endpoint
2026-04-09 20:47:32 +02:00
Alexander fac140b793 perf: optimize DB connections, queries, and indexes
Fix dev-mode reconnect storm by persisting mongoose connection state on
globalThis instead of a module-level flag that resets on Vite HMR.

Eliminate redundant in_season DB query on /rezepte — derive seasonal
subset from all_brief client-side. Parallelize all page load fetches.

Replace N+1 settlement queries in balance route with single batch $in
query. Parallelize balance sum and recent splits aggregations.

Trim unused dateModified/dateCreated from recipe brief projections.

Add indexes: Payment(date, createdAt), PaymentSplit(username),
Recipe(short_name), Recipe(season).
2026-04-06 12:42:54 +02:00
Alexander 5d7a959355 nutrition: detect recipe refs in ingredients, show in edit UI with multiplier
Skip embedding matching for anchor-tag ingredients that reference other
recipes. Instead, mark them with recipeRef/recipeRefMultiplier fields so
their nutrition is resolved via resolveReferencedNutrition with a
user-configurable fraction. The edit UI shows these as teal REF badges
with an editable "Anteil" input.
2026-04-04 09:43:49 +02:00
Alexander d2a0411937 recipes: nutrition calculator with BLS/USDA matching, manual overwrites, and skip
Dual-source nutrition system using BLS (German, primary) and USDA (English, fallback)
with ML embedding matching (multilingual-e5-small / all-MiniLM-L6-v2), hybrid
substring-first search, and position-aware scoring heuristics.

Includes per-recipe and global manual ingredient overwrites, ingredient skip/exclude,
referenced recipe nutrition (base refs + anchor tags), section-name dedup,
amino acid tracking, and reactive client-side calculator with NutritionSummary component.
2026-04-01 13:00:55 +02:00
Alexander 19e46b2b3a fix: replace any types with proper types across codebase
Replace ~100 `any` usages with proper types: use existing interfaces
(RecipeModelType, BriefRecipeType, IPayment, etc.), Record<string, unknown>
for dynamic objects, unknown for catch clauses with proper narrowing,
and inline types for callbacks. Remaining `any` types are in Svelte
components and cases where mongoose document mutation requires casts.
2026-03-02 20:15:08 +01:00
Alexander d2ac67fb44 fix: resolve all 1008 svelte-check type errors across codebase
Add type annotations, JSDoc types, null checks, and proper generics
to eliminate all svelte-check errors. Key changes include:
- Type $state(null) variables to avoid 'never' inference
- Add JSDoc typedefs for plain <script> components
- Fix mongoose model typing with Model<any> to avoid union complexity
- Add App.Error/App.PageState interfaces in app.d.ts
- Fix tuple types to array types in types.ts
- Type catch block errors and API handler params
- Add null safety for DOM queries and optional chaining
- Add standard line-clamp property alongside -webkit- prefix
2026-03-02 08:40:18 +01:00
Alexander 12f45c5cbb recipes: add cake form size scaling for ingredient multiplier
Allow recipes to specify a default pan shape (round, rectangular, gugelhupf)
with dimensions. On the recipe page, users can enter their own pan size to
auto-calculate an ingredient multiplier based on the 2D area ratio.
2026-02-27 20:10:21 +01:00
Alexander b8469d4ae2 recipes: replace placeholder images with OKLAB dominant color backgrounds
Instead of generating/serving 20px placeholder images with blur CSS, extract
a perceptually accurate dominant color (Gaussian-weighted OKLAB average) and
use it as a solid background-color while the full image loads. Removes
placeholder image generation, blur CSS/JS, and placeholder directory references
across upload flows, API routes, service worker, and all card/hero components.
Adds admin bulk tool to backfill colors for existing recipes.
2026-02-17 18:25:17 +01:00
Alexander bf7210dc2e feat: add base multiplier support for recipe references
Add optional baseMultiplier field to ingredient and instruction references, allowing base recipes to be included at scaled amounts (e.g., 0.5 for half the recipe).

- Add baseMultiplier field to Recipe schema with default value of 1
- Update TypeScript types to include baseMultiplier
- Add multiplier input field to BaseRecipeSelector modal
- Apply baseMultiplier to ingredient amounts during flattening
- Combine baseMultiplier with recipe multiplier in links
- Display and allow editing baseMultiplier in recipe editor

The multiplier cascades through nested references and works alongside the standard recipe multiplier for compound scaling.
2026-01-13 19:14:10 +01:00
Alexander 327aa6824b feat: implement base recipe references with customizable ingredients and instructions
Add comprehensive base recipe system allowing recipes to reference other recipes dynamically. References can include custom items before/after the base recipe content and render as unified lists.

Features:
- Mark recipes as base recipes with isBaseRecipe flag
- Insert base recipe references at any position in ingredients/instructions
- Add custom items before/after referenced content (itemsBefore/itemsAfter, stepsBefore/stepsAfter)
- Combined rendering displays all items in single unified lists
- Full edit/remove functionality for additional items with modal reuse
- Empty item validation prevents accidental blank entries
- HTML rendering in section titles for proper <wbr> and &shy; support
- Reference links in section headings with multiplier preservation
- Subtle hover effects (2% scale) on add buttons
- Translation support for all reference fields
- Deletion handling expands references before removing base recipes
2026-01-04 15:21:25 +01:00
Alexander ee387159ba feat: add untranslated recipes page for recipe admins
Add new page at /rezepte/untranslated for recipe admins to view and manage recipes without approved English translations. Includes translation status tracking, statistics dashboard, and visual badges.

Changes:
- Add API endpoint to fetch recipes without approved translations
- Create untranslated recipes page with auth checks for rezepte_users group
- Add translation status badges to Card component (pending, needs_update, none)
- Add database index on translations.en.translationStatus for performance
- Create layout for /rezepte route with header navigation
- Add "Unübersetzt" link to navigation for authorized users
2026-01-03 20:03:36 +01:00
Alexander fc24f46145 implement content-hash based image cache invalidation
Add content-based hashing to recipe images for proper cache invalidation
while maintaining graceful degradation through dual file storage.

Changes:
- Add imageHash utility with SHA-256 content hashing (8-char)
- Update Recipe model to store hashed filenames in images[0].mediapath
- Modify image upload endpoint to save both hashed and unhashed versions
- Update frontend components to use images[0].mediapath with fallback
- Add migration endpoint to hash existing images (production-only)
- Update image delete/rename endpoints to handle both file versions

Images are now stored as:
  - recipe.a1b2c3d4.webp (hashed, cached forever)
  - recipe.webp (unhashed, graceful degradation fallback)

Database stores hashed filename for cache busting, while unhashed
version remains on disk for backward compatibility and manual uploads.
2026-01-02 12:06:56 +01:00
Alexander ace23e09b0 add translation support for portions, baking, cook times, and ingredient units
Add comprehensive translation support for previously untranslatable fields:
- Portions (serving sizes)
- Time fields (preparation, cooking, total_time)
- Baking properties (temperature, length, mode)
- Fermentation times (bulk, final)
- Ingredient units (EL→tbsp, TL→tsp, etc.)

Fix terminology replacement to work correctly:
- Pre-process German cooking terms BEFORE sending to DeepL
- Post-process to convert US English to British English AFTER DeepL
- Split applyIngredientTerminology into replaceGermanCookingTerms (pre) and applyBritishEnglish (post)

Database schema:
- Add translatable fields to translations.en object

Translation service:
- Include new fields and ingredient units in batch translation
- Add field-specific translation in translateFields()
- Update change detection to track new fields
- Pre-process all texts to replace German terms before DeepL
- Post-process all texts to apply British English after DeepL

UI components:
- Display all new fields in translation approval interface
- Add editable inputs for English translations
- Support nested field editing (baking.temperature, fermentation.bulk, etc.)

Fix changed fields detection:
- Only show changed fields when editing existing translations
- Don't show false warnings for first-time translations
2025-12-27 13:57:42 +01:00
Alexander 1f16d1c5c9 add English translation support for recipes with DeepL integration
- Add embedded translations schema to Recipe model with English support
- Create DeepL translation service with batch translation and change detection
- Build translation approval UI with side-by-side editing for all recipe fields
- Integrate translation workflow into add/edit pages with field comparison
- Create complete English recipe routes at /recipes/* mirroring German structure
- Add language switcher component with hreflang SEO tags
- Support image loading from German short_name for English recipes
- Add English API endpoints for all recipe filters (category, tag, icon, season)
- Include layout with English navigation header for all recipe subroutes
2025-12-26 20:28:43 +01:00
Alexander 01b2409a8d add Note field in recipe 2023-07-21 00:18:37 +02:00
Alexander 3aa3f7949a initial implementation of placeholder images, thumbnails and blurring between using sharp 2023-07-11 18:47:29 +02:00
Alexander 825245c74c Update 2023-06-27 19:01:06 +02:00
Alexander f1dc876590 Does not work: uploading images
Adding/Editing/Deleting works
SeasonsSelect works
Nice recipe layout
2023-06-24 15:35:38 +02:00
Alexander 651a48f6e2 First almost fully functioning MVP.
Lacking:
- Seasons cannot be added/edited
- image upload
- layout recipe/adding
2023-06-24 15:35:38 +02:00
Alexander 9feb0c273e Lots of changes, started on working /add 2023-06-24 15:35:37 +02:00
Alexander cbe36be64b Initial commit 2023-06-24 15:35:36 +02:00