# Swirl Master β€” Ninja Swirl Receptencompanion v1.0 > 🍦 Jouw persoonlijke receptencompanion voor de Ninja Swirl by CREAMi. > Ontdek recepten, mix & match smaken, en leer je machine kennen. ![Status](https://img.shields.io/badge/status-production-green) ![Version](https://img.shields.io/badge/version-1.0-purple) ![License](https://img.shields.io/badge/license-MIT-blue) --- ## πŸš€ Quick Start ```bash # 1. Dependencies installeren cd /root/projects/jg/2026-ninja-swirl-recipes/deliverables pip3 install -r requirements.txt # 2. Database seeden python3 generate_seed.py # 3. Server starten (development) python3 api_server.py # 4. Open in browser # http://localhost:5060 ``` Voor productie: zie [Productie Deployment](#-productie-deployment) hieronder. --- ## πŸ“‹ Inhoudsopgave 1. [Over Swirl Master](#-over-swirl-master) 2. [Features](#-features) 3. [Architectuur](#-architectuur) 4. [Bestandenlijst](#-bestandenlijst) 5. [Installatie (Productie)](#-productie-deployment) 6. [API Documentatie](#-api-documentatie) 7. [Recepten Toevoegen](#-recepten-toevoegen) 8. [Testing](#-testing) 9. [Rollback Procedure](#-rollback-procedure) 10. [Bekende Issues & Edge Cases](#-bekende-issues--edge-cases) 11. [Toekomstige Features](#-toekomstige-features) --- ## 🍦 Over Swirl Master Swirl Master is een innovatieve webapp speciaal gebouwd voor eigenaren van de Ninja Swirl by CREAMi ijsmachine (model NC701). De app biedt: - **30+ recepten** verdeeld over alle 13 programma's - **Mix & Match generator** voor oneindige smaakcombinaties - **Machine gids** met complete handleiding per type iJs - **Quiz** die je helpt het perfecte ijstype te vinden - **Favorieten** opslag (localStorage + API) - **Dark mode** voor 's avonds iJs maken GeΓ―nspireerd door het [GreenThumb](https://mescalinerabbit.shop/greenthumb/) design. --- ## ✨ Features ### 🏠 Dashboard - Live statistieken (aantal recepten, programma's, favorieten) - Uitgelichte populaire recepten - Snelle type-selector - IJs-tip van de dag (roteert) - "Welk type past bij jou?" quiz ### πŸ“– Receptenbank - 30+ recepten over 11+ types - Filters: type, dieet (vegan, keto, glutenvrij, etc.), moeilijkheid - Sortering: populariteit, moeilijkheid, snelheid, beoordeling, naam - Real-time zoekfunctie (naam, ingrediΓ«nt, tag) - Uitgebreide receptdetail met: - IngrediΓ«ntenlijst - Stap-voor-stap bereiding - Mix-in suggesties - Voedingsinformatie - Pro tips ### 🎲 Mix & Match Generator - 4-kolom selector: Basis β†’ Smaak β†’ Mix-in β†’ Topping - Compatibility scoring algoritme (op basis van smaakpaar-theorie) - Automatische programma-aanbeveling - "Verras me!" random generator - Recept opslaan als favoriet ### πŸ“š Machine Gids - Overzicht van alle 13 programma's - Stap-voor-stap uitleg hoe de machine werkt - Voorbereiding & pint management - Onderhoud & schoonmaak - Probleemoplossing (7 veelvoorkomende issues) - 10 Pro Tips van iJsmeesters ### ⭐ Favorieten - Lokaal opgeslagen (geen account nodig) - Snelle toegang tot opgeslagen recepten - Werk ook offline (frontend-only) --- ## πŸ— Architectuur ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Browser (Client) β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ β”‚ index. β”‚ β”‚ style. β”‚ β”‚ app.js β”‚β”‚ β”‚ β”‚ html β”‚ β”‚ css β”‚ β”‚ β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ RECIPES[] β”‚β”‚ β”‚ β”‚ 5 tabs: β”‚ β”‚ Purple/ β”‚ β”‚ β€’ PROGRAMS{} β”‚β”‚ β”‚ β”‚ Dashboardβ”‚ β”‚ Pink/ β”‚ β”‚ β€’ MixMatch engineβ”‚β”‚ β”‚ β”‚ Recipes β”‚ β”‚ Mint β”‚ β”‚ β€’ Quiz logic β”‚β”‚ β”‚ β”‚ MixMatch β”‚ β”‚ theme β”‚ β”‚ β€’ Favorites mgr β”‚β”‚ β”‚ β”‚ Guide β”‚ β”‚ β”‚ β”‚ β€’ Guide content β”‚β”‚ β”‚ β”‚ Favoritesβ”‚ β”‚ Dark modeβ”‚ β”‚ β”‚β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β”‚ β”‚ β”‚ localStorage (favorites) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ HTTP (optional) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Nginx (Reverse Proxy) β”‚ β”‚ Port 80/443 β”‚ β”‚ Static files + API proxy β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Flask API Server (PM2) β”‚ β”‚ Port 5060 β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ β”‚ /api/recipesβ”‚ β”‚/api/ β”‚ β”‚ /api/ β”‚β”‚ β”‚ β”‚ β”‚ β”‚programs β”‚ β”‚favorites β”‚β”‚ β”‚ β”‚ GET (filter)β”‚ β”‚GET β”‚ β”‚GET/POST/DELETEβ”‚ β”‚ β”‚ β”‚ POST (add) β”‚ β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ β”‚/api/mixmatchβ”‚ β”‚/api/statsβ”‚ β”‚ /api/health β”‚β”‚ β”‚ β”‚ /suggest β”‚ β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ SQLite DB β”‚ β”‚ β”‚ β”‚ swirl_master β”‚ β”‚ β”‚ β”‚ .db β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ recipes β”‚ β”‚ β”‚ β”‚ β€’ favorites β”‚ β”‚ β”‚ β”‚ β€’ ratings β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Dataflow 1. **Pagina laad**: `app.js` heeft alle recepten ingebouwd β†’ direct renderen (geen API call nodig voor frontend-only modus) 2. **API optioneel**: Als de Flask backend draait, kan de frontend API gebruiken voor community features 3. **Favorites**: Standaard in `localStorage` (browser); optioneel gesynchroniseerd via API met SQLite 4. **Mix & Match**: Volledig client-side; geen API nodig 5. **Recept zoeken**: Client-side filtering; API endpoint beschikbaar voor externe integratie --- ## πŸ“ Bestandenlijst ``` 2026-ninja-swirl-recipes/ β”œβ”€β”€ deliverables/ # Alle productiebestanden β”‚ β”œβ”€β”€ index.html # Hoofd HTML (11.8 KB) β”‚ β”œβ”€β”€ style.css # Volledige stylesheet (26.8 KB) β”‚ β”œβ”€β”€ app.js # Applicatie + database (84.7 KB) β”‚ β”œβ”€β”€ api_server.py # Flask REST API (22.9 KB) β”‚ β”œβ”€β”€ generate_seed.py # Database seed generator (5.5 KB) β”‚ β”œβ”€β”€ seed_recipes.json # Seed data (gegenereerd) β”‚ β”œβ”€β”€ swirl_master.db # SQLite database (gegenereerd) β”‚ β”œβ”€β”€ requirements.txt # Python dependencies β”‚ β”œβ”€β”€ ecosystem.config.js # PM2 configuratie β”‚ β”œβ”€β”€ nginx-swirl.conf # Nginx reverse proxy config β”‚ β”œβ”€β”€ .env.example # Environment template β”‚ β”œβ”€β”€ test_smoke.py # Automatische smoke tests (9.8 KB) β”‚ └── README.md # Dit bestand β”œβ”€β”€ archive/ # Oude versies β”œβ”€β”€ logs/ # PM2 logs β”œβ”€β”€ research/ # Onderzoek & referenties └── working/ # Werkbestanden ``` --- ## πŸ”§ Productie Deployment ### Stap 1: Dependencies ```bash # Python packages cd /root/projects/jg/2026-ninja-swirl-recipes/deliverables pip3 install -r requirements.txt # PM2 (als nog niet geΓ―nstalleerd) npm install -g pm2 ``` ### Stap 2: Database Initialiseren ```bash # Genereer seed data python3 generate_seed.py # Test database init (gebruikt api_server.py's init_db()) python3 -c "from api_server import init_db; init_db(); print('βœ… Database OK')" ``` ### Stap 3: PM2 Starten ```bash cd /root/projects/jg/2026-ninja-swirl-recipes/deliverables pm2 start ecosystem.config.js pm2 save # Check status pm2 status swirl-master pm2 logs swirl-master --lines 20 ``` ### Stap 4: Nginx Configureren ```bash # Rate limit zone toevoegen aan nginx.conf (in http {} block) # Voeg toe: limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; # Site configureren sudo cp nginx-swirl.conf /etc/nginx/sites-available/swirl sudo ln -sf /etc/nginx/sites-available/swirl /etc/nginx/sites-enabled/swirl # Of voor een subpath (mescalinerabbit.shop/swirl/): # Pas de location blocks aan naar /swirl/ { # alias /root/projects/jg/2026-ninja-swirl-recipes/deliverables/; # } # Testen sudo nginx -t # Reload sudo systemctl reload nginx ``` ### Stap 5: SSL (als nodig) ```bash # Certbot (als nog niet gedaan voor dit domein) sudo certbot --nginx -d swirl.mescalinerabbit.shop ``` ### Stap 6: Environment Variables ```bash # Voor productie, kopieer .env en vul in cp .env.example .env # Bewerk .env met je instellingen # Voor PM2, kunnen env vars in ecosystem.config.js gezet worden ``` ### Stap 7: Verify ```bash # Smoke tests python3 test_smoke.py --host http://localhost:5060 # Manual check curl http://localhost:5060/api/health | jq . curl http://localhost:5060/api/recipes | jq '.count' curl http://localhost:5060/api/programs | jq '.count' # Browser check # Open https://swirl.mescalinerabbit.shop (of http://localhost:5060) ``` --- ## πŸ”Œ API Documentatie ### Health | Endpoint | Method | Beschrijving | |----------|--------|-------------| | `/api/health` | GET | Health check + database status | ### Recipes | Endpoint | Method | Parameters | Beschrijving | |----------|--------|-----------|-------------| | `/api/recipes` | GET | `type`, `diet`, `q`, `sort`, `limit` | Recepten ophalen met filters | | `/api/recipes/` | GET | β€” | EΓ©n recept ophalen | | `/api/recipes` | POST | JSON body | Nieuw recept toevoegen | ### Programs | Endpoint | Method | Beschrijving | |----------|--------|-------------| | `/api/programs` | GET | Alle 13 programma's | | `/api/programs/` | GET | EΓ©n programma | ### Favorites | Endpoint | Method | Headers | Beschrijving | |----------|--------|---------|-------------| | `/api/favorites` | GET | `X-Session-ID` | Favorieten ophalen | | `/api/favorites/` | POST | `X-Session-ID` | Toevoegen | | `/api/favorites/` | DELETE | `X-Session-ID` | Verwijderen | ### Mix & Match | Endpoint | Method | Body | Beschrijving | |----------|--------|------|-------------| | `/api/mixmatch/suggest` | POST | `{"base":"...","flavor":"...","mixin":"...","topping":"..."}` | Genereer recept | ### Stats | Endpoint | Method | Beschrijving | |----------|--------|-------------| | `/api/stats` | GET | App statistieken | ### Voorbeelden ```bash # Alle vegan recepten curl "http://localhost:5060/api/recipes?diet=vegan" # Favoriet toevoegen curl -X POST http://localhost:5060/api/favorites/ic-vanilla \ -H "X-Session-ID: user-123" # Mix & Match curl -X POST http://localhost:5060/api/mixmatch/suggest \ -H "Content-Type: application/json" \ -d '{"base":"coconut-milk","flavor":"mango","mixin":"chili"}' ``` --- ## πŸ§ͺ Testing ### Smoke Tests (Automatisch) ```bash cd /root/projects/jg/2026-ninja-swirl-recipes/deliverables python3 test_smoke.py ``` De smoke test controleert: - βœ… Health endpoint - βœ… Statische bestanden (HTML, CSS, JS) - βœ… Recepten API (filteren, zoeken, sorteren) - βœ… Programma's API - βœ… Favorieten API (CRUD) - βœ… Mix & Match API - βœ… Stats API - βœ… Edge cases (404, invalid input, lege queries) ### Post-Deployment Checklist - [ ] PM2 proces draait: `pm2 status swirl-master` - [ ] Health check OK: `curl localhost:5060/api/health` - [ ] Index laadt: `curl localhost:5060/` - [ ] CSS laadt: `curl localhost:5060/style.css` - [ ] JS laadt: `curl localhost:5060/app.js` - [ ] Recepten API: `curl localhost:5060/api/recipes | jq .count` - [ ] Nginx proxy: `curl https://swirl.mescalinerabbit.shop/api/health` - [ ] Smoke tests pass: `python3 test_smoke.py` - [ ] Browser test: Open URL, check alle 5 tabs - [ ] Dark mode toggle werkt - [ ] Favorieten opslaan werkt (refresh pagina) - [ ] Mix & Match genereert recept --- ## πŸ”„ Rollback Procedure Als de deployment faalt: ### Snelle Rollback (PM2) ```bash # Stop nieuwe versie pm2 stop swirl-master # Roll back naar vorige versie (als backup aanwezig) cp -r /root/projects/jg/2026-ninja-swirl-recipes/archive/v0.9/* \ /root/projects/jg/2026-ninja-swirl-recipes/deliverables/ # Herstart pm2 restart swirl-master # Verify curl localhost:5060/api/health ``` ### Database Rollback ```bash # Backup vooraf maken! cp swirl_master.db swirl_master.db.bak # Rollback cp swirl_master.db.bak swirl_master.db pm2 restart swirl-master ``` ### Nginx Rollback ```bash # Verwijder broken config sudo rm /etc/nginx/sites-enabled/swirl sudo nginx -t && sudo systemctl reload nginx ``` --- ## ⚠️ Bekende Issues & Edge Cases 1. **Offline modus**: De frontend werkt volledig zonder backend. Favorites worden in localStorage opgeslagen. De API is optioneel voor geavanceerde features. 2. **iOS Safari**: De `100vh` bug kan zorgen voor layout issues op oudere iPhones. Opgelost met `min-height: 100vh` in plaats van `height`. 3. **Koude vriezer**: Bij vriezer temperaturen onder -25Β°C kan het iJs te hard worden voor de Creamifier. De app vermeldt RE-SPIN als oplossing. 4. **Geen echte afbeeldingen**: De recepten gebruiken emoji's in plaats van foto's voor snelheid en onderhoudbaarheid. 5. **Voorraadbeheer**: Nog geen integratie met boodschappenlijstje (gepland voor v1.1). 6. **Gedeeld favorieten**: Per apparaat/browser opgeslagen. Account-systeem gepland voor v2.0. --- ## πŸš€ Toekomstige Features (Roadmap) ### v1.1 - [ ] Boodschappenlijstje genereren uit recepten - [ ] Recept foto upload (via API) - [ ] Seizoensfilters (zomer/winter recepten) - [ ] Recept delen via link ### v1.2 - [ ] Community recepten (met moderatie) - [ ] Beoordelingen & reviews - [ ] Recept vertaling (NL/EN) - [ ] PWA / Service Worker (offline modus) ### v2.0 - [ ] Gebruikersaccounts - [ ] Cloud synchronisatie favorieten - [ ] Voeding tracker integratie - [ ] Maandelijkse iJs-challenge --- ## πŸ“œ License MIT β€” Vrij te gebruiken en aan te passen. Gebouwd door Jorick van Gemert voor de Ninja Swirl by CREAMi community. Niet geaffilieerd met SharkNinja. Alle merknamen zijn eigendom van hun respectievelijke eigenaren. --- *🍦 Swirl Master v1.0 β€” Because every day is ice cream day.*