Adaugă produse noi sau importă un meniu întreg — complet și corect, tip de produs, TVA, unități, rețete, taguri de rutare, alergeni, categorii. Folosește la „adaugă produsul X la N lei", „pune Y în meniu", „fă o rețetă pentru Z", „importă meniul de pe site/PDF/Excel", „introdu produsele", „pune-le pe categorii", „taguri pentru imprimante/KDS". Pentru pagina de produs din magazinul online bogată (galerie, descriere lungă, specificații, garanție, FAQ, preț redus, accesorii, pachete) → vezi skill-ul `construieste-website` + `knowledge/website-builder-pdp.md`.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Adaugă produse noi sau importă un meniu întreg — complet și corect, tip de produs, TVA, unități, rețete, taguri de rutare, alergeni, categorii. Folosește la „adaugă produsul X la N lei", „pune Y în meniu", „fă o rețetă pentru Z", „importă meniul de pe site/PDF/Excel", „introdu produsele", „pune-le pe categorii", „taguri pentru imprimante/KDS". Pentru pagina de produs din magazinul online bogată (galerie, descriere lungă, specificații, garanție, FAQ, preț redus, accesorii, pachete) → vezi skill-ul `construieste-website` + `knowledge/website-builder-pdp.md`.
Adaugă produse / importă meniu / creează rețete — corect și complet
Citește întâi knowledge/agent-operare-avansata.md pentru execuție idempotentă, apoi knowledge/produse-meniu-retete.md (termenii: produs ≠ articol de meniu ≠ rețetă) și secțiunea „⚠ De știut la scrieri prin MCP" din knowledge/tools-mcp.md.
Două moduri de lucru:
(A) Un produs-două („adaugă cola la 12 lei") → sari direct la Fazele 1, 2, 4, 5 — scurt, fără ceremonie.
(B) Import în masă (meniu întreg, zeci-sute de produse) → toate fazele, în ordine.
Regula de bază peste tot: nu inventa NIMIC — nici prețuri, nici gramaje, nici alergeni. Ce lipsește se întreabă sau se lasă gol.
Faza 0 — Strânge datele (doar la import)
Întreabă userul de unde vin datele: website-ul restaurantului? PDF cu meniul? Excel/export din vechiul POS? poze? pagina de Glovo/Wolt? Cere-i fișierele direct în chat.
Website: ia conținutul URL-ului. Dacă HTML-ul vine gol → e un SPA (React/Angular/Vue); caută API-ul din spate — platformele de meniu au de regulă un endpoint JSON public (exemplu real: SmartMenu servește totul din Firebase Realtime DB, https://smart-menu-...firebasedatabase.app/restaurant-menus/{slug}.json → categorii → produse, cu name/price/description/weight/allergens/imageUrl per produs). Dacă nu găsești API-ul, cere userului un export sau screenshot-uri — nu ghici conținutul.
Per produs vrei: nume, preț, categorie/secție (bucătărie vs bar), descriere, gramaj, alergeni, poză (URL), slug-ul SEO din URL (ultimul segment, ex. site-exemplu.ro/limonada-de-casa → limonada-de-casa), codurile de scanner dacă există (sku, barcode, ean — critic la retail), și pentru băuturi: cum se vinde (sticlă întreagă vs porție turnată).
Slug-ul sursă: la magazine care se MUTĂ pe Symbai, trimite slug-ul vechi ca arg slug la add_menu_item/bulk_add_menu_items (și create_menu_category) ca să PĂSTREZI URL-urile indexate (continuitate SEO, fără 404). Dacă nu-l trimiți, platforma generează automat unul curat din nume. Detalii: knowledge/onboarding/02d-import-surse-externe.md → „Slug-ul SEO din URL-ul sursei".
Inventariază ce lipsește și pune userului UN singur set compact de întrebări, nu câte una pe rând.
Alternativă in-app (propune-o când userul are PDF/poze/Excel și preferă să nu treci tu prin MCP): paginile /menu/import-pdf (extrage produse + prețuri + poze + design) și /ai-bulk-import (Excel cu mapare AI) fac importul direct în aplicație.
Faza 1 — Descoperă stilul clientului (OBLIGATORIU înainte de orice scriere)
list_brands + list_locations + list_menus — brandul și meniul țintă. Dacă creezi meniu nou cu create_menu: se naște draft — activează-l cu update_menu(status: "active").
list_product_types(brandId) — tipurile de produs REALE ale clientului (poate avea tipuri custom; folosește-le pe ale lui).
Stilul de taguri: list_tag_summary + list_tags — vezi ce taguri există și câte produse are fiecare (ex. „BAR" și „BUCATARIE", fiecare cu zeci de produse). Tagurile existente au deja reguli de rutare către imprimante/KDS — refolosește-le întocmai (același nume, nu variante noi). Care taguri au deja reguli de rutare active vezi cu list_tag_routing_rules.
list_menu_categories(brandId) — structura categoriilor (e ierarhică).
Stilul de bar: search_products_db pe 2-3 băuturi cheie (ex. „vodka", „cola") + get_warehouse_products_summary pe gestiunea barului — vezi dacă clientul ține băuturile ca marfă la bucată sau ca materie primă la litru cu rețete de porționare (40 ml). Introdu produsele noi ÎN ACELAȘI stil.
Dedupe: search_products_db pe fiecare nume nou înainte de creare. create_product face dedupe doar pe nume EXACT — „Coca Cola" vs „Coca-Cola" creează dublură.
Faza 2 — Decide modelarea per produs
Arborele de decizie (confirmat de clasificatorul oficial Symbai):
Clientul vinde…
Tip
Unitate
Rețetă
Băutură îmbuteliată/doză, țigări, snacks, vândute ca atare
merchandise (marfă)
buc
NU — consum direct 1:1 din stoc
Shot/pahar turnat din sticlă (Vodka 40ml, vin la pahar)
produsul vândut: merchandise, buc, CU rețetă
—
0.04 l (sau 40 ml) din sticla-sursă
Sticla-sursă a porțiilor
raw_material (doar pt. porții/cocktailuri) sau merchandise (dacă se vinde și întreagă)
l (litri!)
NU; nu intră în meniu dacă nu se vinde întreagă
Cocktail, cafea, limonadă (≥2 ingrediente)
finished_good
buc/porție
DA
Preparat de bucătărie
finished_good
buc/porție
DA
Sos/semipreparat de casă refolosit în rețete
wip (semipreparat)
kg/l
DA
Ingredient cumpărat
raw_material
unitatea de achiziție (kg/l/buc)
NU
Meniu de eveniment la preț fix, fără rețetă cunoscută
masa_servita — NU e în enum-ul create_product; creează-l ca tip custom cu create_product_type(brandId, code, name, …conturi), apoi folosește code-ul tău la creare
—
NU (cost ulterior prin fișă de consum)
Semipreparatul se scade ca atare, nu pe ingrediente: la vânzarea unui preparat care are ca ingredient un semipreparat (wip), din stoc scade semipreparatul, un singur nivel în jos — nu ingredientele lui. Deci semipreparatul trebuie produs (din modulul Producție) ca să existe pe stoc; altfel intră pe minus la fiecare vânzare. Costul, în schimb, se calculează pe toate nivelurile, deci un semipreparat neprodus arată cost corect și stoc negativ în același timp.
Capcana unității la spirtoase: sticla TREBUIE ținută la l (litri). Dacă e în „buc", rețeta „40 ml" e neconvertibilă → consumă 0.04 BUCĂȚI per shot, fără niciun avertisment prin MCP (greșeala clasică: food cost de sute de ori mai mare și stocuri negative absurde). Conversia e automată DOAR în aceeași familie: g↔kg, ml↔cl↔dl↔l.
TVA România: 0 / 11 / 21. Mâncare preparată și băuturi nealcoolice de regulă 11; alcoolul mereu 21; setează vat explicit la creare. La import HoReCa fără TVA, serverul are fallback determinist (alimente/apă 11, alcool/băuturi zaharoase/cafea/non-food/incert 21), dar explicitul câștigă.
Marfa fără rețetă e normală (nu e o problemă de date); un finished_good fără rețetă E o problemă — nu scade stoc și rămâne necostat în P&L.
Faza 3 — Propune și cere aprobarea (doar la import)
Construiește tabelul complet ÎNAINTE de orice scriere și arată-l userului: nume | tip | UM | TVA | categorie | preț | tag rutare | rețetă (da/nu) | gramaj | descriere | poză. Confirmă numărul de produse. Abia după aprobare scrii.
Faza 4 — Execută în ordinea corectă
Categoriile de meniu întâi (la import): pentru multe categorii folosește bulk_create_menu_categories({ brandId, items }); părinții trebuie să fie înaintea copiilor când folosești parentName. Punctual, create_menu_category per secție (Gustări, Cocktailuri, Vin Alb…), ierarhic cu parentId. Tool-urile sunt idempotente și atașează categoriile la meniurile brandului.
Materiile prime apoi (bulk_create_products cu type + unit + vat + warehouseId + description + weight + sku/barcode/ean dacă sursa le are), apoi produsele vândute. Pentru retail, codurile de bare/EAN se pun la creare/import; altfel scannerul POS/inventar nu are ce potrivi. Dacă ai doar costuri estimate înainte de prima recepție, setează standardCost / set_standard_costs; nu inventa stoc sau NIR.
⚠ Dedupe silențios cu success:true: create_product / create_menu / create_menu_category / create_tag / create_allergen întorc entitatea EXISTENTĂ dacă numele/perechea există — parametrii tăi NU se aplică pe ea. Citește răspunsul, nu doar status-ul.
Rețete (modul retete): create_recipe cu productId EXPLICIT mereu (fără el → match PARȚIAL pe nume sau auto-creează un produs nou greșit). add_recipe_ingredients cu productId, nu productName (typo la nume → auto-creează un raw_material dublură).
⚠ Poarta de unități — verificare OBLIGATORIE înainte de add_recipe_ingredients: pentru fiecare ingredient citește cu get_product_details unitatea în care e ținut produsul și scrie în rețetă o cantitate din aceeași familie (masă cu masă, volum cu volum, bucăți cu bucăți). Traducerea automată merge doar în familie: g↔kg, ml↔cl↔dl↔l. Între familii diferite nu se poate traduce și cantitatea se ia ca atare: „25 g" pe un produs ținut la bucată se consumă ca 25 de bucăți. Prin conexiune nu primești niciun avertisment (în aplicație, la salvarea rețetei, apare unul) — greșeala se vede abia în food cost și în stocuri negative absurde. Control pe rețete existente: scan_recipe_unit_mismatches (citire) listează perechile imposibile, separate în „reparabile automat" și „de rezolvat manual"; fix_recipe_unit_mismatches (🔒, modul ) le corectează pe cele sigure. ⚠ Corecția schimbă — consumul deja înregistrat se îndreaptă abia după o recalculare (vezi skill-ul și ). Echivalentul din aplicație: Setări → Reparații → „Corectează unități neconvertibile".
Faza 5 — Verifică prin CITIRE (niciodată prin UI)
list_menu_items(menuId) — numărul și prețurile vs sursă. Pentru meniuri mari folosește export_menu(menuId, "markdown"|"csv") ca tabel complet sau paginează list_menu_items cu categoryId/limit/offset; răspunsul compact automat nu conține toate detaliile (descriere, gramaj, poze).
list_untagged_products — niciun produs nou fără tag de rutare.
analyze_food_costs sau generate_report(food_cost) — un cost absurd (150%+) = aproape sigur unitate greșită în rețetă.
list_recipes + get_recipe_details pe 2-3 rețete noi — confirmă trei lucruri, nu unul: (a) productId e exact produsul creat; (b) randamentul e gol sau 1 dacă rețeta e scrisă pentru o porție — orice cifră mai mare acolo împarte tot consumul și e greșeala cel mai greu de observat mai târziu; (c) unitatea fiecărui ingredient e din aceeași familie cu unitatea produsului-ingredient. Pentru un control pe tot brandul, nu doar pe eșantion, rulează scan_recipe_unit_mismatches. În fabrică, folosește includeUnlinked:true când investighezi rețete orfane; dacă o rețetă apare pe alt produs duplicat cu același nume, nu o recrea și nu o muta implicit — verifică ambele ID-uri și repară explicit legătura.
UI-ul se actualizează abia după refresh — succes la tool = salvat; nu repeta scrierea.
Faza 6 — Ce rămâne din aplicație (puțin)
Aproape tot importul se face acum prin conexiune (categorii, descriere, gramaj, poze, alergeni). Rămâne pentru user doar:
Regulile de rutare pentru taguri NOI — dacă ai introdus o secție pentru care clientul nu avea deja un tag cu regulă, regula tag→imprimantă/KDS se creează din Setări → Imprimante. Spune-i clar ce tag și unde trebuie să iasă.
Poze care nu se pot recunoaște după nume — un folder cu poze denumite IMG_0042, DSC_1177, fără nicio legătură cu preparatul. Potrivirea pe nume nu are de unde să știe ce e în ele, iar tu nu ghicești. Două ieșiri: userul redenumește fișierele după preparat (atunci le urci singur, vezi Faza 4 pasul 6), sau le potrivește vizual din pagina Poze Bulk Meniu (/menu/pricing/bulk-photos), unde AI-ul se uită în poză, nu la nume. Un folder cu nume normale („ciorba de vacuta.jpg") NU intră aici — pe acela îl faci prin conexiune.
Dacă tot dai de un perete (ceva ce userul poate face în aplicație dar tu nu poți prin conexiune) — raportează cu trimite_ticket_symbai (tip „sugestie", cu dedupeKey); echipa Symbai prioritizează pe baza ticketelor.
Reguli de aur
Prețul de vânzare = meniu. Costul = rețetă + recepții (NIR). P&L = tipul de produs. Rutarea bonurilor = taguri. Nu le amesteca.
receptionPrice la marfă = preț de raft (se completează automat din primul preț de meniu), NU cost — nu-l „repara" pentru food cost.
Caută înainte de a crea; citește după ce scrii; nu repeta o scriere „ca să se prindă".
ID-uri, nu nume, peste tot unde ai ambele opțiuni.
Dacă tokenul nu are modulul de scriere necesar („Permisiune insuficientă"), explică activarea din portal Hub → Acces AI.
inventar
doar definiția rețetei
verifica-consumul
knowledge/consum-zilnic-cost-marfa.md
⚠ Randamentul (yield) este un DIVIZOR real, nu o etichetă descriptivă: tot ce scrii în rețetă se împarte la el la fiecare vânzare. Lasă-l gol sau pe 1 când rețeta e scrisă pentru o porție (cazul obișnuit la restaurant). Pune un număr mai mare doar dacă ai scris cantitățile pentru mai multe porții deodată (o oală de 50 de porții → 50). Contează doar cifra, nu unitatea de lângă ea: „5 kg" pe un produs vândut la bucată se citește „împarte la 5" și scade de cinci ori mai puțin din fiecare ingredient — stocul pare că nu se mișcă, iar food cost-ul iese suspect de mic. Zecimalele se scriu cu punct: „2,5" se citește ca 2. Singura cale de a-l schimba prin conexiune este update_recipe.
În meniu, complet dintr-un apel: add_menu_item(menuId, productId, price, name, menuCategoryId, description, gramaj, sortOrder) — pune prețul, categoria, descrierea și gramajul deodată. E UPSERT (dacă produsul e deja în meniu, câmpurile se aplică pe item-ul existent); numele afișat ia implicit numele produsului. Categoria se oglindește automat și pe produs. Prețul de vânzare se setează DOAR aici.
Imagini: set_product_image(productId, imageUrl) cu URL-ul public al pozei (de pe meniul/site-ul vechi) — se descarcă, se optimizează și se propagă la articolele de meniu. gallery: true pentru poze suplimentare (galeria de pe pagina de produs din magazin: bulk_set_product_images pune mai multe deodată, prima = coperta). Ai un URL de poză dar nu ești sigur ce produs e? interpret_menu_photo(imageUrl) întoarce cele mai probabile articole de meniu cu scor de încredere (opțional restrânge cu candidates) — verifici potrivirea ÎNAINTE de set_product_image.
Un FOLDER de poze pe calculatorul userului („am pozele la toate preparatele") — o faci singur, prin conexiune, fără să-l trimiți în aplicație. Rețeta cu trei pași și capcanele ei: knowledge/poze-produse-in-masa.md. Pe scurt: listezi fișierele → match_product_photos_by_filename(fileNames) îți arată ce produs ia fiecare poză și cât de sigură e potrivirea (previzualizare, nu scrie nimic) → upload_product_photos(photos) le urcă (fiecare poză = fileName + conținutul citit de pe disc, codat base64). Potrivirea ignoră diacriticele, prefixele de aparat foto și contoarele, iar ce nu e sigur NU se scrie: îți vine înapoi de confirmat cu userul. La final, list_products_without_photo îți spune ce a rămas descoperit.
Magazin online — pagină de produs bogată: dacă produsele ajung pe site, pune și galerie + descriere lungă + specificații + preț redus + garanție + FAQ + accesorii/pachet pe add_menu_item/update_menu_item (descriptionHtml, specs, compareAtPrice, warrantyMonths, faq, badges, installmentMonths, videoUrl, safetyCert, displaySku) + set_product_recommendations + set_product_bundle. Rețeta completă cu bife: knowledge/website-builder-pdp.md.
6b. Combo-uri și pachete — alege corect, sunt trei lucruri diferite:
Clientul ALEGE ceva la comandă (ex. „Șaorma + sucul la alegere", „Meniu Cryspi + sos") → NU e pachet, e grup de modificatori OBLIGATORIU: set_product_option_groups(productId, groups) cu isRequired:true, minSelect:1. Leagă fiecare opțiune de produsul real (linkedProductId) ca să scadă și stocul, și ca TVA-ul să iasă corect pe bon. Verifică apoi cu get_product_option_groups. ⚠ Fără linkedProductId opțiunea e doar text pentru bucătărie: nu scade stoc.
Conținut FIX, vândut ca un singur produs (ex. „Coș cadou: 2 vinuri + 1 ciocolată") → pachet: produsul trebuie să aibă tipul „Ambalaje/pachet" (change_product_type dacă nu îl are), apoi set_product_package(productId, items) (🔒 înlocuiește tot conținutul; verifică cu get_product_package).
Sugestie pe pagina de produs din magazinul online („Cumpărate frecvent împreună") → set_product_bundle. Nu are efect la POS.
Tabel de decizie + capcane: knowledge/modificatori-optiuni-produs.md.
Taguri pentru rutare: întâi search_products_for_tagging (dry-run, confirmă numărul), apoi bulk_assign_tag cu entityIds sau filtre (categoryName face match pe subtree + fără diacritice). Tag NOU = bonuri pierdute: un tag creat de tine NU rutează nicăieri până nu există regula în aplicație — produsele lui generează bonuri „unrouted" care nu se printează și nu apar pe niciun ecran, FĂRĂ eroare. Dacă chiar e nevoie de tag nou: create_tag + spune-i userului EXPLICIT să creeze regula în Setări → Imprimante (rutare taguri) și verifică apoi. Pentru lucrul amănunțit cu etichete (rutare/marketing/audit) → skill-ul gestioneaza-etichete + knowledge/etichete-taguri.md.
Alergeni: set_product_allergens(productId, allergenIds) — ⚠ ÎNLOCUIEȘTE tot setul, citește întâi ce are produsul. Dacă lista de alergeni e goală, cere userului să ruleze seed-ul UE din pagina Alergeni. Produsele cu rețetă moștenesc automat alergenii ingredientelor — setează manual doar ce nu vine din rețetă.
TVA la final: dacă au rămas găuri, auto_assign_vat_batch (cu onlyMissing) + verificare prin citire.
Stoc inițial doar dacă userul îl cere: set_initial_stock (creează document de ajustare + mișcări reale).
Anti-capcane: NU folosi auto_create_menu_from_products pe un cont viu, cu date reale (bagă TOATE produsele nemeniuite cu preț 0 într-un meniu activ); la bulk_update_menu_item_prices dă MEREU brandId (altfel face match pe nume în tot sistemul); NU schimba warehouseId pe produse cu stoc „din curățenie" (declanșează transfer contabil automat); standardCost nu mișcă stoc și nu înlocuiește NIR-ul.