mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:41:09 +02:00
feat(brain): add domain events + tools for remaining 9 modules
Batches 5+6: extends to 29 modules. Adds events and tools for cycles, firsts, guides, inventory, photos, plants, news, recipes, questions. New domain events (12 types): - Cycles: CycleDayLogged - Firsts: FirstCreated - Guides: GuideCreated - Inventory: InventoryItemCreated - Photos: PhotoDeleted - Plants: PlantCreated, PlantDeleted - News: ArticleSaved - Recipes: RecipeCreated, RecipeDeleted - Questions: QuestionAsked New tools (7 tools): - Cycles: log_cycle_day - Firsts: create_first - Guides: create_guide - Inventory: create_inventory_item - Plants: create_plant - Recipes: create_recipe Skipped (no simple create API): context (read-only), news (complex LocalCachedArticle input), questions (requires questionId). Totals: 67 event types, 47 tools across 29 modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c7de86282b
commit
c95aaa4d48
19 changed files with 287 additions and 0 deletions
|
|
@ -442,6 +442,87 @@ export interface SocialEventDeletedPayload {
|
|||
|
||||
export type SocialEventsEventType = 'SocialEventCreated' | 'SocialEventDeleted';
|
||||
|
||||
// ── Cycles ──────────────────────────────────────────
|
||||
|
||||
export interface CycleDayLoggedPayload {
|
||||
logId: string;
|
||||
date: string;
|
||||
flow?: string;
|
||||
}
|
||||
export type CyclesEventType = 'CycleDayLogged';
|
||||
|
||||
// ── Firsts ──────────────────────────────────────────
|
||||
|
||||
export interface FirstCreatedPayload {
|
||||
firstId: string;
|
||||
title: string;
|
||||
isLived: boolean;
|
||||
}
|
||||
export type FirstsEventType = 'FirstCreated';
|
||||
|
||||
// ── Guides ──────────────────────────────────────────
|
||||
|
||||
export interface GuideCreatedPayload {
|
||||
guideId: string;
|
||||
title: string;
|
||||
}
|
||||
export type GuidesEventType = 'GuideCreated';
|
||||
|
||||
// ── Inventory ───────────────────────────────────────
|
||||
|
||||
export interface InventoryItemCreatedPayload {
|
||||
itemId: string;
|
||||
name: string;
|
||||
category?: string;
|
||||
}
|
||||
export type InventoryEventType = 'InventoryItemCreated';
|
||||
|
||||
// ── Photos ──────────────────────────────────────────
|
||||
|
||||
export interface PhotoDeletedPayload {
|
||||
photoId: string;
|
||||
}
|
||||
export type PhotosEventType = 'PhotoDeleted';
|
||||
|
||||
// ── Plants ──────────────────────────────────────────
|
||||
|
||||
export interface PlantCreatedPayload {
|
||||
plantId: string;
|
||||
name: string;
|
||||
species?: string;
|
||||
}
|
||||
export interface PlantDeletedPayload {
|
||||
plantId: string;
|
||||
}
|
||||
export type PlantsEventType = 'PlantCreated' | 'PlantDeleted';
|
||||
|
||||
// ── News ────────────────────────────────────────────
|
||||
|
||||
export interface ArticleSavedPayload {
|
||||
articleId: string;
|
||||
title: string;
|
||||
}
|
||||
export type NewsEventType = 'ArticleSaved';
|
||||
|
||||
// ── Recipes ─────────────────────────────────────────
|
||||
|
||||
export interface RecipeCreatedPayload {
|
||||
recipeId: string;
|
||||
title: string;
|
||||
}
|
||||
export interface RecipeDeletedPayload {
|
||||
recipeId: string;
|
||||
}
|
||||
export type RecipesEventType = 'RecipeCreated' | 'RecipeDeleted';
|
||||
|
||||
// ── Questions ───────────────────────────────────────
|
||||
|
||||
export interface QuestionAskedPayload {
|
||||
questionId: string;
|
||||
question: string;
|
||||
}
|
||||
export type QuestionsEventType = 'QuestionAsked';
|
||||
|
||||
// ── Body ────────────────────────────────────────────
|
||||
|
||||
export interface WorkoutStartedPayload {
|
||||
|
|
@ -525,6 +606,15 @@ export type ManaEventType =
|
|||
| ChatEventType
|
||||
| MemoroEventType
|
||||
| SkilltreeEventType
|
||||
| CyclesEventType
|
||||
| FirstsEventType
|
||||
| GuidesEventType
|
||||
| InventoryEventType
|
||||
| PhotosEventType
|
||||
| PlantsEventType
|
||||
| NewsEventType
|
||||
| RecipesEventType
|
||||
| QuestionsEventType
|
||||
| SocialEventsEventType
|
||||
| BodyEventType
|
||||
| SystemEventType;
|
||||
|
|
@ -606,6 +696,26 @@ export type ManaEvent =
|
|||
// Skilltree
|
||||
| DomainEvent<'SkillXpAdded', SkillXpAddedPayload>
|
||||
| DomainEvent<'SkillCreated', SkillCreatedPayload>
|
||||
// Cycles
|
||||
| DomainEvent<'CycleDayLogged', CycleDayLoggedPayload>
|
||||
// Firsts
|
||||
| DomainEvent<'FirstCreated', FirstCreatedPayload>
|
||||
// Guides
|
||||
| DomainEvent<'GuideCreated', GuideCreatedPayload>
|
||||
// Inventory
|
||||
| DomainEvent<'InventoryItemCreated', InventoryItemCreatedPayload>
|
||||
// Photos
|
||||
| DomainEvent<'PhotoDeleted', PhotoDeletedPayload>
|
||||
// Plants
|
||||
| DomainEvent<'PlantCreated', PlantCreatedPayload>
|
||||
| DomainEvent<'PlantDeleted', PlantDeletedPayload>
|
||||
// News
|
||||
| DomainEvent<'ArticleSaved', ArticleSavedPayload>
|
||||
// Recipes
|
||||
| DomainEvent<'RecipeCreated', RecipeCreatedPayload>
|
||||
| DomainEvent<'RecipeDeleted', RecipeDeletedPayload>
|
||||
// Questions
|
||||
| DomainEvent<'QuestionAsked', QuestionAskedPayload>
|
||||
// Social Events
|
||||
| DomainEvent<'SocialEventCreated', SocialEventCreatedPayload>
|
||||
| DomainEvent<'SocialEventDeleted', SocialEventDeletedPayload>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ import { storageTools } from '$lib/modules/storage/tools';
|
|||
import { chatTools } from '$lib/modules/chat/tools';
|
||||
import { memoroTools } from '$lib/modules/memoro/tools';
|
||||
import { skilltreeTools } from '$lib/modules/skilltree/tools';
|
||||
import { cyclesTools } from '$lib/modules/cycles/tools';
|
||||
import { firstsTools } from '$lib/modules/firsts/tools';
|
||||
import { guidesTools } from '$lib/modules/guides/tools';
|
||||
import { inventoryTools } from '$lib/modules/inventory/tools';
|
||||
import { plantsTools } from '$lib/modules/plants/tools';
|
||||
import { newsTools } from '$lib/modules/news/tools';
|
||||
import { recipesTools } from '$lib/modules/recipes/tools';
|
||||
import { questionsTools } from '$lib/modules/questions/tools';
|
||||
|
||||
let initialized = false;
|
||||
|
||||
|
|
@ -49,5 +57,13 @@ export function initTools(): void {
|
|||
registerTools(chatTools);
|
||||
registerTools(memoroTools);
|
||||
registerTools(skilltreeTools);
|
||||
registerTools(cyclesTools);
|
||||
registerTools(firstsTools);
|
||||
registerTools(guidesTools);
|
||||
registerTools(inventoryTools);
|
||||
registerTools(plantsTools);
|
||||
registerTools(newsTools);
|
||||
registerTools(recipesTools);
|
||||
registerTools(questionsTools);
|
||||
initialized = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { cycleTable } from '../collections';
|
|||
import { toCycle } from '../queries';
|
||||
import { daysBetween } from '../utils/phase';
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { createBlock, updateBlock, deleteBlock } from '$lib/data/time-blocks/service';
|
||||
import type { LocalCycle } from '../types';
|
||||
|
||||
|
|
@ -68,6 +69,11 @@ export const cyclesStore = {
|
|||
const plaintextSnapshot = toCycle(newLocal);
|
||||
await encryptRecord('cycles', newLocal);
|
||||
await cycleTable.add(newLocal);
|
||||
emitDomainEvent('CycleDayLogged', 'cycles', 'cycleDayLogs', newLocal.id, {
|
||||
logId: newLocal.id,
|
||||
date: newLocal.startDate,
|
||||
flow: null,
|
||||
});
|
||||
return plaintextSnapshot;
|
||||
},
|
||||
|
||||
|
|
|
|||
22
apps/mana/apps/web/src/lib/modules/cycles/tools.ts
Normal file
22
apps/mana/apps/web/src/lib/modules/cycles/tools.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const cyclesTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'log_cycle_day',
|
||||
module: 'cycles',
|
||||
description: 'Loggt einen Zyklus-Tag (Menstruationszyklus)',
|
||||
parameters: [
|
||||
{
|
||||
name: 'flow',
|
||||
type: 'string',
|
||||
description: 'Staerke',
|
||||
required: false,
|
||||
enum: ['light', 'medium', 'heavy', 'spotting', 'none'],
|
||||
},
|
||||
],
|
||||
async execute(params) {
|
||||
const { cyclesStore } = await import('./stores/cycles.svelte');
|
||||
const entry = await cyclesStore.createCycle({});
|
||||
return { success: true, data: entry, message: 'Zyklus-Tag geloggt' };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { firstTable } from '../collections';
|
||||
import { toFirst } from '../queries';
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import type {
|
||||
First,
|
||||
FirstCategory,
|
||||
|
|
@ -49,6 +50,11 @@ export const firstsStore = {
|
|||
const plaintextSnapshot = toFirst(newLocal);
|
||||
await encryptRecord('firsts', newLocal);
|
||||
await firstTable.add(newLocal);
|
||||
emitDomainEvent('FirstCreated', 'firsts', 'firsts', newLocal.id, {
|
||||
firstId: newLocal.id,
|
||||
title: data.title ?? '',
|
||||
isLived: false,
|
||||
});
|
||||
return plaintextSnapshot;
|
||||
},
|
||||
|
||||
|
|
|
|||
14
apps/mana/apps/web/src/lib/modules/firsts/tools.ts
Normal file
14
apps/mana/apps/web/src/lib/modules/firsts/tools.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const firstsTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'create_first',
|
||||
module: 'firsts',
|
||||
description: 'Erstellt ein "Erstes Mal" (Bucket-List-Traum oder erlebtes Ersterlebnis)',
|
||||
parameters: [{ name: 'title', type: 'string', description: 'Was', required: true }],
|
||||
async execute(params) {
|
||||
const { firstsStore } = await import('./stores/firsts.svelte');
|
||||
const first = await firstsStore.createDream({ title: params.title as string });
|
||||
return { success: true, data: first, message: `Erstes Mal: "${params.title}"` };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
import { guideTable, sectionTable, stepTable, runTable } from '../collections';
|
||||
import { toGuide, toSection, toStep, toRun } from '../queries';
|
||||
import { encryptRecord, decryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { createBlock, updateBlock, deleteBlock } from '$lib/data/time-blocks/service';
|
||||
import type {
|
||||
LocalGuide,
|
||||
|
|
@ -48,6 +49,10 @@ export const guidesStore = {
|
|||
const snapshot = toGuide({ ...newLocal });
|
||||
await encryptRecord('guides', newLocal);
|
||||
await guideTable.add(newLocal);
|
||||
emitDomainEvent('GuideCreated', 'guides', 'guides', newLocal.id, {
|
||||
guideId: newLocal.id,
|
||||
title: dto.title ?? '',
|
||||
});
|
||||
return snapshot;
|
||||
},
|
||||
|
||||
|
|
|
|||
16
apps/mana/apps/web/src/lib/modules/guides/tools.ts
Normal file
16
apps/mana/apps/web/src/lib/modules/guides/tools.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const guidesTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'create_guide',
|
||||
module: 'guides',
|
||||
description: 'Erstellt eine neue Anleitung / Guide',
|
||||
parameters: [
|
||||
{ name: 'title', type: 'string', description: 'Titel der Anleitung', required: true },
|
||||
],
|
||||
async execute(params) {
|
||||
const { guidesStore } = await import('./stores/guides.svelte');
|
||||
const guide = await guidesStore.createGuide({ title: params.title as string });
|
||||
return { success: true, data: guide, message: `Guide "${params.title}" erstellt` };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -11,6 +11,7 @@ import type { LocalItem } from '../types';
|
|||
import type { ItemStatus } from '../queries';
|
||||
import { InventoryEvents } from '@mana/shared-utils/analytics';
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
|
||||
export const itemsStore = {
|
||||
async create(data: {
|
||||
|
|
@ -49,6 +50,11 @@ export const itemsStore = {
|
|||
const plaintextSnapshot = toItem(newLocal);
|
||||
await encryptRecord('invItems', newLocal);
|
||||
await invItemTable.add(newLocal);
|
||||
emitDomainEvent('InventoryItemCreated', 'inventory', 'inventoryItems', newLocal.id, {
|
||||
itemId: newLocal.id,
|
||||
name: data.name ?? '',
|
||||
category: data.categoryId,
|
||||
});
|
||||
InventoryEvents.itemCreated();
|
||||
return plaintextSnapshot;
|
||||
},
|
||||
|
|
|
|||
20
apps/mana/apps/web/src/lib/modules/inventory/tools.ts
Normal file
20
apps/mana/apps/web/src/lib/modules/inventory/tools.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const inventoryTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'create_inventory_item',
|
||||
module: 'inventory',
|
||||
description: 'Erfasst einen Gegenstand im Inventar',
|
||||
parameters: [
|
||||
{ name: 'name', type: 'string', description: 'Name', required: true },
|
||||
{ name: 'collectionId', type: 'string', description: 'Sammlungs-ID', required: true },
|
||||
],
|
||||
async execute(params) {
|
||||
const { itemsStore } = await import('./stores/items.svelte');
|
||||
const item = await itemsStore.create({
|
||||
name: params.name as string,
|
||||
collectionId: params.collectionId as string,
|
||||
});
|
||||
return { success: true, data: item, message: `"${params.name}" im Inventar erfasst` };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { articleTable } from '../collections';
|
||||
import { extractFromUrl } from '../api';
|
||||
import { toArticle } from '../queries';
|
||||
|
|
@ -50,6 +51,10 @@ export const articlesStore = {
|
|||
const snapshot = toArticle(newLocal);
|
||||
await encryptRecord('newsArticles', newLocal);
|
||||
await articleTable.add(newLocal);
|
||||
emitDomainEvent('ArticleSaved', 'news', 'newsArticles', newLocal.id, {
|
||||
articleId: newLocal.id,
|
||||
title: input.title ?? '',
|
||||
});
|
||||
return snapshot;
|
||||
},
|
||||
|
||||
|
|
|
|||
4
apps/mana/apps/web/src/lib/modules/news/tools.ts
Normal file
4
apps/mana/apps/web/src/lib/modules/news/tools.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
// News tools are limited — saveFromCurated requires a full LocalCachedArticle
|
||||
// which is complex for LLM tool calling. Read-only for now.
|
||||
export const newsTools: ModuleTool[] = [];
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { PhotosEvents } from '@mana/shared-utils/analytics';
|
||||
import { db } from '$lib/data/database';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import type { LocalFavorite, Photo, PhotoFilters, PhotoStats } from '../types';
|
||||
|
||||
const MEDIA_URL = () =>
|
||||
|
|
@ -181,6 +182,7 @@ export const photoStore = {
|
|||
|
||||
photos = photos.filter((p) => p.id !== mediaId);
|
||||
if (selectedPhoto?.id === mediaId) selectedPhoto = null;
|
||||
emitDomainEvent('PhotoDeleted', 'photos', 'photos', mediaId, { photoId: mediaId });
|
||||
PhotosEvents.photoDeleted();
|
||||
return true;
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { db } from '$lib/data/database';
|
|||
import { toPlant, toWateringSchedule } from './queries';
|
||||
import { PlantsEvents } from '@mana/shared-utils/analytics';
|
||||
import { encryptRecord, decryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { createBlock } from '$lib/data/time-blocks/service';
|
||||
import { uploadPlantPhoto, identifyPlant, type IdentifyResult } from './api';
|
||||
import type {
|
||||
|
|
@ -45,6 +46,11 @@ export const plantMutations = {
|
|||
const plaintextSnapshot = toPlant(newLocal);
|
||||
await encryptRecord('plants', newLocal);
|
||||
await db.table('plants').add(newLocal);
|
||||
emitDomainEvent('PlantCreated', 'plants', 'plants', newLocal.id, {
|
||||
plantId: newLocal.id,
|
||||
name: dto.name,
|
||||
species: dto.scientificName,
|
||||
});
|
||||
PlantsEvents.plantCreated();
|
||||
return plaintextSnapshot;
|
||||
},
|
||||
|
|
@ -77,6 +83,7 @@ export const plantMutations = {
|
|||
deletedAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
emitDomainEvent('PlantDeleted', 'plants', 'plants', id, { plantId: id });
|
||||
PlantsEvents.plantDeleted();
|
||||
},
|
||||
|
||||
|
|
|
|||
14
apps/mana/apps/web/src/lib/modules/plants/tools.ts
Normal file
14
apps/mana/apps/web/src/lib/modules/plants/tools.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const plantsTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'create_plant',
|
||||
module: 'plants',
|
||||
description: 'Erfasst eine neue Pflanze',
|
||||
parameters: [{ name: 'name', type: 'string', description: 'Name der Pflanze', required: true }],
|
||||
async execute(params) {
|
||||
const { plantMutations } = await import('./mutations');
|
||||
const plant = await plantMutations.create({ name: params.name as string });
|
||||
return { success: true, data: plant, message: `Pflanze "${params.name}" erstellt` };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
import { db } from '$lib/data/database';
|
||||
import { encryptRecord, decryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { researchApi, type ResearchEvent, type ResearchSource } from '$lib/api/research';
|
||||
import type { LocalAnswer, LocalQuestion } from '../types';
|
||||
|
||||
|
|
@ -47,6 +48,10 @@ async function createManual(input: CreateManualAnswerInput): Promise<string> {
|
|||
};
|
||||
await encryptRecord('answers', row);
|
||||
await db.table('answers').add(row);
|
||||
emitDomainEvent('QuestionAsked', 'questions', 'questions', id, {
|
||||
questionId: id,
|
||||
question: input.content ?? '',
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
|
|||
3
apps/mana/apps/web/src/lib/modules/questions/tools.ts
Normal file
3
apps/mana/apps/web/src/lib/modules/questions/tools.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
// Questions module requires a questionId for answers — no simple create tool yet.
|
||||
export const questionsTools: ModuleTool[] = [];
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { emitDomainEvent } from '$lib/data/events';
|
||||
import { recipeTable } from '../collections';
|
||||
import { toRecipe } from '../queries';
|
||||
import type { LocalRecipe, Difficulty, Ingredient } from '../types';
|
||||
|
|
@ -40,6 +41,10 @@ export const recipesStore = {
|
|||
const snapshot = toRecipe({ ...newLocal });
|
||||
await encryptRecord('recipes', newLocal);
|
||||
await recipeTable.add(newLocal);
|
||||
emitDomainEvent('RecipeCreated', 'recipes', 'recipes', newLocal.id, {
|
||||
recipeId: newLocal.id,
|
||||
title: input.title ?? '',
|
||||
});
|
||||
return snapshot;
|
||||
},
|
||||
|
||||
|
|
@ -76,6 +81,7 @@ export const recipesStore = {
|
|||
deletedAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
emitDomainEvent('RecipeDeleted', 'recipes', 'recipes', id, { recipeId: id });
|
||||
},
|
||||
|
||||
async toggleFavorite(id: string) {
|
||||
|
|
|
|||
20
apps/mana/apps/web/src/lib/modules/recipes/tools.ts
Normal file
20
apps/mana/apps/web/src/lib/modules/recipes/tools.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import type { ModuleTool } from '$lib/data/tools/types';
|
||||
export const recipesTools: ModuleTool[] = [
|
||||
{
|
||||
name: 'create_recipe',
|
||||
module: 'recipes',
|
||||
description: 'Erstellt ein neues Rezept',
|
||||
parameters: [
|
||||
{ name: 'title', type: 'string', description: 'Name des Rezepts', required: true },
|
||||
{ name: 'description', type: 'string', description: 'Beschreibung', required: false },
|
||||
],
|
||||
async execute(params) {
|
||||
const { recipesStore } = await import('./stores/recipes.svelte');
|
||||
const recipe = await recipesStore.createRecipe({
|
||||
title: params.title as string,
|
||||
description: params.description as string | undefined,
|
||||
});
|
||||
return { success: true, data: recipe, message: `Rezept "${params.title}" erstellt` };
|
||||
},
|
||||
},
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue