14 / WORK / CASE STUDY
Four Times for Cook — AI Recipe & Health Platform
Built for the 2024 National Science and Technology Museum × MOE “AI Health Application” program — BERT-tagged recipe recommendation, health tracking and food-surplus ordering; recently hardened and rebuilt with AI assistance, open-sourced as a portfolio piece.
- TYPE
- AI TOOLING
- SCOPE
- AI health program · self-built → AI-assisted rebuild
- STACK
- DJANGO · DRF · BERT · PYTORCH · REACT · VITE · TAILWIND
- LINKS
- LIVE
01 / PROBLEM
Four Times for Cook was my 2024 project for the National Science and Technology Museum × Ministry of Education “AI Health Application” program: a platform folding personalized recipe recommendation, daily health tracking (calories / water / exercise), a nutrition knowledge base and food-surplus ordering into one “eat well, waste less” product. The recommendation engine centers on a BERT named-entity model that parses a user’s natural-language request into 12 entity classes — ingredient, nutrition, chronic disease, allergen and more — then runs a knowledge query over the recipe database. Two years on, the goal was to turn that student project into a public, security-clean portfolio piece.
02 / CONSTRAINTS
- Three public repos — a Django REST backend, a React frontend and a PyTorch BERT model. Attribution kept honest: the original project (2024) is my own work from the program; the recent security audit and full rebuild were done with AI (Claude) assistance, every fix tied to a verifiable commit, no numbers inflated.
- The showcase environment has no MySQL, no GPU and no original training data, yet the demo still has to run in full.
- After a full frontend rewrite, it still had to line up exactly with the existing Django API contract.
03 / ARCHITECTURE
A single audit across the three repos ran as parallel agents, producing 175 adversarially-verified findings (4 critical), remediated in a P0-security → P1-correctness → P2-architecture order and landed as 54 atomic commits with 26 regression tests (13 backend, 8 frontend, 5 model) all green.
The backend is Django 5 + DRF + SimpleJWT across four domain apps (member, recipe, record, health); the BERT model is a bert-base-cased token classifier with 12 BIO labels whose state_dict feeds backend inference. The frontend was fully rewritten from the unmaintained Create React App to Vite + TypeScript + Tailwind + shadcn — a green “food-as-medicine” design system, 11 pages, in-memory tokens and a centralized API service layer.
04 / RESPONSIBILITIES
Independently built the original three pieces (backend API, frontend, BERT model) during the 2024 program. The 2026 security audit, backend hardening, frontend rebuild and model fixes were done with AI (Claude) assistance across the three repos, with verifiable commit history and test results.
05 / CHALLENGES → SOLUTIONS
CHALLENGE
The backend had two directly exploitable flaws: any logged-in user could read, edit or delete every member through a ModelViewset (IDOR), and password reset changed any account’s password given only an email and birthdate.
SOLUTION
Member endpoints were narrowed to owner-only self-service with the auto CRUD removed; password reset became a signed single-use-token flow with throttling and no account-existence leak; the global permission default — which had listed both IsAuthenticated and AllowAny, i.e. fully open — was collapsed to a single IsAuthenticated. Every fix was captured as a regression test (13, all green).
CHALLENGE
Recipes are the platform’s core feature, yet every response 500’d — the serializer called .get() on an attributes table that was never populated, so it always raised DoesNotExist.
SOLUTION
Changed .get() to .filter().first() returning empty attributes when absent, and fixed a chain of always-crashing endpoints alongside it — weekly records, profile update, health-target computation — so the core flows actually return data.
CHALLENGE
The BERT trainer’s argmax reduced the sequence axis instead of the label axis, crashing training outright; accuracy was divided by a length that is always 2, and the test set doubled as the validation set (leakage) — it looked like it was training while the numbers meant nothing.
SOLUTION
Fixed the argmax axis, split disjoint train/val/test sets, computed accuracy over valid tokens, switched to AdamW with a scheduler, added seqeval entity-level F1 and a fixed seed, and unified the state_dict save/load contract. A tiny sample fixture lets python train.py actually complete one epoch on CPU and save a reloadable model.
CHALLENGE
The frontend’s API base was hard-coded to a long-dead ngrok tunnel, so anyone cloning it saw nothing but errors — and the portfolio still had to demo in full on GitHub Pages with no backend at all.
SOLUTION
The rewrite bakes in a Demo/API toggle: Demo mode intercepts every API call with MSW and returns a full set of Traditional-Chinese seed data (recipes, nutrition, health, surplus) so the site runs completely on GitHub Pages with no backend; the frontend service layer was checked against all 18 backend endpoints — 18/18 aligned.
06 / SYSTEM FACTS
175
findings (4 critical)
54
atomic commits
26
regression tests, all green
3
repos: API · web · model
07 / LESSONS
A wrong metric is more dangerous than no metric: the BERT argmax on the wrong axis made training look alive while the printed accuracy was meaningless. A model’s “green” must be checked for measuring the right thing, not just for printing a number.
Turning an old project into a public portfolio piece hinges first on running standalone with no backend: a seed/mock layer comes before any visual refresh — without it the demo fails to even load.
When rewriting a frontend, the API contract with the backend is what to lock first: aligning all 18 endpoints before redrawing screens keeps the integration from silently breaking after the refactor.
NEXT
Multi-tenant SaaS HRIS