dashboard-refresh-after-actionsrun.md02_define/output/spec.md/csm/dashboard, /sdm/dashboard and /expert/dashboard have no route-policy entries, so the
deny-by-default proxy redirects them to the /csm, /sdm and /expert role homes (which
re-export the same pages). The dashboards' server actions call
revalidatePath("/sdm/dashboard") etc., invalidating paths that are never served, so the
actually-served role-home pages keep stale data after a blocker update, outreach send, or
work-queue action until a hard reload.
Take the recommended option: make the revalidated path the served path, consistently across all
three personas. Retarget revalidatePath("/sdm/dashboard") to /sdm (SDM outreach action) and
the three revalidatePath("/expert/dashboard") calls to /expert (expert blocker actions). The
CSM dashboard actions had no revalidation at all, so resolving a blocker or posting outreach
left the served /csm page stale — both now call revalidatePath("/csm"). A sweep of every
revalidatePath call site in apps/web confirmed no other target points at a path outside the
route-policy allow-list. No route-policy entries were added and no page markup changed.
revalidatePath target in apps/web matches a served route-policy path (no
revalidate-a-redirect anywhere after the sweep)./csm, /sdm and /expert role homes still render identically (no page or policy
changes, actions only)./…/dashboard routes (the non-chosen alternative).unstable_cache/revalidateTag to Next 16 use cache — the deferred
"stub 5" cache-tag wiring noted in lib/queries/workspace-cache.ts is a different, larger
change.03_build/output/notes.mdsetSdmOutreachState revalidated
/sdm/dashboard, a path with no route-policy entry that the proxy never serves. Retargeted
to the served /sdm role home.raiseBlocker, escalateBlocker and
clearBlocker revalidated /expert/dashboard (same never-served drift). All three
retargeted to the served /expert role home.resolveCsmBlockerAction and
postOutreachAction had no revalidation at all, so the served /csm page kept stale queue
and outreach rows. Both now call revalidatePath("/csm"); postOutreachAction still
returns the OutreachState for the in-place card update.revalidatePath call site in apps/web (grep) against lib/route-policies.ts; the only
never-served targets were the four fixed here. All remaining targets (/admin/*,
/services, /products, /skills, /users, /proposals, /service-leads,
/expert/bids, /expert/my-knowledge, /notifications, /settings,
/setup-checklist, /integrations, /projects/brd/*, /expert-evidence,
lib/taxonomy-revalidate.ts base paths) match a policy entry directly or via a
non-exact prefix rule./csm, /sdm and /expert role homes still render identically — no page,
component or route-policy file was touched; the diff is confined to the three actions
files.apps/web/lib/route-policies.ts: the role homes are the
exact-match entries /csm, /sdm, /expert (lines near the end of ROUTE_POLICY_RULES),
and ROLE_HOME in apps/web/lib/auth.ts confirms they are where the proxy redirects.postOutreachAction changed from returning the service call directly to capturing the
result, revalidating, then returning it — verify the ActionResult<OutreachState> contract
is unchanged (it is; only the ordering of return vs revalidate differs)./expert, matching the stub's one-target-per-persona recommendation; a CSM
invoking them gets the CSM queue refresh from the CSM actions' own revalidation. No current
UI imports these expert actions (checked consumers), so this is latent-path hygiene.apps/web/app/(app)/customer/dashboard/actions.ts
(completeCustomerActionItemAction) also has no revalidatePath, but /customer/dashboard
HAS a route-policy entry (it is served), and the customer persona is outside this stub's
scope — left untouched.