Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created August 31, 2026 15:42
Show Gist options
  • Select an option

  • Save sunmeat/64abb14b88aca398afeacbd4354dab7a to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/64abb14b88aca398afeacbd4354dab7a to your computer and use it in GitHub Desktop.
cinema hikes p43 architecture

cinema-hikes

Architecture

⚙️ Backend


CinemaHikes.slnx
│
├── src/
│   ├── CinemaHikes.Domain/
│   │   ├── Entities/
│   │   │   ├── Users/
│   │   │   │   ├── FavoriteMovie.cs            # : IUserMovieRelation
│   │   │   │   └── ViewHistoryEntry.cs         # : IUserMovieRelation
│   │   │   │
│   │   │   └── Catalog/                        # Каталог фильмов — без актёров/каста
│   │   │       ├── Movie.cs
│   │   │       ├── Genre.cs
│   │   │       ├── MovieGenre.cs                # join-таблица
│   │   │       ├── VideoSource.cs               # плеер/источник: PageUrl на сайт-источник (FR-04)
│   │   │       ├── MovieLink.cs                 # MovieId, Quality, Url — прямая ссылка (FR-06), обычная таблица без TTL
│   │   │       └── Review.cs
│   │   │
│   │   │   └── Parsing/
│   │   │       └── ParsingSourceConfig.cs        # конфиг сайта-источника, обслуживается IParsingSourceRepository
│   │   │
│   │   ├── Enums/
│   │   │   ├── SourceStatus.cs                  # Active, Dead, Checking
│   │   │   ├── VideoQuality.cs                  # Q360, Q480, Q720, Q1080
│   │   │   └── ReviewStatus.cs                  # Pending, Approved, Rejected
│   │   │
│   │   ├── Interfaces/                          # Порты (реализуются в Infrastructure)
│   │   │   ├── Repositories/
│   │   │   │   ├── IMovieRepository.cs
│   │   │   │   ├── IGenreRepository.cs
│   │   │   │   ├── IVideoSourceRepository.cs
│   │   │   │   ├── IMovieLinkRepository.cs           # обычный CRUD над movie_links
│   │   │   │   ├── IReviewRepository.cs
│   │   │   │   ├── IUserMovieRelationRepository.cs   # generic<T> — Favorite/History
│   │   │   │   └── IParsingSourceRepository.cs
│   │   │   ├── IUserMovieRelation.cs
│   │   │   ├── IUnitOfWork.cs
│   │   │   ├── IJwtTokenService.cs
│   │   │   ├── ICurrentUserService.cs
│   │   │   │
│   │   │   └── Bot/                              # ↓ порты бота — реальные имена из вашего репозитория
│   │   │       ├── IBrowserConfig.cs             # CreateLaunchOptions() / CreateContextOptions()
│   │   │       ├── IBrowserFactory.cs            # CreatePageAsync(IBrowserConfig) / DisposeAsync()
│   │   │       ├── IFilmParserFacade.cs          # GetFilmSrc(pageUrl, videoQuality)
│   │   │       ├── IPageConfig.cs                # InitPageAsync(page, pageUrl)
│   │   │       ├── Parsers/
│   │   │       │   ├── IFilmUrlParser.cs         # GetFilmUrlAsync(page, videoQuality)
│   │   │       │   └── IPageElementParser.cs     # ParseElementAsync(page)
│   │   │       ├── ITelegramFileSender.cs        # SendVideoAsync / SendLinkAsync
│   │   │       └── IVideoSizeChecker.cs          # лимит 2GB (A-03/R-02)
│   │   │
│   │   └── Specifications/
│   │       ├── MovieFilterSpecification.cs      # жанр/год/рейтинг (FR-01)
│   │       ├── MovieSearchSpecification.cs      # поиск по названию (FR-02)
│   │       └── ActiveSourcesSpecification.cs    # NFR-05: >=2 живых источника
│   │
│   ├── CinemaHikes.Application/
│   │   ├── Services/
│   │   │   ├── MovieService.cs                  # FR-01, FR-02, FR-03, FR-04
│   │   │   ├── MovieDownloadService.cs          # FR-06 — ключевой сервис бота (см. ниже)
│   │   │   ├── TelegramSearchService.cs         # FR-05 — поиск для inline-кнопок бота
│   │   │   ├── GenreService.cs
│   │   │   ├── AuthService.cs                   # FR-08
│   │   │   ├── FavoriteService.cs
│   │   │   ├── ViewHistoryService.cs
│   │   │   ├── ReviewService.cs
│   │   │   ├── AdminMovieService.cs             # CRUD фильмов/жанров
│   │   │   ├── AdminSourceService.cs           
│   │   │   ├── AdminUserService.cs              # управление пользователями/ролями (AspNetUsers)
│   │   │   └── AdminAnalyticsService.cs         # агрегаты по ViewHistoryEntry/Review
│   │   │
│   │   ├── DTOs/
│   │   │   ├── Catalog/
│   │   │   │   ├── MovieListItemDto.cs
│   │   │   │   ├── MovieDetailsDto.cs
│   │   │   │   ├── VideoSourceDto.cs
│   │   │   │   ├── GenreDto.cs
│   │   │   │   └── ReviewDto.cs
│   │   │   ├── Auth/
│   │   │   │   ├── RegisterRequestDto.cs
│   │   │   │   ├── LoginRequestDto.cs
│   │   │   │   └── AuthResponseDto.cs
│   │   │   ├── User/
│   │   │   │   ├── FavoriteDto.cs
│   │   │   │   └── ViewHistoryDto.cs
│   │   │   └── Bot/
│   │   │       ├── TelegramMovieResultDto.cs
│   │   │       └── DownloadResultDto.cs          # File(url) | Link(url)
│   │   │
│   │   ├── Validators/
│   │   │   ├── RegisterRequestValidator.cs      # пароль >= 6 символов (FR-08 AC)
│   │   │   ├── MovieCreateValidator.cs
│   │   │   └── ParsingSourceValidator.cs
│   │   │
│   │   └── Mappings/
│   │       ├── MovieProfile.cs
│   │       └── UserProfile.cs
│   │
│   ├── CinemaHikes.Infrastructure/
│   │   │
│   │   ├── DependencyInjection.cs               # AddInfrastructure(IServiceCollection)
│   │   │
│   │   ├── Persistence/
│   │   │   ├── CinemaHikesDbContext.cs
│   │   │   ├── EntityTypeConfigurations/
│   │   │   │   ├── MovieEntityTypeConfiguration.cs
│   │   │   │   ├── GenreEntityTypeConfiguration.cs
│   │   │   │   ├── VideoSourceEntityTypeConfiguration.cs
│   │   │   │   ├── MovieLinkEntityTypeConfiguration.cs     # unique index (MovieId, Quality)
│   │   │   │   ├── ParsingSourceConfigEntityTypeConfiguration.cs
│   │   │   │   └── ...
│   │   │   └── Migrations/
│   │   │
│   │   ├── Identity/
│   │   │   ├── AppUser.cs : IdentityUser<int>
│   │   │   └── IdentityConfig.cs
│   │   │
│   │   ├── Repositories/
│   │   │   ├── Catalog/
│   │   │   │   ├── MovieRepository.cs
│   │   │   │   ├── GenreRepository.cs
│   │   │   │   ├── VideoSourceRepository.cs
│   │   │   │   ├── MovieLinkRepository.cs        # GetByMovieAndQuality, Upsert
│   │   │   │   └── ReviewRepository.cs
│   │   │   ├── Users/
│   │   │   │   └── UserMovieRelationRepository.cs   # generic<T> where T : class, IUserMovieRelation
│   │   │   ├── Parsing/
│   │   │   │   └── ParsingSourceRepository.cs
│   │   │   └── UnitOfWork.cs
│   │   │
│   │   ├── Bot/                                  # ↓ реализация — 1:1 с вашим репозиторием
│   │   │   ├── Configs/
│   │   │   │   ├── BrowserProfileConfig.cs        # record: UserAgent, Platform, Viewport, Locale, TimezoneId
│   │   │   │   ├── RandomBrowserConfig.cs         # : IBrowserConfig — headless Chromium args
│   │   │   │   └── RezkaPageConfig.cs             # : IPageConfig — GotoAsync + WaitForTimeout
│   │   │   │
│   │   │   ├── Facades/
│   │   │   │   └── RezkaFilmParserFacade.cs       # : IFilmParserFacade — оркестрирует парсинг страницы
│   │   │   │
│   │   │   ├── Factories/
│   │   │   │   └── PlaywrightBrowserFactory.cs    # : IBrowserFactory — Chromium.LaunchAsync + anti-detect script
│   │   │   │
│   │   │   ├── Parsers/
│   │   │   │   └── Rezka/
│   │   │   │       ├── RezkaFilmUrlParser.cs           # : IFilmUrlParser — клик по качеству, чтение <video src>
│   │   │   │       ├── RezkaGearIconParser.cs          # : IPageElementParser — клик по шестерёнке плеера
│   │   │   │       └── RezkaVideoQualityMenuParser.cs  # : IPageElementParser — открывает меню качества
│   │   │   │
│   │   │   ├── Providers/
│   │   │   │   └── BrowserProfileProvider.cs      # статический пул реалистичных профилей браузера (anti-bot)
│   │   │   │
│   │   │   └── Telegram/
│   │   │       ├── TelegramFileSender.cs          # : ITelegramFileSender (Telegram.Bot, SendVideo/SendMessage)
│   │   │       └── VideoSizeChecker.cs            # : IVideoSizeChecker (HEAD-запрос на прямую ссылку)
│   │   │
│   │   ├── BackgroundJobs/
│   │   │   └── RevalidateMovieLinksJob.cs        # перепроверка "протухших" ссылок в movie_links
│   │   │
│   │   └── Security/
│   │       ├── JwtTokenService.cs
│   │       └── CurrentUserService.cs
│   │
│   ├── CinemaHikes.WebApi/
│   │   ├── Controllers/
│   │   │   ├── AuthController.cs
│   │   │   ├── MoviesController.cs
│   │   │   ├── GenresController.cs
│   │   │   ├── FavoritesController.cs
│   │   │   ├── HistoryController.cs
│   │   │   ├── ReviewsController.cs
│   │   │   └── Admin/
│   │   │       ├── AdminMoviesController.cs
│   │   │       ├── AdminSourcesController.cs
│   │   │       ├── AdminUsersController.cs
│   │   │       └── AdminAnalyticsController.cs
│   │   ├── Middleware/
│   │   │   └── ExceptionHandlingMiddleware.cs
│   │   └── Program.cs
│   │
│   └── CinemaHikes.TelegramBotDownloader/
│       ├── .example.env
│       ├── Handlers/
│       │   ├── SearchTextHandler.cs              # текст → TelegramSearchService (FR-05)
│       │   ├── MovieSelectedCallbackHandler.cs   # выбор фильма → карточка + кнопки качества
│       │   └── DownloadCallbackHandler.cs        # выбор качества → MovieDownloadService (FR-06)
│       ├── RateLimiting/
│       │   └── TelegramRateLimiter.cs            # NFR-03, ConcurrentDictionary<long, DateTime>, in-memory
│       └── Program.cs                             # DI, TelegramBotClient, OnMessage/OnUpdate
│
└── tests/
    ├── CinemaHikes.Domain.UnitTests/
    ├── CinemaHikes.Application.UnitTests/
    ├── CinemaHikes.WebApi.IntegrationTests/
    └── CinemaHikes.TelegramBot.IntegrationTests/

📃 Frontend


cinema-hikes-frontend/
│
├── public/                      # Статика, которая не обрабатывается Webpack/Vite
│   ├── favicon.ico
│   └── assets/                  # Локальные заглушки (например, аватарка по умолчанию)
│
├── src/
│   │
│   ├── app/                     # 1. Инициализация и глобальные настройки
│   │   ├── providers/           
│   │   │   ├── AntdThemeProvider.tsx  # Настройка темной темы (Netflix style) через ConfigProvider
│   │   │   ├── AuthProvider.tsx       # Проверка токена при старте приложения
│   │   │   └── QueryProvider.tsx      # Настройка @tanstack/react-query (кэш запросов)
│   │   ├── router/              
│   │   │   ├── index.tsx              # Конфигурация react-router-dom
│   │   │   └── ProtectedRoute.tsx     # Защита роутов (редирект на логин, проверка UserRole)
│   │   ├── store/               
│   │   │   └── useAuthStore.ts        # Zustand: хранение JWT и данных текущего AppUser
│   │   ├── styles/              
│   │   │   └── global.css             # Глобальные сбросы и миксины (если не хватает antd)
│   │   └── App.tsx              # Корневой компонент (собирает провайдеры и роутер)
│   │
│   ├── layouts/                 # 2. Каркасы страниц (оболочки)
│   │   ├── MainLayout.tsx       # Клиентская часть: antd <Layout> + Navbar + Footer
│   │   ├── AdminLayout.tsx      # Админка: antd <Layout> + <Sider> (боковое меню)
│   │   └── AuthLayout.tsx       # Страницы входа: минималистичный фон для центрирования форм
│   │
│   ├── pages/                   # 3. Страницы (Только сборка фичей, минимум логики)
│   │   ├── public/              
│   │   │   ├── HomePage.tsx       # Слайдеры новинок, популярное
│   │   │   ├── CatalogPage.tsx    # Грид фильмов с фильтрацией (FR-01)
│   │   │   └── MoviePage.tsx      # Плеер, описание, отзывы (FR-03, FR-04)
│   │   ├── auth/                
│   │   │   ├── LoginPage.tsx      
│   │   │   └── RegisterPage.tsx   
│   │   ├── private/             
│   │   │   └── ProfilePage.tsx    # Личный кабинет (вкладки: Избранное, История)
│   │   └── admin/               
│   │       ├── DashboardPage.tsx  # Сводка и статистика (AdminAnalyticsController)
│   │       ├── MoviesMgmtPage.tsx # Таблица управления каталогом (CRUD)
│   │       └── UsersMgmtPage.tsx  # Управление правами (AdminUsersController)
│   │
│   ├── features/                # 4. Изолированные бизнес-модули (соответствуют сервисам C#)
│   │   ├── auth/                
│   │   │   ├── api/               # loginRequest, registerRequest
│   │   │   └── components/        # LoginForm, RegisterForm (на базе antd <Form>)
│   │   │
│   │   ├── catalog/             
│   │   │   ├── api/               # fetchMovies, fetchGenres (связь с MoviesController)
│   │   │   ├── hooks/             # useMoviesQuery, useGenresQuery
│   │   │   └── components/        # MovieFilterBar, MovieSearchInput, MovieCarousel
│   │   │
│   │   ├── movie-details/       
│   │   │   ├── api/               # fetchMovieDetails, fetchVideoSources
│   │   │   └── components/        # VideoPlayer, ReviewList (antd <List>), ReviewForm
│   │   │
│   │   ├── user-profile/        
│   │   │   ├── api/               # fetchFavorites, fetchHistory
│   │   │   └── components/        # FavoritesGrid, HistoryTimeline (antd <Timeline>)
│   │   │
│   │   └── admin/               
│   │       ├── api/               # admin CRUD методы
│   │       └── components/        # MoviesTable (antd <Table>), MovieEditModal (antd <Modal>)
│   │
│   ├── shared/                  # 5. Переиспользуемые технические и UI-модули
│   │   ├── api/                 
│   │   │   └── axiosClient.ts     # Базовый Axios + Interceptors (прикрепление JWT, обработка 401/403)
│   │   ├── types/                 # ⚠️ Точные копии ваших DTO из C# (interfaces)
│   │   │   ├── common.ts          # PaginatedResponse<T>
│   │   │   ├── enums.ts           # VideoQuality, SourceStatus, UserRole
│   │   │   └── dtos.ts            # MovieDetailsDto, MovieListItemDto и т.д.
│   │   ├── ui/                    # Глупые обертки над antd для соблюдения дизайн-кода проекта
│   │   │   ├── MovieCard/         # Карточка фильма (обертка над antd <Card>)
│   │   │   ├── GenreTag/          # Тег жанра (обертка над antd <Tag>)
│   │   │   └── PageSpinner.tsx    # Крутилка загрузки (antd <Spin>)
│   │   ├── hooks/               
│   │   │   └── useDebounce.ts     # Для оптимизации поиска (чтобы не спамить API при вводе)
│   │   └── utils/               
│   │       ├── dateUtils.ts       # Форматирование дат (через dayjs, который встроен в antd)
│   │       └── formatRuntime.ts   # Перевод минут в формат "1 ч 45 мин"
│   │
│   ├── main.tsx                 # Точка входа React
│   └── vite-env.d.ts            # Типизация Vite
│
├── .env                         # VITE_API_URL=https://localhost:5001/api
├── package.json
├── tsconfig.json
└── vite.config.ts               # Настройки сборщика, алиасы путей (@/features, @/shared)

🗄️ Database


CinemaHikes Database (PostgreSQL)
│
├── Identity/                          # ASP.NET Core Identity (AppUser : IdentityUser<int>)
│   ├── AspNetUsers
│   │   ├── Id               int           [PK]
│   │   ├── Email             varchar256    UNIQUE
│   │   ├── UserName           varchar256    UNIQUE
│   │   ├── PasswordHash        text
│   │   ├── RegisteredAt         timestamptz   # кастомное поле (FR-08)
│   │   └── AmountOfHats          int           DEFAULT 0
│   │
│   ├── AspNetRoles
│   │   ├── Id               int           [PK]
│   │   └── Name              varchar50     UNIQUE
│   │
│   └── AspNetUserRoles                # join-таблица AspNetUsers ↔ AspNetRoles
│       ├── Id               int           [PK]
│       ├── UserId             int           → FK AspNetUsers
│       └── RoleId              int           → FK AspNetRoles
│
├── Catalog/                            # Каталог фильмов — без актёров/каста
│   ├── Movies
│   │   ├── Id               int           [PK]
│   │   ├── RuTitle           varchar255
│   │   ├── UaTitle            varchar255
│   │   ├── RuInEngTitle         varchar255
│   │   ├── ReleaseYear            smallint
│   │   ├── PosterUrl               varchar500
│   │   ├── KpRating                 numeric(3,1)
│   │   └── CreatedAt                  timestamptz
│   │
│   ├── Genres
│   │   ├── Id               int           [PK]
│   │   └── Name              varchar50     UNIQUE
│   │
│   ├── MovieGenres                     # join-таблица Movies ↔ Genres
│   │   ├── Id               int           [PK]
│   │   ├── MovieId            int           → FK Movies
│   │   └── GenreId             int           → FK Genres
│   │
│   ├── VideoSources                    # плеер/источник: PageUrl на сайт-источник (FR-04)
│   │   ├── Id               int           [PK]
│   │   ├── MovieId            int           → FK Movies
│   │   ├── ProviderName         varchar50
│   │   ├── PageUrl                varchar500
│   │   ├── Priority                smallint
│   │   └── Status                   enum (SourceStatus)
│   │
│   ├── MovieLinks                      # прямая ссылка (FR-06), обычная таблица без TTL
│   │   ├── Id               int           [PK]
│   │   ├── MovieId            int           → FK Movies
│   │   ├── Quality             enum (VideoQuality)   UNIQUE*
│   │   ├── Url                  varchar1000
│   │   └── UpdatedAt              timestamptz          # * UNIQUE(MovieId, Quality)
│   │
│   └── Reviews
│       ├── Id               int           [PK]
│       ├── MovieId            int           → FK Movies
│       ├── UserId              int           → FK AspNetUsers
│       ├── Text                 nvarchar(200)
│       ├── Rating                smallint
│       ├── Status                 enum (ReviewStatus)
│       └── CreatedAt                timestamptz
│
├── Users/                              # Личный кабинет (IUserMovieRelation)
│   ├── FavoriteMovies
│   │   ├── Id               int           [PK]
│   │   ├── UserId             int           → FK AspNetUsers
│   │   ├── MovieId             int           → FK Movies
│   │   └── CreatedAt             timestamptz
│   │
│   └── ViewHistory
│       ├── Id               int           [PK]
│       ├── UserId             int           → FK AspNetUsers
│       ├── MovieId             int           → FK Movies
│       ├── ProgressSeconds      int
│       └── CreatedAt              timestamptz
│
└── Parsing/                            # обслуживается IParsingSourceRepository
    └── ParsingSourceConfigs
        ├── Id               int           [PK]
        ├── Name              varchar50     UNIQUE
        ├── BaseUrl             varchar255
        ├── ParserType           varchar50
        └── IsEnabled              boolean
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment