尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗AI-биржа вакансий. Вакансии собираются из Telegram-каналов и нормализуются нейросетью. Кандидат откликается в один клик с сопроводительным письмом, которое пишет ИИ под конкретную вакансию. Работодатели публикуют вакансии напрямую и разбирают отклики в своём кабинете.
| Часть | Где | Что делает |
|---|---|---|
| Сайт | src/ | Next.js 16 + Tailwind. Лента с фильтрами, Smart Apply, кабинеты кандидата и работодателя |
| API писем | src/app/api/cover-letter | Генерирует сопроводительное через Gemini. Только для вошедших, с лимитом запросов |
| Сборщик | main.py | Раз в 6 часов (GitHub Actions) забирает новые посты из каналов таблицы channels, нормализует их через Gemini и сохраняет вакансии со ссылкой на оригинал |
| База | supabase/migrations/ | Таблицы, триггеры и правила доступа (RLS) для Supabase, по миграциям |
Роли. Роль (candidate или employer) выбирается при регистрации и потом не меняется: это гарантирует триггер в базе. Работодатель попадает в /employer, кандидат — на главную и в /applications.
.env.example в .env.local и заполните ключи.supabase/migrations/
(по возрастанию имени). Базовую миграцию безопасно запускать повторно.npm install
npm run dev
Сайт откроется на http://localhost:3000.pip install -r requirements.txt
python main.py
Каналы для парсинга добавляются в таблицу channels (username, is_active = true).
Тесты сборщика (без сети): python -m pytest -q tests.psql; база fastcv_test пересоздаётся):
FASTCV_DB_TESTS=1 PGHOST=localhost PGUSER=postgres PGPASSWORD=postgres python -m pytest -v tests/db
В CI они идут на каждый PR вместе с тестами сборщика и сборкой сайта.
Lighthouse (скорость и доступность fastcv.ru на мобильном) запускается после каждого
выката в продакшн; баллы приходят комментарием к коммиту.Каждое изменение схемы — новый файл supabase/migrations/<ГГГГММДДччммсс>_<что_меняем>.sql.
Файлы применяются по возрастанию имени; уже применённые не правятся.
supabase db push) или SQL Editor, тем же содержимым файла.npm run db:types).Миграции, изменяющие данные, пишите так, чтобы повторный запуск ничего не ломал
(create ... if not exists, create or replace, проверки в do $$ ... $$).
Новая таблица — сразу с grant. Supabase больше не выдаёт права на новые таблицы
автоматически: без явного grant select, insert, … to authenticated правила RLS ничего
не открывают, и запросы молча возвращают ошибку. Тест «у каждого правила RLS есть права
на таблицу для его роли» ловит это до слияния.
Типы таблиц для TypeScript лежат в src/lib/database.types.ts и генерируются из схемы.
После новой миграции обновите их (нужен Supabase CLI
и supabase login):
npm run db:types
Клиенты Supabase типизированы этими типами: опечатка в имени колонки или неверный тип
значения ловится на npx tsc --noEmit и в CI.
last_post_id. Сборщик берёт посты новее него и, если с прошлого запуска вышло больше страницы, листает историю назад (до 5 страниц, около 100 постов). Новый канал начинается с 10 последних постов.source_post = канал/id), поэтому отредактированный пост не создаёт вторую запись. Одинаковый текст в разных каналах отсекается по хешу.stack). Модели перебираются по очереди (gemini-3.1-flash-lite → gemini-3.5-flash-lite → gemini-3.6-flash, переопределяется переменной GEMINI_MODELS): если одна перегружена (503), упёрлась в лимит (429) или снята с поддержки (404), запрос уходит в следующую. Таймаут запроса — 60 секунд. Если не ответила ни одна, канал останавливается на этом посте и продолжит с него в следующий запуск; после трёх таких каналов подряд остальные откладываются целиком.archived_at и пропадают из ленты. Данные не удаляются. Вакансии прямых работодателей не архивируются.failed_runs, а причина пишется в last_error. Список таких каналов выводится в конце лога.Ботов два, у каждого свой токен:
| Бот | Токен | Для чего |
|---|---|---|
| Оповещения | TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID (секреты GitHub) | сбои сборщика и утренняя сводка — только владельцу |
| Подборки | TELEGRAM_JOBS_BOT_TOKEN (Vercel, Production + секрет GitHub) | кандидатам: привязка чата и новые подходящие вакансии |
Бот подборок отвечает сразу: Telegram присылает сообщения на /api/telegram/webhook
(подпись — заголовок X-Telegram-Bot-Api-Secret-Token). Webhook и имя бота для ссылки в
профилях настраивает кнопка «Подключить бота подборок» в /admin; после смены токена её
нужно нажать снова. Подборки рассылает сборщик после каждого запуска.
Перед показом демо-аккаунты возвращаются в исходное состояние одной кнопкой: Actions → Demo Reset → Run workflow
(или python demo_reset.py с переменными SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, DEMO_CANDIDATE_EMAIL, DEMO_EMPLOYER_EMAIL).
Сбрасываются отклики, письма, отметки и лимиты ИИ демо-кандидата; профиль кандидата очищается (кроме имени — на показе
его заполняет ИИ по резюме), три вакансии демо-работодателя создаются заново (функция reset_demo). Аккаунты заводятся обычной регистрацией на сайте, их адреса — в переменных
репозитория DEMO_CANDIDATE_EMAIL и DEMO_EMPLOYER_EMAIL.
| База Supabase | Сайт | |
|---|---|---|
| Рабочее | First_DB (wyanvkaoqxgceaxzlqvk) | fastcv.ru — ветка main |
| Тестовое (staging) | fastcv-staging (zcyccnlweanhcsumplbx) | превью Vercel для каждого PR |
Превью и локальная разработка (vercel env pull) ходят в тестовую базу: регистрация,
отклики и эксперименты на превью не трогают рабочие данные. Миграции сначала
применяются к тестовой базе, потом к рабочей.
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY и GEMINI_API_KEY в Environment Variables. В NEXT_PUBLIC_SUPABASE_ANON_KEY — только публичный ключ (sb_publishable_… или anon): всё с префиксом NEXT_PUBLIC_ попадает в браузер. С секретным ключом сборка остановится. Переменные NEXT_PUBLIC_* вшиваются при сборке, поэтому после их изменения нужен редеплой.NEXT_PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY и GEMINI_API_KEY.https://<ваш-домен>/auth/callback в Redirect URLs, чтобы работала ссылка подтверждения почты.