1. Проектирование архитектуры и базы данных для учета аренды и ЖКХ
Проектирование архитектуры и базы данных для учета аренды и ЖКХ
Любое надежное мобильное приложение начинается с фундамента — грамотно спроектированной архитектуры и структуры хранения данных. Приложение для учета аренды и жилищно-коммунальных услуг (ЖКХ) работает с финансовыми показателями, историей платежей и тарифами. Ошибка в проектировании на начальном этапе приведет к тому, что при изменении стоимости киловатта электроэнергии у пользователей «поедет» вся история предыдущих расчетов.
Архитектура программного обеспечения — это совокупность важнейших решений об организации системы, выборе структурных элементов и их интерфейсов. В контексте мобильной разработки на фреймворке Flutter правильная архитектура позволяет разделить визуальную часть (кнопки, списки) и бизнес-логику (расчеты, сохранение в базу).
Выбор архитектурного паттерна
Для масштабируемых проектов в экосистеме Flutter стандартом де-факто является Clean Architecture (Чистая архитектура), часто в связке со стейт-менеджером BLoC (Business Logic Component). Этот подход делит приложение на независимые слои.
> Архитектура определяет структуру, взаимосвязь между компонентами и их взаимодействия. Четко разработанная архитектура не только упрощает процесс разработки, но и обеспечивает масштабируемость, гибкость и удобство сопровождения кода. > > Архитектура Flutter проекта простым языком
В нашем приложении мы выделим три основных слоя:
!Схема слоев Чистой архитектуры в приложении
Использование паттерна Репозиторий (Repository) позволяет скрыть от бизнес-логики то, откуда именно берутся данные. Доменный слой просто запрашивает getTariffs(), а репозиторий сам решает, достать их из локальной базы данных устройства или скачать с сервера.
Проектирование базы данных
Поскольку приложение должно вести строгий учет финансов и показаний, нам требуется реляционная база данных. В мобильной разработке для локального хранения чаще всего используется SQLite. Реляционная модель позволяет жестко связать арендаторов, их счетчики и справочник тарифов.
Сравним подходы к хранению данных, чтобы обосновать наш выбор:
| Характеристика | Реляционные БД (SQLite) | NoSQL БД (Hive, SharedPreferences) | | :--- | :--- | :--- | | Структура данных | Строгие таблицы со связями | Гибкие документы (JSON) | | Сложные запросы | Поддерживаются (JOIN, агрегация) | Ограничены или отсутствуют | | Целостность данных | Высокая (внешние ключи) | Зависит от кода приложения | | Применение в нашем проекте | Идеально для связи тарифов, показаний и платежей | Подходит только для сохранения настроек темы (светлая/темная) |
Основные сущности и таблицы
Для реализации требований необходимо спроектировать несколько взаимосвязанных таблиц. Каждая таблица представляет собой отдельную сущность.
1. Таблица арендаторов (Tenants)
Хранит базовую информацию о квартиросъемщиках.
* id — уникальный идентификатор;
* name — ФИО или название;
* apartment_number — номер квартиры или комнаты;
* base_rent — фиксированная сумма арендной платы.
2. Справочник тарифов (Tariffs)
Вынесение тарифов в отдельный справочник — критически важное архитектурное решение. Тарифы меняются (обычно раз в год), и если мы будем хранить стоимость киловатта прямо в таблице платежей, мы не сможем гибко управлять историей.
* id — идентификатор тарифа;
* service_type — тип услуги (электричество, холодная вода, горячая вода);
* rate — стоимость за единицу (например, за 1 кВт·ч или 1 куб. м);
* effective_date — дата, с которой тариф вступает в силу.
3. Показания счетчиков (MeterReadings)
Фиксирует данные приборов учета на определенную дату.
* id — идентификатор записи;
* tenant_id — ссылка на арендатора (внешний ключ);
* service_type — тип услуги;
* value — показание счетчика;
* reading_date — дата снятия показаний.
4. Платежи (Payments)
Объединяет все начисления и фактические оплаты.
* id — идентификатор платежа;
* tenant_id — ссылка на арендатора;
* amount — сумма;
* payment_type — тип (аренда, электричество, вода);
* status — статус (оплачено, ожидается, просрочено);
* created_at — дата формирования счета.
Математика расчетов ЖКХ
Бизнес-логика приложения опирается на точные математические расчеты. Когда пользователь вводит новые показания счетчика, приложение должно найти предыдущее показание, вычислить разницу и умножить ее на актуальный тариф.
Формула расчета стоимости потребленного ресурса выглядит следующим образом:
Где: * — итоговая стоимость к оплате (Cost); * — текущие (новые) показания счетчика; * — предыдущие показания счетчика; * — ставка тарифа из справочника, актуальная на дату снятия показаний.
Рассмотрим на конкретном примере с числами. Допустим, в прошлом месяце показания счетчика электроэнергии составляли 1540 кВт·ч. В текущем месяце квартиросъемщик прислал фото счетчика с цифрой 1690 кВт·ч. В справочнике тарифов указано, что стоимость 1 кВт·ч составляет 5 рублей.
Сначала находим объем потребления: 1690 - 1540 = 150 кВт·ч. Затем умножаем объем на тариф: 150 × 5 = 750 рублей. Именно эта сумма должна быть записана в таблицу Payments со статусом «ожидается».
!Интерактивный калькулятор расчета стоимости услуг ЖКХ по показаниям счетчиков
Связь базы данных и интерфейса
Чтобы данные из таблиц попали на экран смартфона, они должны пройти через все слои архитектуры. Процесс выглядит так:
Сначала пользователь открывает экран «Детали арендатора». Виджет отправляет событие LoadTenantDetails в контроллер состояния (BLoC). Контроллер обращается к доменному слою (Use Case), который запрашивает данные у Репозитория.
Репозиторий выполняет SQL-запрос к локальной базе данных SQLite. Например, чтобы получить историю платежей конкретного человека, выполняется запрос с использованием оператора WHERE tenant_id = 1. База данных возвращает сырые строки, которые Репозиторий преобразует в удобные объекты языка Dart (модели данных). Эти объекты передаются обратно в контроллер, который обновляет состояние экрана, и пользователь видит красивый список платежей.
Разделение тарифов и показаний счетчиков позволяет реализовать сложный, но необходимый функционал: перерасчет. Если выяснится, что тариф изменился задним числом, приложение сможет пройтись по таблице MeterReadings, взять разницу показаний и умножить на новое значение из таблицы Tariffs, автоматически обновив суммы в таблице Payments.
Проектирование базы данных — это процесс создания цифрового слепка реального мира. Чем точнее таблицы и связи отражают реальные процессы аренды и оплаты ЖКХ, тем проще будет добавлять новые функции в приложение в будущем.