Build AnyList Complete
YESreplaces $0.83/mosaves $9.96/yrback to the verdict
Shared grocery lists that work in a shop with no signal and merge sensibly when two people add items at once, recipes with ingredients that generate a list, a weekly meal plan, and a printable shopping list for the person who would rather have paper.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the sync server and the build.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - have readyfree
Why Phase 2's merge behaviour needs two real devices, and the offline case needs a real shop with real signal problems.
Get it Your own and one other household member's. Ten minutes of their time, twice.
Verify
Two devices are installed and can both edit a list - installfree
Why Service workers and installation both require a secure context, so a local address will not work on a phone.
Get it A tunnelling tool such as cloudflared, which is free. open ↗
Verify
The phone loads it over HTTPS and the service worker registers - have ready5 to 10 USD a month, or free on hardware you own
Why Product phase only. Sync needs somewhere both phones can reach.
Get it Any small virtual server, or a machine at home behind a tunnel. This workload is tiny.
Verify
Both phones reach it over HTTPS - have readyfree
Why Phase 3's import needs variety: some sites publish structured data and some do not, and you need both cases.
Get it Pick five you actually cook, from five different sites. Keep the URLs as fixtures.
Verify
At least one imports structurally and at least one falls back to paste
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- households(id, name, created_at), members(id, household_id, name, invite_token, joined_at) - lists(id, household_id, name, position) - items(id, list_id, text, quantity, category, checked_at, checked_by, created_at, updated_at, deleted_at) · deleted_at is a tombstone, never a removed row - recipes(id, household_id, title, source_url, servings, instructions), recipe_ingredients(recipe_id, text, quantity, unit, category) - plans(id, household_id, week_start), plan_entries(plan_id, day, meal, recipe_id, note) - operations(id, member_id, entity, entity_id, op, payload, at) · the sync log, which is what makes concurrent editing work - Deletions are tombstones. A deleted item that is simply absent will be resurrected by the next device to sync.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DB_PATH | required | ./data/household.db | Lists, recipes, plans and the operation log. |
PUBLIC_URL | required | https://lists.example.com | Used in invite links. Must be HTTPS or installation and offline support will not work. |
INVITE_SECRETsecret | required | generate-a-long-random-value | Signs invite tokens so a household cannot be joined by guessing. |
SYNC_PULL_INTERVAL_SECONDS | required | 30 | How often a foregrounded client pulls. Frequent enough to feel shared, infrequent enough to be polite. |
OPERATION_RETENTION_DAYS | required | 60 | How long the sync log is kept. Long enough for a device that has been off for a while. |
BACKUP_DEST | optional | s3://your-bucket/household | Product phase only. Where nightly backups go. |
The build, in order
A list that works with no signal
You can add and check off items in a shop with the phone offline, and nothing is lost.
Service worker precaching the shell, a manifest with icons, and IndexedDB for data.
Files
vite.config.tsterminalnpm create vite@latest . -- --template vanilla-ts npm install -D vite-plugin-pwa
Local write first, queue second, network never on the critical path.
Files
src/ops.tsIn an actual shop if you can. Desktop testing hides everything that matters here.
done when · tick each as it passeswatch out- Browser storage can be evicted, and on some platforms it is far more aggressive for sites that are not installed to the home screen. Prompt for installation, and make an export available, because losing a household's recipe collection to a storage eviction is a genuinely bad afternoon.
Sync that merges rather than clobbers
Two people editing the same list at the same time both keep their changes.
Per household, since a watermark. Small payloads and simple ordering.
Files
server/sync.tsAdditions merge, checks are last-write-wins per item, deletions are tombstones. Test each case.
Files
src/merge.tsBoth devices offline, both editing, then both reconnect. This is the case that matters and the one that is skipped.
Files
test/merge.test.ts
done when · tick each as it passeswatch out- Syncing the whole list as one document means the last device to save wins and the other person's additions vanish silently, which in a shop means someone comes home without the milk. Sync per-item operations so two additions merge naturally.
Recipes, and getting them in without typing
A recipe can be added from a page in a few seconds, and its ingredients become list items.
Most cooking sites publish it. It is far more reliable than parsing the visible page.
Files
src/import/structured.tsA text box with a light parser for quantities. Honest and adequate, unlike a fragile scraper.
Files
src/import/paste.tsNumbers scale; a pinch does not. Test with a recipe containing both.
Files
src/scale.ts
done when · tick each as it passeswatch out- Parsing a recipe out of page prose is unreliable and always will be. Most cooking sites publish structured recipe metadata specifically so applications can read it, so use that first and fall back to a paste box rather than to a fragile parser you will maintain forever.
Meal plans and a list that makes sense in a shop
A week of meals produces one sensible shopping list.
Days and meals, with recipes assigned and free-text notes for the nights nobody is cooking.
Files
src/plan.tsMerge on name and compatible unit only. Anything else stays separate.
Files
src/combine.tsCategories assigned per ingredient, ordered to match a real shop. This is what makes the list usable.
Files
src/categories.ts
done when · tick each as it passeswatch out- Combining ingredients across recipes without reconciling units produces a list saying two hundred grams of onion and one onion as separate lines, which is worse than not merging at all. Merge only where units are compatible, and leave the rest as separate lines rather than guessing.
The household, and paper
Everyone in the house can use it, including the person who wants it printed.
A token that joins a household. No public signup, because a family application does not need one.
Files
server/invite.tsItems, quantities and sections. No navigation, no colours, nothing cut off. Print it on paper.
Files
src/print.cssWho checked an item, shown quietly. Useful in a shared list, and not a scoreboard.
Files
src/items.ts
done when · tick each as it passeswatch out- A default web print of an application interface produces a page of navigation and cut-off text, and the person who wanted paper will not ask twice. Write a print stylesheet and check it on actual paper before calling it done.
Hosting, backups and handing it overproduct builder
It runs somewhere the household can reach, and it survives you being unavailable.
A small server or a machine at home behind a tunnel. Certificates, because a warning page loses the household immediately.
Files
CaddyfileNightly database copies off the machine, plus a Markdown recipe export anyone can read without the application.
Files
scripts/backup.shsrc/export.tsWhere it runs, how to reach the export, and who to contact. Somewhere findable without the application working.
Files
docs/household.md
done when · tick each as it passeswatch out- A household application that only you can fix becomes a problem the week you are away, and the recipes people rely on are suddenly unavailable. The export and the note are what make that recoverable by someone else, and both need to exist before they are needed.
That is the whole plan for AnyList Complete. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Barcode scanning, voice entry and mobile capture polish.
- Retailer integrations that place an order.
- Voice assistant integration.
- Setup-free sharing for a household member who will not tolerate a step.
- excellent mobile capture, retailer integrations, voice assistants, and polished sharing
- frictionless family sync
- retailer and smart-home integrations
- large recipe or product database
- mobile polish
- A pantry list so the shopping list can subtract what you already have
- Recurring items that reappear weekly without being added
- A simple nutrition note per recipe, entered by hand rather than looked up
Need the files? The project pack on the verdict page hands your agent the whole brief · more home.