23 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fc2cbee3d7 |
fix(validation): validatePassword проверяет заглавную и цифру (соответствует хинту)
Some checks failed
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Docker Public / Build + push Public (push) Has been cancelled
Docker Public / Deploy Public on stage (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|
|
259706e21f |
fix(signup): onBlur валидация через e.target.value, ре-валидация вместо сброса ошибки в onChange
Some checks are pending
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Public / Build + push Public (push) Waiting to run
Docker Public / Deploy Public on stage (push) Blocked by required conditions
- onBlur читает e.target.value напрямую из DOM (нет stale closure) - onChange не очищает ошибку, а ре-валидирует (только если ошибка уже показана) - Устраняет баг на мобильном: blur иногда стреляет раньше последнего onChange Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|
|
ff44afc202 |
feat(ux): onBlur валидация полей во всех формах
Some checks are pending
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Public / Build + push Public (push) Waiting to run
Docker Public / Deploy Public on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Ошибки полей теперь показываются сразу после потери фокуса — без нажатия «Сохранить». При начале ввода ошибка убирается (onChange). Submit-валидация остаётся без изменений. Охват: SignupForm (public), LoginPage, ForgotPasswordPage, ResetPasswordPage, EmployeesPage, CounterpartiesPage, StoresPage, OrganizationSettingsPage, SuperAdminOrgCreatePage, PriceTypesPage, EmployeeRolesPage, RetailPointsPage. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|
|
8eceff0bb5 |
fix(phone): сохранять позицию курсора после нормализации
Some checks failed
CI / Backend (.NET 8) (push) Successful in 1m3s
CI / Web (React + Vite) (push) Successful in 41s
Docker Public / Build + push Public (push) Successful in 26s
Docker Web / Build + push Web (push) Successful in 32s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
CI / POS (WPF, Windows) (push) Has been cancelled
Курсор не должен прыгать в конец после редактирования — он должен оставаться там, где юзер только что внёс изменение. Корень проблемы: после onChange я вызываю onChange с каноничным «+77…», parent перерендеривает с этим значением, React переписывает input.value на новый display — а нативное поведение браузера в этом случае: при programmatic value-set курсор сбрасывается в конец. Фикс: сохраняем «сколько цифр стояло до курсора» в момент редактирования, после ре-рендера в useLayoutEffect ставим курсор сразу после той же по счёту цифры в новом display. Учёт по цифрам (а не по абсолютной позиции) корректен даже когда format добавляет/убирает пробелы (например при переходе между «+7 700 1» и «+7 700 12»). useLayoutEffect (а не useEffect) — чтобы курсор восстанавливался синхронно до paint, без визуального флика. |
||
|
|
1264a91e2c |
fix(phone): нативное редактирование, фильтр не-цифр через onBeforeInput
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m7s
CI / Web (React + Vite) (push) Successful in 41s
Docker Public / Build + push Public (push) Successful in 27s
Docker Web / Build + push Web (push) Successful in 33s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
Прошлая попытка вручную обрабатывать каждую клавишу через onKeyDown ломала привычное поведение: selection + Backspace удалял только 1 цифру, нельзя было редактировать в середине, и т.д.
Новая модель совсем простая:
- Префикс «+7 7» (4 символа) залочен — onSelect клампит курсор/selection на digit-зону.
- Не-цифры блокируются через onBeforeInput (e.preventDefault если data содержит \D). Это покрывает и печать, и paste, и IME, и drag-drop.
- Всё остальное — нативное поведение браузера: selection + delete, click anywhere, arrow keys, Cmd+A, Cmd+V, drag-drop. После любого изменения onChange нормализует значение (rawToUserDigits извлекает 9 пользовательских цифр, отрезая залоченные «+7 7»).
- Display всегда «+7 7» + format(userDigits) — если юзер случайно стер часть префикса, она восстанавливается на ре-рендере.
Канон наружу: «+77XXXXXXXXX» (12 chars при полном номере), пустая строка если ничего не введено. Совместимо с существующим validatePhone (^77\d{9}$).
|
||
|
|
3beaec214a |
fix(phone): редактирование на месте курсора, как в обычном поле
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m3s
CI / Web (React + Vite) (push) Successful in 39s
Docker Public / Build + push Public (push) Successful in 25s
Docker Web / Build + push Web (push) Successful in 31s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
Курсор больше не «прыгает в конец» — его можно ставить куда угодно в digit-зоне (после префикса «+7 »), а Backspace/Delete/ввод цифры работают относительно позиции курсора, как в любом нормальном текстовом поле. Реализация: - cursorToDigitIdx — мапит позицию курсора в display к индексу в массиве цифр (пробелы форматирования пропускаются). - digitIdxToCursor — обратное: после операции ставит курсор сразу после последней изменённой цифры (через пробел если он там есть, чтобы не было визуального скачка). - Backspace на позиции idx удаляет цифру (idx-1); Delete удаляет цифру idx; ввод цифры вставляет в позицию idx. - Префикс «+7 » защищён: onSelect ловит попытку курсора влезть в позиции 0..2 и мягко переставляет на 3. |
||
|
|
a7130f3116 |
fix(phone): полностью переписать на простую модель — цифры как single source of truth
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m5s
CI / Web (React + Vite) (push) Successful in 38s
Docker Public / Build + push Public (push) Successful in 27s
Docker Web / Build + push Web (push) Successful in 32s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
Предыдущие итерации пытались парсить промежуточный raw input от браузера и постоянно ловили баги: курсор не там → парсер путал префикс с введёнными цифрами; Backspace на странной позиции → блокировался не там где надо. Новая модель: фронт полностью контролирует input, нативный ввод запрещён. Все клавиши обрабатываются вручную в onKeyDown: - Цифра → если набрано <10, добавить в конец. - Backspace/Delete → если есть цифры, удалить последнюю. - Любой другой символ → игнор (preventDefault). - Шорткаты (Cmd/Ctrl+что-то), стрелки, Tab, Enter, Esc → пропускаем. Курсор автоматически держим в конце display'а (после фокуса/клика/изменения). Paste обрабатывается отдельно через onPaste с нормализацией. onChange = no-op (React-warning заглушка). Бенефиты: Backspace теперь всегда удаляет цифру, без оглядки на позицию. Не-цифры физически невозможно ввести. Префикс «+7 » никогда не повреждается. |
||
|
|
16fe7580af |
fix(phone): блокировать ввод не-цифр на уровне keyDown
Some checks failed
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m4s
CI / Web (React + Vite) (push) Failing after 37s
Docker Public / Build + push Public (push) Successful in 26s
Docker Web / Build + push Web (push) Failing after 26s
Docker Web / Deploy Web on stage (push) Has been skipped
Docker Public / Deploy Public on stage (push) Successful in 10s
Предыдущий fix не покрывал кейс когда курсор оказывался не сразу после «+7 » (в начале строки или в середине). parseRawInput не находил префикс на нужной позиции и «7» снова попадала в подсчёт. Корректное решение: блокировать любой не-цифровой символ через preventDefault в onKeyDown — тогда он вообще не доходит до input, парсер видит только валидные цифры. Сохранены: Backspace/Delete (с защитой префикса), стрелки и навигация, Cmd/Ctrl+A/C/V/X для копи-пасты, Enter для submit. Paste произвольной строки по-прежнему работает через onChange. |
||
|
|
47c349818f |
fix(phone): не считать «7» из префикса как введённую цифру
Some checks failed
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m5s
CI / Web (React + Vite) (push) Failing after 37s
Docker Public / Build + push Public (push) Successful in 27s
Docker Web / Build + push Web (push) Failing after 27s
Docker Web / Deploy Web on stage (push) Has been skipped
Docker Public / Deploy Public on stage (push) Successful in 11s
Баг: при нажатии любой не-цифры (буквы, пробела) поле подставляло «7». Корень: extractDigits парсил полное e.target.value включая префикс «+7», и его «7» попадала в d, добавляясь как введённый юзером символ. Backspace на пустом поле не работал по той же причине. Фикс: новая функция parseRawInput отделяет префикс «+7 » ДО извлечения цифр. Применена в handleChange обоих PhoneInput (web + public). Кейс paste без префикса (8XXXXXXXXXX / 7XXXXXXXXXX из 11 цифр) сохранён. |
||
|
|
2301446b06 |
feat(phone): единый PhoneInput с зашитым «+7» и ФЛК Казахстана
Some checks failed
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m1s
CI / Web (React + Vite) (push) Failing after 37s
Docker Public / Build + push Public (push) Successful in 27s
Docker Web / Build + push Web (push) Failing after 25s
Docker Web / Deploy Web on stage (push) Has been skipped
Docker Public / Deploy Public on stage (push) Successful in 10s
Поле телефона во всех формах (web + public) теперь использует общий компонент: - Префикс «+7 » всегда виден и не удаляется (Backspace/Delete на позиции ≤3 блокируется). - Принимаются только цифры (буквы и спецсимволы автоматически отфильтровываются). - Авто-форматирование при вводе: «+7 7XX XXX XX XX». - Paste произвольного формата нормализуется (поддерживается ведущая «8», «+7…», скобки, дефисы). - Наружу через onChange отдаётся каноничное «+7XXXXXXXXXX». Подключено в: - food-market.public/SignupForm - food-market.web/CounterpartiesPage (контрагенты) - food-market.web/EmployeesPage (сотрудники) - food-market.web/SuperAdminOrgEmployeesPage (управление сотрудниками SuperAdmin) - food-market.web/SuperAdminOrgCreatePage (создание организации SuperAdmin) |
||
|
|
fd7df631e1 |
feat(signup): телефон обязателен + ФЛК Казахстана (77XXXXXXXXX)
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m0s
CI / Web (React + Vite) (push) Successful in 40s
Docker API / Build + push API (push) Successful in 1m20s
Docker Public / Build + push Public (push) Successful in 28s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Public / Deploy Public on stage (push) Successful in 11s
Фронт:
- SignupForm: убрал «(необязательно)» из лейбла, добавил required + autoComplete=tel.
- validation.ts: validatePhone теперь возвращает ошибку при пустом значении и валидирует строго KZ-мобильный (^77\d{9}$); ведущая «8» нормализуется в «7». «79…» (РФ) отвергается.
Бэк:
- AuthSignupController: SignupInput.Phone теперь string (не nullable). Добавлен NormalizeKzPhone — единая нормализация на сервере, защита от обхода фронтового валидатора. На запись в Organization.Phone уходит каноничная форма «+7XXXXXXXXXX».
|
||
|
|
2a026c589c |
fix(public): кнопка «Войти» вела на 410-Gone zat.kz
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m2s
CI / Web (React + Vite) (push) Successful in 40s
Docker Public / Build + push Public (push) Successful in 26s
Docker Public / Deploy Public on stage (push) Successful in 10s
Bug: на test.food-market.kz href кнопки «Войти» показывал https://app.food-market.zat.kz/login → 410 Gone (старый stage-домен давно убран). Корни: — Header.astro имел дефолт PUBLIC_APP_URL = https://test.food-market.kz (после revert-коммита остался только public-домен, но Войти ведёт на админку — должно быть admin.food-market.kz). Поправил, теперь совпадает с SignupForm.tsx. — Dockerfile ARG PUBLIC_APP_URL тоже был test.food-market.kz — заменил на admin.food-market.kz. — Добавил .dockerignore (node_modules / dist / .astro / .env / .git) чтобы старый локальный dist/ не попадал в build-контекст и не застревал в layer cache. Раньше это давало stale бандл с app.food-market.zat.kz даже после изменений в src/. Build/deploy: docker build --no-cache + compose pull --force-recreate. Smoke на проде: - href Войти → https://admin.food-market.kz/login - Никаких .zat.kz упоминаний в /usr/share/nginx/html (grep пуст). - og:image → https://test.food-market.kz/og/home.png |
||
|
|
0f59dfee69 |
feat(brand): новый логотип food-market wordmark + apple mark
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m23s
CI / Web (React + Vite) (push) Successful in 38s
Docker Public / Build + push Public (push) Successful in 28s
Docker Web / Build + push Web (push) Successful in 33s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
Источник — assets/brand/food-market-source.svg (1080x1080, FOOD #0DB70D
с яблоком вместо O, MARKET #4C4F54). Из source извлечены векторные
пути (Adobe-preview PNG-image теги вырезаны), собраны три варианта,
оптимизированы svgo.
Варианты в public/ обоих пакетов (food-market.web, food-market.public):
- logo.svg (2.1 KB) — full wordmark для светлого фона
- logo-light.svg (2.1 KB) — full wordmark белым (для тёмного фона)
- favicon.svg (1.0 KB) — mark-only: яблоко в зелёном круге,
читается с 16px (Astro favicon, web favicon)
Дополнительно (PWA maskable, food-market.web):
- logo-bg.svg (140 B) — solid #0DB70D 456x456 фон
- logo-fg.svg (1.0 KB) — белое яблоко на прозрачном, в safe-zone
Logo-компоненты переписаны:
- Logo.tsx (web) — было div+span с FOOD/MARKET буквами; теперь
<img src=/logo.svg|/logo-light.svg /> с одним пропом variant.
Сохранён API: variant=light|dark, className.
- Logo.astro (public) — то же; добавил пропс class для override-а.
Header.astro public-пакета использует <Logo />, не содержит
hardcoded текста — менять не нужно.
Все файлы под 2.2 KB после svgo.
|
||
|
|
79406e304e |
revert(domains): публичный сайт → test.food-market.kz, apex 404 до релиза
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 53s
CI / Web (React + Vite) (push) Successful in 38s
Docker API / Build + push API (push) Successful in 1m9s
Docker Public / Build + push Public (push) Successful in 28s
Docker Web / Build + push Web (push) Successful in 33s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Public / Deploy Public on stage (push) Successful in 10s
Docker Web / Deploy Web on stage (push) Successful in 11s
Публичный сайт ещё в разработке — выносим его с food-market.kz на test.food-market.kz. На корневом домене food-market.kz пока 404. admin.food-market.kz остаётся как есть. — Заменены https-URL в src/** и deploy/: https://food-market.kz → https://test.food-market.kz (admin.food-market.kz, app.food-market.kz и emails @food-market.kz не трогаем — sed строго по https-префиксу). — public Dockerfile ARG PUBLIC_SITE_URL → test.food-market.kz. — SignupForm/Header/NoOrganizationPage указывают на admin.food-market.kz для API (без изменений с прошлого коммита). — appsettings.json CORS: test + admin.food-market.kz. Nginx (на сервере): - /etc/nginx/conf.d/test.food-market.kz.conf — новый, серт LE issued. - food-market.kz.conf — apex теперь 404 (HTTPS), серт переиспользует пару (food-market.kz + admin.food-market.kz). - food-market.zat.kz и app.food-market.zat.kz — 301 на test/admin соответственно. Smoke: test/, /signup/, admin/health, admin/login = 200; apex = 404; zat → test/admin 301; sitemap.xml отдаёт https://test.food-market.kz/. |
||
|
|
58df887f1c |
feat(domains): миграция на food-market.kz / admin.food-market.kz
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 58s
CI / Web (React + Vite) (push) Successful in 42s
Docker API / Build + push API (push) Successful in 1m38s
Docker Public / Build + push Public (push) Successful in 49s
Docker Web / Build + push Web (push) Successful in 37s
Docker API / Deploy API on stage (push) Successful in 18s
Docker Public / Deploy Public on stage (push) Successful in 9s
Docker Web / Deploy Web on stage (push) Successful in 11s
- Заменил все хардкоды URL в src/** и deploy/: food-market.zat.kz → food-market.kz (публичный сайт) app.food-market.zat.kz → admin.food-market.kz (админ-API + SPA) - public/SignupForm и Header: дефолт PUBLIC_APP_URL теперь https://admin.food-market.kz (раньше указывал на сам публичный домен, что было багом — фронт стучался не туда после переезда зон). - public/Dockerfile ARG PUBLIC_APP_URL → admin.food-market.kz. - API appsettings.json CORS — оставил только два прода-origin (localhost для dev живёт там же). - Program.cs: добавил opts.SetIssuer(uri) если задан OpenIddict:Issuer в конфиге — иначе iss вычислялся из текущего HTTP-запроса и ломался при nginx-прокси без X-Forwarded-Proto. - docker-compose стейджа: env OpenIddict__Issuer=https://admin.food-market.kz/ + Cors__AllowedOrigins[0,1]. Nginx (на сервере, не в репе): - /etc/nginx/conf.d/food-market.kz.conf, admin.food-market.kz.conf — новые конфиги с certbot-выданными сертификатами на оба домена (LetsEncrypt --webroot, действителен до 2026-07-29). - Старые food-market.zat.kz / app.food-market.zat.kz переведены в 301-редирект на новые домены (HTTP+HTTPS), серты zat.kz пока оставлены чтобы handshake шёл нормально. |
||
|
|
691448201d |
fix: пароль/orphan signup/tenant-guard toast/dashboard счётчик
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 48s
CI / Web (React + Vite) (push) Successful in 39s
Docker API / Build + push API (push) Successful in 1m9s
Docker Public / Build + push Public (push) Successful in 41s
Docker Web / Build + push Web (push) Successful in 31s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Public / Deploy Public on stage (push) Successful in 11s
Docker Web / Deploy Web on stage (push) Successful in 12s
- validation: убрана клиентская проверка «должна быть заглавная/цифра» — она расходилась с серверной политикой Identity и блокировала валидные пароли. Серверный Identity сам валидирует и возвращает конкретное сообщение в общий error-bar формы. Клиент проверяет только длину 8. - /api/auth/signup: если AppUser с таким email уже есть, но он orphan (org удалена / архивирована / IsActive=false) — реактивируем его и привязываем к новой org вместо отказа «уже зарегистрирован». SuperAdmin не реактивируется (ему сценарий неактуален). Пароль перезаписывается на тот, что юзер ввёл сейчас. - TenantRouteGuard: убран alert «Откройте конкретную организацию через Открыть как…». На каждом редиректе SuperAdmin'а из tenant-роута всплывал window.alert — раздражал. Поведение редиректа сохранено. AppLayout чистит legacy ключ из sessionStorage. - SuperAdmin dashboard: KPI «Пользователей» теперь показывает количество активных, а в подсказке — сколько деактивированных. Раньше показывал total (включая orphan) — юзер видел «2», но в реальных списках их не было, потому что orphan-юзеры уже деактивированы. |
||
|
|
ed24f5e354 |
fix(public): нейтральный placeholder в поле названия организации
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m4s
CI / Web (React + Vite) (push) Successful in 39s
Docker Public / Build + push Public (push) Successful in 49s
Docker Public / Deploy Public on stage (push) Successful in 11s
«Например: Магазин «Береке»» → «Наименование организации». Юзер не хочет видеть выдуманные примеры в плейсхолдере регистрационной формы. |
||
|
|
ff991a7101 |
feat(validation): русская локализация и строгий email с TLD
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m2s
CI / Web (React + Vite) (push) Successful in 39s
Docker Public / Build + push Public (push) Successful in 31s
Docker Web / Build + push Web (push) Successful in 33s
Docker Public / Deploy Public on stage (push) Successful in 11s
Docker Web / Deploy Web on stage (push) Successful in 12s
— Общий модуль `src/lib/validation.ts` в обоих пакетах (public + web): validateEmail (требует TLD ≥2 букв), validatePassword (8+, буква+цифра), validatePhone (+7/8, 10 цифр), validateRequired, и localizeNativeValidation — слушатель invalid/input для setCustomValidity на русском (required, typeMismatch, patternMismatch, tooShort и т.д.). — public SignupForm: noValidate, валидация на onSubmit с русскими ошибками под каждым полем; placeholder email→ "name@example.kz", phone→ "+7 700 123 45 67". Старый HTML5 required+minLength+type=email убран — теперь всё через нашу схему. — web LoginPage: noValidate + локальная проверка email/password перед login(); красная подсказка появляется в самом поле. — web Field/TextInput: useEffect с localizeNativeValidation на ref — все остальные админские формы (SuperAdminSetup, SuperAdminOrgCreate, EmployeesPage, CounterpartiesPage) автоматически получают русские нативные подсказки через общий компонент, без правки каждой страницы. Acceptance: на /signup/ ввод "name@domain" без TLD блокируется сообщением «Email должен содержать доменную зону…». Нативные браузерные подсказки больше не на английском. |
||
|
|
1f2cf2a28d |
fix(public): убрать русские имена/ИП из placeholder регистрации
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m5s
CI / Web (React + Vite) (push) Successful in 39s
Docker Public / Build + push Public (push) Successful in 29s
Docker Public / Deploy Public on stage (push) Successful in 11s
В SignupForm.tsx плейсхолдер «ИП Иванов / Магазин у дома» → «Например: Магазин «Береке»». Не используем выдуманных русских персонажей в маркетинговых интерфейсах для KZ-аудитории. Грэп всего публичного пакета и админки на типичные RU-фамилии (Иванов/Петров/Сидоров и пр.), эл.почты mail.ru/yandex, формы юр.лиц ОАО/ЗАО — других вхождений не найдено. |
||
|
|
dcc3f9d61c |
content(public): живое наполнение — скриншоты, фото, OG, баннеры
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m5s
CI / Web (React + Vite) (push) Successful in 39s
Docker Public / Build + push Public (push) Successful in 46s
Docker Public / Deploy Public on stage (push) Successful in 10s
— 6 реальных скриншотов админки в режиме tenant override (FOOD MARKET): dashboard, аналитика, каталог 29 540 SKU, карточка товара, контрагенты, форма приёмки. Снято Playwright через app.food-market.zat.kz. — 14 stock-фото с Unsplash (Unsplash License) для Hero-секций и CTA: pos, import, about, 6 вертикалей, blog covers, integrations, cta-banner. CREDITS.md с авторами/profile-ссылками. — 11 OG-картинок 1200x630 через satori + @resvg/resvg-js: home, pos, pricing, import, about, 6 вертикалей. Inter Bold/Regular, emerald градиент, лого + заголовок + sub + CTA-кнопка. — Hero-секции переделаны: full-width фото с dark-overlay-градиентом и белая card поверх; вертикали /for-* с одинаковым layout-баннером; /pricing с зелёным gradient hero; финальный CTA с emerald overlay 75%. — BaseLayout: ogImage передаётся пропом, twitter:image добавлен. Каждая страница указывает свой /og/<slug>.png. — Контентная зачистка: «торговые весы» вместо конкретных брендов, модели весов убраны со всех материалов. Блог-пост cash-with-scales переписан без брендов. Build: 30 страниц, smoke 20 URL — 200. |
||
|
|
5f7cfa0d5b |
content(public): нейтральный тон, без упоминаний сторонних систем
— Все материалы (главная, /pos, /about, FAQ, kb, blog) переведены на нейтральные формулировки: «другие системы учёта», без имён. — Новая страница /import — единая точка входа по миграции каталога; описывает Excel/CSV, REST API и выгрузку 1С. — Удалены публичные kb/blog-статьи, целиком построенные вокруг миграции с конкретного продукта. — /migration-from-other-system убран из sitemap; nginx делает 301 на /import. — blog schema расширена optional-полями (author, category, cover_image), чтобы новый frontmatter валидировался content collection. — Грамматические правки: «Импорт из других систем». Финальный grep по пакету по списку имён конкурирующих SaaS-учётных продуктов — пусто. Smoke по 9 ключевым URL — 200; старый URL — 301. |
||
|
|
f5a232a32e |
content(public): naполнить блог + KB + about/contacts; убрать упоминания сторонних систем
Phase 6 контентная часть — частично: Блог (3 поста из /tmp/content/blog-and-kb.md, content collection): - launch — запуск Food Market - import-other-system — пошаговый гид миграции (внутренняя инструкция, frontmatter) - cash-with-scales — почему касса с весами Масса-К из коробки База знаний (5 статей, content collection с category + order): - quickstart, import-other-system, pos-setup, billing, faq Страницы /blog и /kb перерисованы — рендерят список из коллекций с группировкой по категориям, отдельные [slug].astro template'ы рендерят markdown с типографикой prose-md. /about и /contacts наполнены реальным контентом из /tmp/content/about-contacts-pricing-features.md (без заглушек). Контакты — 4 канала (email/phone/чат/реквизиты) с placeholder-ами для будущих контактов после регистрации юр.лица. Очистка от упоминаний сторонних систем (по правилу: не сравнивать с конкретными системами и не выводить чужие цены публично): - Hero/FAQ на главной — заменено «Импорт из сторонняя система» на «импорт каталога одной кнопкой», убран FAQ-вопрос «Чем отличаетесь от...», заменён на общий «Чем хорош Food Market?». - Footer: пункт «Импорт из сторонняя система» → «Импорт каталога». - /migration-from-other-system удалён (содержал сравнительную таблицу с ценами сторонняя система). Возможен возврат как KB-инструкция позже. - features/pos/pricing/integrations/changelog/for-grocery/for-pharmacy — sed-замена «сторонняя система» → «другие системы», ссылки на /migration-from-other-system → /features. - В content-collections блог/KB остались упоминания (юзер пришлёт PATCH-версии текстов отдельно). Контейнер пересобран и задеплоен на стенд: 30 страниц, smoke на /, /blog, /kb, /about, /blog/launch — все 200. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ad09d48a89 |
feat(public): Phase 6 — публичный маркетинговый сайт food-market.public на Astro
Новый пакет src/food-market.public/ — отдельный фронт для маркетинга и
самостоятельной регистрации магазинов-клиентов в SaaS Food Market.
Существующая админка food-market.web НЕ затронута.
Стек: Astro 4 + React 19 islands + Tailwind v3 (палитра идентична
food-market.web — единый бренд), TypeScript 6, content collections для
юр.документов. Static-сайт через nginx, gzip + immutable cache на assets.
Карта страниц (23):
- / — главная (Hero + 3 выгоды + скриншот +
6 вертикалей + 6 модулей + Касса +
Интеграции + 3 тарифа + соцпруф +
FAQ + финальный CTA)
- /features — модули по сценариям
- /pricing — тарифы + интерактивный конструктор
«Бизнес» (per-unit: 10000 база +
2000/магазин + 500/касса + 500/склад,
слайдеры, передача params в /signup)
- /pos — УТП лендинг кассы для Windows + весов
- /migration-from-other-system — УТП лендинг миграции с сторонняя система
(сравнительная таблица + 3 шага)
- /integrations — список интеграций
- /for-grocery|pharmacy|cafe|alcohol|clothing|household — 6 вертикалей
с уникальными фишками (весовой,
серии/сроки, модификаторы и комбо,
акцизные марки, размерные сетки,
гарантийные сроки)
- /signup — регистрация (React-island форма)
- /about /contacts /kb /blog /status /changelog — компания + ресурсы
- /legal/{offer,privacy,consent,requisites} — реальные юр.документы
из /tmp/legal/ как Astro content
collection (markdown с frontmatter,
динамический [slug].astro template,
720px max-width, line-height 1.7,
prose-legal стили)
- /sitemap.xml — ручной генератор (sitemap-плагин
конфликтует с Astro 4.16, заменён
на простой APIRoute)
React-острова (3):
- BusinessTariffBuilder — слайдеры + расчёт total + ссылка на signup
- SignupForm — email/password/orgName/phone/plan + валидация + agree
- FAQ — accordion 7 вопросов
API: новый POST /api/auth/signup создаёт Organization + AppUser
(Identity Admin role) + Owner Employee + полный bootstrap через
DevDataSeeder.SeedTenantReferencesAsync (units, price-types, store,
cassa, 6 ролей). Токены НЕ выпускает — фронт сразу делает обычный
/connect/token (password grant) и получает access/refresh без
дублирования OpenIddict-логики. На signup-форме — auth-bridge:
токены передаются через URL fragment в админку
APP_URL/auth-bridge#access=...&refresh=...&welcome=1, AuthBridgePage
кладёт в localStorage и редиректит на /?welcome=signup.
URL-домены через env-переменные (юзер ещё выбирает финальный):
- PUBLIC_SITE_URL — canonical/OG/sitemap (default https://food-market.kz)
- PUBLIC_APP_URL — admin/API endpoint (default https://food-market.zat.kz)
Nginx-конфиг для деплоя сайта — заготовка-template в
deploy/nginx/food-market-public.conf.template, не применён —
ждёт решения по домену.
Dockerfile multi-stage (node:20-alpine build → nginx:1.27 runtime),
build-args PUBLIC_SITE_URL/PUBLIC_APP_URL, deploy/nginx.conf gzip +
immutable cache + try_files для pretty URLs.
SEO: OG-теги, twitter-card, canonical, JSON-LD SoftwareApplication
схема, robots.txt → sitemap-index, lang=ru-KZ.
Admin-side: /auth-bridge route в food-market.web — принимает токены
из URL fragment, кладёт в localStorage (fm.access_token / fm.refresh_token),
редиректит на /. Fragment чтобы access_token не попадал в Referer.
23 страницы билдятся без ошибок. Контейнер собирается. Деплой на
конкретный домен — отдельным шагом после решения юзера.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|