feat(chat): free-form GRUPPE channels with mutable participants
- ChatChannelType.GRUPPE: created by Leitungsteam (any KC) or a Gemeinde Verantwortliche/r (own KC), mixing team users and guests/Konfis as explicit ChatParticipant rows (unlike GEMEINDE_GRUPPE, membership is not derived from Gemeinde) - POST /chat/:kcId/gruppen to create, GET participant-candidates, and POST/DELETE /chat/gruppen/:channelId/participants to manage membership (creator, LT, or Verantwortliche/r of that KC) - ChatGateway broadcasts chat:participants-changed on membership change - PushService updated for nullable ChatParticipant.userId + new guestAccountId column - SyncService now replicates ChatParticipant - Prisma migration + 14 new unit tests (75/75 passing), tsc clean - CI: add .gitea/workflows/cybedefend-scan.yml + .cybedefend project config
This commit is contained in:
@@ -103,13 +103,28 @@ client's host - no separate web server is needed.
|
||||
(`WEBDAV_*` env vars), switchable to S3-compatible storage with
|
||||
`STORAGE_PROVIDER=s3` (`S3_*` env vars).
|
||||
- `chat/` — Gemeinde-Gruppenchat, 1:1 Direktnachrichten, Leitungsteam-über-
|
||||
greifende Kanäle und Broadcast (Konfis lesen nur). Channel administration
|
||||
and message history are plain REST (`ChatController`); real-time send/
|
||||
receive is a raw `ws` gateway (`ChatGateway`, path `/chat`) since passport
|
||||
guards don't apply to WS upgrades — auth happens once via `?token=` at
|
||||
connect time (`TokenVerificationService` tries Authentik JWKS, then falls
|
||||
back to a guest token). Access rules live in `ChatService` and are shared
|
||||
between the REST and WS entry points.
|
||||
greifende Kanäle, Broadcast (Konfis lesen nur), and free-form `GRUPPE`
|
||||
chats. Channel administration and message history are plain REST
|
||||
(`ChatController`); real-time send/receive is a raw `ws` gateway
|
||||
(`ChatGateway`, path `/chat`) since passport guards don't apply to WS
|
||||
upgrades — auth happens once via `?token=` at connect time
|
||||
(`TokenVerificationService` tries Authentik JWKS, then falls back to a
|
||||
guest token). Access rules live in `ChatService` and are shared between
|
||||
the REST and WS entry points.
|
||||
- `POST /chat/:kcId/gruppen` lets a Leitungsteam member (any KC) or a
|
||||
Gemeinde Verantwortliche/r (their own KC — `RolesGuard`'s kcId scoping)
|
||||
create a `GRUPPE` channel with any mix of team users and Konfis (guests)
|
||||
from that KC as initial participants (`participantUserIds`,
|
||||
`participantGuestIds`); the creator is always included. Unlike
|
||||
`GEMEINDE_GRUPPE`, membership isn't derived from `Gemeinde` — every
|
||||
participant is an explicit `ChatParticipant` row, so a Konfi (who always
|
||||
belongs to exactly one Gemeinde) can be added regardless of which
|
||||
Gemeinde the chat's creator manages.
|
||||
- `POST` / `DELETE /chat/gruppen/:channelId/participants` (body
|
||||
`{ userId }` or `{ guestId }`) add/remove a participant afterwards.
|
||||
Allowed for the channel's creator, any Leitungsteam member, or a
|
||||
Verantwortliche/r of that KC — not the participants themselves, and not
|
||||
guests.
|
||||
- `sync/` — replicates mutations between the local (on-site) and cloud
|
||||
server. `SyncService.capture()` is called by feature services right after
|
||||
a write, appending an entry to the append-only `SyncLogEntry` log tagged
|
||||
|
||||
Reference in New Issue
Block a user