Закрыть слабые места MVP: токены доступа, стойкие коды, отмена брони, правила протухания, a11y - #5
Open
devin-ai-integration[bot] wants to merge 1 commit into
Open
Conversation
…ncel/close, a11y Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Author
Результаты e2e-тестированияЛокальный бэкенд (
Не тестировалось: реальная оплата Kaspi Pay (демо), Pages-версия Ключевые скриншоты
|
wpalish
pushed a commit
that referenced
this pull request
Jul 14, 2026
PR #6 (+7908/−3565) не мерджится целиком: отведён от 37e0557 (удалил бы Telegram-уведомления и связку Pages→бэкенд), требует новые обязательные env и ломает 10-минутный онбординг партнёра (pending+email-верификация+MFA). Оставлен открытым как банк решений. Отсюда взято лучшее малое, реализовано своими руками (их код не исполнялся, только читался): - коды выдачи: 6 символов из криптостойкого алфавита без похожих символов (0/O, 1/I/L) — 27^6 ≈ 387 млн комбинаций вместо 65 тыс. у hex-4; легко диктовать на кассе (идея дублируется и в Devin PR #5) - security-заголовки: + Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy - Dockerfile: non-root пользователь, PYTHONDONTWRITEBYTECODE/UNBUFFERED, YUMMY_DB_PATH=/data по умолчанию - tools/create_admin.py: bootstrap/повышение админа через getpass (пароль не светится в history), promote отзывает все сессии (token_ver+1) - .github/dependabot.yml: еженедельные обновления pip/actions/docker - ci/github-actions.yml.example: полный CI (pytest+bandit+CodeQL+trivy+доксборка), как example — токен без scope workflow не может пушить воркфлоу Проверено: 75 тестов зелёные, create_admin смок (created/promoted) на врем. БД. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wpalish
pushed a commit
that referenced
this pull request
Jul 15, 2026
…ние по коду) Идея «отмена брони» — из Devin PR #5 (код оттуда не брался — база устарела), реализована под текущую архитектуру: - POST /orders/cancel {code} — отмена ДО начала окна выдачи: бокс атомарно возвращается в продажу, статус cancelled. Владение подтверждает код заказа — та же модель доверия, что у /redeem. Повторная отмена/отмена выданного — 409. - POST /orders/refund {code} — «заказ не выдали», доступен С начала окна. ФИКС РЕАЛЬНОГО БАГА: кнопка «Вернуть деньги» звала /admin/refund — в проде с YUMMY_ENFORCE_AUTH=1 покупатель получал 401. Теперь самообслуживание. - UI: «Отменить бронь» до окна / «Вернуть деньги» после начала окна, обе обновляют и заказы, и каталог; KZ-переводы всех новых строк. - Демо-режим (docs/): те же правила в client-store; витрина пересобрана с YUMMY_PAGES_API_BASE (живой бэкенд сохранён). - Оба эндпоинта под rate-limit заказов + аудит-лог с IP. 81 тест (6 новых: до/после окна, повтор, issued, неизвестный код, возврат остатка). Проверено live: cancel → повтор 409 → refund, новые коды YM-XXXXXX. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wpalish
pushed a commit
that referenced
this pull request
Jul 16, 2026
…арточка); +контраст футера По UX-ревью: - #1 localStorage-нотис был плавающей центр-карточкой (читалось как «глюк» поверх секций) → тонкая полоса во всю ширину, приклеена к низу (над bottom-nav на мобиле, к краю на десктопе). Показ один раз (флаг ym_cookies уже был). - #6 контраст копирайта/FAQ-текста в футере поднят (.6→.78, .7→.82 opacity) — запас под WCAG AA. Уже было в коде: #4 срочность («🔥 осталось N» + окно выдачи), #7 соцсети на светлом --on-ink (не бледные). Требуют ассетов (отдельно): #2 превью карты, #3 логотипы партнёров/отзывы, #5 лого-марка, #8 PWA-бейджи. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wpalish
pushed a commit
that referenced
this pull request
Jul 16, 2026
…ив cold-start - #5 бренд-идентичность: SVG логотип-марка (сюрприз-бокс + листок-росток = спасённая еда/эко, бренд-палитра) вместо generic-текста. Применён в хедере, футере, онбординге, SVG-favicon (apple-touch остался PNG — iOS не любит SVG). - #9 cold-start: ci/keep-warm.yml.example — GitHub Actions cron пингует /health каждые 10 мин (бесплатно). Как .example (пуш workflow'ов блокирует scope токена); либо добавить через GitHub web UI. Надёжный фикс — Render Starter $7. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Закрывает найденные минусы MVP (кроме реальной оплаты Kaspi — это отдельный этап с ключами/хостингом).
Безопасность / доступ
POST /boxes,/partners/{id}/boxes|orders,/redeem, новыйPOST /partner/boxes/{id}/close) требуютX-Partner-Token;redeem/боксы проверяют владение (require_partner→ pid). Токены в колонкеpartners.token(миграция черезPRAGMA table_info+ALTER TABLE), сидятся какpt-p1-demo… (в продеPARTNER_TOKEN_P1и т.п.). ДобавленGET /partner/me./admin/*) требуетX-Admin-Token(ADMIN_TOKEN, сравнение черезsecrets.compare_digest).uuid4().hex[:4](65k вариантов) →secrets.choice× 6 из алфавита без 0/O/1/I/L (~10^9); при коллизии UNIQUE ретрай с новым кодом внутри той же транзакции (code_factory).Бизнес-логика
/boxes, бронь на них отклоняется (409);refundвозвращает бокс в наличие только пока окно не закрылось.POST /orders/{code}/cancel(только статусpaid, бокс возвращается в продажу) и снятие бокса с продажи партнёром.+7 7XX…, окно самовывоза — ISO, конец > начало и не в прошлом.Фронтенды (обе версии:
app/static/index.htmlи Pages-демоdocs/index.html)/partner/me.GET /orders/{code}/qr), кнопка «Отменить бронь», кнопка «Снять» бокс.crypto.getRandomValues), автопересев если все боксы протухли, фильтр протухших, SRI-хеш на CDN-скрипт qrcode.role="dialog", автофокус,aria-label,data-*-обработчики вместо inlineonclick, консистентныйesc(), favicon + description/og-теги.Тесты: +7 кейсов (бронь протухшего, отмена, отмена после окна, close_box, токены партнёра, refund после окна, ретрай коллизии кода) — 14 passed.
Link to Devin session: https://app.devin.ai/sessions/56d5c80a4b774d5d87cb2c0a92705728
Requested by: @wpalish