Skip to content

Модули услуг (разбор artel-23ru)

Статус: проектирование по донору. Разбор рабочего кода artel-23ru (сайт электромонтажной артели) — самая зрелая SEO-модель услуг из проектов студии. Здесь услуги проработаны как SEO-комбинаторная машина: 3-уровневая иерархия × 4 SEO-оси = тысячи ЧПУ-страниц, полные русские падежи, двойная микроразметка. Для CMS это перенос и обобщение, а не разработка с нуля.

⚠️ Обобщение уже частично сделано (сверено по коду, июль 2026): весь этот стек перенесён в universal в обобщённом виде — те же модели/сервисы/трейты, но setting() из БД вместо config('artel.*') и SeoBlock с entity-scope. Версии в universal свежее. При портировании в CMS брать universal-версию за основу, этот разбор — как описание предметной модели.

Что уникального в artel-23ru

Проверено по коду (app/Models/, routes/web.php, Services/SeoService.php):

  • 3-уровневая иерархия ServiceDirection → ServiceCategory → Service (чистый FK parent→child, cascadeOnDelete, unique(category_id, slug));
  • 4 SEO-оси кросс-продукта: услуга × район × бренд × тип объекта — одни и те же категории/услуги под разными URL-префиксами дают тысячи посадочных;
  • движок падежей HasDeclensions — 6 русских падежей на каждую сущность (город/категория/бренд/локация), хранятся в JSON declensions, {city_gen}, {category_prep}, «в Краснодаре»;
  • двойная микроразметка — JSON-LD (Service + provider: LocalBusiness + Offer) + дублирующая inline itemprop (редкость), ItemList/ListItem для прайс-листов;
  • промышленный слой 301 — ~80 хардкод-редиректов старых slug после переименований (признак реального прода);
  • E-E-A-T сигналwiki_url на направление/категорию/услугу (ссылка на источник).

Это глубже, чем услуги в gulaev-dev/er. В universal с июня 2026 живёт обобщённый порт этого же стека (см. врезку выше) — сравнение «глубже, чем в universal» устарело.

Структура сущностей

МодельТаблицаКлючевые связи
ServiceDirectionservice_directionshasMany(ServiceCategory)
ServiceCategoryservice_categoriesbelongsTo(Direction), hasMany(Service), belongsToMany(Brand)
ServiceservicesbelongsTo(Category); цена inline (price/price_type/unit)
BrandServicebrand_servicesоверрайд услуги под бренд (unique(brand_id, service_id))
CaseStudycase_serviceкейсы/портфолио, pivot к услугам

4-го уровня нет. «Работы» вынесены в параллельную подсистему сметы (estimate_*), не связанную с услугами FK. Оси «районы» и «типы объектов» — чистая URL-комбинаторика (без pivot): все категории показываются на каждой локации, уникальность даёт SEO-текст.

SEO-вложенность URL

/uslugi/                              все направления+категории
/uslugi/{direction}/                  посадочная направления (whitelist из 7 slug)
/uslugi/{category}/                    прайс-лист категории
/uslugi/{category}/{service}/          карточка услуги
/elektrik/{location}/{category}/       район × категория
/brendy/{brand}/{category}/            бренд × категория
/brendy/{brand}/{category}/{service}/  бренд × услуга (3 уровня)
/dlya-biznesa/{objectType}/{category}/ тип объекта × категория

Кросс-оси — withoutScopedBindings() (осознанный декартов продукт, category не дочерняя к location/brand). Мультигород заложен (поддомены, ResolveCityMiddleware), но в URL услуг пока через middleware, не в пути.

Рекомендуемая разбивка на 5 модулей

Три первых — обязательны и связаны иерархией; два последних — опциональны и независимы.

Модуль 1. «Услуги (иерархия)» ★★★

Границы: Direction → Category → Service, цены (price/price_type/unit, «по договору»), sort_order + drag&drop, RelationManager'ы для вложенного редактирования, unique(category_id, slug), wiki_url. Зависит от: ядра; suggests City/мультигород (city-падежи, middleware, гео-оси) — на сайте одного города модуль работает без него. Не включать: SEO-тексты, бренды, калькулятор.

Модуль 2. «SEO услуг с вложенностью» ★★★ — главный переносимый актив

Границы: SeoBlock (page_type/position/format/template/{переменные}/per-city), SeoMeta (ручной оверрайд), SeoService::render(), движок падежей HasDeclensions, сборка ЧПУ и 301, генерация breadcrumbs + Schema.org (Service/Offer/ItemList/ BreadcrumbList) + og_image-каскад, Sitemap кросс-продуктов. Зависит от: модуля 1 (сущности как контекст) и City. Ключевое: проектировать generic — контекст-массив сущностей + реестр переменных, чтобы движок работал не только с услугами, а с любой сущностью. Это то, что делает услуги artel глубже прочих проектов. Смыкается с SEO-гибкостью и умным фильтром.

Модуль 3. «Кросс-оси услуг» (районы/бренды/типы объектов) ★★

Границы: Location (self-ref: район→микрорайон→улица→ЖК), Brand + pivot brand_category + оверрайд brand_services, ObjectType; контроллеры кросс-продукта {ось}/{category} и {brand}/{category}/{service}. Зависит от: модулей 1 и 2. Решить на старте: реальные pivot (Location↔Category) или URL-комбинаторика как в artel. Pivot = чище фильтрация, дороже контент-менеджмент.

Модуль 4. «Портфолио/кейсы услуг» ★★ (слабо связан)

Границы: CaseStudy + pivot case_service, метрики (JSON), типы (b2b/private), город, медиа. Зависит от: модуля 1 опционально (кейс может жить без услуг).

Модуль 5. «Калькулятор/Смета услуг» ★★ (независимый)

Границы: простой calculator_sections/items + wizard-смета estimate_projects/rooms/points/lines + estimate_works/materials (3 tier цен) + estimate_formulas (конфигурируемые коэффициенты). Зависит от: только City. Связь с услугами — опциональная строковая (calc_section). Портировать самостоятельным модулем, не встраивать в ядро услуг.

Граф зависимостей модулей услуг

City ──► Услуги(1) ──► SEO-услуг(2) ──► Кросс-оси(3)

         Кейсы(4) ────────┘ (опц.)
         Калькулятор(5) ── (независим, только City)

Это конкретный пример иерархии зависимостей модулей: жёсткая цепочка 1→2→3 + опциональные 4, 5.

Уроки для контракта (чего избегать)

Из «нечистот» artel (не критично, но учесть при портировании):

  • $guarded=['id'] вместо $fillable — в CMS вернуть whitelist;
  • нет afterSave/сброса кеша в Filament-ресурсах — в CMS обязательна инвалидация тегов;
  • хардкод whitelist slug направлений в роуте, список «электрических» категорий в контроллере — в CMS вынести в конфиг/БД (см. anti-hardcode).

Итог

Услуги artel-23ru — эталон SEO-глубины для CMS. Переносим как 5 модулей с чёткими границами, а движок SEO услуг (модуль 2) обобщаем до generic-движка, применимого к любой иерархической сущности. Добавлено в реестр модулей.

Внутренняя база знаний студии