Safer SMS reply forwarding and Telegram retries
7 September 2026Two-run database installation for this release
- The pending member-services, Courses and sender changes can now be installed
with one SQL Editor apply file and one independent checker: 14 unchanged source units, nine postflight sections and one atomic apply transaction.
- Commit and CI gates check the generated files against their sources. The
existing local/CI rehearsal proves double-apply, rollback on a late failure and rejection of a broken final authority, without adding another runner.
- This does not repeat the completed insurance data copy, rerun old rollout
authorities, activate payment handovers or enable notifications. SQL still precedes application deployment; see the 7 September consolidated release note.
SMS and Telegram reply forwarding
- An SMS owner-forward failure no longer closes the inbound webhook as a
success. The gateway can redeliver it; the existing per-recipient delivery ledger prevents accepted or uncertain Telegram sends being repeated.
- SMS and Telegram replies now distinguish a definite recipient failure from a
different recipient's uncertain delivery, so a partial failure is not lost.
- SMS receipt evidence records why forwarding was skipped (for example, no bot,
no enabled owner recipient, consent keyword or no prior outbound message).
- Rejected SMS webhook authentication now records a fixed, rate-limited reason
in server logs. Keys, signatures, timestamps, contact identifiers and message contents are never logged. Signature verification and its five-minute replay window remain enforced; this diagnoses the phone's 401 rather than bypassing it.
- This correction adds no SQL migration, environment variable or feature flag.
Existing provider-receipt and delivery-outcome SQL remains a prerequisite. It does not replay historic messages or change production configuration.
Creative Ways' live device/webhook setup remains subject to read-only diagnosis and an owner-operated end-to-end test. Local tests do not establish physical SMS receipt or Telegram delivery.
The missing temporary checkout's member-services and forwarding changes were recovered into a permanent checkout. The separate member-services SQL-first rollout remains required; see the 7 September recovery evidence report for the fresh checks, rather than treating earlier temporary logs as current proof.
Club email senders and replies
- Immediate, scheduled and attachment email now share one tenant-bound sender
resolver. A failed club lookup stops delivery with a safe, visible error; it no longer silently sends club content as AllSorted without a reply address.
- Club email uses the club name (or its existing sender-name override) and
Club Details email as Reply-To. The sending address stays on the verified platform domain. Explicit platform account mail keeps platform branding.
- Communications final checks show From and Replies go to, with an explicit
warning if the configured platform reply fallback is being used. Deliverability also checks club sender readiness rather than reporting domain-only readiness.
- Outbox and scheduled-recipient ledgers retain the resolved sender before a
provider attempt. Failed/missing evidence writes block delivery. Preparation failures use the existing bounded retry path instead of claiming a time-budget continuation. No old sender is guessed or backfilled from current settings.
- SQL before code: apply the new additive
club-email-sender-identity-01.sql, then its postflight. Existing rollout bundles have not been rewritten. No new env variable, flag, inbox, reply handling service or DNS change is introduced. Replies go to the chosen email mailbox; the member portal remains read-only correspondence.
Email sender lookup correction
- Removed a nonexistent
clubs.addresscolumn from both sender projections.
It caused valid club sender settings to be rejected before provider dispatch, leaving email jobs waiting on the existing bounded retry schedule.
- The selected columns now have a compile-time schema check. Regression tests
simulate returned PostgreSQL unknown-column errors, including the optional legacy sender-name fallback, instead of always returning the fixture data.
- Club identity, Reply-To validation, consent checks, tenant scope and delivery
idempotency remain enforced. No new SQL, environment variable or flag is required for this correction. It does not reset or replay queued messages.
Member Requirements insurance transition — pending activation
- The Member Requirements summary and modal rows now show red for an expired
requirement, otherwise amber when one expires within 30 days (including today and day 30). Missing dates stay neutral and explicit; they never claim green. This display window does not change payment eligibility or attendance rules.
- For an explicitly mapped club, the profile action opens the same Member
Requirements modal as the card. The old insurance editor is hidden and the server refuses stale-tab edits/imports into retired insurance fields.
- Existing insurance read models and saved merge tags resolve the mapped
requirement's current date, exact membership-number field and current paid cycle. Register rows keep their original selected fields. Programme and member type restrictions remain combined; failed canonical reads never revive old data.
- Mapped clubs no longer produce legacy insurance Action Centre entries or
mirror canonical payments into the old member paid flag. Requirement payment tasks and generic events retain their existing idempotent processing.
- Deployment boundary: the binding-table preparation has already been
applied, but Creative Ways has not been activated. Deploy and verify the compatible code before a separately reviewed, owner-applied activation. Existing payment records and late-settlement handlers are retained; this change does not cancel charges, publish automations, send messages or move additional member data. No new environment variable or feature flag.
Course progress across the club
- Courses now has a Progress tab: filter by member, course, programme and
recorded progress, with an optional past/future-access and archived-course view.
- Desktop uses a member-by-course matrix with the member column kept visible
while scrolling. Mobile uses expandable member cards. Course headings focus the view on that course; errors provide retry rather than showing an empty list.
- One server-scoped database read returns each 25-member / eight-course window
and exact matching counts. Duplicate access sources count once. Programme filters use formal programme enrolments, not timetable rosters.
- This is recorded learning progress, not an access grant or a new certificate
decision. Existing enrolments, learning, assessments and certificates are unchanged. Practical-development and assessor sign-off remain a separate stage.
- SQL before code: apply the additive
course-progress-overview-01.sqland
its read-only postflight. No new environment variable or feature flag. The new read requires the existing Courses module and effective course-view permission.
Optional course development and assessment — local, not yet released
- Course setup now supports versioned practical-session minimums, grouped
competencies, staff-verified learning and an optional final conversation. Learner details in Courses → Progress support dated evidence, audited corrections, development actions and authorised staff sign-off.
- Existing learners retain their earlier requirements; future grants use the
published version. Changing a learner's version is explicit and is refused after practical evidence or completion. Referenced learning and quizzes are preserved; later editions use new learning items rather than rewriting them.
- Server-side completion requires every enabled condition. Final decisions,
corrections and certificate claims are serialised. Private assessor notes are omitted from the member portal; only explicitly shared feedback appears.
- Versioned certificates retain their course/template snapshot, stable number
and create-only storage path. Staff can recover a missing certificate without re-completing the course or overwriting an issued PDF. Existing course certificate templates and private storage are reused.
- Owner-approved erasure: permanently deleting a member removes their course
evidence and assessment history. Archiving preserves it. Certificate files are transactionally queued for retryable cleanup after a 15-minute render grace; the existing safeguarding and financial-retention policy is unchanged. The new course data is also included in staff subject-access exports.
- SQL before code: the additional
course-development-01.sqland
course-development-certificates-01.sql, course-member-erasure-01.sql and their final postflight are required, alongside the earlier progress-overview unit. No new environment variable, feature flag, automatic attendance credit, AI assessment or public certificate verification is introduced.