История разработки

Некоторое время я с интересом наблюдал за развитием фреймворка MiMiMi - от его первого наброска, бывшего скорее личным экспериментом одиночки вебмастера на давно забытом всеми поле миниатюрных компонентов разработки, до последней версии, способной уже дать легковесные решения для некоторых базовых ситуаций в вебстудиях.

Положеная в основу MiMiMi идея искать для задач кратчайший алгоритм тоже оказалась близкой мне по духу. Поэтому, рассматривая первые появляющиеся во фреймворке демонстрационные примеры, я стал задумываться: "А что мог бы показать я как разработчик для русскоязычной аудитории?"

Только мне хотелось, чтобы моё демо решало настоящую проблему людей, а не боролось с какой-то ситуацией в сферическом вакууме. Находясь по воле случая в зоне боевого столкновения, я неизбежно обратился к трудностям вынужденных переселенцев. Люди там теряют жильё, поспешно мигрируют из разрушенных посёлков. Попадая обнищавшими в неизвестные им города, часто имеют в кармане лишь смартфон да мессенджер на нём.

Для них остро стоит вопрос поиска работы, поэтому хождение на биржу труда, вычитывание раздела вакансий в местной газете объявлений становится ежедневной рутиной. Вот я и подумал, почему бы не разработать крохотное приложение, которое легко устанавливается на бюджетный хостинг, настраивается на конкретный город и присылает вакансии страждущему в Телеграм или Max канал, специально созданный под его беду.

Принцип работы приложения

В каждом городе Российской Федерации есть муниципальный центр занятости, проще говоря, городская биржа труда. Одному из сотрудников центра делегирована задача ежедневно отправлять в открытую государственную базу данных РФ сведения о новых вакансиях, появившихся в городе за истекшие сутки.

Так вот, как я себе представлял, моё приложение размещается в виде вебсайта на каком-нибудь хостинге и занимается простым действием: ежечасно опрашивает государственную БД на предмет появившейся вакансии для заданного города, а в случае появления, тут же считывает её в форме JSON-пакета, затем парсит, то есть извлекает только нужные нам подробности, и пересылает в заблаговременно созданный Телеграм канал уже в читабельной форме.

Для удобства приложение имеет бекенд, то есть админпанель, где вы задаёте основные настройки сайта и перечень заданий для парсера, а также фронтенд, то есть лицевая сторона сайта для просмотра тех же вакансий людьми, кто предпочитает пользоваться браузером, а не мессенджером.

Исходный код моего приложения очень простой, и тем не менее, предлагает вполне себе приличный функционал. Поэтому далее я опишу, как создавал приложение, чтобы вы понимали, где что искать в нём, если захотите самостоятельно доработать функционал под себя.

Подготовка

Прежде всего я скачал с официального сайта последнюю версию фреймворка (7.3 на тот момент) в виде ZIP-файла и распаковал содержимое в директорию веб-сервера на своём локальном компьютере - его называют localhost.

Получился некий набор директорий и файлов, к которым я сразу же добавил пустую папку repost.vacancies - здесь будет моё приложение.

Вот что получилось.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Затем я стал думать, из каких основных модулей и их дочерних субмодулей будет состоять моё приложение. Ведь разработка с применением фреймворка MiMiMi подразумевает, что любое приложение состоит из обязательного главного файла Application.php и опционального набора модулей, представляющих собой директорию с одноимённым PHP-файлом в ней.

Главный файл

Прежде чем перейти к дочерним модулям, я создал главный модуль приложения - это файл Application.php, и прописал в нём программный код как я видел себе первые шаги работы приложения.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Фреймворк устроен так, что любые запросы к серверу, которые не указывают на реально существующий статический файл (наподобие картинки, стиля, явапскрипта и тому подобных), всегда заворачиваются на главный модуль приложения, а именно его общедоступный метод run().

Недолго размышляя, я возложил на этот метод всего 2 обязанности: запустить модуль сеанса для различения обычных пользователей сайта и его администраторов, и маршрутизировать запрос к конкретному модулю контроллера, сопоставленному с URL-ом запрошенной страницы.

Здесь я допустил некрасивую вольность: намертво вшил в исходный код метода все сопоставления URL-ов и обслуживающих их контроллеров. Получился вот такой список URL-ов:

