metravel-quest

star 0

Создание/обновление городских квест-маршрутов на metravel.by: данные квеста, скрипт-миграция, заливка на бэкенд. Триггеры: «сделай квест по городу <X>», «добавь квест», «обнови квест».

kelios By kelios schedule Updated 6/10/2026

name: metravel-quest description: >- Создание/обновление городских квест-маршрутов на metravel.by: данные квеста, скрипт-миграция, заливка на бэкенд. Триггеры: «сделай квест по городу », «добавь квест», «обнови квест».

metravel-quest

Движок и регламент для публикации городских квестов на metravel.by. Квест — это пеший маршрут по точкам города: на каждой точке игрок читает живую историю/легенду и выполняет задание (что-то посчитать, найти, прочитать).

Принципы (ОБЯЗАТЕЛЬНО)

  1. Не дублировать. Перед созданием проверь существующие квесты и не делай повтор по quest_id и по городу: GET https://metravel.by/api/quests/ (список) и GET https://metravel.by/api/quests/by-quest-id/<quest_id>/ (деталь). Если квест по этому городу уже есть — обновляй его (тот же quest_id, миграция идемпотентна), а не плоди дубль.
  2. 8–12 точек must-see в логичном пешем маршруте. Бери реально главные достопримечательности города (рейтинги Google Maps top sights, TripAdvisor), а не случайные. Упорядочь по координатам в естественный пеший путь — с севера на юг или по районам, чтобы человек шёл связно, а не метался по карте.
  3. Квест — это СВЯЗНАЯ ИСТОРИЯ, а не список точек. Погружение. У квеста сквозная нить: intro задаёт завязку и героя/тему, каждая точка двигает рассказ дальше, финал закрывает арку. Человек должен чувствовать себя ВНУТРИ истории, идти по сюжету, а не отмечаться на достопримечательностях. Между точками — мостики («отсюда переулок выведет тебя к…»), чтобы маршрут читался как одно повествование. Тема/мотив (легенда, личность, эпоха, ремесло) проходит через весь квест. 3a. На каждой точке — живой слой деталей. Не сухая справка, а то, что делает место интересным: ЛЕГЕНДА (подавай как легенду), реальная ИСТОРИЯ и событие, ЛИЧНОСТИ (кто здесь жил/творил/бывал, человеческая деталь), АРХИТЕКТУРА (что видно глазами и почему так — стиль, материал, деталь), КУЛЬТУРНЫЕ ОСОБЕННОСТИ и быт, происхождение названия (топонимика). Всё ДОСТОВЕРНОЕ, сверенное веб-поиском: факт не подтверждён — не пиши его, новую «наблюдаемую» деталь не выдумывай. Факты — как факты, легенды — как легенды.
  4. Игровое задание, выполнимое на месте. На каждой точке — задание, которое реально сделать стоя перед объектом: найти деталь, прочитать табличку/дату, назвать предмет в руках статуи, узнать блюдо/материал/символ. Не абстрактные вопросы из интернета, а наблюдение здесь и сейчас. У каждого задания — hint и корректный answer_pattern. Счёт объектов — ТОЛЬКО при 100% уверенности в числе (устойчивый, не зависит от ракурса/сезона/реставрации). Число плавающее/спорное → не делай счёт «с запасным range», а замени на более ИНТЕРЕСНЫЙ вопрос с бесспорным однозначным ответом (эталон: Plac Nowy — вместо счёта окошек «что за блюдо жарят?» = запеканка). Где счёт оставлен — давай мягкий range ±1 вокруг верного числа (n≥3, где реально сбиться: 8 лягушек → 7–9, 12 кресел → 11–13); exact — только для бесспорных 1–2 (2 башни, 1 проезд), где ±1 пропустил бы явно неверное. 4b. Планка вопроса (4 критерия, ВСЕ обязательны): (1) ответ 100% однозначен и проверяем (источник/видно на месте); (2) виден стоя на точке — наблюдение здесь-и-сейчас, не эрудиция; (3) НЕ выдаётся в story/hint; (4) объект стабилен (не снимут, не зависит от сезона/реставрации/ракурса). 4c. Одобренные ТИПЫ вопросов (опирайся на них): (A) узнай культовую вещь места — фирменный символ/блюдо/явление (запеканка на Plac Nowy); (B) прочитай конкретную надпись/дату/имя на табличке/памятнике/надгробии (сверь по фото/Mapillary, что читаемо); (C) найди спрятанную стабильную деталь и назови (бронзовый дракончик у моста); (D) что символизирует / кто-что изображён — смысл памятника (пустые стулья → депортированные) или узнаваемая фигура/зверь/предмет на рельефе/гербе/статуе. ИЗБЕГАЙ: счёт нестабильного (окна/гномы/утки/деревья/ярусы); архитектурные термины-загадки (аркада, аттик, пинакли); субъективное («сколько ярусов», «какая форма»); невидимое-эрудиция. Где НИ ОДИН тип не даёт 100% — делай свободный «впечатленческий» any_text (живо, погружает, всегда засчитывается), а НЕ шаткий вопрос. 4a. Подсказка НЕ содержит ответа. hint — это наводка «куда/как смотреть» («подойди ближе к стене», «подними взгляд на вершину колонны», «пересчитай колонны на фасаде»), а НЕ сам ответ и не его половина. Запрещено: называть ответ или его синоним («…— от СССР», «это гусеница танкетки Голиаф»), давать точное число/диапазон ответа («их от 3 до 5»), писать «Крест и …». Подсказка открывается только после 2 неверных попыток — она должна помочь додумать, а не выдать. Проверка перед заливкой: для каждого шага убедись, что ответ (и ключевые слова answer_pattern.value) не встречается в тексте hint.
  5. Вступление и финал. intro (is_intro, answer_pattern.type='any') — завязка, тон, правила прохождения, направление к первой точке. Финал (quest-finales) — тёплый человеческий вывод о городе и маршруте. Это ТЕКСТ финала; финальное ВИДЕО+постер — отдельный пост-шаг, см. скилл metravel-quest-finale (не забудь его для нового квеста).
  6. Тон живой, человеческий. Без AI-обвязки, без канцелярита, без эмодзи и шаблонных заголовков. Пиши как увлечённый гид, а не как генератор.
  7. Интересные опциональные места С РАСПИСАНИЕМ. По ходу маршрута добавляй ОПЦИОНАЛЬНЫЕ точки (answer_pattern.type='any', пометка «по желанию») — то, что обогащает прогулку: музей (напр. Czartoryski с «Дамой с горностаем»), тематический/кошерный ресторан, знаковая кофейня, смотровая. Для каждого такого места УКАЗЫВАЙ ЧАСЫ РАБОТЫ и (если есть) сайт — чтобы человек знал, открыто ли сейчас; музеи и кафе с расписанием особенно. Источник кандидатов и их opening_hours/сайта — node scripts/quest-poi-suggest.js --quest-id=<id> (--kinds=museum,gallery,kosher,cafe,attraction); часы из OSM сверяй с офиц. сайтом (могут устареть). Опциональная точка не блокирует прохождение.

