Files
BalanceWatch/AGENTS.md
T
wt e73d4dd5e4
Build / Build (watchOS Simulator) (push) Canceled after 0s
Build / Build (watchOS Device) (push) Canceled after 0s
Create AGENTS.md
2026-10-30 12:29:10 +07:00

11 KiB
Raw Blame History

AGENTS.md — BalanceWatch

Этот файл — точка входа для AI-агентов и разработчиков. Прочитай его целиком перед любым изменением в репозитории.

Что это за проект

BalanceWatch — самостоятельное (watch-only) приложение для учёта личных финансов под watchOS 10+. Это клиент экосистемы Balance: те же сущности и тот же протокол синхронизации используют iOS/macOS-, Android- и web-клиенты, а синхронизируются все они через self-hosted сервер BalanceServer.

Проект выделен из монорепозитория Balance: туда входили таргет BalanceWatch и общий код, который этот таргет компилировал. Здесь этот код живёт как копия (см. раздел «Общий контракт»).

  • UI: SwiftUI, только системные компоненты.
  • Хранилище: SwiftData, только локально (cloudKitDatabase: .none).
  • Синхронизация: HTTP(S) к BalanceServer, сессия хранится в Keychain.
  • Внешних зависимостей (SPM/CocoaPods) нет — не добавляй их без явной необходимости.

Структура

BalanceWatch/
├── AGENTS.md
├── README.md
├── .github/workflows/build.yml   # CI: сборка для симулятора и устройства
├── BalanceWatch.xcodeproj/        # один таргет и одна схема — BalanceWatch
└── BalanceWatch/
    ├── App/
    │   ├── BalanceWatchApp.swift          # @main, ModelContainer, тема
    │   ├── WatchRootView.swift            # главный экран: баланс, месяц, навигация
    │   ├── WatchAddTransactionView.swift  # добавление операции
    │   └── WatchFeatures.swift            # аналитика, операции, бюджеты,
    │                                      # категории, корректировка баланса, настройки
    ├── Models/        # SwiftData-модели и системные категории
    ├── Shared/        # BalanceModelContainer, AppTheme,
    │                  # CategoryDesignOptions, ServerSync (ServerAccountStore)
    ├── Utilities/     # FinanceCalculations, форматирование валют и дат
    ├── Views/Components/CategoryIconView.swift
    └── Assets.xcassets

Xcode-проект

project.pbxproj использует папки, синхронизируемые с файловой системой (PBXFileSystemSynchronizedRootGroup, objectVersion 77, нужен Xcode 16+). Любой файл, положенный в BalanceWatch/, сам попадает в таргет:

  • чтобы добавить файл, просто создай его в нужной папке, project.pbxproj трогать не нужно;
  • project.pbxproj редактируй только ради build settings;
  • не клади в BalanceWatch/ файлы, которые не должны попасть в бандл (скрипты, документацию, тестовые данные).

Ключевые build settings: SDKROOT = watchos, WATCHOS_DEPLOYMENT_TARGET = 10.0, INFOPLIST_KEY_WKWatchOnly = YES, GENERATE_INFOPLIST_FILE = YES (своего Info.plist нет — ключи задаются через INFOPLIST_KEY_*), bundle id com.tolamironcenko.Balance.watchkitapp, SWIFT_VERSION = 5.0.

Правила разработки

1. Где что менять

Что Где
Экраны часов App/
Модель данных Models/ + Shared/BalanceModelContainer.swift
Финансовые правила Utilities/FinanceCalculations.swift
Авторизация и синхронизация Shared/ServerSync.swift
Переиспользуемые view Views/Components/

Не дублируй доменную логику во view: расчёты — в FinanceCalculations, сеть — в ServerAccountStore.

2. SwiftData

Схема зарегистрирована в BalanceModelContainer.schema: FinanceTransaction, MonthlyBudget, CustomCategory, SyncTombstone.

  • У пользователей уже есть локальные базы. Не удаляй и не переименовывай persisted-поля без стратегии миграции; новые поля делай со значением по умолчанию или опциональными.
  • Если основное хранилище не открылось, make() откатывается на in-memory контейнер BalanceRecovery. Не убирай этот fallback.
  • CloudKit не используется и не должен включаться: единственный источник синхронизации — BalanceServer.

