Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Feature-specific MQTT topics and payloads are described in:
- [Jukebox MQTT Notifications](doc/jukebox-mqtt-notifications.md)
- [Daily Task MQTT Notifications](doc/daily-task-mqtt-notifications.md)
- [Friendship MQTT Notifications](doc/friendship-mqtt-notifications.md)
- [Soulhome MQTT Notifications](doc/soulhome-mqtt-notifications.md)

## Getting started

Expand Down
38 changes: 38 additions & 0 deletions doc/mqtt-notification-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ documented per feature.
| `friendship` | `FRIEND_REQUEST_CREATED`, `FRIEND_REQUEST_ACCEPTED`, `FRIEND_REQUEST_REJECTED` |
| `inactive_room` | `INACTIVE_ROOMS_REMOVED` |
| `stock` | `STOCK_ITEM_ADDED`, `STOCK_ITEM_REMOVED` |
| `soulhome` | `SOULHOME_ROOM_ACTIVATED`, `SOULHOME_ROOM_DEACTIVATED`, `SOULHOME_ROOM_LAYOUT_UPDATED` |

## Frontend Routing

Expand Down Expand Up @@ -61,12 +62,18 @@ switch (message.topic) {
case 'stock':
handleStock(message.type, message.payload);
break;
case 'soulhome':
handleSoulhome(message.type, message.payload);
break;
}
```

See [Stock MQTT Notifications](stock-mqtt-notifications.md) for the full
stock-specific topic and payload contract.

See [Soulhome MQTT Notifications](soulhome-mqtt-notifications.md) for the full
Soul Home room notification topic and payload contract.

## Clan Member Notifications

Subscribe to clan member changes with:
Expand Down Expand Up @@ -223,3 +230,34 @@ Payload:
}
}
```

## Soulhome Notifications

Soul Home room changes are published to:

```text
/clan/{clanId}/soulhome/{soulHomeId}/update
```

Use `/clan/{clanId}/soulhome/+/update` to subscribe to all Soul Home room
changes for a clan.

Payload:

```ts
{
topic: 'soulhome',
type:
| 'SOULHOME_ROOM_ACTIVATED'
| 'SOULHOME_ROOM_DEACTIVATED'
| 'SOULHOME_ROOM_LAYOUT_UPDATED',
payload: {
topic: `/clan/${clanId}/soulhome/${soulHomeId}/update`,
clan_id: string,
soulHome_id: string,
mode?: 'single' | 'batch',
rooms: object[],
ts: number
}
}
```
216 changes: 216 additions & 0 deletions doc/soulhome-mqtt-notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Soulhome MQTT Notifications

The backend publishes clan Soul Home room state and layout notifications through
MQTT using the common topic format built by `NotificationSender`.

Soulhome notifications describe committed room changes. Layout notifications
are sent only after `PUT /room` has successfully saved the room and furniture
changes.

## Subscribe Topic

Frontend clients that need Soul Home room changes for one clan should subscribe
to:

```text
/clan/{clanId}/soulhome/+/update
```

The published topic is:

```text
/clan/{clanId}/soulhome/{soulHomeId}/update
```

Where:

- `{clanId}` is the clan whose Soul Home changed.
- `{soulHomeId}` is the Soul Home containing the changed room or rooms.

## Payload

All Soulhome notifications use the common MQTT envelope:

```ts
{
topic: 'soulhome',
type:
| 'SOULHOME_ROOM_ACTIVATED'
| 'SOULHOME_ROOM_DEACTIVATED'
| 'SOULHOME_ROOM_LAYOUT_UPDATED',
payload: SoulHomeRoomNotificationPayload
}
```

The inner `payload.topic` identifies the logical Soul Home room event for the
frontend. It is not the MQTT broker topic.

```ts
type SoulHomeRoomNotificationPayload = {
topic: `/clan/${clanId}/soulhome/${soulHomeId}/update`,
clan_id: string,
soulHome_id: string,
mode?: 'single' | 'batch',
rooms: Array<{
_id: string,
roomPosition?: number,
roomStatus?: 'Active' | 'Inactive',
deactivationTime?: string | null,
roomColour?: string,
wallpaper?: string,
floorType?: string,
furnitureChanged?: boolean
}>,
ts: number
}
```

