bloc_concurrency
Custom event transformers inspired by ember concurrency. Built to be used with the bloc state management package.
A mobile application for the MIREA - Russian Technological University, which includes a schedule, news and many other functions
Custom event transformers inspired by ember concurrency. Built to be used with the bloc state management package.
An extension to the bloc state management library which automatically persists and restores bloc states.
Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.
Flutter plugin for Google Analytics for Firebase, an app measurement solution that provides insight on app usage and user engagement on Android and iOS.
Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS.
A builder that supports generated strongly-typed route helpers for package:go_router
v5.9.3A flutter plugin for adapting screen and font size.Guaranteed to look good on different models
v8.3.2Flutter's №1 non-commercially aimed map client: it's easy-to-use, versatile, vendor-free, fully cross-platform, and 100% pure-Flutter
v10.1.0Official extension image, support placeholder(loading)/ failed state, cache network, zoom/pan, photo view, slide out page, editor(crop,rotate,flip), painting etc.
v3.2.1Highly customizable, feature-packed calendar widget for Flutter.
A Flutter widget for rendering static HTML and CSS as Flutter widgets.
v3.0.0This extension package allows the
{"path":"packages/academic_calendar"}^1.0.1^3.5.0{"path":"packages/ads_ui"}^1.1.0{"path":"packages/analytics_repository"}^7.0.0{"path":"packages/app_ui"}{"path":"packages/article_repository"}^9.2.0^0.3.0^4.1.3^5.1.1^3.2.0^3.0.0{"path":"packages/campus_repository"}^5.0.0^1.16.2^1.1.2^1.18.0{"path":"packages/community_catalog_repository"}{"path":"packages/community_repository"}{"path":"packages/connectivity_client"}^1.0.2{"path":"packages/deep_link_client"}{"git":{"url":"https://github.com/0niel/device_calendar.git","ref":"develop"}}^5.1.2^1.0.2{"git":{"url":"https://github.com/0niel/dot_navigation_bar.git","ref":"master"}}^0.6.0^1.1.1^2.0.5^10.0.1^12.0.0-beta.4^2.0.0^12.1.2^4.4.0^16.1.1^1.1.1{"sdk":"flutter"}^4.5.0^9.1.1^3.3.1^3.0.0-beta.2^3.0.0-beta.2^3.0.0-beta.2^3.0.0-beta.2^3.0.0-beta.2^2.0.8{"sdk":"flutter"}^8.2.2^3.1.0+7447^2.4.3^3.3.1^11.5.1^11.0.0^5.9.3^10.0.0^1.1.0^0.7.0^0.8.0^2.0.5^6.0.0{"sdk":"flutter"}^0.8.03.1.0{"path":"packages/friends_repository"}{"path":"packages/gamification_repository"}^14.0.2^17.1.00.9.1^1.2.2^1.1.5^11.0.0^1.1.2^0.20.24.12.0^0.9.1{"path":"packages/local_auth_client"}{"path":"packages/local_notifications_client"}{"path":"packages/local_notifications_repository"}^2.0.2+1^1.1.1{"path":"packages/lost_and_found_repository"}^0.5.0^1.15.0^2.0.0{"path":"packages/mini_apps_repository"}^7.2.0{"path":"packages/network_location_client"}{"path":"packages/news_blocks"}{"path":"packages/news_blocks_ui"}{"path":"packages/news_repository"}{"path":"packages/nfc_pass_client"}{"path":"packages/nfc_pass_repository"}^4.4.0{"path":"packages/package_info_client"}^10.1.0^1.0.0^1.0.1^2.1.13.12.0^2.11.0^2.5.2+1{"path":"packages/permission_client"}{"path":"packages/storage/persistent_storage"}^0.15.0^3.0.2{"path":"packages/preferences_repository"}{"path":"packages/promo_repository"}^4.1.0^3.0.0^1.5.1^0.28.0^3.3.2{"path":"packages/schedule"}{"path":"packages/schedule_exporter_repository"}{"path":"packages/schedule_repository"}{"path":"packages/storage/secure_storage"}9.20.09.20.09.20.0{"path":"packages/service_catalog_repository"}{"path":"packages/share_launcher"}^13.1.0^2.0.11^0.2.12^1.0.2^7.4.0{"path":"packages/stac_bridge"}{"path":"packages/storage/storage"}^1.1.0^2.1.1{"path":"packages/study_groups_repository"}{"path":"packages/auth_client/supabase_authentication_client"}^2.8.3^32.1.23^32.2.3^3.0.3^0.10.0{"path":"packages/auth_client/token_storage"}^1.3.3any^2.0.0^0.1.0{"path":"packages/university_provider"}^6.1.12{"path":"packages/user_repository"}^4.5.3^0.9.0^2.9.2^0.4.0+20.2.9^6.6.1^8.0.0^1.1.2^1.1.2^10.0.02.15.1any^5.3.2^0.14.1{"sdk":"flutter"}3.2.5^4.1.16.14.0^1.0.5^2.4.210.3.03.1.3English project snapshot. Visit GitHub for the latest content.
Открытая платформа студенческого приложения на Flutter. Репозиторий можно адаптировать под другой университет без форка бизнес-логики: tenant, публичный брендинг и deep links задаются конфигурацией, а университетские источники данных подключаются через нормализованный ingest-контракт Supabase.
Конфигурация по умолчанию сохраняет совместимость с РТУ МИРЭА. Встроенный MIREA-фетчер выключен по умолчанию и не должен использоваться для другого tenant.
lib/<feature>, а
переиспользуемые клиенты, модели и репозитории — в Dart workspace packages/.bloc/hydrated_bloc для состояния, yx_scope для dependency injection и
go_router для навигации.json_serializable для генерируемых immutable-моделей и JSON DTO.Основной поток данных:
внешний источник -> Python worker -> Edge Function /ingest
-> Supabase RPC/таблицы -> repository -> BLoC -> Flutter UI
Flutter не должен обращаться к внутренним таблицам или использовать
service_role. Привилегированная запись контента проходит через защищённую
функцию supabase/functions/ingest, а схема БД
изменяется только миграциями из
supabase/migrations.
Нужны Flutter, FVM и Java 17 для
Android. Версия Flutter закреплена в .fvmrc.
dart pub global activate fvm
fvm install
fvm flutter pub get
Создайте две локальные compile-time конфигурации:
cp .env.example .env
cp config/university.example.json config/university.local.json
В PowerShell используйте Copy-Item вместо cp. В .env укажите публичные
SUPABASE_URL и SUPABASE_PUBLISHABLE_KEY. В
config/university.local.json задайте tenant и брендинг. Затем проверьте
конфигурацию и сгенерируйте код:
fvm dart run tool/configure_university.dart
fvm dart run build_runner build
Запуск development flavor на Android/iOS/macOS:
fvm flutter run \
--flavor development \
--target lib/main/main_development.dart \
--dart-define-from-file=.env \
--dart-define-from-file=config/university.local.json \
--dart-define-from-file=config/firebase.local.json
Firebase-файл опционален: без него Analytics и FCM корректно отключаются.
Нативные google-services.json, GoogleService-Info.plist и сгенерированный
firebase_options.dart не являются частью открытого исходного кода.
Для Windows уберите --flavor development. Подробности о схеме конфигурации и
режиме --check описаны в
docs/university-configuration.md.
Локальные .env, tenant-файлы, Firebase-конфигурация, ключи подписи и Telegram
session-файлы нельзя коммитить. Пример university config содержит только
публичные значения и не заменяет настройку собственных Firebase/Supabase
проектов.
Локальная конфигурация находится в supabase/config.toml. Для работы с
миграциями нужен Supabase CLI и Docker:
supabase start
supabase db reset
Не изменяйте уже применённые миграции: создавайте новую через
supabase migration new <name>. Секрет ingest-функции хранится только на
сервере и в локальном окружении worker.
Для одного tenant задайте Edge secrets INGEST_API_KEY и
INGEST_ORGANIZATION_ID. Общий backend нескольких университетов должен
использовать INGEST_TENANT_KEYS — JSON-карту organization_id к отдельному
ключу каждого worker. Не используйте один неприкреплённый ключ для всех tenant.
Worker находится в tools/social_media_fetcher и использует
uv. Он нормализует контент и отправляет его в
Edge ingest; напрямую в БД не пишет.
Для RSS/Atom и официальных API предпочтителен no-code путь через self-hosted
n8n: импортируйте готовый
rss-to-ingest.json и
используйте HTTP Request node для Facebook Graph API, YouTube, Mastodon или
иного документированного API. Python-коннектор оставлен для источников, которым
нужна пользовательская сессия или особая обработка, например Telegram Stories.
Полный контракт и правила расширения — в
tools/social_media_fetcher/docs/architecture.md.
cd tools/social_media_fetcher
cp .env.example .env
uv sync --locked
uv run python worker.py
MIREA_ENABLED=true допустим только при APP_ORGANIZATION_ID=mirea. Telegram
подключается явно через TELEGRAM_CHANNELS и TELEGRAM_STORY_CHANNELS. Для
пользовательской Telegram-сессии используйте отдельный согласованный аккаунт и
setup_telegram_session.py; полученный session string считается секретом и не
должен попадать в логи, issues или Git.
Stories-медиа загружается только через подписанные Storage URL. Workflow
cleanup-story-media.yml независимо от Telegram-сессии удаляет истёкшие и
осиротевшие объекты; для него задаются SUPABASE_URL,
INGEST_ORGANIZATION_ID и tenant-bound INGEST_API_KEY.
fvm dart analyze --fatal-warnings
fvm flutter test
cd tools/social_media_fetcher
uv run ruff format --check .
uv run ruff check .
uv run pytest
CI повторяет анализ и тесты Flutter и ключевых workspace-пакетов, проверки Python worker, format/lint/type-check Edge ingest и fresh replay Supabase миграций. CI имеет только read-доступ к репозиторию. Релиз Shorebird запускается только вручную отдельным workflow.
Перед pull request прочитайте CONTRIBUTING.md и CODE_OF_CONDUCT.md. Уязвимости нельзя публиковать в обычных issues — используйте SECURITY.md.
Проект распространяется по лицензии MIT.