Tmavý režim
Profil (/profile)
Správa uživatelského profilu, per-aplikačních preferencí, notifikačních preferencí a Web Push subscripcí.
Lazy vytváření
Profil a preference se vytvářejí automaticky při prvním přístupu — není potřeba žádná explicitní inicializace.
GET /profile/me — vlastní profil
Vrátí globální profil přihlášeného uživatele. Pokud profil neexistuje, vytvoří se automaticky.
http
GET /api/profile/me
Authorization: Bearer <token>Response
json
{
"success": true,
"data": {
"id": 42,
"email": "jan.novak@firma.cz",
"displayName": "Jan Novák",
"avatarUrl": "https://example.com/avatar.jpg",
"locale": "cs",
"theme": "light",
"brand": "atrea",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}| Pole | Hodnoty | Výchozí |
|---|---|---|
locale | "cs", "en", ... | "cs" |
theme | "light", "dark", "system" | "light" |
brand | slug brandu (např. "atrea", "vallox") | "atrea" |
PUT /profile/me — aktualizace profilu
http
PUT /api/profile/me
Authorization: Bearer <token>
Content-Type: application/jsonRequest body
json
{
"displayName": "Jan Novák",
"avatarUrl": "https://example.com/avatar.jpg",
"locale": "cs",
"theme": "dark",
"brand": "vallox"
}Všechna pole jsou volitelná — aktualizují se pouze ta, která pošlete.
GET /profile/me/admin-status — admin status
Vrátí kompletní admin/role profil přihlášeného uživatele — FE z toho rozhoduje, které admin záložky zobrazit, bez extra requestů.
http
GET /api/profile/me/admin-status
Authorization: Bearer <token>Response
json
{
"code": "OK",
"response": {
"email": "jan.novak@firma.cz",
"isSuperAdmin": false,
"appAdminFor": ["kgb", "ui-template"],
"roles": [
{ "appCode": "kgb", "roleCodes": ["designer"] },
{ "appCode": "ui-template", "roleCodes": ["user"] }
]
}
}| Pole | Typ | Význam |
|---|---|---|
isSuperAdmin | boolean | Uživatel je v super_admins. |
appAdminFor | string[] | Seznam appCode, kde má uživatel záznam v app_admins. |
roles | Array<{ appCode, roleCodes }> | Globální role uživatele přes user_app_roles. |
Migrace ze starší verze
Dříve endpoint vracel pouze { isSuperAdmin, email }. Nová pole jsou aditivní — staré klienty stále fungují, ale FE už nemusí pro každou aplikaci dotazovat /users/admins/apps/....
GET /profile/me/apps — všechny per-app preference
http
GET /api/profile/me/apps
Authorization: Bearer <token>Response
json
{
"success": true,
"data": [
{
"applicationCode": "crm",
"showHelp": true,
"notificationsEnabled": true
},
{
"applicationCode": "vallox-panel",
"showHelp": false,
"notificationsEnabled": false
}
]
}GET /profile/me/apps/:appCode — per-app preference
Vrátí preference pro konkrétní aplikaci. Pokud preference neexistují, vytvoří se s výchozími hodnotami.
http
GET /api/profile/me/apps/crm
Authorization: Bearer <token>Response
json
{
"success": true,
"data": {
"applicationCode": "crm",
"showHelp": true,
"notificationsEnabled": true
}
}PUT /profile/me/apps/:appCode — aktualizace per-app preference
http
PUT /api/profile/me/apps/crm
Authorization: Bearer <token>
Content-Type: application/jsonRequest body
json
{
"showHelp": false,
"notificationsEnabled": true
}| Pole | Typ | Popis |
|---|---|---|
showHelp | boolean | Zobrazovat nápovědu v UI |
notificationsEnabled | boolean | Globální přepínač notifikací pro tuto aplikaci |
GET /profile/:email — profil jiného uživatele (admin)
http
GET /api/profile/jan.novak@firma.cz
Authorization: Bearer <admin-token>Auth: JWT + AppAdmin nebo SuperAdmin
Notifikační preference
GET /profile/me/notifications/:appCode
Vrátí per-type notifikační preference pro aplikaci.
http
GET /api/profile/me/notifications/crm
Authorization: Bearer <token>Response
json
{
"code": "OK",
"response": [
{
"notificationTypeId": 1,
"code": "new_task",
"name": "Nový úkol",
"description": "Notifikace o přidělení nového úkolu (může být null).",
"emailEnabled": true,
"pushEnabled": true,
"userCanDisable": true,
"email": true,
"push": false
}
]
}| Pole | Typ | Význam |
|---|---|---|
description | string | null | Vždy explicitní null, nikdy undefined — FE může zobrazit přímo. |
emailEnabled / pushEnabled | boolean | Master switch z admin konfigurace (kanál povolen pro aplikaci). |
userCanDisable | boolean | Pokud false, UI musí přepínače skrýt nebo zamknout. |
email / push | boolean | Aktuální stav přepínače pro uživatele (default z defaultEmail/defaultPush). |
Seed generic typu
Každá aplikace má automaticky seedovaný notifikační typ generic (idempotent při init + nově při POST /applications). Díky tomu se v UI hned objeví přepínač pro testovací notifikace bez ručního seedu.
PUT /profile/me/notifications/preferences/bulk — bulk update
http
PUT /api/profile/me/notifications/preferences/bulk
Authorization: Bearer <token>
Content-Type: application/jsonjson
{
"updates": [
{ "notificationTypeId": 1, "email": true, "push": true },
{ "notificationTypeId": 2, "email": false }
]
}PUT /profile/me/notifications/preferences/:notificationTypeId — jeden typ
http
PUT /api/profile/me/notifications/preferences/1
Authorization: Bearer <token>
Content-Type: application/jsonjson
{
"email": true,
"push": false
}WARNING
Uživatel může měnit preference pouze pro typy, kde userCanDisable = true. Pro ostatní typy vrátí API chybu 403.
Web Push subscripce
GET /profile/me/push/vapid-key — VAPID public key
Vrátí VAPID public key pro inicializaci Web Push v prohlížeči.
http
GET /api/profile/me/push/vapid-key
Authorization: Bearer <token>Response
json
{
"success": true,
"data": {
"vapidPublicKey": "BM8U3B..."
}
}POST /profile/me/push/subscribe — registrace subscripce
http
POST /api/profile/me/push/subscribe
Authorization: Bearer <token>
Content-Type: application/jsonjson
{
"subscription": {
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"keys": {
"p256dh": "BMutZ...",
"auth": "Kd9..."
}
},
"deviceLabel": "Můj notebook Chrome"
}POST /profile/me/push/unsubscribe — odregistrování
http
POST /api/profile/me/push/unsubscribe
Authorization: Bearer <token>
Content-Type: application/jsonjson
{
"endpoint": "https://fcm.googleapis.com/fcm/send/..."
}GET /profile/me/push/subscriptions — seznam subscripcí
http
GET /api/profile/me/push/subscriptions
Authorization: Bearer <token>Response
json
{
"code": "OK",
"response": [
{
"id": 12,
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"deviceLabel": "Můj notebook Chrome",
"lastUsedAt": "2026-05-10T08:22:13.000Z",
"createdAt": "2024-01-20T10:00:00.000Z",
"updatedAt": "2026-05-10T08:22:13.000Z"
}
]
}| Pole | Typ | Význam |
|---|---|---|
lastUsedAt | string | null | Časová značka posledního úspěšného doručení (null, dokud z této subscripce nešel push). |
DELETE /profile/me/push/subscriptions/:id — smazat jedno zařízení
Smaže subscription podle numerického id. Vlastnictví je vynuceno tokenem.
http
DELETE /api/profile/me/push/subscriptions/12
Authorization: Bearer <token>http
204 No ContentAuto-cleanup
Při send-time se subscription, která vrátí HTTP 410 Gone nebo 404, automaticky smaže z DB, takže mrtvé záznamy nezůstávají.
Viz Web Push pro kompletní dokumentaci Web Push integrace.
In-app inbox
Notifikace se logují do notifications tabulky. Inbox endpointy nad ní vystavují historii pro UI (read/unread, mark read).
GET /profile/me/notifications/inbox
Vrátí poslední notifikace doručené aktuálnímu uživateli.
http
GET /api/profile/me/notifications/inbox?limit=50&unreadOnly=true&appCode=kgb
Authorization: Bearer <token>| Query param | Typ | Default | Význam |
|---|---|---|---|
limit | int (1–200) | 50 | Max počet položek. |
unreadOnly | bool | false | Pouze nepřečtené. |
appCode | string | — | Zúžit na jednu aplikaci. |
json
{
"code": "OK",
"response": [
{
"id": 421,
"appCode": "kgb",
"appName": "KGB",
"type": "project_shared",
"subject": "Sdílený projekt: Bytovka Praha",
"status": "sent",
"statusReason": null,
"locale": "cs",
"readAt": null,
"createdAt": "2026-05-12T09:14:00.000Z",
"payload": { "projectName": "Bytovka Praha" }
}
]
}GET /profile/me/notifications/inbox/unread-count
Levný počet nepřečtených pro badge v UI.
json
{ "code": "OK", "response": { "count": 3 } }PATCH /profile/me/notifications/inbox/:id/read
Označí jednu položku za přečtenou. Vrací 204 No Content.
POST /profile/me/notifications/inbox/read-all
Označí všechny nepřečtené za přečtené, volitelně zúženo na { appCode }. Vrací { updated: number }.