feat(groups): application groups (data, admin, user grouping) [BUNYIP-100 1/2] #145

Merged
vas2000-work merged 3 commits from feat/bunyip-100-application-groups into main 2026-06-14 06:29:36 +02:00
Owner

What

BUNYIP-100, PR 1 of 2. User-facing application groups so apps that are really one product (e.g. Mokosh = mokosh-server + mokosh-apps + ...) render together. PR 2 will add the unified per-card download affordance and retire the public Downloads page.

Layers

Data - new application_groups table + nullable applications.group_id FK (ON DELETE SET NULL, so deleting a group ungroups its members). ApplicationGroup model + repository; group_id threaded onto Application and ApplicationResponse.

Assignment - a dedicated ApplicationRepository::set_group, deliberately separate from the shared update. That method COALESCEs every column and is called with partial bodies (e.g. an is_active toggle), so it can neither clear group_id to NULL nor be trusted to leave it untouched. A direct SET group_id = $1 both sets and clears.

API - admin CRUD under /v1/admin/application-groups, app assignment via PUT /v1/admin/applications/{id}/group, and a public GET /v1/application-groups (display metadata only) the web layer uses to group apps.

Web admin - a Groups management page (list / create / edit / delete) and a Group selector on the application edit form, posting to the dedicated set-group endpoint.

Web user - the Applications page renders apps under their group heading (groups in sort_order), with an "Other" section for ungrouped apps. With no groups defined it falls back to the previous flat grid. The card markup is extracted into an app_card helper shared by both paths.

Verification

just check-container green: fmt, clippy -D warnings, and 224 workspace lib tests (api 19, domain 186, oci 9, oidc 9). Not exercised here: the live request flow and the migration apply, which need the running stack.

Heads-up

This and the BUNYIP-99 surface-tags PR (#142) both touch application_form and the admin applications list in bunyip-web/src/handlers/admin.rs; expect a small merge conflict to resolve when the second of the two merges.

#BUNYIP-100

## What BUNYIP-100, PR 1 of 2. User-facing application groups so apps that are really one product (e.g. Mokosh = mokosh-server + mokosh-apps + ...) render together. PR 2 will add the unified per-card download affordance and retire the public Downloads page. ## Layers **Data** - new `application_groups` table + nullable `applications.group_id` FK (`ON DELETE SET NULL`, so deleting a group ungroups its members). `ApplicationGroup` model + repository; `group_id` threaded onto `Application` and `ApplicationResponse`. **Assignment** - a dedicated `ApplicationRepository::set_group`, deliberately separate from the shared `update`. That method COALESCEs every column and is called with partial bodies (e.g. an `is_active` toggle), so it can neither clear `group_id` to NULL nor be trusted to leave it untouched. A direct `SET group_id = $1` both sets and clears. **API** - admin CRUD under `/v1/admin/application-groups`, app assignment via `PUT /v1/admin/applications/{id}/group`, and a public `GET /v1/application-groups` (display metadata only) the web layer uses to group apps. **Web admin** - a Groups management page (list / create / edit / delete) and a Group selector on the application edit form, posting to the dedicated set-group endpoint. **Web user** - the Applications page renders apps under their group heading (groups in `sort_order`), with an "Other" section for ungrouped apps. With no groups defined it falls back to the previous flat grid. The card markup is extracted into an `app_card` helper shared by both paths. ## Verification `just check-container` green: fmt, clippy `-D warnings`, and 224 workspace lib tests (api 19, domain 186, oci 9, oidc 9). Not exercised here: the live request flow and the migration apply, which need the running stack. ## Heads-up This and the BUNYIP-99 surface-tags PR (#142) both touch `application_form` and the admin applications list in `bunyip-web/src/handlers/admin.rs`; expect a small merge conflict to resolve when the second of the two merges. #BUNYIP-100
feat(groups): application groups (data, admin management, user grouping)
All checks were successful
Check / fmt / clippy / build / test (pull_request) Successful in 1m6s
ecc3912f32
BUNYIP-100 PR 1 of 2. Adds user-facing application groups so apps that are really one product (e.g. Mokosh = several apps) render together.

Data: new `application_groups` table and a nullable `applications.group_id` FK (ON DELETE SET NULL, so removing a group ungroups its members). `ApplicationGroup` model + repository, and `group_id` threaded onto `Application` and `ApplicationResponse`. Assignment uses a dedicated `ApplicationRepository::set_group` rather than the shared `update`: that method COALESCEs every column and is called with partial bodies (e.g. an is_active toggle), so it can neither clear group_id nor be trusted to leave it untouched.

API: admin CRUD under `/v1/admin/application-groups`, app assignment via `PUT /v1/admin/applications/{id}/group`, and a public `GET /v1/application-groups` (display metadata only) the web layer uses to group apps.

Web admin: a Groups management page (list / create / edit / delete) and a Group selector on the application edit form, posting to the dedicated set-group endpoint.

Web user: the Applications page renders apps under their group heading (groups in sort order), with an "Other" section for ungrouped apps. With no groups defined it falls back to the previous flat grid. The card markup is extracted into an `app_card` helper shared by the grouped and ungrouped sections.

Verified: `just check-container` green (fmt, clippy -D warnings, 224 lib tests across the workspace). Not exercised here: live request flow and migration apply, which need the running stack.

Note: this and the BUNYIP-99 surface-tags PR both touch `application_form` and the admin applications list; expect a small merge conflict in admin.rs to resolve when the second of the two merges.

#BUNYIP-100

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into feat/bunyip-100-application-groups
All checks were successful
Check / fmt / clippy / build / test (pull_request) Successful in 1m17s
5c17cd2a16
# Conflicts:
#	bunyip-web/src/handlers/admin.rs
Merge branch 'main' into feat/bunyip-100-application-groups
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
Check / fmt / clippy / build / test (pull_request) Successful in 1m0s
0c39e6aa3d
vas2000-work deleted branch feat/bunyip-100-application-groups 2026-06-14 06:29:36 +02: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
psa-systems/bunyip!145
No description provided.