← ОбложкаИдея 2 · презентацияАдминка · прототипДизайн-гайд
О!БРАТНЫЙ АУКЦИОН · ADMIN DESIGN SYSTEM v0.1

Гайд для Vue + Python

Токены как CSS-переменные, две темы переключаются атрибутом data-theme на <html>. Компоненты именуются с префиксом O. Ниже каждый компонент показан в тёмной и светлой теме.

01 · Токены
data-theme="dark"по умолчанию
--bg #0A0A0A
--surf #161616
--surf2 #1F1F1F
--line #262626
--ink #F3F3F3
--muted #9A9A9A
--acc-ink #8FE855
--tint #E3FAD5
data-theme="light"салатовый текст темнеет до #3E8A12 ради контраста
--bg #F3F3F3
--surf #FFFFFF
--surf2 #EDEDED
--line #E0E0E0
--ink #0A0A0A
--muted #6A6A6A
--acc-ink #3E8A12
--tint #E3FAD5
Общие для обеих тем
--acc #8FE855 (заливка, текст на ней всегда #0A0A0A)
--warn #FF2358 · --orange #FF6D3A
--pink #FF45B4 · --blue #007AFF
Радиусы--r-sm 10px · чипы-статусы, свитчи
--r-md 12–14px · кнопки, инпуты, строки
--r-lg 16–20px · карточки
--r-xl 24px · панели, модалки
--r-pill 999px · чипы
Отступы (шаг 4)4 · 8 · 12 · 16 · 20 · 24 · 32 · 48
Карточка: padding 20–24
Строка таблицы: 14 × 20
Gap между карточками: 14–20
ТипографикаUnbounded 700/900заголовки экранов (20), KPI-цифры (28–34), названия (20–22)Inter 400–700 — весь UI: 14 база, 13 вторичный, 12 подписи, 11 моно-лейблы таблиц
02 · Компонентыслева тёмная, справа светлая — одна разметка, разные переменные
OBtn · variant: primary | secondary | ghost | danger · size: md | sm
Выставить на аукционОтменаПодробнее →Снять офферsmdisabled
OInput · OSelect · OSlider · OSwitch
Базовая цена, ₽8 400
ОтельБриз Лофт⌄
Пол цены · ошибка5 000ниже минимума площадки (60%)
вклвыкл
OChip · status: live | won | lost | skipped | pending | warn · OChip.dna
идётвыигранпроигранпропущенна модерацииdna · тишина ●●●●○chip · фильтрchip · активный фильтр
OMatchRing · OTimer · OPriceDelta · OHonestMinus
94%
истекает 2:597 100 ₽8 400 ₽−15%—бар до 01:00
OCard.kpi · OEventBar · OToast
Win-rate55%+12 п.п.
«Горизонт 21» перебил ставку
✓Политика агента сохранена✕
OTable · header mono 11px · row 14×20 · hover surf2 · selected border acc
КАТЕГОРИЯЦЕНАВ АУКЦИОНАХ
Стандарт, корпус A8 400 ₽да
Стандарт, корпус B · hover9 000 ₽да
OBtn · variant: primary | secondary | ghost | danger · size: md | sm
Выставить на аукционОтменаПодробнее →Снять офферsmdisabled
OInput · OSelect · OSlider · OSwitch
Базовая цена, ₽8 400
ОтельБриз Лофт⌄
Пол цены · ошибка5 000ниже минимума площадки (60%)
вклвыкл
OChip · status: live | won | lost | skipped | pending | warn · OChip.dna
идётвыигранпроигранпропущенна модерацииdna · тишина ●●●●○chip · фильтрchip · активный фильтр
OMatchRing · OTimer · OPriceDelta · OHonestMinus
94%
истекает 2:597 100 ₽8 400 ₽−15%—бар до 01:00
OCard.kpi · OEventBar · OToast
Win-rate55%+12 п.п.
«Горизонт 21» перебил ставку
✓Политика агента сохранена✕
OTable · header mono 11px · row 14×20 · hover surf2 · selected border acc
КАТЕГОРИЯЦЕНАВ АУКЦИОНАХ
Стандарт, корпус A8 400 ₽да
Стандарт, корпус B · hover9 000 ₽да
03 · Правила интерфейса
Салатовый = наше действие и наша победаPrimary-кнопка, лидирующая позиция, выигранный лот, активный свитч. Не использовать для декора. На светлой теме салатовый — только заливка; как текст — #3E8A12.
Малиновый = честность и дедлайнЧестный минус, таймер оффера, проигрыш, низкая загрузка, ошибки форм. Оранжевый — события конкурентов и «требует внимания», не ошибка.
Агент объясняет себяКаждое действие агента в логе — с причиной и номером правила («пол 7 056 ₽», «перебивание 2/3»). Любой автоматический шаг можно переопределить вручную.
Один экран — одна правая панельСписок слева, деталь/симуляция справа (sticky). Модалки — только для деструктивных подтверждений.
Цифры — tabular-numsЦены «7 100 ₽» с неразрывным пробелом, таймеры и время — моноширинным. Зачёркнутая базовая цена всегда рядом с ценой оффера.
Живые состоянияПульс-точка у «идёт», анимация прилёта новой строки лога (land, 400 мс), таймеры тикают каждую секунду через WebSocket.
04 · Карта Vue-компонентов
ui/ · базовые (без бизнес-логики)
OBtn variant, size, loading, disabledOInput / OSelect / OSlider / OSwitch v-model, label, error, hintOChip status | dna | filter, activeOCard kpi | default, slot headerOTable columns[], rows[], selectedId, @selectOTabs, OToast, ODrawer, OConfirm
domain/ · аукционные
OMatchRing value 0–100, sizeOTimer expiresAt → «истекает 2:59», emit expiredOPriceDelta price, basePrice → цена + зачёркнутая + %OHonestMinus text, editableOLotRow / OLotDetail lot, ourOfferOBidLog events[] (WS-поток)OAgentSimulator policy, lot → steps[]OOccupancyBars days[]
views/ · маршруты
/dashboard/hotels · /hotels/:id/hotels/:id/rooms/hotels/:id/agent/auctions · /auctions/:lotId/bookings/admin/lots · /admin/moderation/admin/settings · /admin/users
Pinia stores: theme (dark/light → data-theme, localStorage), auth (роль → видимость раздела «Площадка»), auctions (WS-подписка на лоты отельера).
05 · Модель данных и API (Python)
Сущности
Hotelier — юрлицо, users[], statusHotel — name, address, geo, dna_attributes[], honest_minus*, checkin/checkout, moderation_statusRoomType — hotel, name, capacity, base_price, attributes[] (quiet, balcony, desk, wifi_mbps), total, in_auction, allowed_perks[]Availability — room_type, date, free, price_overrideAgentPolicy — hotel, strategy, floor_pct, occupancy_rules, horizon_rules, perks[], auto_rebid, max_rebids, min_match, daily_auction_limitLot — user, city, dates, guests, budget, dna_json, status, expires_atOffer — lot, hotel, room_type, price, perks[], match_pct, expires_at, rank, source (agent | manual), statusBidEvent — lot, offer, type, reason, ts (лог торгов)Booking — offer, guest, total, status, pms_ref
REST (FastAPI) · /api/v1
GET/POST /hotels · PATCH /hotels/{id}GET/POST /hotels/{id}/room-typesPUT /room-types/{id}/availabilityGET/PUT /hotels/{id}/agent-policyPOST /hotels/{id}/agent-policy/simulateGET /lots?match_min=70&status=liveGET /lots/{id} · GET /lots/{id}/eventsPOST /lots/{id}/offers (manual)DELETE /offers/{id} (снять)GET /bookings— админ —GET /admin/lots · /admin/statsPOST /admin/hotels/{id}/moderateGET/PUT /admin/settingsGET/POST /admin/users · rolesWS /ws/hotelier/{id} → offer.new, offer.outbid, lot.closed, booking.created
Агент · воркер (Celery/arq)
1. on lot.created — для каждого отеля в радиусе: match = cos-similarity(dna_lot, attrs_room_type) × доступность. Если match < min_match — BidEvent «skipped».2. first_offer — цена = base × max(floor_pct, rule(occupancy, horizon)); перки — из allowed_perks по ценности для ДНК; апгрейд — если free(upper) ≥ 3.3. on offer.outbid — если auto_rebid и rebids < max: снизить к полу шагом 3–5% или добавить перку; иначе BidEvent «hold».4. guard-rails площадки — скидка > max_discount → заморозка и очередь модерации; offers_per_lot ≤ 10; TTL оффера 10 мин.5. on lot.accepted — Booking → PMS webhook, остальные офферы → closed.