Event Match
Flutter-приложение с Node.js-сервером для подбора до трёх event-подрядчиков: жёсткие ограничения, детерминированный скоринг, объяснения на…
О проекте
Команда: aipunks
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Flutter-приложение с Node.js-сервером для подбора до трёх event-подрядчиков: жёсткие ограничения, детерминированный скоринг, объяснения на проверенных фактах, кнопки ослабления условий, плюс кабинеты, модерация, переписка и GPT-помощник.
Как устроено
Каталог из 66 исходных и 434 синтетических профилей (всего 500) загружается в SQLite. Ядро на Dart сначала применяет жёсткие фильтры (формат, язык, часы, занятость по календарю, бюджет), затем считает скор с весами: бюджет 0.30, форматы 0.20, совпадения описания 0.20, языки 0.15, часы 0.15; порядок — score↓, цена↑, id↑. GPT через OpenAI Responses API только выбирает порядок из заранее проверенных explanation_options. Ответы кэшируются по hash каталога; при сбое AI остаётся локальная выдача. Если вариантов мало, до трёх кнопок ослабляют по одному параметру.
Ключевые решения
- hard-constraint filtering
- weighted deterministic scoring
- constraint relaxation suggestions
- grounded explanations
- AI response cache
Особенности
GPT не сочиняет причины: ему разрешено выбрать только точный вариант из explanation_options, и сервер с клиентом это проверяют. Три отдельных исхода: подобрали, категории нет, кандидаты не прошли условия.
Стек
Flutter · Dart · Node.js · SQLite · GitHub Actions
Модели
OpenAI Responses API (GPT)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-d2c4660e-aipunks.
README
README.mdEvent Match · aipunks
Подбор event-подрядчиков в Казахстане (#79-lite): до трёх рекомендаций, проверенная доступность, контрастные факты и конкретные изменения условий, если вариантов мало.
Стек: Flutter 3.44.1 / Dart 3.12.1, Node.js 24.16+, SQLite, OpenAI Responses API. Firebase не используется при запуске. Локальный подбор работает без сервера и интернета; AI-редактор — дополнительный слой.
Запуск
Сначала зависимости Flutter — они нужны и общему Dart-ядру сервера:
cd apps/event_match
flutter pub get
cd ../api
npm ci
Создайте apps/api/.env по .env.example, задайте OPENAI_API_KEY=... только в этом файле. Ключ не передаётся во Flutter. Затем:
npm start
Сервер запускается на 127.0.0.1:8787, автоматически импортирует 500 профилей в apps/api/data/event-match.sqlite и создаёт первого администратора, если в базе ещё нет админа.
По умолчанию логин — [email protected]. Случайный пароль сохраняется в локальный файл apps/api/data/event-match.sqlite.admin-credentials.json, исключённый из Git. Свои данные можно задать до первого запуска через ADMIN_EMAIL, ADMIN_NAME и ADMIN_PASSWORD в apps/api/.env. Повторный запуск не меняет существующие аккаунты и пароли.
Скрипт создания админа находится в репозитории: apps/api/src/admin-create.mjs. Его можно запустить отдельно командой npm run admin:create из apps/api, без запуска API и Flutter. Подробнее — первый администратор.
В другом терминале из корня репозитория:
cd apps/event_match
flutter run -d chrome --web-port=5173
После изменения pubspec.yaml, добавления фото или шрифтов полностью остановите
старый flutter run клавишей q и запустите его заново. Hot reload может оставить
старый набор ресурсов: тогда существующий assets/images/event-table.jpg
возвращает 404, а шрифты заменяются системными. Фото включено в pubspec.yaml;
копировать его в web/ или подключать через внешний URL не нужно.
Конфигурация Chrome в VS Code использует 5173. В loopback-режиме без ALLOWED_ORIGINS разрешены произвольные локальные dev-порты Chrome; явно заданный список ограничивает их. Если сервер не запущен, приложение загружает встроенный JSONL и показывает локальные объяснения.
Android-эмулятор по умолчанию использует http://10.0.2.2:8787. Для физического телефона нужен адрес компьютера в общей сети, настройка HOST, локальный токен и разрешение брандмауэра — инструкция. Локальный HTTP разрешён только в debug Android; для release нужен HTTPS. iOS в этой конфигурации не проверялся.
Что реализовано
- Кабинеты клиента/подрядчика, админка и план события перенесены из новых веток и подключены к SQLite.
- ИИ-помощник с уточнениями-кнопками и переписка с опубликованными подрядчиками — в правых панелях.
- Регистрация, модерация публикаций, календари, права доступа и личные данные — через локальный API.
- Запуск кабинетов, выдача первого администратора и ограничения — инструкция интеграции.
- Все жёсткие ограничения, включая календарь площадок и
max_hours: null. - Полный набор нарушений; основная причина: формат → язык → часы → занятость → бюджет.
- Детерминированный скоринг: бюджет 0.30, число форматов 0.20, совпадения описания 0.20, языки 0.15, часы 0.15; поправки на происхождение данных.
- Порядок: score ↓, цена ↑, id ↑. Score — соответствие продуктовой эвристике, не рейтинг качества.
- Индивидуальный факт + соответствие бюджету; общие условия в сводке. Почти одинаковые описания не объявляются разными преимуществами.
- До трёх кнопок ослабления, каждая меняет ровно один параметр. Число вариантов пересчитывается.
- Три исхода: подобрали / категории нет / кандидаты не прошли условия.
- SQLite-каталог и постоянный кэш AI; hash каталога и версия алгоритма.
- Переключатель GPT/локальные факты, источник текста в карточке, вклад фич в раскрытых деталях.
- При сбое AI, несовпадении версий или отсутствии ключа — локальная выдача без изменения порядка.
В подборке показаны 1–2 предложения: подтверждённое условие/цитата профиля и стартовая цена относительно лимита с оговоркой об итоговой стоимости. GPT выбирает порядок двух проверенных предложений; сервер и клиент принимают только точный вариант из explanation_options. Это ограниченный выбор формулировки, а не свободное сочинение причин. Без GPT остаются те же проверенные факты. В каталоге GPT по-прежнему генерирует сводку услуг: заголовок «Об услугах» не обещает соответствия заказу. В подборке заголовок «Почему в подборке», неизвестное вынесено в «Что уточнить». Источник GPT отмечается только после принятого ответа модели. Правила и исследования.
Если профили не имеют подтверждённых отличий, карточки честно сообщают об этом. Абсолютная неповторяемость объяснений для таких данных не заявляется. Прежнее ядро учитывает пожелания лексически. Новый помощник разбирает пожелания и отрицания GPT, проверяет признаки по цитатам и явно отмечает неподтверждённые требования; это не гарантия полного смыслового понимания.
Демо на расширенном каталоге
Все запросы — свадьба, без языка/часов, если не указано иное.
| Сценарий | Условия | Ожидаемый результат |
|---|---|---|
| Плотный пул | Алматы, Ведущий, 06.10.2026, 1 000 000 ₸ | Из 16 прошедших: Кики → Эмилия → Лунный Ветер |
| Соседняя дата | То же, 05.10.2026 | Из 13 прошедших: Эмилия → Лунный Ветер → Лазурный Ветер; исключения по занятости в сводке |
| Редкая категория | Алматы, Флорист, 10.10.2026, 1 000 000 ₸ | Тони Тони Чоппер; предложение 09.10 с двумя вариантами |
| Никто не проходит | Алматы, Ведущий, 26.12.2026, 1 ₸ | Нет результата; повышение бюджета до 650 000 ₸ даёт один вариант |
| Нет категории | Зарубежье, Флорист, 10.10.2026, 1 000 000 ₸ | Отдельный исход и предложения других городов |
| Честная эквивалентность | Алматы, Лайв-бэнд, 23.09.2026, 2 000 000 ₸ | Два близких профиля отмечены как не имеющие уникального преимущества |
Пересчёт без сборки приложения: dart run tool/audit_catalog.dart из apps/event_match.
Проверки без сборок Web/APK
# apps/event_match
flutter analyze
flutter test
# apps/api
npm test
Серверные тесты используют подменный GPT, не тратят API-бюджет. Явный живой тест при работающем сервере: node --env-file=.env src/smoke.mjs. Он делает одну генерацию при промахе кэша и повторяет только успешный ответ для проверки кэша.
Данные и устройство
Исходные data/catalog.csv и снимок data/catalog.original.jsonl содержат 66 профилей организаторов (13 синтетических). Рабочий JSONL содержит 500 профилей: исходные 66 без изменений и 434 новых с ID DEMO-* и synthetic: true. Всего синтетических — 447. В карточках новые записи отмечены как «Демонстрационный профиль · добавлен нами»; их цены, услуги и календари вымышлены.
Из корня: node scripts/seed_catalog.mjs воспроизводит тот же каталог без сети. Из apps/api: npm run db:seed повторно генерирует каталог и атомарно импортирует его в SQLite; npm run catalog:audit проверяет уникальность. После изменения каталога перезапустите работающий API и перезагрузите приложение: оба держат снимок в памяти. Для восстановления исходного снимка из CSV: python scripts/import_catalog.py data/catalog.csv data/catalog.original.jsonl, затем повторите засеивание.
Редкие категории сохранены по три профиля. Новые календари занимают 30–50% дней осенью и 70–80% в декабре; декабрьские выходные новых профилей заняты. Подробные результаты и границы проверки уникальности — в отчёте.
Авторы коммитов
История коммитов
- 2026-09-23 17:59feat: update localization and remove account language picker [skip ci]Danildos
- 2026-09-23 17:52feat: enable language switching across application [skip ci]Danildos
- 2026-09-23 17:52Merge integrated admin and explanations into main [skip ci]Danildos
- 2026-09-23 17:51fix: integrate comparison tests and localized panel labels [skip ci]Danildos
- 2026-09-23 17:49Merge feat/bootstrap-admin-account preserving account types [skip ci]Danildos
- 2026-09-23 17:48Merge codex/match-explanations with inline comparison [skip ci]Danildos
- 2026-09-23 17:42chore: include authorized hackathon demo API configuration [skip ci]Danildos
- 2026-09-23 17:42ayeDanildos
Все коммиты (29)
- 2026-09-23 17:40feat: bootstrap initial admin on API startupjlokerov
- 2026-09-23 17:36feat: ground match explanations in verified request factsdev-dmitrii-g
- 2026-09-23 17:22ui: simplify hero action and strengthen palette accentsDanildos
- 2026-09-23 17:10feat: integrate local accounts, messaging and GPT assistant [skip ci]Danildos
- 2026-09-23 16:46feat(assistant): integrate live matching into catalog and event workflowsdev-dmitrii-g
- 2026-09-23 16:42fix(planning): preserve event drafts and save edits without losing contextdev-dmitrii-g
- 2026-09-23 16:40fix(accounts): prevent stale calendar saves and allow moderator revocationdev-dmitrii-g
- 2026-09-23 16:19docs(communication): record isolated release verificationdev-dmitrii-g
- 2026-09-23 16:19docs(communication): document delivered inquiry and support workflowsdev-dmitrii-g
- 2026-09-23 16:18feat(communication): add private inquiries, messaging, and administrator supportdev-dmitrii-g
- 2026-09-23 16:04chore(preview): add non-destructive local account and event fixturesdev-dmitrii-g
- 2026-09-23 15:57feat: add favorites folders and alternative date searchDanildos
- 2026-09-23 15:55docs: record verification of integrated account and planning flowsdev-dmitrii-g
- 2026-09-23 15:55feat(assistant): add conversational matching with validated Firebase backenddev-dmitrii-g
- 2026-09-23 15:54feat(planning): add saved event plans with team and budget comparisondev-dmitrii-g
- 2026-09-23 15:53feat(accounts): add authenticated workspaces and moderated live catalogdev-dmitrii-g
- 2026-09-23 15:39feat: redesign Event Match for desktop and mobilejlokerov
- 2026-09-23 15:32test: cover AI summaries and document responsive cards [skip ci]Danildos
- 2026-09-23 15:28feat: add SQLite API and seed 500 contractor profilesDanildos
- 2026-09-23 14:27feat: refresh adaptive UI and configure Firebase apps [skip ci]Danildos
- 2026-09-23 14:05baseDanildos
Структура репозитория (321 файлов)
.agents/skills/git-advanced-workflows/SKILL.md .agents/skills/git-advanced-workflows/references/details.md .agents/skills/ui-ux-pro-max/SKILL.md .agents/skills/ui-ux-pro-max/data/app-interface.csv .agents/skills/ui-ux-pro-max/data/catalog-summary.json .agents/skills/ui-ux-pro-max/data/charts.csv .agents/skills/ui-ux-pro-max/data/colors.csv .agents/skills/ui-ux-pro-max/data/data-provenance.json .agents/skills/ui-ux-pro-max/data/google-font-licenses.json .agents/skills/ui-ux-pro-max/data/google-fonts.csv .agents/skills/ui-ux-pro-max/data/icons.csv .agents/skills/ui-ux-pro-max/data/landing.csv .agents/skills/ui-ux-pro-max/data/motion.csv .agents/skills/ui-ux-pro-max/data/phosphor-icons-upstream.json .agents/skills/ui-ux-pro-max/data/products.csv .agents/skills/ui-ux-pro-max/data/react-performance.csv .agents/skills/ui-ux-pro-max/data/stacks/angular.csv .agents/skills/ui-ux-pro-max/data/stacks/astro.csv .agents/skills/ui-ux-pro-max/data/stacks/avalonia.csv .agents/skills/ui-ux-pro-max/data/stacks/flutter.csv .agents/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv .agents/skills/ui-ux-pro-max/data/stacks/javafx.csv .agents/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv .agents/skills/ui-ux-pro-max/data/stacks/laravel.csv .agents/skills/ui-ux-pro-max/data/stacks/nextjs.csv .agents/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv .agents/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv .agents/skills/ui-ux-pro-max/data/stacks/react-native.csv .agents/skills/ui-ux-pro-max/data/stacks/react.csv .agents/skills/ui-ux-pro-max/data/stacks/shadcn.csv .agents/skills/ui-ux-pro-max/data/stacks/svelte.csv .agents/skills/ui-ux-pro-max/data/stacks/swiftui.csv .agents/skills/ui-ux-pro-max/data/stacks/threejs.csv .agents/skills/ui-ux-pro-max/data/stacks/uno.csv .agents/skills/ui-ux-pro-max/data/stacks/uwp.csv .agents/skills/ui-ux-pro-max/data/stacks/vue.csv .agents/skills/ui-ux-pro-max/data/stacks/winui.csv .agents/skills/ui-ux-pro-max/data/stacks/wpf.csv .agents/skills/ui-ux-pro-max/data/styles.csv .agents/skills/ui-ux-pro-max/data/typography.csv .agents/skills/ui-ux-pro-max/data/ui-reasoning.csv .agents/skills/ui-ux-pro-max/data/ux-guidelines.csv .agents/skills/ui-ux-pro-max/references/pro-rules.md .agents/skills/ui-ux-pro-max/references/quick-reference.md .agents/skills/ui-ux-pro-max/scripts/core.py .agents/skills/ui-ux-pro-max/scripts/design_system.py .agents/skills/ui-ux-pro-max/scripts/reasoning_contract.py .agents/skills/ui-ux-pro-max/scripts/search.py .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-api.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-catalog.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-existing.csv .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-metadata.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-overrides.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/icons-curated.csv .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-core.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-package.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-exports.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-package.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-baseline.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-cases.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-thresholds.json .agents/skills/ui-ux-pro-max/scripts/tests/test_catalog_refresh.py .agents/skills/ui-ux-pro-max/scripts/tests/test_catalog_summary_line_endings.py .agents/skills/ui-ux-pro-max/scripts/tests/test_core.py .agents/skills/ui-ux-pro-max/scripts/tests/test_core_data_quality.py .agents/skills/ui-ux-pro-max/scripts/tests/test_data_contracts.py .agents/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py .agents/skills/ui-ux-pro-max/scripts/tests/test_design_system_stack.py .agents/skills/ui-ux-pro-max/scripts/tests/test_native_desktop_stack_freshness.py .agents/skills/ui-ux-pro-max/scripts/tests/test_relevance_evaluator.py .agents/skills/ui-ux-pro-max/scripts/tests/test_skill_script_paths.py .agents/skills/ui-ux-pro-max/scripts/tests/test_style_taxonomy.py .agents/skills/ui-ux-pro-max/scripts/tests/test_text_layout_resilience.py .agents/skills/ui-ux-pro-max/scripts/tests/test_web_stack_freshness.py .agents/skills/ui-ux-pro-max/scripts/validate_data.py .firebaserc .github/workflows/flutter.yml .gitignore README.md apps/api/.env apps/api/.env.example apps/api/data/assistant_catalog.json apps/api/data/catalog.json apps/api/package-lock.json apps/api/package.json apps/api/src/admin-create.mjs apps/api/src/admin-grant.mjs apps/api/src/assistant-smoke.mjs apps/api/src/assistant/actions.mjs apps/api/src/assistant/catalog.mjs apps/api/src/assistant/dialogue.mjs apps/api/src/assistant/engine.mjs apps/api/src/assistant/openai.mjs apps/api/src/assistant/runtime.mjs apps/api/src/assistant/service.mjs apps/api/src/assistant/types.mjs apps/api/src/assistant/validation.mjs apps/api/src/bootstrap-admin.mjs apps/api/src/database.mjs apps/api/src/explanations.mjs apps/api/src/import.mjs apps/api/src/server.mjs apps/api/src/smoke.mjs apps/api/src/worker.mjs apps/api/src/workspace.mjs apps/api/test/assistant_core.test.mjs apps/api/test/assistant_provider.test.mjs apps/api/test/assistant_runtime.test.mjs apps/api/test/assistant_service.test.mjs apps/api/test/backend.test.mjs apps/api/test/bootstrap-admin.test.mjs apps/api/test/helpers/assistant_cache.mjs apps/api/test/http.test.mjs apps/api/test/seed.test.mjs apps/api/test/workspace.test.mjs apps/event_match/.gitignore apps/event_match/.metadata apps/event_match/README.md apps/event_match/analysis_options.yaml apps/event_match/android/.gitignore apps/event_match/android/app/build.gradle.kts apps/event_match/android/app/src/debug/AndroidManifest.xml apps/event_match/android/app/src/main/AndroidManifest.xml apps/event_match/android/app/src/main/kotlin/com/example/event_match/MainActivity.kt apps/event_match/android/app/src/main/res/drawable-v21/launch_background.xml apps/event_match/android/app/src/main/res/drawable/launch_background.xml apps/event_match/android/app/src/main/res/mipmap-hdpi/ic_launcher.png apps/event_match/android/app/src/main/res/mipmap-mdpi/ic_launcher.png apps/event_match/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png apps/event_match/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png apps/event_match/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png apps/event_match/android/app/src/main/res/values-night/styles.xml apps/event_match/android/app/src/main/res/values/styles.xml apps/event_match/android/app/src/profile/AndroidManifest.xml apps/event_match/android/build.gradle.kts apps/event_match/android/gradle.properties apps/event_match/android/gradle/wrapper/gradle-wrapper.properties apps/event_match/android/settings.gradle.kts apps/event_match/assets/data/catalog.jsonl apps/event_match/assets/data/demo.jsonl apps/event_match/assets/fonts/CormorantGaramond-Italic.ttf apps/event_match/assets/fonts/CormorantGaramond-OFL.txt apps/event_match/assets/fonts/Manrope-OFL.txt apps/event_match/assets/fonts/Manrope.ttf apps/event_match/assets/fonts/NotoSans-OFL.txt apps/event_match/assets/fonts/NotoSans.ttf apps/event_match/assets/images/event-table.jpg apps/event_match/ios/.gitignore apps/event_match/ios/Flutter/AppFrameworkInfo.plist apps/event_match/ios/Flutter/Debug.xcconfig apps/event_match/ios/Flutter/Release.xcconfig apps/event_match/ios/Runner.xcodeproj/project.pbxproj apps/event_match/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata apps/event_match/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist apps/event_match/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings apps/event_match/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme apps/event_match/ios/Runner.xcworkspace/contents.xcworkspacedata apps/event_match/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist apps/event_match/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings apps/event_match/ios/Runner/AppDelegate.swift apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/AppIcon.appiconset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json apps/event_match/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png apps/event_match/ios/Runner/Assets.xcassets/LaunchImage.imageset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/LaunchImage.imageset/[email protected] apps/event_match/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md apps/event_match/ios/Runner/Base.lproj/LaunchScreen.storyboard apps/event_match/ios/Runner/Base.lproj/Main.storyboard apps/event_match/ios/Runner/Info.plist apps/event_match/ios/Runner/Runner-Bridging-Header.h apps/event_match/ios/Runner/SceneDelegate.swift apps/event_match/ios/RunnerTests/RunnerTests.swift apps/event_match/lib/app/account_shell.dart apps/event_match/lib/app/app.dart apps/event_match/lib/app/app_theme.dart apps/event_match/lib/app/communication_scope.dart apps/event_match/lib/app/design_tokens.dart apps/event_match/lib/app/firebase_bootstrap.dart apps/event_match/lib/core/local_api.dart apps/event_match/lib/features/assistant/data/api_assistant_service.dart apps/event_match/lib/features/assistant/data/basic_assistant_service.dart apps/event_match/lib/features/assistant/data/firebase_assistant_service.dart apps/event_match/lib/features/assistant/domain/assistant_models.dart apps/event_match/lib/features/assistant/domain/assistant_service.dart apps/event_match/lib/features/assistant/presentation/assistant_controller.dart apps/event_match/lib/features/assistant/presentation/assistant_host.dart apps/event_match/lib/features/assistant/presentation/assistant_screen.dart apps/event_match/lib/features/assistant/presentation/widgets/assistant_recommendations.dart apps/event_match/lib/features/auth/data/firebase_auth_gateway.dart apps/event_match/lib/features/auth/data/local_auth_gateway.dart apps/event_match/lib/features/auth/domain/auth_gateway.dart apps/event_match/lib/features/auth/presentation/auth_pages.dart apps/event_match/lib/features/auth/presentation/session_controller.dart apps/event_match/lib/features/auth/presentation/settings_page.dart apps/event_match/lib/features/matching/data/api_catalog_repository.dart apps/event_match/lib/features/matching/data/api_recommendation_service.dart apps/event_match/lib/features/matching/data/catalog_repository.dart apps/event_match/lib/features/matching/data/favorites_repository.dart apps/event_match/lib/features/matching/data/local_recommendation_service.dart apps/event_match/lib/features/matching/domain/alternative_dates.dart apps/event_match/lib/features/matching/domain/catalog_version.dart apps/event_match/lib/features/matching/domain/explanation_policy.dart apps/event_match/lib/features/matching/domain/favorites.dart apps/event_match/lib/features/matching/domain/matching_engine.dart apps/event_match/lib/features/matching/domain/models.dart apps/event_match/lib/features/matching/domain/normalization.dart apps/event_match/lib/features/matching/domain/recommendation_service.dart apps/event_match/lib/features/matching/presentation/favorites_controller.dart apps/event_match/lib/features/matching/presentation/favorites_page.dart apps/event_match/lib/features/matching/presentation/matching_controller.dart apps/event_match/lib/features/matching/presentation/matching_screen.dart apps/event_match/lib/features/matching/presentation/selection_presentation.dart apps/event_match/lib/features/matching/presentation/widgets/ai_explanation.dart apps/event_match/lib/features/matching/presentation/widgets/alternative_dates_strip.dart apps/event_match/lib/features/matching/presentation/widgets/catalog_hero.dart apps/event_match/lib/features/matching/presentation/widgets/contractor_card.dart apps/event_match/lib/features/matching/presentation/widgets/contractor_details.dart apps/event_match/lib/features/matching/presentation/widgets/equal_card_grid.dart apps/event_match/lib/features/matching/presentation/widgets/favorite_folder_picker.dart apps/event_match/lib/features/matching/presentation/widgets/order_filters.dart apps/event_match/lib/features/matching/presentation/widgets/recommendation_comparison.dart apps/event_match/lib/features/matching/presentation/widgets/selection_overview.dart apps/event_match/lib/features/matching/presentation/widgets/side_panel.dart apps/event_match/lib/features/messages/messages_panel.dart apps/event_match/lib/features/planning/data/firestore_event_plan_repository.dart apps/event_match/lib/features/planning/domain/event_plan.dart apps/event_match/lib/features/planning/domain/event_plan_engine.dart apps/event_match/lib/features/planning/domain/event_plan_repository.dart apps/event_match/lib/features/planning/presentation/event_plan_page.dart apps/event_match/lib/features/workspace/data/firestore_workspace_repository.dart apps/event_match/lib/features/workspace/data/local_workspace_repository.dart apps/event_match/lib/features/workspace/data/workspace_catalog_repository.dart apps/event_match/lib/features/workspace/domain/workspace_models.dart apps/event_match/lib/features/workspace/domain/workspace_repository.dart apps/event_match/lib/features/workspace/presentation/admin_page.dart apps/event_match/lib/features/workspace/presentation/catalog_page.dart apps/event_match/lib/features/workspace/presentation/client_page.dart apps/event_match/lib/features/workspace/presentation/contractor_page.dart apps/event_match/lib/features/workspace/presentation/workspace_widgets.dart apps/event_match/lib/firebase_options.dart apps/event_match/lib/l10n/app_localizations.dart apps/event_match/lib/l10n/messages.dart apps/event_match/lib/l10n/messages.json apps/event_match/lib/main.dart apps/event_match/pubspec.lock apps/event_match/pubspec.yaml apps/event_match/test/advanced_filters_test.dart apps/event_match/test/ai_explanation_test.dart apps/event_match/test/alternative_dates_test.dart apps/event_match/test/api_service_test.dart apps/event_match/test/assistant_test.dart apps/event_match/test/assistant_transport_test.dart apps/event_match/test/assistant_widget_test.dart apps/event_match/test/auth_session_test.dart apps/event_match/test/auth_widget_test.dart apps/event_match/test/catalog_layout_regression_test.dart apps/event_match/test/catalog_test.dart apps/event_match/test/client_workspace_test.dart apps/event_match/test/communication_preview_test.dart apps/event_match/test/communications_test.dart apps/event_match/test/contractor_details_test.dart apps/event_match/test/controller_test.dart apps/event_match/test/design_preview_test.dart apps/event_match/test/event_plan_navigation_test.dart apps/event_match/test/event_plan_test.dart apps/event_match/test/event_plan_widget_test.dart apps/event_match/test/explanation_policy_test.dart apps/event_match/test/favorites_flow_test.dart apps/event_match/test/favorites_panel_test.dart apps/event_match/test/favorites_test.dart apps/event_match/test/favorites_widgets_test.dart apps/event_match/test/matching_test.dart apps/event_match/test/pipeline_test.dart apps/event_match/test/provider_admin_test.dart apps/event_match/test/selection_comparison_test.dart apps/event_match/test/selection_handoff_test.dart apps/event_match/test/widget_test.dart apps/event_match/test/workspace_domain_test.dart apps/event_match/tool/audit_catalog.dart apps/event_match/tool/matching_worker.dart apps/event_match/web/favicon.png apps/event_match/web/icons/Icon-192.png apps/event_match/web/icons/Icon-512.png apps/event_match/web/icons/Icon-maskable-192.png apps/event_match/web/icons/Icon-maskable-512.png apps/event_match/web/index.html apps/event_match/web/manifest.json data/catalog.csv data/catalog.original.jsonl design-system/event-match/MASTER.md docs/architecture.md docs/catalog-seeding.md docs/design-references.md docs/development.md docs/favorites-and-dates.md docs/feature-integration.md docs/firebase.md docs/local-backend.md docs/match-explanations.md docs/pipeline.md docs/product-ideas.md docs/selection-comparison.md scripts/audit_catalog.mjs scripts/import_catalog.py scripts/seed_catalog.mjs skills-lock.json
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.