Release Notes — Jul 1, 2026 — dev → prod promotion (renewable admin sessions + cross-portal cookie fixes + membership periods)

What this release is. The dev → prod promotion (MR membervu/membervu-saas!264MERGED), everything accumulated on dev since the Jun 29 release (!249). 51 commits · 124 files · ~16 issues. Verify on staging (https://stg-rcme.membervu.com; admin portal https://stg-admin.membervu.com) and on the prod release build now that it has landed. The headline is a session-management wave: super-admin sessions are now renewable (they used to silently log you out), and two cross-portal cookie collisions are fixed. Plus a billing batch (manual-dues activation, new membership periods), a couple of events fixes, and security hardening.

🧭 New to MemberVu? Start here

MemberVu is a multi-tenant membership platform with two web apps: the org portal (stg-rcme.membervu.com — admins + members of a club) and the super-admin portal (stg-admin.membervu.com, separate login — Zeniark platform operators).

The change most likely to affect your testing is session behavior: the super-admin portal now stays logged in across a normal work session instead of dropping you (#531), and the org + admin portals no longer step on each other's cookies when both are open in the same browser (#539/#540). If you test both portals side-by-side, that's exactly the scenario these fixes target.

Recommended path: (1) read the env + login box; (2) test renewable admin sessions (§🔐 #531) and the two-portal cookie scenario (§🔐 #539/#540); (3) test manual-dues activation (§💳 #527) and new membership periods (§💳 #504); (4) work the rest top-to-bottom.

⚙️ Before you start — environment & logins

SurfaceURLLogin to use
Org portal (tenant)stg-rcme.membervu.comAdmin admin@rcme.membervu.com / Admin123!; Treasurer treasurer@demo.membervu.com / Treasurer123!
Member viewstg-rcme.membervu.comMember testmember@rcme.membervu.com / Member123!; Expired expired@demo.membervu.com / Expired123!
Super-admin portalstg-admin.membervu.comSuper Admin superadmin@zeniark.com / SuperAdmin123!
Email inbox (MailHog)stg-webmail.membervu.com
Scope notes — read before testing.

🔐 Auth, session & security — #530, #531, #532, #533, #539, #540

#ChangeWhat to verify on stage
#531 high-blastRenewable super-admin sessions — platform login now issues a refresh token (server-side allow-list), so admin-portal sessions renew in the background instead of dying at the access-token boundary.On stg-admin.membervu.com, log in and keep working past ~15 min (or until the access token would have expired) → you are not bounced to login; the session refreshes silently. Log out → you're fully signed out (refresh token revoked).
#532Admin-portal refresh client + soft re-auth — the admin app proactively refreshes and re-authenticates without a hard reload.While using the admin portal, an in-flight session refresh happens without a full page reload / without losing your place.
#533Shared session module — both portals now use one implementation of the session/refresh logic (internal refactor).Regression-only: org portal login/refresh and admin portal login/refresh both still behave correctly (no functional change expected — confirm nothing broke).
#530Access-token & impersonation TTL alignment — access-token lifetime matches prod magnitude; impersonation token TTL is single-sourced at 15 min.When a super-admin impersonates a member, that impersonated session is short-lived (~15 min) and clearly bounded; normal sessions use the standard lifetime.
#539 two-portalCross-portal refresh-cookie isolation — platform and tenant refresh cookies now have distinct names + scoped paths so they don't collide in a shared browser cookie jar.Open the org portal and admin portal in the same browser and log into both. Logging in/out of one does not silently log you out of the other; each portal's session refreshes independently.
#540 two-portal · securityBearer preferred over stale cookie — a lingering auth_token cookie no longer shadows a valid admin Authorization: Bearer header (which previously caused spurious 403s).With both portals open, perform admin actions in the super-admin portal → they succeed (no unexpected 403 Forbidden) even if an org-portal auth_token cookie is present.

💳 Billing & payments — #527, #504, #503, #502, #497

#ChangeWhat to verify on stage
#527 moneyManual bank-transfer dues approval activates the member — approving a manual dues payment now flips membership to active in the same step.Submit a bank-transfer dues payment for an inactive/pending member, then approve it as admin → the member becomes ACTIVE immediately (no separate activation needed). Confirm the status change and the membership dates.
#504QUARTERLY + LIFETIME membership periods — new billing-period options on membership types.Create/edit a membership typeQUARTERLY and LIFETIME are selectable and save correctly. A LIFETIME member's dues logic + emails don't error on the (null) next-due date. Existing MONTHLY/ANNUAL types are unchanged.
#503Void-invoice lifted to all sources — voiding is no longer restricted to a subset of invoice origins.Void an invoice created from different sources (dues, event, manual) → the void action is available and works for each.
#502Humanized invoice status across the full surface via a single util.Invoice status labels read as human text (e.g. "Partially Paid", "Voided") consistently across list, detail, and exports — not raw enums.
#497 moneyDiscount cap-guard correctness — a PENDING allocation must not inflate amountPaidCents.With a discount cap in play, a pending payment/allocation does not count toward the paid total or the discount cap; only settled amounts do. Cross-check the balance.

🎟️ Events — #524 + staff check-in link

#ChangeWhat to verify on stage
#524EVENT_ENDED instead of ACCESS_CODE_EXPIRED when an event is over — clearer member-facing error.Try to use a check-in access code for an event that has already ended → the message says the event has ended, not that the code expired.
Staff check-in URL surfaced in the Access Codes panel.In an event's Access Codes panel, the staff check-in URL is visible and copyable, so staff can open the check-in surface directly.

🛡️ Security & hardening — #501, #509, #523

#ChangeWhat to verify on stage
#501 securityRate-limit unauthenticated membership applicationsPOST /membership/apply is now throttled (closes a spam vector).Submitting many membership applications rapidly from one client eventually returns 429 (throttled). A normal single application still works.
#509Fail loud on unresolvable tenant originbuildTenantOrigin now throws HTTP 400 instead of returning a bad origin; Tenant.appDomain is backfilled + made required.Tenant-origin links in emails (invites, resets, event links) point at the correct tenant host. There should be no malformed links (e.g. https://rcme.http/...); a misconfigured tenant fails with a clear error rather than sending a broken link.
#523Async S3 avatar presign migration — member avatar URLs are presigned on the async path; bare S3 keys presigned inline when the redirect service is off.Member avatars load everywhere they appear (member list, profile, attendee exports) — no broken images or expired-link errors.

🔧 CI / build (ops) — #262 + guardrails

#ChangeWhat to verify on stage
#262Frontend builds copy the shared libs/ workspace — required so both portals resolve the shared session module (#533).Ops-only: the frontend images build successfully on prod/stage (no module-resolution error). No member-facing change — see §Deploy.
G10 / G2CI guardrails refined — G10 email-timezone check is now precise (multi-line { timeZone } aware); G2 tenant-origin check no longer false-positives on comments.Ops-only: notification/email dates still render in the tenant timezone (not UTC). No behavior change for testers beyond correct email dates.

Suggested review order

  1. Renewable admin sessions (#531) — stay logged into the super-admin portal past the old expiry window; confirm no silent logout.
  2. Two-portal cookie scenario (#539/#540) — org + admin portal in one browser; neither breaks the other's session and no spurious admin 403s.
  3. Manual-dues activation (#527) — approving a bank-transfer dues payment activates the member in the same step.
  4. New membership periods (#504) — QUARTERLY + LIFETIME selectable and saved; LIFETIME doesn't error.
  5. Billing correctness — void-all-sources (#503), humanized status (#502), discount cap vs pending allocation (#497).
  6. Events — EVENT_ENDED message (#524) + staff check-in URL.
  7. Hardening — application rate limit (#501), tenant-origin links fail loud / no malformed URLs (#509), avatars load (#523).
  8. Skip: live gateway/webhook capture (inert in QA — records only). Use "Record Payment" for manual payments.

🚀 Deploy / migration notes (ops + reviewer gate)

Four migrations — deploy via prisma migrate deploy only (applied in timestamp order); never reset/reseed on prod. Three are additive; one is a constraint that is self-protected by its paired backfill:
  1. 20260630000000_backfill_tenant_appdomain (#509) — idempotent backfill of any NULL Tenant.appDomain to <slug>.membervu.com. Data-only, safe to re-run.
  2. 20260630000001_tenant_appdomain_not_null (#509) — ALTER … SET NOT NULL. Safe because the backfill above runs first. Post-deploy check: SELECT count(*) FROM "Tenant" WHERE "appDomain" IS NULL; = 0.
  3. 20260630000002_add_quarterly_lifetime_membership_periods (#504) — enum ADD VALUE IF NOT EXISTS 'QUARTERLY' / 'LIFETIME'. Additive; existing rows unaffected.
  4. 20260630000003_platform_refresh_tokens (#531) — new PlatformRefreshToken table + PlatformAdmin.tokenVersion INTEGER NOT NULL DEFAULT 0. Additive (backfills in place).
🏗️ Build-pipeline change (#262): both frontend Dockerfiles now COPY libs/ into the build context (required for the shared session module). Build the frontend images from the repo root so libs/ is present, and invalidate the frontend build cache so the new step is honored.
⚙️ Config on prod: PLATFORM_REFRESH_TOKEN_TTL_SECONDS is new but optional (default 43200 = 12 h — shorter than the tenant refresh TTL because platform admins are higher-privilege). The SESSION_COOKIE_DOMAIN / SAMESITE / SECURE trio should already be set from the Jun 29 deploy — re-confirm, since renewable admin sessions rely on the same cookie machinery. Confirm the cron secret is still set.
✅ Merge: clean dev → prod merge — 0 conflicts this cycle (no reconciliation branch needed).
🔙 Rollback: redeploy prod from rollback/prod-pre-release-2026-07-01 (60c28ec1) — code rollback only; all migrations are forward-safe, do not reverse-migrate a live DB.

Source of truth: the membervu/membervu-pm tracker + MR membervu/membervu-saas!264 (merged), direct dev → prod promotion. This page is the tester/reviewer-facing view; the full release note (deploy gate, config, rollback) is membervu-saas/docs/runbooks/2026-07-01-prod-release-dev-to-prod.md. Builds on the Jun 29, 2026 release. Verified present on dev on 2026-07-01. Gateway flows inert in all QA environments.