Qadam Roadmap
проектdocs/Agents/knowledge-base.md

База знаний — продукт и доменная модель Qadam

Обновлён 1 апр. 2026 г., 12:41 · 0 комментариев

База знаний — продукт и доменная модель Qadam

Паспорт документа

  • Статус документа: working reference
  • Актуально на: 28 марта 2026 года
  • Владелец: backend/platform-команда
  • Пересмотр: при изменении инженерного backlog, локального workflow или платформенного статуса
  • Область применения: внутренний инженерный knowledge/rules/backlog слой проекта
  • Связанные документы:

Этот файл содержит доменную и продуктовую базу знаний по Qadam. Для правил разработки и operational-практик используй rules/, а для текущего статуса платформы и production truth сверяйся с ../current-state.md, ../roadmap.md и ../api-routes.md.

Product Overview

Qadam (Қадам, "Step") is an EdTech aggregator for supplementary education in Uzbekistan. It connects learners (primarily parents looking for education for their children) with educational providers across three categories:

  1. Offline Learning Centers (school_offline) — physical institutions: language schools, IT academies, exam prep centers, art studios, sports clubs
  2. Online Schools (online_school) — digital courses and mini-group classes sold on the platform
  3. Individual Tutors (individual_contributor) — private tutors, coaches, mentors

The core user journey: Parent searches → Finds a course → Submits a lead (inquiry) → Provider contacts them → Enrollment.

Product Name & Branding

  • Product name: Qadam (Қадам)
  • Primary color: #1DB57A (green)
  • Font: "Outfit" (Google Fonts) + system sans-serif fallback
  • Container: max-width 1280px
  • Responsive: mobile-first with md/lg breakpoints
  • Dark theme: not implemented

User Roles & Subtypes

Current Roles

RoleCodeSubtypesDescription
Buyerbuyerparent, studentSearches courses, submits leads, writes reviews
Sellersellerschool_offline, online_school, individual_contributorManages courses, handles leads, manages staff
Seller Staffseller_staffEmployee bound to a seller organization
AdminadminModeration, reference data, analytics

Route Access