https://ваш.сайт/

https://ваш.сайт/faq
https://ваш.сайт/faq/for-developers

https://ваш.сайт/parse

https://ваш.сайт/login
https://ваш.сайт/logout
https://ваш.сайт/password/change

https://ваш.сайт/settings

https://ваш.сайт/tasks
https://ваш.сайт/tasks/add
https://ваш.сайт/tasks/copy
https://ваш.сайт/tasks/delete
https://ваш.сайт/tasks/edit

https://ваш.сайт/vacancies/delete
https://ваш.сайт/vacancies/edit
https://ваш.сайт/vacancies

https://ваш.сайт/robots.txt
https://ваш.сайт/sitemap.xml

Вшить связи намертво - это не критично в данном случае, но всё же недостаток приложения. Он создаст лишнюю мороку по переписыванию связей, если мы захотели бы поменять завтра, скажем, структуру URL-а, или имена контроллеров, или добавить функционал, или наоборот убрать лишнее.

Модуль сеанса

Думаю, вы догадались, что я назвал этот модуль логичным именем Session.

По сути, он является примитивной обёрткой для стандартных директив языка программирования, обслуживающих сеансовые переменные, и предлагает простейшие методы для извлечения, сохранения или удаления заданной переменнной сеанса: get(), set(), remove().

Вот что получилось на данном шаге разработки.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [-] Session
    │       │       └─> Session.php
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Чтобы различать пользователей и админов сайта, я планировал реализовать самую простую схему авторизации, которая при успешном входе хранит в сеансе лишь единственную переменную с именем "user_marker". А наличие этой переменной является сигналом, что на сайте сейчас присутствует администратор.

В идеале, конечно добавить бы ещё переменную для таймаута, чтобы между соседними неудачными авторизациями выдерживать паузу и тем самым избежать атак на перебор пароля. Но я уже не стал заморачиваться, так как приложение служит всё же демонстрационным целям, а при желании вы легко доработаете этот момент под свой стандарт безопасности.

Готовим структуру модулей

Итак теперь, когда стало понятно, каким будет формат URL-а и какие модули станут основными в приложении, я перешёл к формированию файловой структуры модулей.

Так как мне нравилась архитектура Model-View-Controller, где модули контроллеров отвечают за конкретный алгоритм взаимодействия с пользователем, а модули моделей отвечают за алгоритмы оперирования своей таблицей базы данных, и модули представлений - за определённый вид упаковки результирующих данных, прежде чем отправить их в браузер или мессенджер, то и файловую структуру модулей я стремился выстроить похожей на эту архитектуру.

Значит, у меня получилась вот такая понятная схема.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [-] Controllers
    │       │       └─> Controllers.php
    │       ├─> [-] Models
    │       │       └─> Models.php
    │       ├─> [+] Session
    │       ├─> [-] Views
    │       │       └─> Views.php
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Здесь мы видим главный файл приложения, плюс уже упоминавшийся модуль сеанса, плюс ещё 3 основных модуля: Controllers, Models, Views. Они играют роль трёх хранителей, а в своей директории каждый станет хранить все дочерние модули соответствующего типа.

Мне лишь оставалось определить перечень дочерних модулей, размещённых в каждом хранителе. Я начал с моделей.

Накидываем модели

По моему представлению, база данных сайта должна была иметь 3 простые таблицы: settings - чтобы хранить настройки приложения, tasks - чтобы хранить задания для парсера, и vacancies - чтобы запоминать уже спарсенные вакансии и не сканировать их всякий раз заново.

Разумеется, для каждой таблицы я создал свою модель: она описывала структуру колонок и предоставляла несколько методов, специфичных для её таблицы.

Вот что у меня получилось на этом этапе.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [+] Controllers
    │       ├─> [-] Models
    │       │       ├─> [-] Settings
    │       │       │       └─> Settings.php
    │       │       ├─> [-] Tasks
    │       │       │       └─> Tasks.php
    │       │       ├─> [-] Vacancies
    │       │       │       └─> Vacancies.php
    │       │       └─> Models.php
    │       ├─> [+] Session
    │       ├─> [+] Views
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Здесь мы видим, что в приложении существует модуль Models, а в нём существуют 3 дочерних модуля: Settings, Tasks, Vacancies.

