Split the settings page and the membership fee tab into focused modules and apply one ENV rule set closes #540 #619

Merged
simon merged 17 commits from issue/mitgliederverwaltung-540 into main 2026-10-25 11:41:06 +01:00
Owner

closes #540, closes #546

Description of the implemented changes

The changes were:

  • Bugfixing
  • New Feature
  • Breaking Change
  • Refactoring

Split remaining LiveView god-modules (global_settings, fees_component): the settings page becomes a coordinator of one component per section and the membership fee tab is split into a cycles component, a receipts component and a pure formatting module, together with the club-name fix (#546), one consistent set of rules for settings that come from environment variables (shown read-only in the UI with the variable named), and test isolation so more of the suite runs async.

What has been changed?

  • Keep a saved club name across restarts and show it without a reload
  • Read ENV through one function that tests can override per process
  • Resolve each integration group in one pure snapshot
  • Split the settings page into one component per section
  • Treat blank ENV as unset and switch each integration as a group
  • Show exactly the ENV-managed settings read-only and name their variables
  • Save each section against the current settings so it never undoes another section's save
  • Show an error instead of crashing when the Vereinfacht contact sync cannot read the members
  • Run the tests that set ENV, app config or settings async on per-process overrides
  • Split the membership fee tab into cycles, receipts and formatting modules
  • Refresh the member's fee status after every cycle change
  • Load the Vereinfacht receipts of the shown member only, never of a contact id sent by the client
  • Keep secret values out of the settings page state
  • Treat a blank *_FILE variable as unset at boot instead of reading an empty path
  • Align the docs with the group and per-field ENV rules
  • Record the ENV rules, the club name and the fee status fixes under Unreleased

Definition of Done

Code Quality

  • No new technical depths
  • Linting passed
  • Documentation is added were needed

Accessibility

  • New elements are properly defined with html-tags
  • Colour contrast follows WCAG criteria
  • Aria labels are added when needed
  • Everything is accessible by keyboard
  • Tab-Order is comprehensible
  • All interactive elements have a visible focus

Testing

  • Tests for new code are written
  • All tests pass
  • axe-core dev tools show no critical or major issues

Additional Notes

  • Breaking change for operators: an installation that sets only some variables of SMTP, single sign-on or Vereinfacht in the environment (e.g. only SMTP_USERNAME or only OIDC_ADMIN_GROUP_NAME) and keeps the rest in the settings page now takes that whole integration from the environment, so the values from the settings page are ignored and mail or sign-on stop working until the environment is complete. Before updating, set the complete group in the environment or remove its variables. The settings page shows the affected group with a warning and the missing variables.
  • Review: the automated review loop reached its cap of 4 iterations and was accepted by a human; all 50 findings across the iterations were fixed, none rejected.
  • Large commits: most commits exceed 5 files or 150 lines. The biggest are "Split the settings page into one component per section" (27 files, +3395/−2266), "Show exactly the ENV-managed settings read-only" (30 files, +1511/−741), "Run the tests … async on per-process overrides" (52 files, mostly tests), "Treat blank ENV as unset …" (20 files), "Split the membership fee tab …" (10 files, +695/−548), "Keep secret values out of the settings page state" (17 files) and "Treat a blank *_FILE variable as unset at boot" (13 files). Every commit compiles on its own with warnings as errors.
  • Club name / branch bugfix/480-fix-minor-bugs: the existing CHANGELOG line about ASSOCIATION_NAME being the read-only source of truth refers to commit 2443bc62, which exists only on the never-merged branch origin/bugfix/480-fix-minor-bugs and never reached main. This PR delivers that behaviour and supersedes the commit; that branch may hold further unmerged work worth checking.
  • Operators, boot behaviour: an empty environment variable now counts as unset, including DATABASE_URL, ADMIN_EMAIL and every *_FILE variable (an empty *_FILE falls back to the plain variable instead of stopping the start, an empty ADMIN_PASSWORD_FILE falls back to ADMIN_PASSWORD), and values are trimmed. Which of VAR and VAR_FILE wins when both are set is unchanged from main (SMTP_PASSWORD over its file, the file for all other secrets); an unreadable SMTP_PASSWORD_FILE now stops the start with a message naming the file. SMTP, single sign-on and Vereinfacht now each switch to ENV mode as a whole as soon as any of their non-secret variables is set.
  • Test suite timing: moving tests from OS/application env and the shared settings row to per-process overrides lets more modules run async; the fast suite median went from 170.0 s to 157.2 s (sync part 93.3 s → 79.3 s) on a 4 vCPU host. Modules that still need shared state stay serial with the measured reason in the module.
closes #540, closes #546 ## Description of the implemented changes The changes were: - [x] Bugfixing - [x] New Feature - [x] Breaking Change - [x] Refactoring Split remaining LiveView god-modules (global_settings, fees_component): the settings page becomes a coordinator of one component per section and the membership fee tab is split into a cycles component, a receipts component and a pure formatting module, together with the club-name fix (#546), one consistent set of rules for settings that come from environment variables (shown read-only in the UI with the variable named), and test isolation so more of the suite runs async. ## What has been changed? - Keep a saved club name across restarts and show it without a reload - Read ENV through one function that tests can override per process - Resolve each integration group in one pure snapshot - Split the settings page into one component per section - Treat blank ENV as unset and switch each integration as a group - Show exactly the ENV-managed settings read-only and name their variables - Save each section against the current settings so it never undoes another section's save - Show an error instead of crashing when the Vereinfacht contact sync cannot read the members - Run the tests that set ENV, app config or settings async on per-process overrides - Split the membership fee tab into cycles, receipts and formatting modules - Refresh the member's fee status after every cycle change - Load the Vereinfacht receipts of the shown member only, never of a contact id sent by the client - Keep secret values out of the settings page state - Treat a blank *_FILE variable as unset at boot instead of reading an empty path - Align the docs with the group and per-field ENV rules - Record the ENV rules, the club name and the fee status fixes under Unreleased ## Definition of Done ### Code Quality - [ ] No new technical depths - [x] Linting passed - [x] Documentation is added were needed ### Accessibility - [ ] New elements are properly defined with html-tags - [ ] Colour contrast follows WCAG criteria - [ ] Aria labels are added when needed - [ ] Everything is accessible by keyboard - [ ] Tab-Order is comprehensible - [ ] All interactive elements have a visible focus ### Testing - [x] Tests for new code are written - [x] All tests pass - [ ] axe-core dev tools show no critical or major issues ## Additional Notes - Breaking change for operators: an installation that sets only some variables of SMTP, single sign-on or Vereinfacht in the environment (e.g. only `SMTP_USERNAME` or only `OIDC_ADMIN_GROUP_NAME`) and keeps the rest in the settings page now takes that whole integration from the environment, so the values from the settings page are ignored and mail or sign-on stop working until the environment is complete. Before updating, set the complete group in the environment or remove its variables. The settings page shows the affected group with a warning and the missing variables. - Review: the automated review loop reached its cap of 4 iterations and was accepted by a human; all 50 findings across the iterations were fixed, none rejected. - Large commits: most commits exceed 5 files or 150 lines. The biggest are "Split the settings page into one component per section" (27 files, +3395/−2266), "Show exactly the ENV-managed settings read-only" (30 files, +1511/−741), "Run the tests … async on per-process overrides" (52 files, mostly tests), "Treat blank ENV as unset …" (20 files), "Split the membership fee tab …" (10 files, +695/−548), "Keep secret values out of the settings page state" (17 files) and "Treat a blank *_FILE variable as unset at boot" (13 files). Every commit compiles on its own with warnings as errors. - Club name / branch `bugfix/480-fix-minor-bugs`: the existing CHANGELOG line about ASSOCIATION_NAME being the read-only source of truth refers to commit 2443bc62, which exists only on the never-merged branch `origin/bugfix/480-fix-minor-bugs` and never reached main. This PR delivers that behaviour and supersedes the commit; that branch may hold further unmerged work worth checking. - Operators, boot behaviour: an empty environment variable now counts as unset, including `DATABASE_URL`, `ADMIN_EMAIL` and every `*_FILE` variable (an empty `*_FILE` falls back to the plain variable instead of stopping the start, an empty `ADMIN_PASSWORD_FILE` falls back to `ADMIN_PASSWORD`), and values are trimmed. Which of `VAR` and `VAR_FILE` wins when both are set is unchanged from main (`SMTP_PASSWORD` over its file, the file for all other secrets); an unreadable `SMTP_PASSWORD_FILE` now stops the start with a message naming the file. SMTP, single sign-on and Vereinfacht now each switch to ENV mode as a whole as soon as any of their non-secret variables is set. - Test suite timing: moving tests from OS/application env and the shared settings row to per-process overrides lets more modules run async; the fast suite median went from 170.0 s to 157.2 s (sync part 93.3 s → 79.3 s) on a 4 vCPU host. Modules that still need shared state stay serial with the measured reason in the module.
Re-running the bootstrap seeds no longer overwrites a stored club name. When ASSOCIATION_NAME is set, every start mirrors it into the stored club name instead, so the variable stays the source of truth.
Each section owns its form and events and only its own params reach a save, so saving one section no longer resets another section's stored secret or drops unsaved input elsewhere. Switching OIDC-only on without a configured provider is now ignored, and toggling direct registration is confirmed with a flash like every other save.
A blank variable now falls back to the stored setting instead of overriding it with an empty value, in the settings resolution as well as when config/runtime.exs reads it at boot. Any non-secret SMTP, OIDC or Vereinfacht variable switches the whole integration to ENV mode; secrets resolve one by one, and OIDC_ONLY, MAIL_FROM_NAME, MAIL_FROM_EMAIL and ASSOCIATION_NAME resolve per field.

BREAKING CHANGE: an installation that sets only some variables of an integration in the environment (e.g. SMTP_USERNAME or OIDC_ADMIN_GROUP_NAME) and keeps the rest in the settings page now takes the whole integration from the environment; the values kept in the settings page are ignored until the environment provides the required ones. Set the complete group in the environment or remove its variables before updating.
Production code reads injected modules, limits and settings through seams a test can override per process, the OIDC discovery cache keeps one entry per document, and the members PDF takes its template paths per call; user-facing behaviour is unchanged. Tests that still need shared state stay serial with the measured reason. The fast suite median drops from 170.0 s to 157.2 s.
The page only learns whether each secret is set. The ENV-mode and stored-secret helpers it no longer needs are removed.
A blank ADMIN_PASSWORD_FILE now falls back to ADMIN_PASSWORD. Which of a secret's variable and its *_FILE wins when both are set is unchanged; the settings page now resolves secrets in the same order as boot.
docs(changelog): record the ENV rules, the club name and the fee status fixes under Unreleased
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is failing
14d16df459
test(settings): create the settings row before the secret property writes behind Ash's back
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
09c063740d
simon merged commit c3d99735f8 into main 2026-10-25 11:41:06 +01:00
simon deleted branch issue/mitgliederverwaltung-540 2026-10-25 11:41:06 +01:00
Sign in to join this conversation.
No description provided.