Invental/Review lessons/Check, then act on stale state

Check, then act on stale state

List allowed statuses for every new path

Every new “who may do X” path widens the state machine; list the allowed source statuses explicitly, and where the database cannot enforce “only one pending”, serialise the check with a row lock.

01 · Before and afterThe pattern

TypeScript
await db.$transaction(async (tx) => {
  await tx.$queryRaw`SELECT id FROM Member WHERE id = ${memberId} FOR UPDATE`;
  const e = await tx.membership.findUnique({ where: { memberId_planId } });
  if (e && !CAN_APPLY.includes(e.status)) throw new Error("not allowed");
  if (await tx.planRequest.findFirst({ where: { memberId, status: "pending" } }))
    throw new Error("already pending");
  await tx.planRequest.create({ data });
});

02 · Run it on your appThe check

If you add a “re-apply” or “upgrade” path, did you list which current statuses may use it (and test banned users)?

If the honest answer is no or not sure, this is worth a look before it reaches production.

Want this checked on your code?

Tell us what you are building and what worries you. We match a senior reviewer to your code and confirm scope before anything starts.

— Get in touch
hi@invental.co ↗
— Or
— What to include

A link or short description of the code or system, what you want checked, your stack, and when you need the answer. No repository access is needed until scope is agreed.

— Or leave a note
We reply within one business day.