# План реализации кассетного каталога, серий и DSL-витрины **Дата и время создания/обновления:** 2026-10-11 17:30 **Проект:** LPON.RU (Django 6.0+, Python 3.12) **Статус:** Согласованный рабочий план **Архитектурная спецификация метаданных:** `metadata_architecture.md` --- ### Архитектурные принципы и ключевые решения #### 1. Серии, коллекции и раритетные записи * **Концепция:** Для тематических архивов (например, радиопередачи Oobu Joobu, японские бутлеги, циклы фолк-концертов) создается обзорная статья `TbArticle` (тип `HUB` или `COLLECTION`). * **Контент:** Предыстория архива, контекст записей, аппаратура оцифровки/записи, сканы оригинальных вкладышей. * **DSL-витрина серии:** Внутрь статьи встраивается DSL-блок, динамически выбирающий кассеты этой серии по тегу или источнику (например, `["offers:series:oobu-joobu", "grid"]`). * **Покупка:** Поддерживается покупка отдельных выпусков/кассет поштучно, а также покупка всего сета через сборный оффер-комплект. #### 2. Двухуровневая медиатека фотографий * **Уровень 1 — Эталонные фото модели (`TbItem` / связанная `TbArticle`):** * Фотографируются один раз на модель: цвет и фактура ленты (Fe, CrO2, Metal), металлизированный ракорд, люминесцентное свечение (TDK BEAM), керамические блоки, сканы каталогов тех лет. * Автоматически подтягиваются во все офферы данной модели кассеты. * **Уровень 2 — Фото конкретного лота (`TbOffer` через `TbImageMetadata`):** * 2-3 честных фото продаваемого экземпляра: реальные потертости корпуса, состояние надписей на вкладыше, целостность язычков защиты от записи. * **Отображение в карточке:** В основном блоке показывается конкретный продаваемый экземпляр, ниже выводится блок «Детали и макросъемка модели». #### 3. Музейный каталог (по типу c-90.org / ez647.sk) и архивные лоты * **Сохранение проданных позиций:** Офферы со статусом `quantity = 0` не удаляются и не закрываются ошибкой 404. Они получают статус «Архивный лот / Продано», оставаясь доступными для SEO, просмотра истории и изучения записей. * **Матричная структура справочника (без жесткого дерева папок):** * Ось брендов: `/cassettes/brands/` (TDK, Maxell, Sony, BASF, AXIA, Denon); * Хронологические линейки: разбивка внутри бренда по модельным годам (например, модельный ряд TDK 1985, 1988, 1990 годов с группировкой по типам ленты Normal / High / Metal); * Ось хронологии: `/cassettes/timeline/` (разбивка по эпохам: 70-е, 80-е, 90-е, 2000-е). --- ### Ближний горизонт (Пошаговый план разработки) #### Шаг 1. Стандартизация схемы метаданных для кассет и всех форматов * Спецификация полностью зафиксирована в `_prj_blueprint/metadata_architecture.md`. * Модуль констант `lpon_site/lpon_site/constants.py` создан и подключен: * Единый реестр перечислений: `MediaType`, `Market`, `TapeType`, `MediaLength`, `ShellColor`, `WriteProtectTabs`, `InlayCondition`, `Packaging`, `OfferExtra`, `Condition`, `Format`. * Режим дефолтных шаблонов с подсказками через `|` (Inline Choice Placeholder) для защиты от ленивого заполнения. * Структура полей `j_item_metadata` (для `TbItem`): * `media_type`: `blank_media`, `music_album`, `audio_recording`, `equipment`; * `tape_type`: `type_1`, `type_2`, `type_3`, `type_4`; * `length`: `46`, `50`, `54`, `60`, `74`, `80`, `90`, `100`, `110`, `120`; * `release_year`: год или диапазон годов выпуска; * `market`: `jp`, `us`, `eu`, `uk`, `su`, `global`; * `gallery_model`: список ID эталонных фото модели в `django-filer`. * Структура полей `j_offer_metadata` (для `TbOffer`): * `packaging`: `sealed`, `opened`; * `is_recorded`: флаг наличия уникальной аудиозаписи; * `recording_info`: краткое резюме записи (или ссылка на отдельную статью `k_offer_to_article`); * `write_protect_tabs`: `intact`, `broken`; * `inlay_condition`: `clean`, `pencil`, `written`, `missing`; * `series_tag`: слаг серии/коллекции (при наличии); * `extras`: словарь опций комплектации (`obi`, `insert`, `poster`, `case_original`, `stickers_sheet` и др.). #### Шаг 2. Ядро DSL и реестр обработчиков (`DSLQueryRegistry`) * Создать модуль реестра обработчиков (Query Handlers), разбирающий кортежи формата: `["source", "view_mode", limit, "sort", extra]` * Реализовать базовые обработчики источников: * Одиночные сущности по слагу (`single_slug`); * Выборки статей (`articles:type:`, `articles:collection:`); * Выборки офферов (`offers:format:cassette`, `offers:label:`, `offers:tape_type:`, `offers:series:`); * Реализовать сортировки: * `new+`, `new-`, `price+`, `price-`, `year+`, `year-`, `view+`, `random`; * Поддержка составных режимов и лимитов (`view_mode = "teaser+list"`, `limit = "2+15"`). * Защита от зацикливания (`visited_slugs`, `MAX_RECURSION_DEPTH = 2`) и безопасная деградация при ошибках в JSON. #### Шаг 3. Шаблоны компонентов и кастомный Template Tag * Реализовать template tag `{% render_hub_blocks article %}` (или фильтр рендеринга хабов). * Разработать базовую карточку кассеты (`cassette_card.html`): * Фото экземпляра, бейджи типа ленты, хронометража и года, плашка состояния («Под перезапись» или «Запись: Название»), цена/статус наличия. * Разработать шаблоны раскладки для разных `view_mode`: * `grid.html` (адаптивная сетка карточек); * `carousel.html` (горизонтальная прокрутка); * `list.html` (компактный табличный список); * `timeline.html` (раскладка по годам и линейкам для музейного каталога); * `teaser.html` (промо-блок статьи/серии). #### Шаг 4. Шаблоны страниц и виртуальные хабы * Шаблон детальной страницы товара/кассеты: * Основная галерея фото конкретного лота + ТТХ и состояние; * Блок «Детали и макросъемка модели» (эталонные фото из `TbItem`); * Блок описания аудиозаписи с треклистом (если привязана статья к офферу); * Автоматический виртуальный DSL-блок («Другие кассеты этого бренда», «Другие кассеты Type II»). * Шаблон страницы серии/коллекции: * Вводная статья + встроенная DSL-сетка кассет серии + блок заказа всей подборки. * Подключение рендеринга блоков в `content/hub.html` и `content/article_detail.html`. #### Шаг 5. Пилотная партия и тестирование витрины * Внести в базу 10-15 реальных кассет разных брендов и категорий: * 3 чистые кассеты Type I (TDK D, Sony HF); * 3 кассеты Type II (Maxell XL-II, TDK SA); * 1 топовая кассета Type IV (Metal) или спец-серия со светящимся корпусом (TDK BEAM); * 1 мини-серия из 3-4 кассет с редкими записями (Oobu Joobu / британский фолк) с оформленной статьей-хабом. * Собрать главный хаб кассетного раздела `/cassettes/`. * Проверить визуальное отображение, фильтрацию и мобильную верстку. --- ### Среднесрочный горизонт #### 6. Бесконтактная корзина и анонимные заказы (Stateless Orders) * Клиентский модуль `!cart-app` (хранение кодов офферов `s_offer_code` в LocalStorage/Cookies). * Интеграция виджета доставки (СДЭК) и генерация анонимных трек-номеров без сбора ПДн в БД сайта (152-ФЗ compliance). #### 7. История слагов и SEO-редиректы * Модель `TbArticleAlias` для автоматического сохранения старых слагов при переименовании статей и отдачи `301 Permanent Redirect`. --- ### Дальний горизонт #### 8. Парсеры и фоновые очереди * Интеграция Celery / Redis воркеров для разбора внешних источников данных. * Реализация интерфейса `ValidatorQueue` в админке для разрешения коллизий синонимов и дубликатов перед записью в основную базу. --- ```text [ TbArtist ] ──(M2M)──► [ TbItem ] ──────► [ TbOffer ] (Донован) (Релиз / Модель) (Конкретный лот на складе) │ │ ▼ ▼ [ TbArticle ] [ TbArticle ] (Эталонная статья) (История записи / лота) ``` | Сущность | Что представляет | Источник наполнения | Связь с артистом | |:-------------------------------|:------------------------------------|:-----------------------------|:---------------------------------| | Винил (LP) | Музыкальный альбом на виниле | Парсер Discogs / MusicBrainz | Да (TbItem.k_item_to_artist) | | Компакт-диск (CD) | Музыкальный альбом на CD | Парсер Discogs / MusicBrainz | Да (TbItem.k_item_to_artist) | | Кассета с записью / Бутлег | Редкий концерт / оцифровка / альбом | Ручной ввод / CSV | Да (TbItem.k_item_to_artist) | | Чистая кассета / MD под запись | Модель носителя (TDK, Maxell, Sony) | Музейный каталог кассет | Нет (привязана к TbLabel бренда) | | Серия / Архив (Oobu Joobu) | Коллекция связанных кассет | Статья-хаб TbArticle | Да (через тег серии и артиста) | --- ### Технический долг и текущие замечания по коду 1. **Импорты во `frontend/views.py`:** Заменить `from lpon_site.settings import *` на `from django.conf import settings` и удалить неиспользуемый `import json`. 2. **Временные вьюхи:** Заменить временные статические функции `catalog()` и `info_articles_list()` на единый диспетчер хабов по мере готовности DSL. 3. **Заглушка `get_hub_context`:** Реализовать полноценный вызов `DSLQueryRegistry` вместо отдачи сырого JSON.