Build AnyList Complete

YESreplaces $0.83/mosaves $9.96/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort weekendthe files for this build are in the project pack

RuntimeNode 22 with SQLiteClientAn installable progressive web applicationOfflineIndexedDB with an operation queueMergePer-item operations rather than whole-list writesAccessOne household, invite links, no public signup

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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.

VariableNeededExampleWhere the value comes from
DB_PATHrequired./data/household.dbLists, recipes, plans and the operation log.
PUBLIC_URLrequiredhttps://lists.example.comUsed in invite links. Must be HTTPS or installation and offline support will not work.
INVITE_SECRETsecretrequiredgenerate-a-long-random-valueSigns invite tokens so a household cannot be joined by guessing.
SYNC_PULL_INTERVAL_SECONDSrequired30How often a foregrounded client pulls. Frequent enough to feel shared, infrequent enough to be polite.
OPERATION_RETENTION_DAYSrequired60How long the sync log is kept. Long enough for a device that has been off for a while.
BACKUP_DESToptionals3://your-bucket/householdProduct phase only. Where nightly backups go.

The build, in order

  1. 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.

    1. Service worker precaching the shell, a manifest with icons, and IndexedDB for data.

      Files vite.config.ts

      terminal
      npm create vite@latest . -- --template vanilla-ts
      npm install -D vite-plugin-pwa
    2. Local write first, queue second, network never on the critical path.

      Files src/ops.ts

    3. In an actual shop if you can. Desktop testing hides everything that matters here.

    done when · tick each as it passes
    watch 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.
  2. Sync that merges rather than clobbers

    Two people editing the same list at the same time both keep their changes.

    1. Per household, since a watermark. Small payloads and simple ordering.

      Files server/sync.ts

    2. Additions merge, checks are last-write-wins per item, deletions are tombstones. Test each case.

      Files src/merge.ts

    3. Both 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 passes
    watch 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.
  3. 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.

    1. Most cooking sites publish it. It is far more reliable than parsing the visible page.

      Files src/import/structured.ts

    2. A text box with a light parser for quantities. Honest and adequate, unlike a fragile scraper.

      Files src/import/paste.ts

    3. Numbers scale; a pinch does not. Test with a recipe containing both.

      Files src/scale.ts

    done when · tick each as it passes
    watch 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.
  4. Meal plans and a list that makes sense in a shop

    A week of meals produces one sensible shopping list.

    1. Days and meals, with recipes assigned and free-text notes for the nights nobody is cooking.

      Files src/plan.ts

    2. Merge on name and compatible unit only. Anything else stays separate.

      Files src/combine.ts

    3. Categories 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 passes
    watch 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.
  5. The household, and paper

    Everyone in the house can use it, including the person who wants it printed.

    1. A token that joins a household. No public signup, because a family application does not need one.

      Files server/invite.ts

    2. Items, quantities and sections. No navigation, no colours, nothing cut off. Print it on paper.

      Files src/print.css

    3. Who checked an item, shown quietly. Useful in a shared list, and not a scoreboard.

      Files src/items.ts

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more home.