3. Изменение и удаление записей

  • Любое изменение синхронизируемой сущности обязано обновлять syncUpdatedAt, иначе изменение не уйдёт на сервер.
  • Удаляй синхронизируемые сущности через modelContext.deleteForSync(...), а не через modelContext.delete(...): первый вариант пишет tombstone в SyncDeletionStore, и удаление доходит до других устройств.
  • Операции и бюджеты хранят snapshot категории (имя, иконка, emoji, цвет). При переименовании пользовательской категории связанные операции и бюджеты нужно обновить — сохраняй это поведение.

4. Финансовые правила

Центральные правила — в FinanceCalculations:

  • общий баланс = доходы − расходы;
  • операции с isBalanceAdjustment == true входят в общий баланс, но не входят в периодическую аналитику (месяц/3 мес./12 мес.);
  • расходы группируются по categoryName.

Эти правила одинаковы во всех клиентах Balance (Apple, Android, web). Не меняй их только здесь.

5. Синхронизация (общий контракт)

ServerAccountStore.shared — единственная точка входа для авторизации и синхронизации (register, login, logout, sync). Эндпоинты — v1/... на BalanceServer; sync устроен как push изменений после последнего push (транзакции → категории → бюджеты → tombstones), затем pull по cursor пачками (syncBatchSize, hasMore).

  • Формат JSON (SyncChange, SyncRequest, SyncResponse, payload'ы сущностей), семантика cursor/sequence и auth-заголовки — общий контракт со всеми клиентами и сервером. Изменение здесь без изменения сервера и остальных клиентов сломает синхронизацию.
  • При смене URL сервера сессия очищается, cursor/push-state сбрасываются, пользователь логинится заново (saveServer). Сохраняй это поведение.

6. Безопасность

  • Пароли не сохраняются нигде. Access/refresh токены — только в Keychain (KeychainStore), никогда не в UserDefaults, SwiftData или файлах.
  • Для удалённого сервера — только HTTPS. HTTP разрешён только для localhost, 127.0.0.1, ::1.
  • Не логируй пароли, токены и заголовок Authorization.
  • Не коммить секреты, production-URL и credentials.

7. UI на часах

  • Предпочитай NavigationStack, List, Form, короткие списки и компактные действия; крупный текст с minimumScaleFactor.
  • Строки интерфейса — на русском (developmentRegion = ru).
  • Акцентный цвет — .indigo; тема берётся из @AppStorage("appTheme") через AppTheme. Валюта — @AppStorage("currencyCode").
  • Ключи @AppStorage/UserDefaults не переименовывай: это сломает настройки у существующих пользователей.

Сборка и проверка

xcodebuild -project BalanceWatch.xcodeproj -scheme BalanceWatch \
  -destination 'generic/platform=watchOS Simulator' \
  CODE_SIGNING_ALLOWED=NO build

CI (.github/workflows/build.yml) собирает проект на macos-15 для симулятора и для устройства без подписи. Перед PR сборка должна быть зелёной в обоих вариантах.

Тестового таргета пока нет. Если добавляешь тесты, не завязывай их на текущую дату и локаль — явно фиксируй Calendar, Date и formatter'ы. Добавив тестовый таргет, добавь и шаг test в CI.

Чек-лист перед PR

  • Изменение лежит в правильном слое (App/, Models/, Shared/, Utilities/).
  • Persisted-поля SwiftData не сломаны, миграция продумана.
  • Изменённые синхронизируемые сущности обновляют syncUpdatedAt.
  • Удаления идут через deleteForSync.
  • Финансовые правила и sync-контракт не разошлись с остальными клиентами Balance.
  • Секреты и токены не попали в репозиторий и логи.
  • CI собирает проект для симулятора и для устройства.
  • README/AGENTS.md обновлены, если поменялась структура или сборка.