Валидация
Текущий подход: только клиентская валидация
Валидация выполняется только на клиенте. Серверных валидаторов бизнес-правил нет. Сервер (Supabase Postgres) обеспечивает только типы колонок, ограничения NOT NULL, политики RLS для владельца строк и правила синхронизации по пользователям.
| Слой | Фреймворк | Назначение |
|---|---|---|
| Клиент (браузер) | Zod v4 | UX форм - дефолты, трим, мгновенные ошибки; проверка формата данных на рантайме |
| Сервер (Supabase Postgres) | Типы колонок + RLS | Типы колонок, NOT NULL, владелец строки (политика RLS) |
Где живёт валидация
| Сущность / применение | Zod-схема |
|---|---|
| Форма транзакции | app/app/components/trns/types.ts (trnItemSchema, transactionSchema) + app/app/components/trnForm/utils/validate.ts |
| Конфиг статистики | app/app/components/stat/useStatConfig.ts (ConfigSchema) |
| Дата / query-параметры | app/app/components/date/statDateParams.ts (queryParamsSchema) |
| Настройки пользователя | app/app/components/user/types.ts (userSettingsSchema) |
| Формат курсов валют | app/app/components/currencies/types.ts (ratesSchema) |
| Локаль | app/app/components/locale/types.ts (localeSchema) |
Что проверяет каждая сторона
Zod (клиент):
.trim().min(1)- не пропускает пустые строки после трима.positive()на суммах.default()для начальных значений форм.transform()для парсинга query-параметров (строка в число / булево)- Discriminated union для типа транзакции (
trnItemSchema=transactionSchema | transferSchema) - Проверка одинаковых кошельков перевода:
incomeWalletId !== expenseWalletId
Supabase Postgres (сервер):
- Типы колонок:
text,numeric,integer,boolean,jsonb NOT NULLна обязательных колонках- RLS: каждая пользовательская таблица имеет
(select auth.uid())::text = "userId"- строки других пользователей невидимы, запись отклоняется - Таблица
ratesдоступна только для чтения аутентифицированным пользователям (без записи с клиента); строки пишет серверная edge-функцияfetch-rates - Триггер автоматически создаёт
user_settingsпри регистрации (начальная инициализация на сервере не нужна)
Серверных валидаторов бизнес-правил нет (нет серверных ограничений длины строк, диапазонов чисел, кросс-полевой валидации). Эти правила живут только в Zod-схемах на клиенте.
Компромисс
Целенаправленный клиент, обходящий форму, может записать произвольные данные в локальную SQLite, которые PowerSync загрузит в Supabase. Postgres примет их, если они проходят типы колонок и RLS. Это осознанный компромисс для однопользовательского приложения личных финансов - дублирование каждого бизнес-правила в виде Postgres-ограничений или политик RLS не оправдано по трудозатратам.
Если в будущем потребуется более строгая проверка, варианты:
- Postgres
CHECKограничения для диапазонов и длин - Supabase Edge Function как прокси загрузки с серверной Zod-валидацией
- Оценка, покрывает ли встроенная валидация Supabase (pg_jsonschema, check constraints) критические правила
Следующие шаги
- Тех. решения - связанные архитектурные решения и их обоснование
- Архитектура - структура проекта и паттерн хранилищ