feat: add AppLayout, BrandLogo, ProfileMenu, and RouteBadge components
- Implemented AppLayout component for application shell with navigation and sidebar. - Created BrandLogo component to display the application logo. - Developed ProfileMenu component for user profile management with dropdown functionality. - Added RouteBadge component to visually represent route numbers with color coding. style: add CSS styles for Dashboard and Routes pages - Introduced Dashboard.css for styling the dashboard layout and components. - Created RoutesPage.css for styling the routes page, including filters and table layout. - Added SchedulesPage.css for styling the schedules layout and route options.
This commit is contained in:
@@ -155,45 +155,48 @@ GOOGLE_APPLICATION_CREDENTIALS=/absolute/private/path/firebase-service-account.j
|
||||
После этого запустите `npm run dev`. Не копируйте JSON в `backend/`, не
|
||||
добавляйте его в `.env` в виде текста и не коммитьте файл.
|
||||
|
||||
### Локальный запуск в Docker Compose
|
||||
### Запуск в Docker Compose на Proxmox
|
||||
|
||||
Значение `GOOGLE_APPLICATION_CREDENTIALS` внутри контейнера должно указывать на
|
||||
путь внутри контейнера, поэтому одного host-пути в корневом `.env` недостаточно.
|
||||
Создайте локальный, не коммитящийся файл
|
||||
`docker-compose.firebase.override.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
environment:
|
||||
FCM_ENABLED: "true"
|
||||
FIREBASE_PROJECT_ID: ridebus-development
|
||||
GOOGLE_APPLICATION_CREDENTIALS: /run/secrets/firebase-service-account.json
|
||||
volumes:
|
||||
- /absolute/private/path/firebase-service-account.json:/run/secrets/firebase-service-account.json:ro
|
||||
```
|
||||
|
||||
Запуск:
|
||||
Docker должен работать внутри VM или LXC-контейнера Proxmox. На этом Docker-
|
||||
хосте создайте закрытый каталог и положите в него service account JSON:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f docker-compose.yml \
|
||||
-f docker-compose.firebase.override.yml \
|
||||
up -d --build backend
|
||||
sudo install -d -m 700 /opt/polotsk-transit/secrets
|
||||
sudo install -m 600 /private/path/firebase-service-account.json \
|
||||
/opt/polotsk-transit/secrets/firebase-service-account.json
|
||||
```
|
||||
|
||||
Основной `docker-compose.yml` передаёт все FCM-переменные, но не требует и не
|
||||
монтирует credential-файл. Поэтому обычный запуск с `FCM_ENABLED=false`
|
||||
остается рабочим без Firebase.
|
||||
В корневом `.env` проекта задайте:
|
||||
|
||||
```env
|
||||
FCM_ENABLED=true
|
||||
FCM_TOPIC=route_alerts
|
||||
FCM_ANDROID_CHANNEL_ID=route_alerts
|
||||
FIREBASE_PROJECT_ID=ridebus-production
|
||||
FIREBASE_SECRETS_DIR=/opt/polotsk-transit/secrets
|
||||
GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/firebase-service-account.json
|
||||
```
|
||||
|
||||
Основной `docker-compose.yml` монтирует `FIREBASE_SECRETS_DIR` в backend как
|
||||
read-only `/run/secrets`. Запуск отдельного override-файла больше не требуется:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build backend
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
При `FCM_ENABLED=false` Firebase не инициализируется, поэтому отсутствие JSON
|
||||
не мешает работе приложения.
|
||||
|
||||
## Формирование сообщения
|
||||
|
||||
FCM получает одновременно видимый `notification` payload и строковый `data`
|
||||
payload. Android priority всегда `high`. Все значения в `data`, включая ID и
|
||||
даты, преобразуются в строки; отсутствующие значения передаются как пустые
|
||||
строки.
|
||||
FCM получает только строковый `data` payload. Верхнеуровневого `notification`
|
||||
и `android.notification` нет, поэтому Android-клиент сам создаёт уведомление и
|
||||
может добавить локальные действия, включая кнопку «Прочитано». Android
|
||||
priority всегда `high`. Все значения в `data`, включая ID, даты, заголовок и
|
||||
текст, являются строками; отсутствующие значения передаются как пустые строки.
|
||||
|
||||
`notification.title` берётся из `alert.title`. Если заголовок отсутствует или
|
||||
`data.title` берётся из `alert.title`. Если заголовок отсутствует или
|
||||
состоит только из пробелов, используется fallback по типу:
|
||||
|
||||
| `alert_type` | Fallback title |
|
||||
@@ -203,7 +206,7 @@ payload. Android priority всегда `high`. Все значения в `data`
|
||||
| `detour` | `Изменение маршрута` |
|
||||
| `info` | `Информация о маршруте` |
|
||||
|
||||
`notification.body` содержит `alert.message`. Для пустого сообщения
|
||||
`data.body` содержит `alert.message`. Для пустого сообщения
|
||||
используется безопасный текст с номером маршрута, а если маршрут не указан —
|
||||
общий текст об обновлении движения.
|
||||
|
||||
@@ -212,10 +215,6 @@ payload. Android priority всегда `high`. Все значения в `data`
|
||||
```json
|
||||
{
|
||||
"topic": "route_alerts",
|
||||
"notification": {
|
||||
"title": "Задержка движения",
|
||||
"body": "Автобусы задерживаются примерно на 15 минут"
|
||||
},
|
||||
"data": {
|
||||
"event": "alert_created",
|
||||
"alertId": "42",
|
||||
@@ -223,14 +222,12 @@ payload. Android priority всегда `high`. Все значения в `data`
|
||||
"routeId": "7",
|
||||
"routeNumber": "5",
|
||||
"startTime": "2026-07-11T09:00:00.000Z",
|
||||
"endTime": "2026-07-11T11:00:00.000Z"
|
||||
"endTime": "2026-07-11T11:00:00.000Z",
|
||||
"title": "Задержка движения",
|
||||
"body": "Автобусы задерживаются примерно на 15 минут"
|
||||
},
|
||||
"android": {
|
||||
"priority": "high",
|
||||
"notification": {
|
||||
"channelId": "route_alerts",
|
||||
"tag": "alert_42"
|
||||
}
|
||||
"priority": "high"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -295,5 +292,5 @@ curl -i -X POST http://localhost:3000/api/v1/alerts \
|
||||
вернуть `201`, а лог должен содержать `alertId`, Firebase code и причину без
|
||||
credentials или токенов.
|
||||
|
||||
Поведение Android при foreground/background зависит от клиентской реализации,
|
||||
но серверный контракт всегда содержит и `notification`, и `data` payload.
|
||||
Поведение Android при foreground/background полностью определяется клиентской
|
||||
обработкой data-only сообщения.
|
||||
|
||||
Reference in New Issue
Block a user