CleanFrame
A personal home screen for Samsung The Frame. A starting point to fork and adapt.
Phone-friendly kitchen recipes for Ian and Avery. Dairy-free, wheat-free, low sugar. No honey, maple, or peanuts.
LifestyleTypeScript · CSSGitHub @Ianshaw93OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Phone-friendly kitchen recipes for Ian and Avery
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Phone-friendly cooking companion for Ian & Avery. One public URL, no login. Open it on both phones while you cook.
Seven dairy-free, wheat-free, low-sugar recipes in the bank. No honey, no maple, no peanuts. The default week plan still uses six of them; the bank can also hold imports that are not assigned to a day.
Bank-only (not on the default week): Cheat Chicken & Sweetcorn Soup — imported from Instagram @jimmy_chews. Assign it under Edit week if you want it on a day.Read the full README ↗Phone-friendly cooking companion for Ian & Avery. One public URL, no login. Open it on both phones while you cook.
Eight dairy-free, wheat-free, low-sugar recipes in the bank. No honey, no maple. Peanuts appear only as the Pad Thai garnish. The default week plan still uses six of them; the bank can also hold imports that are not assigned to a day.
Default week plan:
| Day | Dish | Time |
|---|---|---|
| Mon | Ginisang Hipon | 15 min |
| Tue | Ginger–Sesame Chicken & Broccoli | 20–25 min |
| Wed | Sinigang na Hipon | 30 min |
| Thu | Asian Ground Chicken Rice Bowl | 30 min |
| Fri | Fish Sinigang | 30 min |
| Sat / Sun | Chicken Tinola (buffer / leftovers) | 40 min |
Bank-only (not on the default week):
Home shows the week plan plus every recipe card in the bank. Edit week lets you reassign any recipe to any day. That custom plan is stored in the phone’s localStorage only — it is per-device until sync exists. Reset to default restores the table above.
Payments (/payments, linked from the header) is a shared settle-up page for Ian & Avery: log what either of you bought, see who is owed half, and delete mistakes. Both phones read and write the same ledger through /api/payments (Upstash Redis / Vercel KV). localStorage is only an offline cache, not the source of truth.
Homes (/homes, also in the header) is a weekly Kelvindale-area house scoper. Ian and Abby (Avery) vote independently no / maybe / yes on each listing. Both votes are visible. A listing is a Match when you both vote yes, and Both open when you both vote at least maybe. Pick “I’m Ian” / “I’m Abby” (stored on the phone) so filters know who “me” is. The shortlist lives in Redis at kusina:homes:v1 and uses the same household token as payments.
Shop (/shop, also in the header) is the shared household list for things that are not the weekly meal protein/veg shop: standing restocks, one-off extras, and the Asian grocery run. Both phones read and write Redis key kusina:shop:v1 through /api/shop, using the same household token as payments and homes. Tap a row to tick it, Clear ticks unchecks that section (items stay on the list), and each section has an add box.
Payments will not persist across phones until Redis is configured. On the Vercel free tier, add Upstash Redis (Storage / Marketplace). That injects:
| Env var | Where | Purpose |
|---|---|---|
UPSTASH_REDIS_REST_URL | Server | Redis REST URL |
UPSTASH_REDIS_REST_TOKEN | Server | Redis REST token |
Legacy Vercel KV names also work if that is what the store already injected:
| Env var | Where | Purpose |
|---|---|---|
KV_REST_API_URL | Server | Same as Upstash URL |
KV_REST_API_TOKEN | Server | Same as Upstash token |
Optional but recommended so random visitors cannot wipe the ledger. Use the same random string for both:
| Env var | Where | Purpose |
|---|---|---|
PAYMENTS_HOUSEHOLD_TOKEN | Server | Required on GET/POST/DELETE (Authorization: Bearer …, x-payments-token, or ?token=) |
NEXT_PUBLIC_PAYMENTS_TOKEN | Client (baked into the JS bundle at build time) | Both phones send this automatically — no login, no PIN prompt |
Vercel → kitchen-recipes-app → Storage → create Upstash Redis (free) and link it to the project.
Vercel → Settings → Environment Variables → add PAYMENTS_HOUSEHOLD_TOKEN and NEXT_PUBLIC_PAYMENTS_TOKEN with the same value (Production + Preview).
Redeploy (env vars, especially NEXT_PUBLIC_*, are applied at build time).
Open https://kitchen-recipes-app.vercel.app/payments on both phones. The first request seeds:
After that, adds/deletes on one phone show on the other after refresh (or immediately if you already have the page open and you reload).
Prove the seed from a terminal (use the same token you set, or omit -H if you skipped the household token):
curl -sS https://kitchen-recipes-app.vercel.app/api/payments \
-H "Authorization: Bearer $NEXT_PUBLIC_PAYMENTS_TOKEN"
You should see both Asda shop and Car oil change. Local next dev without Redis uses an in-memory store (lost on restart, not shared). Production returns 503 until Redis env vars are set.
Same Redis + household token as payments. The first GET /api/homes seeds week 2026-W39 (21 Sep 2026): Archerhill Road, 124 Alderman Road, Kelvindale Road, and 243 Alderman Road (also / peek). Later weeks can be appended with POST /api/homes (same body shape as a week in the document). Votes:
curl -sS https://kitchen-recipes-app.vercel.app/api/homes/vote \
-H "Authorization: Bearer $NEXT_PUBLIC_PAYMENTS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"listingId":"archerhill-road-knightswood","person":"ian","choice":"yes"}'
person is ian or abby. choice is no, maybe, or yes. Production returns 503 until Redis env vars are set.
Same Redis and household token. The first GET /api/shop seeds three sections when the key is empty:
POST /api/shop takes { "op": "toggle", "section": "fewWeeks" | "thisWeek" | "asian", "id": "…" }, { "op": "add", "section": "…", "label": "…" }, { "op": "clear", "section": "…" }, or { "op": "needThisWeek", "section": "fewWeeks" | "asian", "id": "…" }. Clear unchecks bought rows; it does not delete them. Need this week copies a standing label (and note) onto This week specials and leaves the original row and its tick alone. A second copy of the same label is a no-op. Ticking the This week row does not tick the standing original. This list does not replace Grocery This Week protein and veg.
curl -sS https://kitchen-recipes-app.vercel.app/api/shop \
-H "Authorization: Bearer $NEXT_PUBLIC_PAYMENTS_TOKEN"
/us (Together) is the sit-down page: non-negotiables, behaviour examples, the toxic-behaviours Doc link slot, an active-listening checklist, takeaways, things to work on, a reviewed-together log, a check-in list, and the Four Horsemen reference. /us/guide is Avery’s notepad guide (listening ticks, horsemen, empathy prompts). It does not write to Redis. Neither route is linked from home or the header. Both are noindex, nofollow and omitted from the sitemap. A small link joins the two pages. Seeded content lives in lib/relationship.ts. Shared edits save through GET/PUT /api/relationship (document version 2; version 1 Redis values migrate on read).
Chat (or any link) can add a spend on the shared ledger. After /payments loads from the API, a valid query is POSTed once, then the URL is replaced with /payments so a refresh does not double-add. If the same paidBy + amount + description + date is already logged (including the seeded Asda shop), the add is skipped and the params are still stripped.
Example:
/payments?paidBy=Ian&amount=57.60&description=Asda%20shop&date=2026-09-17¬e=Delivery%20Fri%2018%20Sep%202026%2C%202%E2%80%933pm%20%C2%B7%2018%20Millhouse%20Drive%2C%20G20%200UE
| Param | Required | Notes |
|---|---|---|
paidBy | yes | Ian or Avery |
amount | yes | Pounds string, e.g. 57.60 (same parsing as the form) |
description | yes | What it was for |
date | no | YYYY-MM-DD. Defaults to today |
note | no | Extra detail |
A short banner appears when an entry is added, e.g. Added: Asda shop £57.60 (Ian).
Each recipe has tap-to-tick ingredients and steps (progress + Clear ticks, stored separately on the device). Cook mode is one big step at a time with Next / Back.
npm install
npm run dev
Open http://localhost:3000.
npm test
Vitest + Testing Library. The suite is written TDD-style and covers:
/payments render, one-tap query-param import (parse, POST, no double-add), and Redis/token helpers/homes seed cards, and Ian/Abby vote UI/api/shop seed and household token, and /shop render/us unlinked + noindex, relationship seed/schema, shared /api/relationship GET/PUT, and active-listening ticksWatch mode:
npm run test:watch
npm run build
npm start
This is a standard Next.js App Router app. Import the GitHub repo in Vercel (framework preset: Next.js).
Payments, Homes, and Shop (both phones): create Upstash Redis, set PAYMENTS_HOUSEHOLD_TOKEN + NEXT_PUBLIC_PAYMENTS_TOKEN to the same secret, then redeploy. See Shared payments setup above. Until Redis is linked, /api/payments, /api/homes, /api/shop, and /api/relationship return 503 in production.
On a phone: Share → Add to Home Screen. A PWA manifest is included.
Next.js App Router, TypeScript, Tailwind CSS.