App reference

ADR-0028: Children run shared lists and meals

Metadata

  • Status: Accepted
  • Date: 2026-08-14
  • Deciders: Eagraí Clainne Team (design interview, 2026-08-14)
  • Related: ADR-0014 (job ownership — the ownership model that lists and meals deliberately do not share); ADR-0015 (item lists); ADR-0002 (centralised RPC authorization — the role gate these verbs use)

Context

The permission matrix treated the container operations of ItemListService (create, rename, delete, uncheck-all) and MealService (create, edit, delete, push-ingredients) as manager verbs, open to ADMIN and MEMBER only. A child could read lists and the meal library, and add items into a list through ItemService.Create, but could not create a list or a meal.

Two problems surfaced together.

First, the user interface hid the gap badly. The web gated every create affordance on one coarse flag, canEdit = ADMIN || MEMBER, so a child saw no create controls at all — even for events and jobs, which the matrix already permits. That defect is tracked and fixed separately; it is what made the missing list and meal rights visible.

Second, and the subject of this ADR: should a child be able to create and manage lists and meals at all? The obvious analogy is ADR-0014, where a child is a "taker" scoped to jobs they own. But that analogy does not hold. Jobs carry an owner. Lists and meals do not — ItemList and Meal are flat records with no owner or creator field. There is nothing to scope a child to.

Decision

Admit CHILD to the full verb set of both ownerless container services, the same rights a MEMBER holds:

  • ItemListService: Create, Read, Update, Delete, List, UncheckAll.
  • MealService: Create, Read, Update, Delete, List, PushIngredients.

A child is a trusted member of the household for the family's shared lists and meal library. Because these records have no owner, no service-layer guard is added or needed — enforcement stays entirely at the interceptor's role gate, as before.

The boundary is drawn at two nearby surfaces that are deliberately left unchanged:

  • Rewards stay member-and-up. A child claims rewards, but does not create or grant them (ADR-0003). Granting points is a parental act.
  • The meal rota board (MealRotaService slot, zone and override verbs) stays member-and-up. Editing the standing who-cooks board is a scheduling act; a child still reads the resolved board and the raw board.

GUEST remains excluded from every verb on both services.

Consequences

  • A child can create a shopping list, rename it, clear it, and delete it; and can add, edit and remove meals in the library and push a meal's ingredients onto a list. This matches how a family actually shares these surfaces.
  • No schema change. ItemList and Meal stay ownerless, so backup, export and the JSONB query paths are untouched.
  • A child could delete a list or meal another member relies on. This is the accepted cost of a shared, ownerless surface — the same exposure a member already carries. The mutation trail and audit log record who did it.
  • The permission-matrix completeness test still passes; only the allowed roles on existing entries changed, no entries were added or removed.
  • If the family later wants per-child ownership of these containers, that is a separate, larger change: an owner field on both entities, a Create that sets it, an ownership guard, and a rule for the existing ownerless rows. It is out of scope here and was rejected as heavier than the problem.

Alternatives considered

  • Create-only for a child. Let a child create a list or meal but not rename, delete or manage it afterward. Rejected: it leaves a child unable to fix their own typo or clear their own list, an odd half-right, and it still needs the same matrix touch.
  • Own-only, mirroring ADR-0014. Give a child rights over the lists and meals they created, scoped by a new owner field. Rejected for this issue: it forces a schema change on two entities, a new guard, and a migration decision for existing ownerless rows — far heavier than the problem, and these surfaces are shared by design, not personal like a job.
  • Leave it adult-only. Rejected: it does not match how a household runs a shared shopping list or menu, and it was the status quo the issue set out to correct.