feat: mark recipe as cooked (multi-cook history + backdate) and enable auto-deduct pantry on cook (v0.75.0)
Adds a general-purpose "mark cooked" dialog for any recipe (not just batch-cook dishes), with a date picker for backdating and a pantry-deduct checkbox defaulted on. Also flips the previously dead-in-the-UI deductFromPantry flag to true for the existing batch-cook and meal-planner cook actions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -290,7 +290,7 @@ export function generateOpenApiSpec(): object {
|
||||
registry.registerPath({ method: "patch", path: "/api/v1/recipes/bulk", summary: "Bulk update visibility/tags (owned only)", security, request: { body: { content: { "application/json": { schema: BulkUpdateRecipesRef } }, required: true } }, responses: { 200: { description: "OK", content: { "application/json": { schema: z.object({ ok: z.boolean() }) } } }, 400: { description: "Invalid request / nothing to update", content: { "application/json": { schema: ApiErrorRef } } }, 401: { description: "Unauthorized", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "post", path: "/api/v1/recipes/bulk/export", summary: "Export several recipes as one Markdown document", description: "Gated by the markdown_export tier feature flag.", security, request: { body: { content: { "application/json": { schema: BulkIdsRef } }, required: true } }, responses: { 200: { description: "Markdown", content: { "application/json": { schema: z.object({ markdown: z.string() }) } } }, 400: { description: "Invalid request", content: { "application/json": { schema: ApiErrorRef } } }, 403: { description: "Feature disabled for your tier", content: { "application/json": { schema: ApiErrorRef } } }, 404: { description: "None of the ids belong to you", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "post", path: "/api/v1/recipes/{id}/fork", summary: "Fork (or duplicate your own) a recipe", description: "Rate-limited: 20 req/min. Source must be your own, public, or unlisted.", security, request: { params: idParam }, responses: { 201: { description: "New recipe id", content: { "application/json": { schema: z.object({ id: z.string() }) } } }, 401: { description: "Unauthorized", content: { "application/json": { schema: ApiErrorRef } } }, 403: { description: "Recipe limit reached for your tier", content: { "application/json": { schema: ApiErrorRef } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "post", path: "/api/v1/recipes/{id}/cooked", summary: "Log that you cooked this recipe", description: "Optionally deducts matching ingredients from your pantry.", security, request: { params: idParam, body: { content: { "application/json": { schema: z.object({ servings: z.number().int().min(1).max(1000).optional(), notes: z.string().max(2000).optional(), deductFromPantry: z.boolean().default(true), batchDishId: z.string().optional() }) } } } }, responses: { 201: { description: "Logged", content: { "application/json": { schema: z.object({ logged: z.boolean() }) } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "post", path: "/api/v1/recipes/{id}/cooked", summary: "Log that you cooked this recipe", description: "Optionally deducts matching ingredients from your pantry. A recipe can be logged as cooked any number of times — each call inserts a new history row, never updates one. cookedAt lets you backdate a cook instead of only logging \"now\".", security, request: { params: idParam, body: { content: { "application/json": { schema: z.object({ servings: z.number().int().min(1).max(1000).optional(), notes: z.string().max(2000).optional(), deductFromPantry: z.boolean().default(true), batchDishId: z.string().optional(), cookedAt: z.string().optional().describe("ISO date (YYYY-MM-DD) or datetime; defaults to now") }) } } } }, responses: { 201: { description: "Logged", content: { "application/json": { schema: z.object({ logged: z.boolean() }) } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "get", path: "/api/v1/recipes/{id}/nutrition", summary: "Get cached nutrition estimate or manually-entered values", security, request: { params: idParam }, responses: { 200: { description: "Nutrition data or null", content: { "application/json": { schema: z.object({ nutrition: z.object({ perServing: NutritionInputRef }).nullable(), manual: z.boolean() }) } } }, 401: { description: "Unauthorized", content: { "application/json": { schema: ApiErrorRef } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "post", path: "/api/v1/recipes/{id}/nutrition", summary: "Compute a fresh AI nutrition estimate (author only)", description: "Rate-limited: 10 req/min. Consumes AI quota. Overwrites any manually-entered nutrition and clears nutritionManual. Gated by the nutrition_estimation tier feature flag.", security, request: { params: idParam }, responses: { 200: { description: "Nutrition data", content: { "application/json": { schema: z.object({ nutrition: z.object({ perServing: NutritionInputRef }) }) } } }, 401: { description: "Unauthorized", content: { "application/json": { schema: ApiErrorRef } } }, 403: { description: "Feature disabled for your tier", content: { "application/json": { schema: ApiErrorRef } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } }, 429: { description: "Rate limited or AI quota exhausted", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
registry.registerPath({ method: "get", path: "/api/v1/recipes/{id}/notes", summary: "Get your own private note on a recipe", security, request: { params: idParam }, responses: { 200: { description: "Note or null", content: { "application/json": { schema: z.object({ note: RecipeNoteRef }) } } }, 401: { description: "Unauthorized", content: { "application/json": { schema: ApiErrorRef } } }, 404: { description: "Not found", content: { "application/json": { schema: ApiErrorRef } } } } });
|
||||
|
||||
Reference in New Issue
Block a user