Сразу отмечу, что модуль хранителя моделей я делал порождением от базового модуля Sqlite, уже входящего в установочный пакет фреймворка MiMiMi. То есть для работы моего приложения не требуется, чтобы на хостинге присутствовал сервер баз данных MySQL, достаточно дефолтной поддержки класса SQLite3 в конфигурации PHP. Если же вы не поняли, о чём сейчас шла речь, уточните данный момент у своего сисадмина.

На всякий случай покажу вам расположение упомянутого базового модуля.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [-] mimimi.modules
    │       ├─> [+] Cache
    │       ├─> [+] Db
    │       ├─> [+] Helper
    │       ├─> [+] Security
    │       ├─> [+] Session
    │       ├─> [+] Settings
    │       ├─> [-] Sqlite
    │       │       └─> Sqlite.php
    │       ├─> [+] Telegram
    │       ├─> [+] Url
    │       └─> [+] Xml
    ├─> [+] newspaper
    ├─> [+] repost.vacancies
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Идём дальше.

Накидываем представления

С самого начала я задумал, что приложение будет отправлять вакансии как в браузер пользователя, так и в мессенджеры Телеграм и/или Max. Поэтому в директории хранителя представлений я не видел иных вариантов, кроме 3 следующих дочерних модулей: Html - чтобы генерировать вакансию в виде классической веб-страницы, Max и Телеграм - чтобы генерировать ту же вакансию в форме запроса к Bot API соответствующего мессенджера.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [+] Controllers
    │       ├─> [+] Models
    │       ├─> [+] Session
    │       ├─> [-] Views
    │       │       ├─> [-] Html
    │       │       │       └─> Html.php
    │       │       ├─> [-] Max
    │       │       │       └─> Max.php
    │       │       ├─> [-] Telegram
    │       │       │       └─> Telegram.php
    │       │       └─> Views.php
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Отмечу также, что мессенджер Max пока (по состоянию на декабрь 2025 года) не предоставляет частным лицам доступ к своему API, поэтому его модуль я сделал обычной заглушкой. То есть модуль Max вообще ничего не делает, лишь имитируя ситуацию, будто вакансию не удалось отправить в мессенджер по неизвестной причине.

Ещё подчеркну, что модуль Telegram я тоже делал порождением от одноимённого базового модуля, уже входящего в установочный пакет фреймворка MiMiMi. Покажу вам и расположение этого базового модуля на всякий случай.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [-] mimimi.modules
    │       ├─> [+] Cache
    │       ├─> [+] Db
    │       ├─> [+] Helper
    │       ├─> [+] Security
    │       ├─> [+] Session
    │       ├─> [+] Settings
    │       ├─> [+] Sqlite
    │       ├─> [-] Telegram
    │       │       └─> Telegram.php
    │       ├─> [+] Url
    │       └─> [+] Xml
    ├─> [+] newspaper
    ├─> [+] repost.vacancies
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Накидываем контроллеры

Исходя из принципа работы приложения, ожидалось наличие следующих типов страниц, а значит, связанных с ними дочерних модулей контроллеров: Dashboard - для всяких там страниц админпанели, Faq - для страниц наподобие "Частые Вопросы-Ответы", Home - для главной страницы сайта, Parser - для конечной точки (URL-а) запуска парсера по расписанию CRON-а, Seo - для типичных документов поисковым роботам, Vacancies - для постраничного листинга вакансий на фронтенде сайта.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [-] Controllers
    │       │       ├─> [-] Dashboard
    │       │       │       └─> Dashboard.php
    │       │       ├─> [-] Faq
    │       │       │       └─> Faq.php
    │       │       ├─> [-] Home
    │       │       │       └─> Home.php
    │       │       ├─> [-] Parser
    │       │       │       └─> Parser.php
    │       │       ├─> [-] Seo
    │       │       │       └─> Seo.php
    │       │       ├─> [-] Vacancies
    │       │       │       └─> Vacancies.php
    │       │       └─> Controllers.php
    │       ├─> [+] Models
    │       ├─> [+] Session
    │       ├─> [+] Views
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Здесь следует отметить, что контроллер Dashboard представляет собой админпанель, в которой я планировал сделать несколько страниц. Соответственно, для каждой я создам субконтроллеры в виде дочерних модулей Dashboard-а, о чём сейчас расскажу.

Страницы админпанели

Исходя из оговоренной выше структуры URL-а, я предположил, что в админпанели мне понадобится всего 4 типа страниц, и с каждым будет сопоставлен свой модуль субконтроллера: Login - для авторизации, завершения работы или смены пароля, Settings - для редактирования настроек сайта, Tasks и Vacancies - для редактирования записей в соответствующих таблицах базы данных.

Вот что у меня получилось на данном шаге.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [-] Controllers
    │       │       ├─> [-] Dashboard
    │       │       │       ├─> [-] Login
    │       │       │       │       └─> Login.php
    │       │       │       ├─> [-] Settings
    │       │       │       │       └─> Settings.php
    │       │       │       ├─> [-] Tasks
    │       │       │       │       └─> Tasks.php
    │       │       │       ├─> [-] Vacancies
    │       │       │       │       └─> Vacancies.php
    │       │       │       └─> Dashboard.php
    │       │       ├─> [+] Faq
    │       │       ├─> [+] Home
    │       │       ├─> [+] Parser
    │       │       ├─> [+] Seo
    │       │       ├─> [+] Vacancies
    │       │       └─> Controllers.php
    │       ├─> [+] Models
    │       ├─> [+] Session
    │       ├─> [+] Views
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Парсер

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

Так как в моём случае планировалось парсить только вакансии с российской платформы "Труд всем", я потому и сделал лишь единственный дочерний модуль под именем Trudvsem.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [-] Controllers
    │       │       ├─> [+] Dashboard
    │       │       ├─> [+] Faq
    │       │       ├─> [+] Home
    │       │       ├─> [-] Parser
    │       │       │       ├─> [-] Trudvsem
    │       │       │       │       └─> Trudvsem.php
    │       │       │       └─> Parser.php
    │       │       ├─> [+] Seo
    │       │       ├─> [+] Vacancies
    │       │       └─> Controllers.php
    │       ├─> [+] Models
    │       ├─> [+] Session
    │       ├─> [+] Views
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

Но при необходимости вы можете дописать модули парсинга из своих источников. Для этого надо иметь навыки программирования, а для вдохновения просто загляните как устроен написанный мной модуль.

Шаблон сайта

Раз уж приложение способно генерировать вакансии в виде классических веб-страниц, значит такая динамическая HTML-разметка должна где-то храниться. Это хранилище называют шаблоном сайта, и в нём размещаются макеты для каждого типа генерируемых страниц.

Обычно файлам макетов дают какое-нибудь классическое и понятное расширение. Например, .html - обозначая тем самым статический макет, .php - намекая на макет динамической генерации.

Я использовал расширение .tpl - это сокращение от слова template, чтобы избежать известной ещё со времён Wordpress-а тривиальной атаки, когда злоумышленник пробует запустить динамический макет с расширением .php, запрашивая его по прямому URL в расчёте на то, что неприспособленный к подобному вызову макет откроет какую-нибудь уязвимость движка сайта.

Итак, я создал шаблон со всеми нужными мне макетами и добавил в директорию приложения как тему под именем Themes/default. Вот что теперь получилось.

localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] repost.vacancies
    │       ├─> [+] Controllers
    │       ├─> [+] Models
    │       ├─> [+] Session
    │       ├─> [-] Themes
    │       │       └─> [-] default
    │       │               ├─> [-] css
    │       │               │       └─> styles.css
    │       │               ├─> [-] dashboard
    │       │               │       ├─> login.tpl
    │       │               │       ├─> logout.tpl
    │       │               │       ├─> password-change.tpl
    │       │               │       ├─> settings.tpl
    │       │               │       ├─> tasks-add.tpl
    │       │               │       ├─> tasks-copy.tpl
    │       │               │       ├─> tasks-delete.tpl
    │       │               │       ├─> tasks-edit.tpl
    │       │               │       ├─> tasks.tpl
    │       │               │       ├─> vacancies-delete.tpl
    │       │               │       └─> vacancies-edit.tpl
    │       │               ├─> [-] faq
    │       │               │       └─> for-developers.tpl
    │       │               ├─> [-] images
    │       │               │       └─> favicon.ico
    │       │               ├─> [-] js
    │       │               │       └─> scripts.js
    │       │               ├─> [-] max
    │       │               │       └─> [-] vacancy
    │       │               ├─> [-] snippets
    │       │               │       ├─> [-] vacancy-card
    │       │               │       │       └─> [-] trudvsem.tpl
    │       │               │       ├─> admintools.tpl
    │       │               │       ├─> demo-remark-1.tpl
    │       │               │       ├─> demo-remark-2.tpl
    │       │               │       ├─> footer.tpl
    │       │               │       ├─> pagination.tpl
    │       │               │       ├─> task-card.tpl
    │       │               │       └─> task-form.tpl
    │       │               ├─> [-] telegram
    │       │               │       └─> [-] vacancy
    │       │               │               └─> [-] trudvsem.tpl
    │       │               ├─> faq.tpl
    │       │               ├─> home.tpl
    │       │               ├─> page404.tpl
    │       │               ├─> parse.tpl
    │       │               ├─> robots.tpl
    │       │               ├─> sitemap.tpl
    │       │               ├─> vacancies.tpl
    │       │               └─> vacancy.tpl
    │       ├─> [+] Views
    │       └─> Application.php
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php

На этом шаге разработка приложения была завершена, и я перешёл к написанию комментариев исходного кода и демонстрационному заполнению страницы "Частые Вопросы-Ответы" с историей разработки приложения.

Путь запроса из браузера

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

Чтобы вы представляли себе путь движения запроса по файлам и модулям сайта, нарисую его схему. Здесь стрелки вправо обозначают порядок загрузки файлов сайта и выполнения их методов, а стрелки влево - какие сущности декларировались загруженным файлом для использования в вашем приложении.

├─> .htaccess
│
│   ┌─<─ несколько констант вида MIMIMI_...
│   ├─<─ процедура mimimiLoad()
│   │
└─> index.php
      │
      ├─> mimimi.core/Config.php
      │               │
      │               └─<─ ещё несколько констант вида MIMIMI_...
      │
      ├─> mimimi.core/RoutinesSystem.php
      │               │
      │               ├─<─ ещё константа вида MIMIMI_...
      │               ├─<─ процедура mimimiInclude()
      │               └─<─ и ещё несколько процедур вида mimimi...()
      │
      │   ┌─────────────────────────────────────┐
      ├─> │ СОЗДАНИЕ ГЛОБАЛЬНОЙ ПЕРЕМЕННОЙ $app │
      │   └─────────────────────────────────────┘
      │
      │                    ┌─> mimimi.core/RoutinesWeb.php
      │                    │               │
      │                    │               ├─<─ процедура mimimiUri()
      │                    │               ├─<─ процедура mimimiModule()
      │                    │               └─<─ и ещё несколько процедур вида mimimi...()
      │                    │
      │                    │                      ┌─<─ класс mimimi.core/Module.php
      │                    │                      │                             │
      │                    ├─<─ класс mimimi.core/NodeModule.php                ├─<─ свойство $owner
      │                    │                      │                             ├─<─ свойство $app
      └─> repost.vacancies/Application.php        ├─<─ свойство $myNodeFile     └─<─ метод    run()
                                │                 └─<─ метод    getNodePath()
                                └─> run()
                                     │
                         ┌───────────┴──────────┐
                         │ ЗАПУСК МОДУЛЯ СЕАНСА │
                         └───────────┬──────────┘                 ┌─<─ класс mimimi.core/Module.php
                                     │                            │
                                     ├─> repost.vacancies/Session/Session.php
                                     │                            │  │
                                     │                            │  └─> run()
                                     │                            │
                                     └─> routeFor()               ├─<─ метод get()
                                             │                    ├─<─ метод set()
                              ┌──────────────┴────────────┐       └─<─ метод remove()                ┌─<─ класс mimimi.core/Module.php
                              │ ЗАПУСК МОДУЛЯ КОНТРОЛЛЕРА │                                          │
                              └──────────────┬────────────┘                   ┌─<─ класс mimimi.core/NodeModule.php
                                             │                                │                                                            ┌─<─ класс mimimi.core/Module.php
                                             └─> repost.vacancies/Controllers/Controllers.php                                              │
                                                                              │    │                                ┌───────────────────┐ ┌┴──────────────────┐
                                                                              │    └─> repost.vacancies/Controllers/│ Некий контроллер: │/│ Некий контроллер: │.php
                                                                              │                                     │     Dashboard     │ │     Dashboard     │
                                                                              ├─<─ метод getPageNum()               │         Faq       │ │         Faq       │
                                                                              ├─<─ метод getItemId()                │        Home       │ │        Home       │
                                                                              └─<─ метод getFilter()                │       Parser      │ │       Parser      │
                                                                                                                    │         Seo       │ │         Seo       │
                                                                                                                    │      Vacancies    │ │      Vacancies    │
                                                                                                                    └───────────────────┘ └────────┬──────────┘
                                                                                                                                                   │
                                                                                                                                                   └─> run()
                                                                                                                                                        │
      ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
      │
      │                                                                                                         ┌─<─ класс mimimi.core/Module.php
      │                                                                                                         │
      │   ┌────────────────────────────────────┐                                         ┌─<─ класс mimimi.core/NodeModule.php
      ├───┤ ИЗВЛЕЧЕНИЕ ДАННЫХ С ПОМОЩЬЮ МОДЕЛИ │                                         │
      │   └─────────────────┬──────────────────┘        ┌─<─ класс mimimi.modules/Sqlite/Sqlite.php
      │                     │                           │                                │
      │                     │                           │                                ├─<─ метод escape()
      │                     │                           │                                ├─<─ метод bind()
      │                     │                           │                                ├─<─ метод makeSET()
      │                     │                           │                                ├─<─ метод exec()
      │                     │                           │                                ├─<─ метод query()
      │                     │                           │                                ├─<─ метод queryFirst()
      │                     │                           │                                ├─<─ метод queryRow()
      │                     │                           │                                └─<─ метод queryRows()
      │                     │                           │
      │                     │                           │                                                 ┌─<─ класс mimimi.core/Module.php
      │                     └─> repost.vacancies/Models/Models.php                                        │
      │                                                 │  │                           ┌───────────────┐ ┌┴──────────────┐
      │                                                 │  └─> repost.vacancies/Models/│ Некая модель: │/│ Некая модель: │.php
      │                                                 │                              │    Settings   │ │    Settings   │
      │                                                 ├─<─ метод addFor()            │      Tasks    │ │      Tasks    │
      │                                                 ├─<─ метод getByFor()          │    Vacancies  │ │    Vacancies  │
      │                                                 ├─<─ метод selectAllFor()      └───────────────┘ └───────┬───────┘
      │                                                 ├─<─ метод removeFor()                                   │
      │                                                 └─<─ метод updateFor()                                   └─> некийМетодМодели()
      │   ┌──────────────────────────────────────────┐                            ┌─<─ класс mimimi.core/Module.php
      ├───┤ ГЕНЕРАЦИЯ ОТВЕТА С ПОМОЩЬЮ ПРЕДСТАВЛЕНИЯ │                            │
      │   └─────────────────────┬────────────────────┘     ┌─<─ класс mimimi.core/NodeModule.php
      │                         │                          │                                                      ┌─<─ класс mimimi.core/Module.php
      │                         └─> repost.vacancies/Views/Views.php                                              │
      │                                                      │                          ┌──────────────────────┐ ┌┴─────────────────────┐
      │                                                      └─> repost.vacancies/Views/│ Некое представление: │/│ Некое представление: │.php
      │                                                                                 │          Html        │ │          Html        │
      │                                                                                 │           Max        │ │           Max        │
      │                                                                                 │        Telegram      │ │        Telegram      │
      │   ┌────────────────────────────────────────────────┐                            └──────────────────────┘ └───────────┬──────────┘
      └─> │ ОТПРАВКА КОНЕЧНОГО HTML В БРАУЗЕР ПОЛЬЗОВАТЕЛЯ │                                                                 │
          └────────────────────────────────────────────────┘                                                                 └─> некийМетодПредставления()

Спасибо за внимание! Если возникнут идеи, предложения - пишите, с интересом выслушаю. Если захотите задонатить на чашку кофе/чая, булочку - буду рад :)