feat(settings): add device-specific settings storage

Implement per-device settings sync via mana-core-auth. Settings are now
stored both locally (localStorage) and in the cloud, with each device
(desktop, mobile, tablet) maintaining its own configuration.

Changes:
- Add deviceSettings JSONB column to user_settings table
- Add device API endpoints (GET/PATCH/DELETE /settings/device/:id/:app)
- Extend user-settings-store with device ID generation and detection
- Integrate calendar settings with cloud sync per device
- Remove todos from calendar header row (sidebar + grid only)
- Add hours dropdown to CalendarHeader for time range configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-12-11 23:49:18 +01:00
parent 5921cfd257
commit c6f8b9f87c
11 changed files with 863 additions and 416 deletions

View file

@ -3,7 +3,7 @@ import { SettingsService } from './settings.service';
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import type { CurrentUserData } from '../common/decorators/current-user.decorator';
import { UpdateGlobalSettingsDto } from './dto';
import { UpdateGlobalSettingsDto, UpdateDeviceAppSettingsDto } from './dto';
import type { UpdateAppOverrideDto } from './dto';
@Controller('settings')
@ -13,7 +13,7 @@ export class SettingsController {
/**
* GET /api/v1/settings
* Get all user settings (global + app overrides)
* Get all user settings (global + app overrides + device settings)
*/
@Get()
async getSettings(@CurrentUser() user: CurrentUserData) {
@ -69,4 +69,95 @@ export class SettingsController {
...settings,
};
}
// ============================================================================
// Device Settings Endpoints
// ============================================================================
/**
* GET /api/v1/settings/devices
* List all devices for the current user
*/
@Get('devices')
async getDevices(@CurrentUser() user: CurrentUserData) {
const result = await this.settingsService.getDevices(user.userId);
return {
success: true,
...result,
};
}
/**
* GET /api/v1/settings/device/:deviceId/:appId
* Get settings for a specific device and app
*/
@Get('device/:deviceId/:appId')
async getDeviceAppSettings(
@CurrentUser() user: CurrentUserData,
@Param('deviceId') deviceId: string,
@Param('appId') appId: string
) {
const settings = await this.settingsService.getDeviceAppSettings(user.userId, deviceId, appId);
return {
success: true,
settings,
};
}
/**
* PATCH /api/v1/settings/device/:deviceId/:appId
* Update settings for a specific device and app
*/
@Patch('device/:deviceId/:appId')
async updateDeviceAppSettings(
@CurrentUser() user: CurrentUserData,
@Param('deviceId') deviceId: string,
@Param('appId') appId: string,
@Body() dto: UpdateDeviceAppSettingsDto
) {
const settings = await this.settingsService.updateDeviceAppSettings(
user.userId,
deviceId,
appId,
dto
);
return {
success: true,
...settings,
};
}
/**
* DELETE /api/v1/settings/device/:deviceId
* Remove a device entirely
*/
@Delete('device/:deviceId')
async removeDevice(@CurrentUser() user: CurrentUserData, @Param('deviceId') deviceId: string) {
const settings = await this.settingsService.removeDevice(user.userId, deviceId);
return {
success: true,
...settings,
};
}
/**
* DELETE /api/v1/settings/device/:deviceId/:appId
* Remove app settings from a specific device
*/
@Delete('device/:deviceId/:appId')
async removeDeviceAppSettings(
@CurrentUser() user: CurrentUserData,
@Param('deviceId') deviceId: string,
@Param('appId') appId: string
) {
const settings = await this.settingsService.removeDeviceAppSettings(
user.userId,
deviceId,
appId
);
return {
success: true,
...settings,
};
}
}