RoleRoutesKey Actions
Guest/, /item/*, /sellers/*Browse catalog, view items, submit leads
Buyer+ /me/*Manage leads, write reviews, edit profile
Seller+ /seller/*Manage items, view leads, manage staff
Seller Staffотдельного стабильного кабинета пока нетВ текущем production редиректится в staff-unavailable
Admin+ /admin/*Moderation, reference data management

Planned CRM Roles (Seller Dashboard)

RoleCodeAccess Level
OwnerownerFull access including billing and org deletion
AdminadminSchedule, staff, clients, analytics management
ManagermanagerLeads, clients, bookings
TeacherteacherOwn schedule, own groups, attendance marking

CRM Permissions Matrix:

FunctionOwnerAdminManagerTeacher
Org settings++--
Role/staff management++--
Service management+++-
Schedule (all staff)+++-
Schedule (own)++++
Client base+++Own only
Bookings (all)+++-
Bookings (own)++++
Groups (all)+++-
Groups (own)++++
Leads+++-
Analytics (full)++--
Analytics (own)++++
Special offers+++-
Finance/reports++--
Attendance marking++++

Core Domain Entities

Item (Course/Service) — Central Entity

The Item is the universal entity representing any educational offering. It is the most important entity in the system.

Key attributes:

FieldTypeDescription
item_idUUIDPrimary key
seller_idUUID FKOwner seller
school_idUUID FK (nullable)Linked offline school
online_school_idUUID FK (nullable)Linked online school
item_namestringCourse title
item_desctextFull description
item_shortdesctextShort description (for cards)
item_price_fromdecimalMin price
item_price_todecimalMax price
item_age_groupstringTarget age group label
item_age_from / item_age_tointAge range
item_classes_from / item_classes_tointSchool grade range
subject_idUUID FKSubject (e.g., Mathematics)
subject_group_idUUID FKSubject group (e.g., School subjects)
item_studytypeenumgroup, mini_group, one_on_one
item_studyformatenumonline, offline, hybrid
item_languageenumru, uz_latin, uz_cyrillic, en, kk, tg, any
item_studyduration_from / tointDuration range
item_isvisiblebooleanVisibility flag
item_image_urlstringCover image
location_idUUID FKLocation reference
schedule_idUUID FKSchedule reference
specialoffer_group_idUUIDSpecial offers group
item_perfomer_group_idUUID FKAssigned teachers/performers
moderation_status_idUUID FKModeration status

Buyer

A technical entity linking an account to either a Parent or Student profile:

  • buyer_type: parent or student
  • Parents can add students (children) to their profile
  • Students can add parents to their profile
  • This bidirectional linking is stored in the respective profile

Seller

A technical entity linking an account to one of three subtypes:

  • school_offlineSchoolProfile (name, phone, email, desc, location)
  • online_schoolOnlineSchoolProfile (name, phone, email, desc)
  • individual_contributorIndividualContributorProfile (name, phone, email, desc, location)

Lead (Inquiry)

A user inquiry about an item:

FieldDescription
lead_typetrial (trial lesson) or buy (enrollment)
lead_nameContact name
lead_phoneContact phone
lead_emailContact email
lead_commentFree-text comment
lead_sourceWhere the lead came from
lead_statuscreatedcontactedenrolled or rejected
is_contacts_confirmedPhone/email verified

Review

  • Rating: 1-5 stars (integer)
  • Text comment
  • Linked to item, buyer, and seller
  • Aggregated stats pre-calculated in SAL layer (rating_avg, reviews_count)

Schedule & Performers

  • ScheduleProfile: datetime range, status, timezone
  • PerformerProfile: active flag, description, specialization, experience, linked to seller_staff
  • PerformerGroupProfile: groups performers for an item

Moderation

  • Items go through moderation before publishing
  • Status codes: active, rejected, pending
  • Admin can add reason and comment
  • is_visible_to_seller controls whether rejection details are shown

Reference Data (Registries)

RegistryFieldsNotes
Subjectsname, desc, group_id, group_nameTwo-level hierarchy: group → subject
Locationsname, longitude, latitudeCities/districts with coordinates
Tagstype, raw_value, name_ru, name_uz, is_visibleBilingual tags
Eventsname, typeUser action types for analytics
Moderation Statusescode, nameactive, rejected, pending

Canonical Enums & Status Machines

Source of truth. All specs MUST use these exact values. If a spec disagrees with this section, the spec is wrong — fix the spec.

ItemStatus (moderation_status)

enum ItemStatus {
  draft             // создан, не отправлен на модерацию
  pending           // на модерации у Admin
  active            // одобрен, публично виден (НЕ approved — это устаревшее)
  rejected          // отклонён, продавец видит причину
  revision_required // требует доработки от продавца
}

Видимость в каталоге: item_isvisible = true AND moderation_status = active

LeadStatus

enum LeadStatus {
  new               // только что создан (НЕ pending, НЕ created)
  contacted         // продавец связался с байером (НЕ processing)
  enrolled          // клиент записан на занятие
  attended          // пришёл на пробное занятие
  no_show           // не пришёл на пробное занятие
  purchased         // оплатил / оформил покупку
  not_purchased     // решил не покупать
  rejected          // продавец отклонил лид
}

ReviewStatus

enum ReviewStatus {
  pending             // ожидает первичной модерации
  published           // одобрен и виден публично (НЕ active)
  rejected            // отклонён модератором
  pending_moderation  // был published, получил жалобу → скрыт, ждёт повторной проверки
}

rating_avg считается только по status = published.

PriceType

enum PriceType {
  per_lesson   // цена за одно занятие
  per_month    // цена в месяц
  per_package  // цена за пакет N занятий  (НЕ просто package)
  one_time     // разовая оплата за весь курс (НЕ subscription)
}

DiscountType

enum DiscountType {
  percent       // скидка в процентах
  fixed_amount  // скидка фиксированной суммой
  gift          // подарок / бонусное занятие
}

ItemView (аналитика просмотров)

ItemViewвходит в MVP (Spec 11). Трекинг уникальных просмотров айтемов для seller dashboard. Spec 06 НЕ исключает ItemView — она исключает лишь view_count на публичной карточке айтема (не отображаем счётчик байеру). Трекинг пишется в БД, данные видны только продавцу в дашборде.

CPL Deduplication Rule

30-дневное окно: если за последние 30 дней уже существует лид с тем же buyer_account_id + item_id (или тем же lead_phone + item_id для незалогиненных) — CPL НЕ начисляется. Лид создаётся, но CplTransaction не генерируется. Это правило обязательно учитывается в Spec 16 (CPL Billing) при биллинге.


Category Tree

The platform has 11 top-level categories with subcategories:

#CategorySlugSubcategories
1School & University subjectsschoolMath, Physics, Chemistry, Biology, History, Informatics, Russian, Literature, Social Studies, Uzbek
2Foreign languageslanguagesEnglish, German, Chinese, French, Russian as foreign, Uzbek as foreign
3IT & BusinessitProgramming, Robotics, 3D Modeling, Circuit Design
4Creative artscreativeDrawing, Music, Dance, Theater, Design
5Beauty & Healthbeauty-health
6SportssportsFootball, Swimming, General fitness
7Drivingdriving
8Soft skillssoft-skillsCritical thinking, Public speaking
9Financial literacyfinance
10Chesschess
11Otherother

Categories use a slug-based system. The getCategoriesInfo(slug) function resolves a slug to its display labels (parent + child).

Пользовательские сценарии

Реально работающие сейчас

1. Catalog → Item → Lead

Buyer открывает каталог →
Открывает карточку айтема →
Создаёт лид через buyer-авторизацию →
Лид появляется в seller-кабинете

2. Seller registration → Profile → Moderation

Seller проходит регистрацию →
Создаёт и редактирует профиль →
Создаёт айтем →
Отправляет его на модерацию →
После approve айтем попадает в публичный каталог

3. Buyer registration / profile backend flow

Buyer регистрируется через registration API →
Создаёт или обновляет профиль →
Parent управляет детьми →
Student управляет interests

Частично реализовано

  • Публичный seller profile
  • Reviews flow
  • Admin moderation
  • Buyer cabinet

Осознанно не считать реализованным

  • Quiz flow
  • Telegram lead notifications
  • CRM booking / schedule / groups
  • Owner analytics и promo tools

Journey 10 (CRM): Teacher Role

Login → Limited menu: My Schedule, My Groups, My Students →
Calendar → Only own bookings → Group → Mark attendance →
Own stats: lessons count, workload percentage

Pages & UI Architecture

Public Pages

PageURLKey Elements
Home / Catalog/Search bar, category nav (pill buttons), filter sidebar (desktop) / drawer (mobile), course feed с infinite scroll, quiz modal, lead modal
Course Detail/item/[slug]SSR page, course details, similar courses, reviews block, sidebar with price + "Enroll" button, lead modal
Seller Profile/sellers/[id]Seller info, course list, rating & reviews
Login/loginRole selection (Buyer/Seller), phone/email login, multi-account support
Registration/register4-step flow: role → account → subtype → onboarding

Buyer Dashboard (/me/*)

Navigation: Overview | Profile | My Leads | My Reviews

PageURLContent
Overview/meDashboard cards with quick links
Profile/me/profileEdit name, phone, email
My Leads/me/leadsLead list + status badges (New, Contacted, Enrolled, Rejected)
My Reviews/me/reviewsReview list with ratings

Seller Dashboard (/seller/*)

Navigation: Overview | About School | My Courses | Leads | Staff

PageURLContent
Overview/sellerStats: course count, leads, rating
About School/seller/profileEdit organization profile
My Courses/seller/itemsCourse list + moderation status badges
Create Course/seller/items/newMulti-step creation form
Edit Course/seller/items/[id]/editPre-filled edit form
Leads/seller/leadsIncoming leads + status change
Staff/seller/staffCRUD staff (name, phone, email, role)

Admin Panel (/admin/*)

Navigation: Overview | Moderation | All Leads | Subjects | Locations

PageURLContent
Overview/adminStats: pending, total courses, leads, sellers
Moderation/admin/moderation/itemsItems pending review + Approve/Reject
All Leads/admin/leadsTable view of all system leads
Subjects/admin/reference/subjectsCRUD subject groups and subjects
Locations/admin/reference/locationsCRUD locations (City, District, Region)

UI Components Inventory

ComponentPurpose
HeaderGlobal nav: logo, city selector, language switcher (RU/UZ), auth buttons
CategoryNavCategory/subcategory navigation (pill-style buttons)
SearchBarSearch input + location selector + mobile filter toggle
FilterSidebarDesktop filter panel (checkboxes, sliders for price/age)
FilterDrawerMobile filter modal (same filters as sidebar)
HeroBannerHero banner on home page
CourseFeedCourse card grid + infinite scroll через sentinel
CourseCardCard: photo, title, seller name, rating, price, format badge, location
CourseCardSkeletonLoading skeleton for course cards
SimilarItems"Similar courses" block on item detail page
ReviewsBlockReviews list with ratings on item detail page
ReviewFormStar rating + text input for writing reviews
LeadModalInquiry modal: name, phone, type (trial/buy), comment
QuizModalQuiz dialog for personalized recommendations
OfferSidebarCourse detail sidebar: price, schedule summary, "Enroll" button
QadamMapOpenStreetMap map with markers
NominatimAutocompleteAddress autocomplete with debounce
ItemBadgeStatus/tag badge

Catalog Filter Fields

The catalog supports filtering by:

FilterTypeValues
Formatcheckboxonline, offline, hybrid
Languagecheckboxru, uz_latin, uz_cyrillic, en, kk, tg, any
Study typecheckboxgroup, mini_group, one_on_one
Time slotcheckboxmorning, afternoon, evening
Price rangesliderpriceFrompriceTo
Age rangesliderageMinageMax
Categorypill buttonsFrom CATEGORY_TREE
LocationselectorFrom LocationRegistry

Filters applied via URL query params with AND logic. UI-driven pagination works through infinite scroll; page и limit используются как внутренние transport-параметры запросов, а не как пользовательский URL state.

When Working with the Catalog

The catalog is the main public-facing feature:

  • Displays items with filters (subject, location, type, price range)
  • Uses server-side rendering for SEO
  • Catalog data is cached in Redis with 5-minute TTL
  • Search is powered by PostgreSQL full-text search (with plans for Elasticsearch later)
  • Categories are displayed in a horizontal navigation bar (pill buttons)

Filtering Logic

Filters are applied via URL query parameters:

  • ?subject=mathematics&location=tashkent&studyFormat=OFFLINE
  • Filters are combined with AND logic
  • Pagination: infinite scroll + transport-level page/limit под капотом

When Working with Locations and Maps

Locations are a critical part of the platform — learning centers, tutors, and group classes have physical addresses. Detailed rules in rules/data-locations-and-maps.md.

Location Types

TypeHas AddressHas CoordinatesExample
OFFLINE_ADDRESSRequiredRequiredLanguage school at a fixed address
ONLINENoNoOnline-only course
HYBRIDRequiredRequiredSchool with online option
MOBILE_TUTORCoverage area onlyNoTutor visits student's home
MULTIPLE_BRANCHESMultiple via ItemBranchYes, per branchLarge school chain

Geocoding — Nominatim (OpenStreetMap)

We use Nominatim for address autocomplete and geocoding:

  • Component: NominatimAutocomplete — debounced autocomplete with 300ms delay
  • Map: QadamMap — renders OpenStreetMap tiles with markers
  • API: https://nominatim.openstreetmap.org/search with countrycodes=uz
  • User-Agent: Required by Nominatim policy — set Qadam/1.0 (contact@qadam.uz)
  • Rate limit: Max 1 request per second (Nominatim policy)
  • Response language: accept-language: uz,ru

Uzbekistan Coordinate Bounds

All coordinates must fall within Uzbekistan's bounding box:

  • Latitude: 37.0 — 45.6
  • Longitude: 55.9 — 73.2

Any coordinates outside these bounds are rejected. This prevents wrong map rendering (e.g., pin in the Atlantic Ocean at [0, 0]).

Key Cities and Their Approximate Coordinates

CityLatitudeLongitude
Tashkent (Тошкент)41.299569.2401
Samarkand (Самарқанд)39.654266.9597
Bukhara (Бухоро)39.774764.4286
Namangan (Наманган)41.001171.6722
Andijan (Андижон)40.783072.3442
Fergana (Фарғона)40.384271.7890
Nukus (Нукус)42.462859.6035
Karshi (Қарши)38.861065.7986

Common Location Bugs to Watch For

  1. Map at [0, 0]: Coordinates are null/undefined, map library defaults to zero. Always check before rendering.
  2. Swapped lat/lon: Nominatim returns lat,lon but GeoJSON uses [lon, lat]. Always use typed Coordinates object.
  3. Results from wrong country: Missing countrycodes=uz in Nominatim query.
  4. SSR crash on map: Map libraries use window object. Always lazy-load with ssr: false.
  5. Rate limited: No debounce on autocomplete. Always debounce 300ms minimum.
  6. Private address exposed: Missing displayPublicly check in DTO. Always filter.

Privacy Rules for Locations

  • City name: Always public (needed for search/filtering)
  • Full address: Only if displayPublicly === true
  • Coordinates: Only if displayPublicly === true
  • Map rendering: Only on item detail page and only if address is public

When Working with Authentication

  • JWT-based authentication via NestJS
  • Tokens stored in httpOnly cookies (not localStorage — this is a fix from the old project which used localStorage)
  • Access token (short-lived) + Refresh token (long-lived)
  • Auth flow: Register → Verify Phone → Login
  • Phone verification via SMS (Uzbekistan phone numbers: +998)
  • Multi-account support: users can be both buyer and seller
  • Login supports both phone and email
  • Registration is a 4-step flow: role → account data → subtype → onboarding
  • Global JWT guard with @Public() decorator for public endpoints

When Working with Internationalization

Detailed rules in rules/patterns-i18n.md.

The platform supports three languages:

  • uz (Uzbek) — primary/source language, always complete
  • ru (Russian) — secondary language (majority of current users)
  • en (English) — tertiary language

Configuration Architecture

LayerFilePurpose
Config source of truth/i18n.jsonDefines source (uz) and target (ru, en) locales
Next.js i18n configapps/web/i18n.config.tsReads from i18n.json, configures next-intl
Translation filesapps/web/messages/{uz,ru,en}.jsonOne JSON file per locale
Server-side loadingapps/web/lib/i18n-server.tsloadTranslations() with caching and Uzbek fallback
Locale detectionapps/web/lib/get-locale.tsCookie → Accept-Language → default (uz)
Server ComponentsgetTranslations() from next-intl/serverNo JS bundle impact
Client ComponentsuseTranslations() from next-intlFor interactive elements only

Two Types of Text

  1. UI strings (buttons, labels, error messages) → Translation JSON files, always translated to all 3 languages
  2. Content (item titles, descriptions, reviews) → Database, in seller's/user's chosen language, NOT translated via i18n

Fallback Strategy

Missing translation keys fall back to Uzbek text (source language). This is implemented by merging locale translations on top of the complete Uzbek file:

const merged = { ...uzTranslations, ...localeTranslations };

This ensures users never see raw translation keys like catalog.title — they see Uzbek text at minimum.

Pluralization

Uzbek and Russian have different plural rules. Always use ICU message format:

{
  "resultsCount": "{count, plural, one {# kurs topildi} other {# ta kurs topildi}}"
}

When Adding New UI Text

  1. Add the key to messages/uz.json first (source language)
  2. Add translations to messages/ru.json and messages/en.json
  3. Use t('namespace.key') in the component
  4. Prefer Server Component getTranslations() over Client Component useTranslations()

Analytical Database Architecture

The database follows a three-layer analytical architecture designed for event sourcing and data warehousing. This architecture is critical for analytics and must be preserved.

Layer Overview

SAA (Staging Area Applied) → SAL (Staging Area Load) → DDS (Data Vault)
LayerPurposeMutability
SAAEnriched operational data. Append-only event streams and profile snapshotsImmutable — new values = new row
SALPre-calculated aggregates and transformationsImmutable — recalculated, not updated
DDSCore data warehouse using Data Vault (Hub/Link/Satellite)Immutable — deduplicated before insert

Key Principles

  1. Append-only: Rows in SAA, SAL, and DDS are never modified. If a value changes, a new row is written with a new event_time.
  2. Every row has event_time: This is the timestamp of when the data was captured, enabling full history reconstruction.
  3. Deduplication: Before writing to DDS, values are checked against existing data. If identical, no new row is created.
  4. Current state via DISTINCT ON: The "current" profile is derived by selecting the most recent row per entity ID.

SAA Table Types

SuffixPurposeExample
*_streamUser action event streams (high volume)buyer_stream, cookie_stream, seller_stream
*_profileEntity characteristics (change-tracked)buyer_profile, seller_profile, item_profile
*_registryAdmin-managed reference datasubject_registry, location_registry, tag_registry

Stream tables always have session_id (user actions happen in sessions). Profile tables store real-world characteristics that change over time. Registry tables contain artificial data created by employees.

SAL Aggregates (Pre-calculated)

TableFieldsPurpose
current_item_review_statsitem_id, rating_avg, reviews_countPer-item review statistics
current_seller_review_statsseller_id, rating_avg, reviews_count, items_countPer-seller review statistics

DDS — Data Vault Pattern

The DDS layer uses Hub/Link/Satellite modeling:

TypePrefixPurposeExample
HubH_Business key registrationh_buyer, h_seller, h_item, h_review
LinkL_Relationships between two entitiesl_seller_item, l_buyer_review, l_item_location
SatelliteS_Entity attributes/characteristicss_item_name, s_school_phone, s_review_rating

Key DDS entities (Hubs): h_buyer, h_parent, h_student, h_seller, h_school, h_item, h_review, h_serp, h_cookie, h_photo, h_video, h_location, h_session, h_event

Rules for DDS:

  • Hub tables contain only the business key + event_time
  • Link tables connect exactly two Hub entities + event_time
  • Satellite tables store one attribute per table (6NF) + event_time
  • Only *_profile and *_registry SAA tables feed into Satellite tables
  • *_stream tables feed into Hub and Link tables only (no attributes)
  • No column in DDS can be null

When Building Features — Database Implications

When adding a new feature, consider:

  1. Operational tables (Prisma schema): These are the tables your NestJS code reads/writes directly
  2. Analytical shadow: Each operational write should eventually flow into the SAA layer for analytics
  3. The Prisma schema is NOT the analytical schema: Prisma models are for the operational database. The SAA/SAL/DDS architecture runs alongside, populated via ETL/CDC processes
  4. Design Prisma models for operational use, but ensure they capture enough data to feed the analytical pipeline later

Текущее расположение репозиториев

qadam-core/
  apps/api/         # NestJS + Fastify backend
  packages/shared/  # Zod schemas, constants, backend contracts
  packages/prisma/  # Prisma schema, migrations, seed
  docs/             # каноническая документация
  specs/            # платформенные спеки

qadam-web/
  apps/web/         # Next.js frontend
  openapi/          # mirror OpenAPI artifact
  docs/             # frontend handoff / fallback docs

Backend Module Structure (NestJS)

Each feature module follows the pattern:

src/modules/{feature}/
  {feature}.controller.ts    # HTTP layer (thin)
  {feature}.service.ts       # Business logic
  {feature}.module.ts        # NestJS module definition
  repositories/
    {feature}.repository.ts  # Data access (Prisma)
  dto/
    create-{feature}.dto.ts  # Input validation schemas
    {feature}.response.ts    # Response DTOs

Frontend Page Structure (Next.js)

Pages use App Router conventions:

app/
  page.tsx                   # Home / Catalog (Server Component)
  item/[slug]/page.tsx       # Item detail (Server Component)
  sellers/[id]/page.tsx      # Seller profile (Server Component)
  login/page.tsx             # Login
  register/page.tsx          # Registration
  me/
    page.tsx                 # Buyer cabinet entry
    profile/page.tsx         # Buyer profile edit
    leads/page.tsx           # Buyer leads list
    reviews/page.tsx         # Buyer reviews
  seller/
    layout.tsx               # Seller dashboard layout
    page.tsx                 # Seller overview
    profile/page.tsx         # Seller profile edit
    items/page.tsx           # Seller items list
    items/new/page.tsx       # Create new item
    items/[id]/edit/page.tsx # Edit item
    leads/page.tsx           # Seller leads
    staff/page.tsx           # Staff management
  admin/
    layout.tsx               # Admin layout
    page.tsx                 # Admin overview
    moderation/items/page.tsx # Item moderation
    leads/page.tsx           # All leads
    reference/
      subjects/page.tsx      # Subject CRUD
      locations/page.tsx     # Location CRUD

Database Connection Strategy

Read/Write Splitting

  • Write operations (INSERT, UPDATE, DELETE): Use primary PostgreSQL connection
  • Read operations (SELECT): Use read replica via prisma.$replica()
  • This reduces load on the primary database and improves read performance

Redis Usage

Use CaseKey PatternTTL
Catalog cachecatalog:{filters_hash}5 min
Reference dataref:subjects, ref:locations30 min
Sessionsession:{token}24 hours
Rate limitingrate:{ip}:{endpoint}1 min
Popular itemspopular:items15 min
Review statsstats:item:{id}, stats:seller:{id}10 min

SEO Requirements

  • All public pages must be server-rendered (SSR or SSG)
  • Each item page must have proper <title>, <meta description>, Open Graph tags
  • Slugs must be transliterated from item titles (Cyrillic → Latin)
  • Sitemap generation for all published items
  • Structured data (JSON-LD) for course/service pages

API Documentation

Текущий base prefix API: /api/v1/.

Источники истины:

  • обзорная карта маршрутов: ../api-routes.md
  • машиночитаемый контракт: ../../apps/api/openapi/openapi.json
  • runtime Swagger UI: /api/docs
  • runtime OpenAPI JSON: /api/openapi.json

Правило:

  • примеры маршрутов внутри старых specs могут содержать исторические имена endpoint-ов;
  • перед реализацией всегда сверяйся с api-routes.md и OpenAPI artifact.

Infrastructure

Текущий production contour

  • product domain: https://qadam.2fab.app
  • roadmap portal: https://qadam-roadmap.2fab.app
  • runtime: systemd + host-level nginx
  • API: 127.0.0.1:5001
  • Web: 127.0.0.1:3000

Local development ports

ServicePort
API (NestJS)localhost:5001
Web (Next.js)localhost:5002
PostgreSQLобычно localhost:5432
Redisобычно localhost:6379

Rate Limiting

  • Global: 100 requests per 60 seconds per IP

Notifications

  • Telegram verification endpoints для seller уже есть
  • доставка lead notifications в Telegram и Email пока не завершена