feat(proj): init
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# 2026-09-20 — Мобильное приложение Please Pay Me собрано на iOS-ките
|
||||
|
||||
## Запрос
|
||||
«Собери теперь приложение please-pay-me, используя эти компоненты» — то есть поверх
|
||||
Cupertino-кита из прошлой сессии сделать рабочее приложение против существующего API.
|
||||
|
||||
## Что сделано
|
||||
|
||||
### Слой данных (`lib/data/`)
|
||||
- `models/` — `Budget`, `BudgetStatus` (+ вычисляемые `spentProgress` / `dailyProgress`),
|
||||
`Expense`, `ExpensesPage`, `Job`, `UpcomingPay`, `WeekendPolicy`, `AuthUser`, `AuthSession`.
|
||||
Зеркалят `web/src/types.ts`, парсятся через `models/json.dart` — толерантные
|
||||
коэрсеры (`int`/`double`/`string`), потому что API отдаёт числа из C#-рекордов.
|
||||
- `api/api_client.dart` — транспорт на `http`: Bearer-токен через `tokenProvider`,
|
||||
маппинг `detail`/`title` в `ApiException`, отдельная обработка 401 с колбэком
|
||||
`onUnauthorized` (разлогинивает сессию).
|
||||
- `repositories/` — интерфейсы `BudgetRepository` / `ExpenseRepository` /
|
||||
`JobRepository` / `UserRepository` + REST-реализации на все ручки `MeController`.
|
||||
- `demo/demo_backend.dart` — in-memory бэкенд, повторяющий математику конверта
|
||||
(`dailyLimit = remaining / daysLeft`). Используется в демо-режиме, превью и тестах;
|
||||
`DemoBackend.empty()` — для пустых состояний.
|
||||
|
||||
### Ядро (`lib/core/`)
|
||||
- `config/app_config.dart` — `PPM_API_BASE_URL`, `PPM_WEB_URL`, `PPM_DEMO` через
|
||||
`--dart-define`; пустой адрес API автоматически включает демо-режим.
|
||||
- `storage/session_storage.dart` — интерфейс + `SharedPreferences` и in-memory реализации.
|
||||
- `state/async_value.dart` — sealed `AsyncLoading/AsyncData/AsyncError` с `map(...)`,
|
||||
чтобы экраны матчились по состоянию, а не жонглировали тремя nullable-полями.
|
||||
- `format/formatters.dart` — деньги (`1 234,50 ₽`), русские плюрали, «Сегодня/Вчера».
|
||||
|
||||
### Состояние (`lib/features/*/`)
|
||||
- `SessionController` — владеет авторизацией и выдаёт репозитории (REST или demo),
|
||||
так что остальное приложение не знает про токены. `sessionKey` пересобирает
|
||||
фичевые контроллеры при входе/выходе.
|
||||
- `BudgetsController` — источник правды по конвертам (список, выбранный, мутации
|
||||
с авто-перезагрузкой, возврат текста ошибки вместо исключения).
|
||||
- `JournalController` — пагинация + группировка по дням + скоуп «текущий/все».
|
||||
- `JobsController` — работы и ближайшая выплата.
|
||||
|
||||
### Экраны (`lib/features/`, `lib/app/`)
|
||||
Пять вкладок: Обзор, Журнал, Бюджеты, Работа, Профиль (+ экран входа и сплэш).
|
||||
Формы — модальные шиты: новая/редактирование траты, бюджета, работы; все они
|
||||
принимают `onSubmit`, возвращающий текст ошибки, и не знают про репозитории.
|
||||
`_SessionGate` разводит `restoring / signedOut / signedIn`.
|
||||
|
||||
### Кит
|
||||
Удалены демо-экраны `lib/ui/screens/*`; добавлены `AppEmptyState`, `AppErrorView`,
|
||||
`AppLoadingView`, `showAppDatePicker`, `showAppFormSheet`.
|
||||
|
||||
### Widgetbook
|
||||
Папка Screens теперь показывает **настоящие экраны** приложения на `DemoScope`
|
||||
(demo-бэкенд + провайдеры), включая пустые состояния, формы и полный таб-бар.
|
||||
|
||||
### Авторизация — известное ограничение
|
||||
Telegram Login Widget работает только в вебе. Мобильный клиент принимает JWT из
|
||||
`localStorage.ppm_session_jwt` веб-кабинета и валидирует его через `GET /api/me`.
|
||||
Нативный вход (WebView с Telegram-виджетом либо one-time code через бота)
|
||||
не делался — это отдельное продуктовое решение.
|
||||
|
||||
## Тесты
|
||||
- `mobile`: 32 теста — парсинг моделей, форматтеры, все контроллеры на demo-бэкенде,
|
||||
виджет-сценарии (вход, табы, пустые состояния, запись траты end-to-end).
|
||||
- `mobile/widgetbook`: 100 — каждый use-case рендерится в light и dark.
|
||||
- `flutter analyze` по обоим пакетам — 0 issues.
|
||||
- `flutter build windows --debug` проходит (проверка плагинов shared_preferences/url_launcher).
|
||||
|
||||
## Запуск
|
||||
```powershell
|
||||
cd mobile
|
||||
.\run.ps1 # демо-данные
|
||||
.\run.ps1 -ApiBaseUrl https://ppm.example.com
|
||||
```
|
||||
Reference in New Issue
Block a user