Технический раздел

Формат файла данных

По образцу scripts/warsaw-quest-data.jsmodule.exports = [ { quest } ]. Структура одного квеста: quest_id (строковый, kebab-case), title, city: { name, lat, lng, country }, meta, storage_key, intro, steps[], finale. У каждого шага — step_id, title, location, story, task, hint, answer_pattern: { type, value }, lat, lng, mapsUrl.

  • Координаты — decimal degrees (lat, lng), напр. 52.25123, 21.00862.
  • mapsUrl — ссылка на Google Maps: https://maps.google.com/?q=<место>.
  • meta: duration_min (минуты на прохождение), difficulty (easy/medium/hard), tags (['legend','history','citywalk',...]), опц. pet_friendly.
  • country — id страны квеста (НЕ travel-страна!): Польша=160, Беларусь=3, Армения=6.

Типы answer_pattern и когда какой

  • any{ type: 'any', value: '' } — любой ответ принимается. Для intro и шагов «просто дойди / нажми далее».
  • exact{ type: 'exact', value: '<строка>' } — точное совпадение после нормализации. Для одного известного числа/слова без вариантов.
  • exact_any{ type: 'exact_any', value: JSON.stringify([...]) } — массив допустимых вариантов (lowercase, без пунктуации). Перечисли падежи и синонимы: ['меч и щит','щит и меч','меч, щит',...]. Для слова/названия/предмета.
  • range{ type: 'range', value: JSON.stringify({ min, max }) } — число в диапазоне. Для заданий «посчитай» (счёт может слегка разойтись).
  • any_text{ type: 'any_text', value: JSON.stringify({ min_length }) } — любой осмысленный текст не короче N символов. Для «опиши в нескольких словах».
  • any_number — любое число. Когда важен сам факт числа, не его значение.
  • approx{ type: 'approx', value: JSON.stringify({ target, tolerance }) } — число около цели ± допуск.