## Room Activated

Sent after one or more rooms have been activated.

### Published Topic

```text
/clan/{clanId}/soulhome/{soulHomeId}/update
```

### Event Type

```text
SOULHOME_ROOM_ACTIVATED
```

### Payload Shape

```ts
{
topic: 'soulhome',
type: 'SOULHOME_ROOM_ACTIVATED',
payload: {
topic: `/clan/${clanId}/soulhome/${soulHomeId}/update`,
clan_id: string,
soulHome_id: string,
rooms: [
{
_id: string,
roomPosition?: number,
roomStatus: 'Active',
deactivationTime: string
}
],
ts: number
}
}
```

## Room Deactivated

Sent after a room has been deactivated.

### Published Topic

```text
/clan/{clanId}/soulhome/{soulHomeId}/update
```

### Event Type

```text
SOULHOME_ROOM_DEACTIVATED
```

### Payload Shape

```ts
{
topic: 'soulhome',
type: 'SOULHOME_ROOM_DEACTIVATED',
payload: {
topic: `/clan/${clanId}/soulhome/${soulHomeId}/update`,
clan_id: string,
soulHome_id: string,
rooms: [
{
_id: string,
roomPosition?: number,
roomStatus: 'Inactive',
deactivationTime: string
}
],
ts: number
}
}
```

## Room Layout Updated

Sent after `PUT /room` has successfully saved room layout and furniture changes.

`PUT /room` accepts either one room object or an array of room objects:

```ts
UpdateRoomDto
```

```ts
UpdateRoomDto[]
```

Both request shapes publish the same event type. The `mode` field tells whether
the request updated one room or multiple rooms:

- `single` means the request body was one room object.
- `batch` means the request body was an array.

Only one MQTT message is published per successful `PUT /room` request. Batch
updates are not split into one message per room.

### Published Topic

```text
/clan/{clanId}/soulhome/{soulHomeId}/update
```

### Event Type

```text
SOULHOME_ROOM_LAYOUT_UPDATED
```

### Payload Shape

```ts
{
topic: 'soulhome',
type: 'SOULHOME_ROOM_LAYOUT_UPDATED',
payload: {
topic: `/clan/${clanId}/soulhome/${soulHomeId}/update`,
clan_id: string,
soulHome_id: string,
mode: 'single' | 'batch',
rooms: [
{
_id: string,
roomColour?: string,
wallpaper?: string,
floorType?: string,
furnitureChanged: boolean
}
],
ts: number
}
}
```

## Frontend Handling

Recommended frontend flow:

1. Subscribe to `/clan/{clanId}/soulhome/+/update` when showing the Soul Home.
2. Use the top-level `type` field to route activation, deactivation, and layout
events.
3. Use `payload.rooms` as an array for both single and batch updates.
4. Use `payload.mode` for layout updates if the UI needs to distinguish one-room
saves from batch saves.
5. Refresh or patch the local Soul Home room cache after receiving the message.
2 changes: 2 additions & 0 deletions src/__tests__/clanInventory/modules/clanInventoryCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ClanHelperService from '../../../clan/utils/clanHelper.service';
import GameEventEmitter from '../../../gameEventsEmitter/gameEventEmitter';
import { RoomScheduler } from '../../../clanInventory/room/room.scheduler';
import RoomRemovalNotifier from '../../../clanInventory/room/roomRemoval.notifier';
import RoomNotifier from '../../../clanInventory/room/room.notifier';

export default class ClanInventoryCommonModule {
private constructor() {}
Expand Down Expand Up @@ -59,6 +60,7 @@ export default class ClanInventoryCommonModule {
ItemHelperService,
StealTokenGuard,
RoomService,
RoomNotifier,
RoomHelperService,
RoomScheduler,
RoomRemovalNotifier,
Expand Down
Loading
Loading