v1.43.0 — Closing the Loop: Expected Outcomes, Release Notes & Launch Feedback
A full closing-the-loop workflow tying *predicted* impact to *actual* impact, plus app-level release notes you can read inside the app and on the marketing site.
Per-initiative
- Expected Outcomes — new section in the row edit modal. Capture metric, target, units, timeframe, and a hypothesis up-front for every initiative. These are the success criteria the loop closes against.
- Launch Outcomes & Release Notes — also on the row edit modal. Stamp a release date and capture release notes for three audiences:
- Dev / technical — what shipped and how
- Customer-facing — what users will notice and gain
- Internal summary — stakeholders, takeaways, next steps
- Launch Outcomes report rewritten (Reports → Launch Outcomes). Now an interactive view per shipped initiative with:
- Closing-the-loop table — expected outcomes paired with actuals; capture the actual value, source (PM / Data / Customer / Sales / Support), and a status pill (Met / Partial / Missed / Pending).
- Release notes editor — three audience tabs, save on blur.
- Feedback thread — typed by source with optional sentiment (positive / neutral / negative). Sales call notes, customer replies, data signals all live alongside the launch they're about.
- Audience filter — pivot the page between All / Dev / Customer / Internal.
- Include unreleased — capture expected outcomes early.
- Export to Markdown — concatenated release notes + outcomes table per shipped row, ready to send out.
App-level release notes
- What's New — new entry in the help FAB (bottom-right ? icon) opens an in-app modal that renders this CHANGELOG. A red dot on the FAB highlights when there's an unseen release; reading clears it.
- Single APP_VERSION constant — replaces stale
v1.36.1(login footer) andv1.29.0(backup metadata) literals. Bump alongsidepackage.jsonper release. - Marketing site /changelog — same content, served at app.pmroadmapper.com/changelog.
Templates parity (under-the-hood)
- Unified template-task sync — every task in every template (CapacityIQ, platform DB, bundled JSON, custom) now lands in both the Task Library and CapacityIQ task types. Manual "↻ Re-sync template tasks" button on the CapacityIQ Task Reference page.
- Fixed bundled-template path for Electron —
data/platform-templates.jsonis now reachable in the Electron renderer (was 404'ing relative torenderer/index.html). - CapacityIQ Templates page now waits for the template library to hydrate before rendering, so all 35 bundled templates appear instead of just the two cached locally.
- Added
data/**/*andCHANGELOG.mdto electron-builder so packaged builds ship the JSON catalogue and release notes.
Plan view polish
- Sprint bar relabelled to Plan progress and centered.
- Gantt view fully dark-mode aware — alternating row stripes, grid lines, month labels, task names, and dependency arrows now switch with the theme instead of staying light-mode.
v1.34.0 — v4 fix batch: import, Template Builder, docs, invites, back nav
See FIX_LOG_V4.md for full per-fix detail. Highlights:
- Fix 1:
restoreJsonBackuprewritten with inline file input; confirm happens after parse;pushCloudDataafter apply. Fixes silent no-op on web. - Fix 2: CapacityIQ templates page now renders a unified view pulling from
capData.templates, the main template library (_tplCache), bundled platform templates, and user customs via a newgetAllTemplates()helper. - Fix 3: New reusable Template Builder modal (~480 lines). Two-column layout with Templates / Task Library tabs, cross-template task selection accumulator, context-aware import handlers for plans / todo / checklist / capacityiq, and Save as custom template. Used by Plans, To-Do, Checklist, and Capacity IQ.
- Fix 4: Document Repository now uploads real files to Supabase Storage (
attachmentsbucket) via direct REST — drag+drop, 50 MB ceiling, download button per item. SeeFIX_LOG_V4.mdfor the one-time bucket SQL. - Fix 5: New "Invite Your Teammates" onboarding step — email rows, Send Invites wires the existing
send-inviteedge function, Google Calendar harvester pulls last-30-days meeting attendees when the v1.33.0 Google Calendar connection is present. - Fix 6: Global toolbar centering fix — every page toolbar now vertically centres its children.
- Fix 7: Plans → Templates button opens the Template Builder in
planscontext instead of the old Template Library overlay. - Fix 8: Browser back navigation wired.
history.pushStateon everyopenXoverlay,popstatehandler closes modals first then navigates,replaceStateon boot so the first Back press doesn't drop to the pre-login screen. Hash routing supported.
Required backend actions (Vela)
- Create Supabase Storage
attachmentsbucket + path-scoped RLS (SQL inFIX_LOG_V4.md). - For Google Contacts integration: add
contacts.readonlyscope to the Supabase Google provider.
v1.33.0 — Capacity Settings + Live Calendar Integration
Highlights
- ToDo-driven capacity view is now fully configurable — set your available
hours per week once and every downstream view (weekly, monthly, yearly,
timesheet target) follows.
- Real Google Calendar and Microsoft Outlook integration via OAuth scopes,
replacing the screenshot-only workaround. Meetings land directly in your
ToDo list with the right duration and date.
- Capacity + integration preferences now sync across Electron + web via the
shared Supabase JSONB blob.
Added
appSettings.capacity—{ hoursPerWeek, hoursPerDay, workDays }with a
new getCapHours() helper as the single source of truth.
- Inline hours-per-week editor at the top of the capacity view; updates
propagate immediately to weekly/monthly/yearly breakdowns and the
timesheet target.
appSettings.integrations.google+appSettings.integrations.microsoft—
persisted connection state, access token, and expiry.
connectGoogleCalendar()/connectOutlookCalendar()— OAuth via
Supabase with read-only calendar scopes
(https://www.googleapis.com/auth/calendar.readonly for Google,
Calendars.Read for Microsoft Graph).
fetchGoogleCalendarEvents(startISO, endISO)— Google Calendar API v3,
calendars/primary/events?singleEvents=true&orderBy=startTime.
fetchOutlookCalendarEvents(startISO, endISO)— Microsoft Graph
/me/calendarview (expands recurring series within the range).
_normalizeGoogleEvent/_normalizeGraphEvent— unified event shape
with quarter-hour rounded duration, source-tagged so imports can be
de-duplicated.
syncConnectedCalendarsNow()— fans out across both providers, degrades
gracefully when one token is expired, and shows a preview modal before
any ToDo is created.
openCalendarIntegrationModal()— connection status page with Connect /
Disconnect for each provider.
- Post-OAuth auto-navigation back to Capacity view (breadcrumbs via
sessionStorage.pmr_post_auth_goto).
buildDataPayload().settings— cross-device sync of capacity +
integrations through the existing roadmap_data blob.
tests/capacity.test.js— 22 pure-function assertions for the new
helpers.
tests/renderer.parse.test.js— V8 parse check of the full 1.3 MB
inline renderer JS (catches hand-editing mistakes before they ship).
npm test,npm run test:capacity,npm run test:parse,
npm run build:web scripts.
Changed
renderTimesheetweekly target is derived fromgetCapHours().hpw
instead of the old hardcoded 35 h.
renderCapacityMonthly/renderCapacityYearlyusehoursPerDayfrom
settings instead of a hardcoded * 8.
_capacityHoursPerWeekis now a live getter over
getCapHours().hpw — kept as a legacy alias so any older call site
reading it still works.
signInWithOAuthin the custom Supabase shim now forwards
opts.options.scopes so calendar scopes reach the provider.
_processOAuthFragmentcapturesprovider_token/
provider_refresh_token from the URL fragment when the round-trip was
launched by a calendar connect flow.
loadProfileSettingsdeep-merges the persistedcapacityand
integrations sub-objects so older per-device settings blobs still
load cleanly.
persistDatanow serialises capacity + integrations into
payload.settings for cloud sync.
Security notes
- Calendar tokens are stored only in the user's own
roadmap_dataJSONB
row (already protected by FORCE RLS with user-id scoping). No service
account, no shared secret, no server-side handling.
- Access is read-only for both providers.
- Tokens expire in ~1 hour; reconnect is a one-click flow rather than a
refresh dance. The refreshToken field is present in the schema in
case a future edge function wants to do server-side refresh later.
Config prerequisites for live calendar sync
Before users can click *Connect Google Calendar* successfully you must
enable the calendar scope on the Supabase Google provider:
1. Supabase Dashboard → Authentication → Providers → Google → *Additional
Scopes* → add https://www.googleapis.com/auth/calendar.readonly.
2. Google Cloud Console → OAuth consent screen → add the same scope to
the OAuth client used by Supabase.
3. For Outlook: Azure Portal → App Registrations → *API permissions* →
add Calendars.Read (Delegated). Grant admin consent.
4. Redirect URIs on both clients already include the Supabase auth
callback — no change needed.
Production RLS verification
Run this in Supabase SQL Editor to confirm the teams / team_members
SELECT policies are the tightened v20260409100000 versions:
```sql
SELECT schemaname, tablename, policyname, cmd, qual
FROM pg_policies
WHERE tablename IN ('teams','team_members')
AND cmd = 'SELECT'
ORDER BY tablename, policyname;
```
Expected for teams: policy name *Owners and members read teams* with
qual scoping to created_by = auth.uid() OR id IN (…team_members…).
Migration notes
No database migration is required. All changes are client-side and
layer onto the existing roadmap_data JSONB blob.