Нормализация ввода (buildAnswerChecker): lowercase, схлоп пробелов, удаление пунктуации, ё→е. Учитывай это, заполняя варианты exact_any в lowercase.

Подсказки по выбору: счёт объектов → range; известное точное число → exact; слово/название → exact_any (перечисли падежи и синонимы); описание своими словами → any_text с min_length; «дойди/нажми» → any.

Процесс

  1. Ресёрч города — собери 8–12 must-see и их легенды/историю/топонимику через веб-поиск. Проверь достоверность фактов, упорядочь в пеший маршрут.
  2. Напиши данныеscripts/<city>-quest-data.js по образцу warsaw-quest-data.js, с явным answer_pattern на каждом шаге.
  3. Напиши/переиспользуй миграциюscripts/migrate-<city>-quest.js, идемпотентную (город→квест→шаги→финал), по образцу scripts/migrate-warsaw-quest.js. Квест создаётся со status=1.
  4. Dry-run — прогони миграцию в режиме проверки, убедись что данные читаются и маппятся, нет ошибок. 4a. Гео-сверка точек (до заливки). Прогони node scripts/quest-geocheck.js --source-file=scripts/<city>-quest-data.js --quest-id=<quest_id> и разбери WARN/FAIL: каждая точка должна стоять на объекте из story/task, а не на парковке/остановке/дороге (см. скилл metravel-quest-geocheck). Исправь lat/lng/mapsUrl в data-файле и перепрогони до 0 реальных проблем.
  5. Залей на прод: NODE_TLS_REJECT_UNAUTHORIZED=0 node scripts/migrate-<city>-quest.js --api-url=https://metravel.by (токен из ~/.metravel_token или --token=; если протух (HTTP 401) — свежий логином e2e: METRAVEL_TOKEN=$(node scripts/get-quest-token.js) node scripts/migrate-<city>-quest.js …).
  6. Проверь GET-ом GET /api/quests/by-quest-id/<quest_id>/: на месте intro, все steps, finale, корректные типы answer_pattern, координаты, mapsUrl.
  7. Обложку загрузи через Django admin → /admin/quests/quest/.
  8. Пройди квест залогиненным на мобильном вьюпорте: понятны ли задания, выполнимы ли на месте, работает ли проверка ответов; проверь печатную версию (QuestPrintable).

Верификация

  • Дев Expo Web проксирует /api на препрод-бэкенд — новый прод-квест там не виден. Для локального теста можно временно залить квест и на препрод (--api-url=<preprod>), затем удалить/перезалить на прод.
  • Prod Static не имеет SPA-fallback для динамических роутов квестов (/quests/{cityId}/{quest_id}) — прямой заход по URL может не открыться, проверяй переходом из списка.
  • Прохождение квеста требует логина (AuthGate). Для QA логинься тестовым e2e-аккаунтом (см. CLAUDE.md), без ручного ввода пароля в поля.

API-справка

  • GET /api/quests/ — список квестов (проверка дублей).
  • GET /api/quests/by-quest-id/<quest_id>/ — деталь по строковому quest_id (intro + steps + finale).
  • Запись (через миграцию, Token): /api/quest-cities/, /api/quests/, /api/quest-steps/, /api/quest-finales/.
  • Фронт-роут детали: /quests/{cityId}/{quest_id} — тянет по строковому quest_id. Проверка ответов — utils/questAdapters.ts (buildAnswerChecker).
Install via CLI
npx skills add https://github.com/kelios/metravel2 --skill metravel-quest
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator