Add groups, invitations and instruments #3

Merged
mcp-bot merged 1 commit from feature/groups into develop 2026-11-01 20:03:51 +01:00
Member

Why

Notenwart serves several groups from one installation, so tenant separation has to be the foundation for every feature that follows, not something added afterwards. This PR puts all access decisions into one place and adds a test that covers every future route automatically.

What

  • Groups, memberships and invitations; roles admin, editor, member
  • access.py as the only place that decides access. Non-members get 404, so a group's existence stays hidden
  • Superadmin creates groups and reaches every group as admin
  • Invitation links: token stored as hash only, link shown once, expiry, use limit (counted in the database), revocation
  • Global instrument list with synonyms, seeded by migration. Editors add, superadmin renames and deletes
  • Profile with own instruments and part numbers
  • The last admin of a group cannot be removed or demoted

Tests

tests/test_tenant_isolation.py sweeps all routes of the app: outsiders get 404, ids of a foreign group under the own slug get 404, roles below the minimum get 403, anonymous visitors go to login. Routes outside /g/{slug} must be listed explicitly, and an unknown path parameter fails the test.

Verification

  • make lint and pytest pass (146 tests)
  • Mutation check: removing the group filter from one lookup and letting everybody into every group both fail the sweep
  • Migrations tested down to base and back up
  • Tested in the browser against Dex: create group, generate invitation, no console or CSP errors

The first sweep version found zero routes and skipped silently, because FastAPI 0.162 includes routers lazily. test_routes_were_found caught that; routes now come from ALL_ROUTERS.

## Why Notenwart serves several groups from one installation, so tenant separation has to be the foundation for every feature that follows, not something added afterwards. This PR puts all access decisions into one place and adds a test that covers every future route automatically. ## What - Groups, memberships and invitations; roles admin, editor, member - `access.py` as the only place that decides access. Non-members get 404, so a group's existence stays hidden - Superadmin creates groups and reaches every group as admin - Invitation links: token stored as hash only, link shown once, expiry, use limit (counted in the database), revocation - Global instrument list with synonyms, seeded by migration. Editors add, superadmin renames and deletes - Profile with own instruments and part numbers - The last admin of a group cannot be removed or demoted ## Tests `tests/test_tenant_isolation.py` sweeps all routes of the app: outsiders get 404, ids of a foreign group under the own slug get 404, roles below the minimum get 403, anonymous visitors go to login. Routes outside `/g/{slug}` must be listed explicitly, and an unknown path parameter fails the test. ## Verification - `make lint` and `pytest` pass (146 tests) - Mutation check: removing the group filter from one lookup and letting everybody into every group both fail the sweep - Migrations tested down to base and back up - Tested in the browser against Dex: create group, generate invitation, no console or CSP errors The first sweep version found zero routes and skipped silently, because FastAPI 0.162 includes routers lazily. `test_routes_were_found` caught that; routes now come from `ALL_ROUTERS`.
Add groups, invitations and instruments
All checks were successful
test / test (pull_request) Successful in 1m17s
da86d1553c
mcp-bot merged commit 4b5f62e36c into develop 2026-11-01 20:03:51 +01:00
mcp-bot deleted branch feature/groups 2026-11-01 20:03:52 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
makeitsystems/Notenwart!3
No description provided.