/** * - the Platform Manager workspace's destinations, as a LIST rather than as forty lines of JSX * buried in a 1,600-line component. * * THE REASON THIS IS A MODULE: this workspace's whole product claim is that its surface is a small, * enumerable set - *"give your web designer a login that can set the portal up and cannot see a single * patient record"*. A claim about a SET has to be made against something you can read; nobody can check * a sentence like that against a chain of `items.push(...)` calls, and nothing failed when the set * changed. is the proof: it removed the payment-settings ENTRY and left the server grant * standing, and no test on either side noticed. * * IT IS NOT A FENCE, AND MUST NEVER BE READ AS ONE. The design says it in its own words: *the nav is * not a fence; a URL reaches anything.* What actually keeps an outside agency out of the chart is the * scope set the auth service stamps into their token and the `allowedRoles` on each route - both pinned * in `akashic-infrastructure` by `platformManagerScopeBoundary.test.ts` and * `platformManagerPhiBoundary.test.ts`. This list is the WORKFLOW half: what the hat is for * project-workspace-design-principles (permissions do access, so workspaces do workflow). * * roles/platform-manager/platform-manager-workspace-design.md, settled with Spencer 2026-08-14. */ export type PlatformManagerDestination = { /** Matches the sidebar item id, so the nav and this list cannot drift apart silently. */ id: string; label: string; to: string; }; /** * The five, IN THE ORDER THEY APPEAR. Order is a decision here, not presentation: * * **Portal pages leads because the workspace LANDS there.** This is a set-up-then-forget workspace - * an agency configures a practice once and comes back occasionally to change one thing - so the design * rules out a dashboard entirely: *"a landing page summarising state would be read once and then be * wrong for a year."* With no dashboard, the landing IS the most-used destination, and portal pages is * the one REQUIRED onboarding task this hat can complete. A practice whose portal pages are unmapped * can never finish setup. */ export const PLATFORM_MANAGER_DESTINATIONS: readonly PlatformManagerDestination[] = [ // 3a - where the product meets the practice's website. The most agency-shaped thing we have, and // the reason the hat exists at all. { id: 'patient-portal-page', label: 'Portal Pages', to: '/dashboard/portal-pages' }, /* * 3b - what the product ASKS. The FORM, never the answers: a QuestionnaireResponse lives with the * patient's chart and is not reachable from here, by scope as well as by nav. * * - RENAMED FROM "Questionnaires", and the rename is the smaller half of the change. * Spencer: *"Let's change the term 'questionnaires' to 'forms'. Within the 'forms' section... we * clearly differentiate 'public forms' from 'clinical questionnaires'."* The section now holds both * kinds, so a name that means only one of them was itself part of the confusion: a practice's public * website contact form filed under "Questionnaires" reads as clinical intake. */ { id: 'questionnaires', label: 'Forms', to: '/dashboard/questionnaires' }, // 3c - what the product does without being asked. RULES, never instances: the task a rule created // for a real patient belongs to the receptionist and the practitioner. { id: 'automated-tasks', label: 'Automated Tasks', to: '/dashboard/automated-tasks' }, /* * 3d LEFT THE NAV IN - *"Akashic Public Form Settings should be moved into the public * forms section of the new 'forms' parent so those remain together."* (Spencer) * * It is a MOVE, not a removal: the settings are rendered inside `Forms Public forms`, beside the * forms they configure, and the route still exists and is still reachable. What goes is a top-level * nav item naming a thing the reader had to already understand - the pairing was invisible while the * two sat in different places, which is the same confusion this whole card is about. * NOTHING ABOUT THE PERMISSION CHANGED. The route's own gate is unchanged and the page re-checks; * this list was never the fence see the note above about, where deleting an entry from a * nav left a server grant standing. */ // 3f - staff only, and kept for a specific reason: staff-to-staff messaging is how an outside // agency asks the practice a question, and it carries no patient data. { id: 'staff-communication', label: 'Messages', to: '/dashboard/staff-messages' }, // Labs, test catalogue, order formats and connections; the technician worklist stays in Labs. { id: 'diagnostics-setup', label: 'Lab and imaging setup', to: '/dashboard/diagnostics-setup' }, /** * THE SIXTH - Spencer, 2026-08-17. What the practice's portal header shows: its logo, a header * image, and its name, with a switch for each. * * IT BELONGS TO THIS HAT because it is the same kind of decision as Portal Pages - how the * practice's portal PRESENTS itself - and a web designer is exactly who is asked to make it. * * AND IT IS ITS OWN NARROW DESTINATION RATHER THAN THE ORGANIZATION SCREEN, WHICH IS THE WHOLE * POINT. That screen carries the practice's contact details, NPI, locations, services and consent * settings. Putting it here to reach a header image would be the payment-settings mistake again * (see the removal recorded below): *a screen that implies an outsider should hold the practice's * own record is worse than no screen.* The set stays small by being specific. * * SHOWN ONLY TO A VIEWER WHO HOLDS `organization: manage`, filtered at the nav site - the same * permission the logo upload has always used, and the same one the server's delegated-editable * allow-list requires. Not gated on being a Platform Manager: the permission is the fence, the hat * is the workflow. */ ]; /** * Destinations that are offered only when the viewer holds a permission, keyed by the section it needs. * * This list is still the whole SET - a reader can see every door this hat has. What varies is who is * offered which, and that has to be visible here rather than buried in the nav's JSX, or the claim this * module exists to make ("the surface is a small, enumerable set") stops being checkable. */ export const PLATFORM_MANAGER_DESTINATION_PERMISSIONS: Readonly> = { 'diagnostics-setup': 'organization', }; /** * Where the workspace opens. * * DERIVED FROM THE LIST, NOT RESTATED. A second literal is how the landing and the first nav item * drift into disagreeing - and this one already had: the workspace opened on Questionnaires while the * design named Portal pages, so the first thing an agency saw was not the task blocking the practice's * setup. */ export const PLATFORM_MANAGER_LANDING = PLATFORM_MANAGER_DESTINATIONS[0].to; /** * GONE, AND RECORDED SO IT CANNOT COME BACK BY ACCIDENT - `Patient Payment Settings`. * * These are the practice's OWN Stripe keys to the practice's OWN money, taken from a dashboard the * owner or the biller controls. Spencer, 2026-08-14, and the argument that settles it is not tidiness: * **the agency cannot do this task anyway.** Everything that was argued for keeping it here - it is * plumbing, it is one-time - is equally true of portal pages; the difference is that portal pages is a * task the agency can actually complete, and *a screen that implies an outsider should hold the * practice's payment credentials is worse than no screen.* * Do not re-add it, and do not "reunite" it here by duplicating the Billing entry: two doors to one * setting is how a practice changes it in one place and reads the other. */ export const REMOVED_FROM_PLATFORM_MANAGER: readonly string[] = ['/dashboard/billing/payments'];