SPI.SKI architecture Обложка
Level 1/14

SPI.SKI: web-apps, окна, карточки, кэш и стили

Самостоятельная карта приложения без запуска реального клиента. Каждый экран объясняет один слой системы: от входа и маршрутов до партнерского кабинета, серверной связи и визуальных режимов.

01 Окна, маршруты и где хранится состояние
02 Внутренние структуры Event, Tickets, Partner
03 Входные и выходные переменные компонентов
04 API, кэш, БД и обратное обновление UI
05 Связанные схемы со сплайнами, без пиксельной привязки

Общая карта презентации: слои проекта и быстрый zoom

Это обзорная карта всех листов. Выбирайте слой, меняйте масштаб и проваливайтесь в нужную карточку.

Большая карта проекта: окна, кэш, API и база как связанные уровни

Один экран показывает, откуда приходят данные, где они живут в клиенте, куда уходят запросы и какие таблицы получают результат.

UI Cache API DB

Как стартует приложение и где живут окна

Главная цепочка: bootstrap, провайдеры, runtime, инициализация данных, router и глобальные controls.

index.tsxglobal.scss + default attrs
Appsrc/App.tsx
ProvidersErrorBoundary, Background, ScreenBlocker
AppInitializersplash + retry loop
MiniAppRuntimeTelegram / VK / Browser auth
Data initDataCache.init + dataManager.init
BrowserRouterReact Router
VkMiniAppShellVK safe-area + swipe guard
PathTrackerlastPath + start_param
/eventsEventsPage
/navigatorNavigatorPage
/my-ticketsMyTicketsPage
/profileProfilePage
/partner/*Partner screens
/admin/tiket_listTicketListPage

Окна приложения: где лежат структуры и чем они запрашиваются

Это не список экранов, а карта связей: маршрут открывает компонент, компонент читает cache/hook, cache вызывает endpoint, ответ возвращается в UI.

/events EventsPage главное окно карточек
/my-tickets MyTicketsPage билеты пользователя
/partner/events PartnerEventsPage списки и статистика
/partner/channels PartnerChannelsPage каналы и модалки
EventsCache useEvents, useActiveEvent events, activeEvent, filters
UserTiketsCache useUserTickets tickets, status_counts
EventStatsCache useEventStats, useEventStat stats + pagination
Channel caches sources/promoter/connected/available channel lists + pages
GET /events EventsReq -> Events spi_ski.events + ticket_types
GET /tickets/user/:id TicketReq -> Tickets spi_ski.tickets
GET /stats/stats OrganizatorStatsReq -> OrganizatorStatsRes events + tickets + referal
GET /channels/* PagReq -> UserTelegramChannelsRes Telegram channel relations
Окно Входные переменные Где хранится Что выходит наружу
EventsPage start_param, filters, active id, search EventsCache, AppProfileCache.lastPath EventCard, buy/share buttons, load more
MyTicketsPage userId, status, page, limit UserTiketsCache, localStorage ticket list, QR state, active badge
PartnerEventsPage role, dateMode, hiddenOnly, sortOrder PartnerRoutingCache, FilterButtonsCache EventsControls, detail/stat view
PartnerChannelsPage role, channel mode, sortOrder FilterButtonsCache.partnerChannels Channels, connect/edit dialogs

Главная карточка: внешний свайп, внутренний свайп и отключенный 3D

Текущий production path отделен от экспериментального 3D-контура, который есть в коде, но выключен.

Current production path
EventsPagestate + active event
EventsSwiperhorizontal Swiper
SwiperSlidevirtual event slide
.inner-scrollvertical card scroll
EventCardbase / market
MediaSliderinternal media carousel
useSwiperScrollManagergesture isolation + scroll restore
load moreEventsCache.loadFromServer(next)
Disabled 3D path
EventsPageMultynot routed to /events
useControlLeva Enable=false
CSS cameratranslate3d + rotate + scale

Объект события: внутренняя структура, карточка и выходные переменные

Главная карточка строится не из одной картинки. Это связка ssEvent, временных tmp-данных, параметров кнопок и вложенных медиа.

ssEvent id, title, description, event_date, location, price images[], tags_id[], organizators[], scanner[] available_tickets, hidden, shareable, stories_enable tmp.availType[], tmp.promotion, tmp.old_price
EventsPage state currentEventIndex mediaIndexes[eventId] activeSlideScrollState isActiveSwipe, swipeDirection
EventPayetParams _activeEvent ticketCount, selectedTypes[] showBuy, showShare, disabled genFromReq -> PayReqItem[]
EventCard EventCardBase / EventCardMarket Header, text, tags, ticket types MediaSlider(images/video) card scroll area
Output UI visible card internal media index fixed action buttons swipe progress events
Server/DB GET /events -> Events POST /events/valid_see events, ticket_types, tags referal/tickets/payments on actions
Структура Вход Преобразование Выход
ssEvent Events.events[] из GET /events EventsCache.setActiveEvent(event) activeEvent для карточки и actions
EventPayetParams activeEvent + ticket type quotas геттеры showBuy, showShare, genFromReq кнопки покупки/списков и массив PayReqItem[]
MediaSlider event.images[], active context, visibility left/center/right позиция, lazy video, keyboard arrows текущий media frame без внешнего SwiperJS
useSwiperScrollManager slide key, active index, scroll element восстановление scrollTop, gesture isolation горизонтальный свайп не ломает вертикальный scroll

Покупка, share и платеж: как активное событие отправляет данные

Здесь показан путь от выбора карточки до реальных endpoint-ов, таблиц БД и обратного обновления билетов.

1. Active event EventsSwiper.onIndexChange EventsCache.setActiveEvent
2. Button params EventPayetParams.setEvent showBuy/showShare/genFromReq
3. Fixed action CustomAnimatedAction buy dialog, promo code, share helper
4. API request dataManager.buyTicket POST /payments/buy
5. DB/service payments, tickets external payment link or free ticket
6. UI refresh clearTiket, loadUserTickets navigate to /my-tickets
Buy path Структура запроса Результат
PayReq eventId, userId, items[], tag, promoCode PayRes: link, ttl, expired или созданный билет
PayReqItem[] ticket_type_id, ticketCount, free строки в tickets, квоты в ticket_types
check_buy eventId, userId подтверждение платежа, обновление tickets
Share path Структура запроса Результат
RefReq eventId, force_new, tag, fromStory share message id / referral link
TelegramApi shareMessage или shareToStory публикация в Telegram runtime
DB share_msg_ids, opened_codes привязка user -> event -> tag/source

Партнерский кабинет: mini-router, фильтры, списки и модалки

Визуально это dashboard, но внутри он связан кэшами состояния, виртуальными списками и общими компонентами.

PartnerPageLayouttabs + page scroll

Organizer

HalfStat
EventsControls
Channels: sources
Channels: connected
Channels: available

Promoter

HalfStat
Channels: promoter
EventsControls connected
EventsControls available
Promoter share flow
PartnerRoutingCachetabs, selected event, view
FilterButtonsCachedate, hidden, sort, channel mode
EventStatsCachestats lists + details
Channel cachessources, promoter, connected, available

Партнерский кабинет: mini-router, фильтры, списки и модалки

Партнерские страницы связаны двумя cache-структурами. URL открывает окно, а конкретный вид, tab и выбранный event живут внутри cache.

PartnerPageLayout tabs + page scroll общая оболочка партнерки
PartnerEventsPage EventsControls fullMode event list или detail
PartnerChannelsPage Channels fullMode sources, connected, available, promoter
PartnerRoutingCache mainTab, eventsTab, eventsView eventsEventId, channelsTab mini-router поверх URL
FilterButtonsCache partnerEvents.organizer/promoter partnerChannels.organizer/promoter dateMode, hiddenOnly, sortOrder, mode
ModalDialogsProvider channel select/edit/available открывается из Channels
EventStatsCache GET /stats/stats stats, pagination, detail
Channel caches GET/POST /channels/* каналы и связи с event
ApiService.saveEvent POST /events/save event + ticketTypes + promotion + media
Партнерская структура Поля Кто читает Куда ведет
PartnerRoutingState mainTab, eventsTab, eventsView, eventsEventId PartnerEventsPage, App.tsx filters main/list/detail/editor transition
FilterButtonsState.partnerEvents organizer/promoter: dateMode, hiddenOnly, sortOrder EventsControls, FilterMainButtonsBase OrganizatorStatsReq для /stats/stats
FilterButtonsState.partnerChannels organizer: mode, sortOrder; promoter: sortOrder PartnerChannelsPage, Channels /channels/channels-* endpoint group
EventSavePayload event, ticketTypes, promotion, media[] useEventEditor, EventEditor events, ticket_types, promo_ticket_types, media files

Связь с сервером: кэш, дедупликация, API и обратное обновление UI

Данные идут через единый слой кэшей, а UI обновляется через подписчиков `CacheEntry`.

UI component
React hook
CacheEntry
DataManager
ApiService
apiBase + axios
Express /api
Routes + DB
StoragelocalStorage, IndexedDB, timeouts
DedupedataManager.loadingPromises
Authx-telegram-init-data or x-vk-launch-params
RefreshDataCache.silentRefresh
server response -> cache.setData -> subscribers -> UI rerender

Связи базы данных: какие таблицы поддерживают основные объекты

Это укрупненная ER-карта по рабочему контуру приложения: пользователи, события, билеты, платежи, партнерские заявки и реферальные открытия.

users id PK telegram_id, vk_user_id parent_user_id -> users.id status, notification_settings
events id PK organizators[] -> users.id scanner[] -> users.id images JSONB, tags_id[]
partners id PK user_id -> users.id company/bank/contact documents JSONB, status
tags id PK user_id -> users.id title, color UNIQUE(user_id,title)
ticket_types id PK event_id -> events.id title, price, quota
tickets event_id -> events.id user_id -> users.id ticket_type_id -> ticket_types.id tag_id -> tags.id
payments user_id -> users.id event_id -> events.id operation_id, status, ttl ticket_types JSONB
share_msg_ids user_id -> users.id event_id -> events.id referal, tag_id -> tags.id
opened_codes user_id -> users.id event_id -> events.id open_code ~= share_msg_ids.referal tag_id -> tags.id
Бизнес-объект Основная таблица Связанные таблицы Кто запрашивает
Пользователь users partners, tickets, payments, share_msg_ids /users/profile, /users, auth middleware
Событие events ticket_types, promo_ticket_types, tickets, tags /events, /events/save, /stats/stats
Покупка payments tickets, ticket_types, users /payments/buy, /payments/check_buy
Промо/реферал share_msg_ids opened_codes, tags, tickets /referal, partner stats, share flows

Стили: DOM-атрибуты, design-mode, market-mode и платформы

Визуальный режим управляется не пропсами компонентов, а атрибутами на `html` и CSS-переменными.

html root attributesdata-theme / data-design-mode / data-market-type

Sources

index.tsx defaults
AppProfileCache
ThemeToggle
DesignSettingsPage
MarketTypeManager

SCSS

global.scss
base variables
telegram-like
telegram-glass
marketplace

Runtime

BackgroundManager
TelegramApi
VkMiniAppShell
BrowserAuthGate

Как читать связи: объект, вход, хранение, запрос, выход

Каждая новая схема устроена одинаково: слева пользовательское окно или объект, в центре состояние/cache, справа endpoint, серверная структура или таблица БД.

Route / Window

Показывает, какое окно открывается и какой компонент является владельцем первого состояния.

Пример: /events -> EventsPage.

State / Cache

Показывает, где данные лежат в памяти, localStorage или IndexedDB и кто подписан на изменения.

Пример: EventsCache.activeEventVariable.

Request / Response

Показывает, какую структуру отправляет UI и какую структуру получает обратно через ApiResponse<T>.

Пример: EventsReq -> Events.

DB Relation

Показывает таблицы, FK, логические связи массивов и где эти связи проявляются в интерфейсе.

Пример: tickets.event_id -> events.id.
Что смотреть Где в презентации Что дает для разработки
Как окно получает данные Окна и хранение, Данные и сервер Понятно, какой cache/endpoint менять при изменении экрана.
Как устроена карточка события Карточки и свайпы, Event object, Buy/share flow Видно, где активное событие, где медиа, где кнопки и где покупка.
Как работает партнерка Партнерский экран, Partner relations Видно, почему URL не описывает весь экран без PartnerRoutingCache.
Какие таблицы связаны База данных Видно, какие серверные запросы затрагивают users/events/tickets/payments/referal.