<!DOCTYPE html>
<html lang="ru-RU">
    <head>
        <base href="<?php printSiteUrl ( ) ?>">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="robots" content="index, follow">
        <title>Как было сделано это приложение</title>
        <meta name="description" content="Краткая история о шагах разработки данного приложения. Прочтите её, если захотите самостоятельно доработать его под себя.">
        <link rel="canonical" href="<?php printSiteUrl ( ) ?>">
        <link rel="shortcut icon" href="<?php printThemeUrl ( ) ?>images/favicon.ico" type="image/ico">
        <link rel="stylesheet" href="<?php printThemeUrl ( ) ?>css/styles.css">
    </head>
    <body>
        <main>
            <h1>История разработки</h1>
            <p>Некоторое время я с интересом наблюдал за развитием фреймворка MiMiMi - от его первого наброска, бывшего скорее личным экспериментом одиночки вебмастера на давно забытом всеми поле миниатюрных компонентов разработки, до последней версии, способной уже дать легковесные решения для некоторых базовых ситуаций в вебстудиях.</p>
            <p>Положеная в основу MiMiMi идея искать для задач кратчайший алгоритм тоже оказалась близкой мне по духу. Поэтому, рассматривая первые появляющиеся во фреймворке демонстрационные примеры, я стал задумываться: "А что мог бы показать я как разработчик для русскоязычной аудитории?"</p>
            <p>Только мне хотелось, чтобы моё демо решало настоящую проблему людей, а не боролось с какой-то ситуацией в сферическом вакууме. Находясь по воле случая в зоне боевого столкновения, я неизбежно обратился к трудностям вынужденных переселенцев. Люди там теряют жильё, поспешно мигрируют из разрушенных посёлков. Попадая обнищавшими в неизвестные им города, часто имеют в кармане лишь смартфон да мессенджер на нём.</p>
            <p>Для них остро стоит вопрос поиска работы, поэтому хождение на биржу труда, вычитывание раздела вакансий в местной газете объявлений становится ежедневной рутиной. Вот я и подумал, почему бы не разработать крохотное приложение, которое легко устанавливается на бюджетный хостинг, настраивается на конкретный город и присылает вакансии страждущему в Телеграм или Max канал, специально созданный под его беду.</p>

            <h2>Принцип работы приложения</h2>
            <p>В каждом городе Российской Федерации есть муниципальный центр занятости, проще говоря, городская биржа труда. Одному из сотрудников центра делегирована задача ежедневно отправлять в открытую государственную базу данных РФ сведения о новых вакансиях, появившихся в городе за истекшие сутки.</p>
            <p>Так вот, как я себе представлял, моё приложение размещается в виде вебсайта на каком-нибудь хостинге и занимается простым действием: ежечасно опрашивает государственную БД на предмет появившейся вакансии для заданного города, а в случае появления, тут же считывает её в форме JSON-пакета, затем парсит, то есть извлекает только нужные нам подробности, и пересылает в заблаговременно созданный Телеграм канал уже в читабельной форме.</p>
            <p>Для удобства приложение имеет бекенд, то есть админпанель, где вы задаёте основные настройки сайта и перечень заданий для парсера, а также фронтенд, то есть лицевая сторона сайта для просмотра тех же вакансий людьми, кто предпочитает пользоваться браузером, а не мессенджером.</p>
            <p>Исходный код моего приложения очень простой, и тем не менее, предлагает вполне себе приличный функционал. Поэтому далее я опишу, как создавал приложение, чтобы вы понимали, где что искать в нём, если захотите самостоятельно доработать функционал под себя.</p>

            <h2>Подготовка</h2>
            <p>Прежде всего я скачал с официального сайта последнюю версию фреймворка (7.3 на тот момент) в виде ZIP-файла и распаковал содержимое в директорию веб-сервера на своём локальном компьютере - его называют localhost.</p>
            <p>Получился некий набор директорий и файлов, к которым я сразу же добавил пустую папку repost.vacancies - здесь будет моё приложение.</p>
            <p>Вот что получилось.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Затем я стал думать, из каких основных модулей и их дочерних субмодулей будет состоять моё приложение. Ведь разработка с применением фреймворка MiMiMi подразумевает, что любое приложение состоит из обязательного главного файла Application.php и опционального набора модулей, представляющих собой директорию с одноимённым PHP-файлом в ней.</p>

            <h2>Главный файл</h2>
            <p>Прежде чем перейти к дочерним модулям, я создал главный модуль приложения - это файл Application.php, и прописал в нём программный код как я видел себе первые шаги работы приложения.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Фреймворк устроен так, что любые запросы к серверу, которые не указывают на реально существующий статический файл (наподобие картинки, стиля, явапскрипта и тому подобных), всегда заворачиваются на главный модуль приложения, а именно его общедоступный метод run().</p>
            <p>Недолго размышляя, я возложил на этот метод всего 2 обязанности: запустить модуль сеанса для различения обычных пользователей сайта и его администраторов, и маршрутизировать запрос к конкретному модулю контроллера, сопоставленному с URL-ом запрошенной страницы.</p>
            <p>Здесь я допустил некрасивую вольность: намертво вшил в исходный код метода все сопоставления URL-ов и обслуживающих их контроллеров. Получился вот такой список URL-ов:</p>
            <pre>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</pre>
            <p>Вшить связи намертво - это не критично в данном случае, но всё же недостаток приложения. Он создаст лишнюю мороку по переписыванию связей, если мы захотели бы поменять завтра, скажем, структуру URL-а, или имена контроллеров, или добавить функционал, или наоборот убрать лишнее.</p>

            <h2>Модуль сеанса</h2>
            <p>Думаю, вы догадались, что я назвал этот модуль логичным именем Session.</p>
            <p>По сути, он является примитивной обёрткой для стандартных директив языка программирования, обслуживающих сеансовые переменные, и предлагает простейшие методы для извлечения, сохранения или удаления заданной переменнной сеанса: get(), set(), remove().</p>
            <p>Вот что получилось на данном шаге разработки.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [-] <code>Session</code>
    │       │       └─> <code>Session.php</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Чтобы различать пользователей и админов сайта, я планировал реализовать самую простую схему авторизации, которая при успешном входе хранит в сеансе лишь единственную переменную с именем "user_marker". А наличие этой переменной является сигналом, что на сайте сейчас присутствует администратор.</p>
            <p>В идеале, конечно добавить бы ещё переменную для таймаута, чтобы между соседними неудачными авторизациями выдерживать паузу и тем самым избежать атак на перебор пароля. Но я уже не стал заморачиваться, так как приложение служит всё же демонстрационным целям, а при желании вы легко доработаете этот момент под свой стандарт безопасности.</p>

            <h2>Готовим структуру модулей</h2>
            <p>Итак теперь, когда стало понятно, каким будет формат URL-а и какие модули станут основными в приложении, я перешёл к формированию файловой структуры модулей.</p>
            <p>Так как мне нравилась архитектура Model-View-Controller, где модули контроллеров отвечают за конкретный алгоритм взаимодействия с пользователем, а модули моделей отвечают за алгоритмы оперирования своей таблицей базы данных, и модули представлений - за определённый вид упаковки результирующих данных, прежде чем отправить их в браузер или мессенджер, то и файловую структуру модулей я стремился выстроить похожей на эту архитектуру.</p>
            <p>Значит, у меня получилась вот такая понятная схема.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [-] <code>Controllers</code>
    │       │       └─> <code>Controllers.php</code>
    │       ├─> [-] <code>Models</code>
    │       │       └─> <code>Models.php</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [-] <code>Views</code>
    │       │       └─> <code>Views.php</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Здесь мы видим главный файл приложения, плюс уже упоминавшийся модуль сеанса, плюс ещё 3 основных модуля: Controllers, Models, Views. Они играют роль трёх хранителей, а в своей директории каждый станет хранить все дочерние модули соответствующего типа.</p>
            <p>Мне лишь оставалось определить перечень дочерних модулей, размещённых в каждом хранителе. Я начал с моделей.</p>

            <h2>Накидываем модели</h2>
            <p>По моему представлению, база данных сайта должна была иметь 3 простые таблицы: settings - чтобы хранить настройки приложения, tasks - чтобы хранить задания для парсера, и vacancies - чтобы запоминать уже спарсенные вакансии и не сканировать их всякий раз заново.</p>
            <p>Разумеется, для каждой таблицы я создал свою модель: она описывала структуру колонок и предоставляла несколько методов, специфичных для её таблицы.</p>
            <p>Вот что у меня получилось на этом этапе.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [+] <code>Controllers</code>
    │       ├─> [-] <code>Models</code>
    │       │       ├─> [-] <code>Settings</code>
    │       │       │       └─> <code>Settings.php</code>
    │       │       ├─> [-] <code>Tasks</code>
    │       │       │       └─> <code>Tasks.php</code>
    │       │       ├─> [-] <code>Vacancies</code>
    │       │       │       └─> <code>Vacancies.php</code>
    │       │       └─> <code>Models.php</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [+] <code>Views</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Здесь мы видим, что в приложении существует модуль Models, а в нём существуют 3 дочерних модуля: Settings, Tasks, Vacancies.</p>
            <p>Сразу отмечу, что модуль хранителя моделей я делал порождением от базового модуля Sqlite, уже входящего в установочный пакет фреймворка MiMiMi. То есть для работы моего приложения не требуется, чтобы на хостинге присутствовал сервер баз данных MySQL, достаточно дефолтной поддержки класса SQLite3 в конфигурации PHP. Если же вы не поняли, о чём сейчас шла речь, уточните данный момент у своего сисадмина.</p>
            <p>На всякий случай покажу вам расположение упомянутого базового модуля.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [-] mimimi.modules
    │       ├─> [+] Cache
    │       ├─> [+] Db
    │       ├─> [+] Helper
    │       ├─> [+] Security
    │       ├─> [+] Session
    │       ├─> [+] Settings
    │       ├─> [-] <em>Sqlite</em>
    │       │       └─> <em>Sqlite.php</em>
    │       ├─> [+] Telegram
    │       ├─> [+] Url
    │       └─> [+] Xml
    ├─> [+] newspaper
    ├─> [+] <code>repost.vacancies</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Идём дальше.</p>

            <h2>Накидываем представления</h2>
            <p>С самого начала я задумал, что приложение будет отправлять вакансии как в браузер пользователя, так и в мессенджеры Телеграм и/или Max. Поэтому в директории хранителя представлений я не видел иных вариантов, кроме 3 следующих дочерних модулей: Html - чтобы генерировать вакансию в виде классической веб-страницы, Max и Телеграм - чтобы генерировать ту же вакансию в форме запроса к Bot API соответствующего мессенджера.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [+] <code>Controllers</code>
    │       ├─> [+] <code>Models</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [-] <code>Views</code>
    │       │       ├─> [-] <code>Html</code>
    │       │       │       └─> <code>Html.php</code>
    │       │       ├─> [-] <code>Max</code>
    │       │       │       └─> <code>Max.php</code>
    │       │       ├─> [-] <code>Telegram</code>
    │       │       │       └─> <code>Telegram.php</code>
    │       │       └─> <code>Views.php</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Отмечу также, что мессенджер Max пока (по состоянию на декабрь 2025 года) не предоставляет частным лицам доступ к своему API, поэтому его модуль я сделал обычной заглушкой. То есть модуль Max вообще ничего не делает, лишь имитируя ситуацию, будто вакансию не удалось отправить в мессенджер по неизвестной причине.</p>
            <p>Ещё подчеркну, что модуль Telegram я тоже делал порождением от одноимённого базового модуля, уже входящего в установочный пакет фреймворка MiMiMi. Покажу вам и расположение этого базового модуля на всякий случай.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [-] mimimi.modules
    │       ├─> [+] Cache
    │       ├─> [+] Db
    │       ├─> [+] Helper
    │       ├─> [+] Security
    │       ├─> [+] Session
    │       ├─> [+] Settings
    │       ├─> [+] Sqlite
    │       ├─> [-] <em>Telegram</em>
    │       │       └─> <em>Telegram.php</em>
    │       ├─> [+] Url
    │       └─> [+] Xml
    ├─> [+] newspaper
    ├─> [+] <code>repost.vacancies</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>

            <h2>Накидываем контроллеры</h2>
            <p>Исходя из принципа работы приложения, ожидалось наличие следующих типов страниц, а значит, связанных с ними дочерних модулей контроллеров: Dashboard - для всяких там страниц админпанели, Faq - для страниц наподобие "Частые Вопросы-Ответы", Home - для главной страницы сайта, Parser - для конечной точки (URL-а) запуска парсера по расписанию CRON-а, Seo - для типичных документов поисковым роботам, Vacancies - для постраничного листинга вакансий на фронтенде сайта.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [-] <code>Controllers</code>
    │       │       ├─> [-] <code>Dashboard</code>
    │       │       │       └─> <code>Dashboard.php</code>
    │       │       ├─> [-] <code>Faq</code>
    │       │       │       └─> <code>Faq.php</code>
    │       │       ├─> [-] <code>Home</code>
    │       │       │       └─> <code>Home.php</code>
    │       │       ├─> [-] <code>Parser</code>
    │       │       │       └─> <code>Parser.php</code>
    │       │       ├─> [-] <code>Seo</code>
    │       │       │       └─> <code>Seo.php</code>
    │       │       ├─> [-] <code>Vacancies</code>
    │       │       │       └─> <code>Vacancies.php</code>
    │       │       └─> <code>Controllers.php</code>
    │       ├─> [+] <code>Models</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [+] <code>Views</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Здесь следует отметить, что контроллер Dashboard представляет собой админпанель, в которой я планировал сделать несколько страниц. Соответственно, для каждой я создам субконтроллеры в виде дочерних модулей Dashboard-а, о чём сейчас расскажу.</p>

            <h2>Страницы админпанели</h2>
            <p>Исходя из оговоренной выше структуры URL-а, я предположил, что в админпанели мне понадобится всего 4 типа страниц, и с каждым будет сопоставлен свой модуль субконтроллера: Login - для авторизации, завершения работы или смены пароля, Settings - для редактирования настроек сайта, Tasks и Vacancies - для редактирования записей в соответствующих таблицах базы данных.</p>
            <p>Вот что у меня получилось на данном шаге.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [-] <code>Controllers</code>
    │       │       ├─> [-] <code>Dashboard</code>
    │       │       │       ├─> [-] <code>Login</code>
    │       │       │       │       └─> <code>Login.php</code>
    │       │       │       ├─> [-] <code>Settings</code>
    │       │       │       │       └─> <code>Settings.php</code>
    │       │       │       ├─> [-] <code>Tasks</code>
    │       │       │       │       └─> <code>Tasks.php</code>
    │       │       │       ├─> [-] <code>Vacancies</code>
    │       │       │       │       └─> <code>Vacancies.php</code>
    │       │       │       └─> <code>Dashboard.php</code>
    │       │       ├─> [+] <code>Faq</code>
    │       │       ├─> [+] <code>Home</code>
    │       │       ├─> [+] <code>Parser</code>
    │       │       ├─> [+] <code>Seo</code>
    │       │       ├─> [+] <code>Vacancies</code>
    │       │       └─> <code>Controllers.php</code>
    │       ├─> [+] <code>Models</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [+] <code>Views</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>

            <h2>Парсер</h2>
            <p>С самого начала мне хотелось, чтобы парсер приложения поддерживал модульность и, благодаря установленным туда модулям парсинга, был бы способен парсить данные из разных источников.</p>
            <p>Так как в моём случае планировалось парсить только вакансии с российской платформы "Труд всем", я потому и сделал лишь единственный дочерний модуль под именем Trudvsem.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [-] <code>Controllers</code>
    │       │       ├─> [+] <code>Dashboard</code>
    │       │       ├─> [+] <code>Faq</code>
    │       │       ├─> [+] <code>Home</code>
    │       │       ├─> [-] <code>Parser</code>
    │       │       │       ├─> [-] <code>Trudvsem</code>
    │       │       │       │       └─> <code>Trudvsem.php</code>
    │       │       │       └─> <code>Parser.php</code>
    │       │       ├─> [+] <code>Seo</code>
    │       │       ├─> [+] <code>Vacancies</code>
    │       │       └─> <code>Controllers.php</code>
    │       ├─> [+] <code>Models</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [+] <code>Views</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>Но при необходимости вы можете дописать модули парсинга из своих источников. Для этого надо иметь навыки программирования, а для вдохновения просто загляните как устроен написанный мной модуль.</p>

            <h2>Шаблон сайта</h2>
            <p>Раз уж приложение способно генерировать вакансии в виде классических веб-страниц, значит такая динамическая HTML-разметка должна где-то храниться. Это хранилище называют шаблоном сайта, и в нём размещаются макеты для каждого типа генерируемых страниц.</p>
            <p>Обычно файлам макетов дают какое-нибудь классическое и понятное расширение. Например, .html - обозначая тем самым статический макет, .php - намекая на макет динамической генерации.</p>
            <p>Я использовал расширение .tpl - это сокращение от слова template, чтобы избежать известной ещё со времён Wordpress-а тривиальной атаки, когда злоумышленник пробует запустить динамический макет с расширением .php, запрашивая его по прямому URL в расчёте на то, что неприспособленный к подобному вызову макет откроет какую-нибудь уязвимость движка сайта.</p>
            <p>Итак, я создал шаблон со всеми нужными мне макетами и добавил в директорию приложения как тему под именем Themes/default. Вот что теперь получилось.</p>
            <pre>localhost
    ├─> [+] five.viewers
    ├─> [+] ide.skeleton
    ├─> [+] media
    ├─> [+] mimimi.core
    ├─> [+] mimimi.install
    ├─> [+] mimimi.modules
    ├─> [+] newspaper
    ├─> [-] <code>repost.vacancies</code>
    │       ├─> [+] <code>Controllers</code>
    │       ├─> [+] <code>Models</code>
    │       ├─> [+] <code>Session</code>
    │       ├─> [-] <code>Themes</code>
    │       │       └─> [-] <code>default</code>
    │       │               ├─> [-] <code>css</code>
    │       │               │       └─> <code>styles.css</code>
    │       │               ├─> [-] <code>dashboard</code>
    │       │               │       ├─> <code>login.tpl</code>
    │       │               │       ├─> <code>logout.tpl</code>
    │       │               │       ├─> <code>password-change.tpl</code>
    │       │               │       ├─> <code>settings.tpl</code>
    │       │               │       ├─> <code>tasks-add.tpl</code>
    │       │               │       ├─> <code>tasks-copy.tpl</code>
    │       │               │       ├─> <code>tasks-delete.tpl</code>
    │       │               │       ├─> <code>tasks-edit.tpl</code>
    │       │               │       ├─> <code>tasks.tpl</code>
    │       │               │       ├─> <code>vacancies-delete.tpl</code>
    │       │               │       └─> <code>vacancies-edit.tpl</code>
    │       │               ├─> [-] <code>faq</code>
    │       │               │       └─> <code>for-developers.tpl</code>
    │       │               ├─> [-] <code>images</code>
    │       │               │       └─> <code>favicon.ico</code>
    │       │               ├─> [-] <code>js</code>
    │       │               │       └─> <code>scripts.js</code>
    │       │               ├─> [-] <code>max</code>
    │       │               │       └─> [-] <code>vacancy</code>
    │       │               ├─> [-] <code>snippets</code>
    │       │               │       ├─> [-] <code>vacancy-card</code>
    │       │               │       │       └─> [-] <code>trudvsem.tpl</code>
    │       │               │       ├─> <code>admintools.tpl</code>
    │       │               │       ├─> <code>demo-remark-1.tpl</code>
    │       │               │       ├─> <code>demo-remark-2.tpl</code>
    │       │               │       ├─> <code>footer.tpl</code>
    │       │               │       ├─> <code>pagination.tpl</code>
    │       │               │       ├─> <code>task-card.tpl</code>
    │       │               │       └─> <code>task-form.tpl</code>
    │       │               ├─> [-] <code>telegram</code>
    │       │               │       └─> [-] <code>vacancy</code>
    │       │               │               └─> [-] <code>trudvsem.tpl</code>
    │       │               ├─> <code>faq.tpl</code>
    │       │               ├─> <code>home.tpl</code>
    │       │               ├─> <code>page404.tpl</code>
    │       │               ├─> <code>parse.tpl</code>
    │       │               ├─> <code>robots.tpl</code>
    │       │               ├─> <code>sitemap.tpl</code>
    │       │               ├─> <code>vacancies.tpl</code>
    │       │               └─> <code>vacancy.tpl</code>
    │       ├─> [+] <code>Views</code>
    │       └─> <code>Application.php</code>
    ├─> [+] static.pages.only
    ├─> [+] tiny.news.feed
    ├─> [+] vue.js.cart
    ├─> .htaccess
    ├─> favicon.ico
    └─> index.php</pre>
            <p>На этом шаге разработка приложения была завершена, и я перешёл к написанию комментариев исходного кода и демонстрационному заполнению страницы "Частые Вопросы-Ответы" с историей разработки приложения.</p>

            <h2>Путь запроса из браузера</h2>
            <p>В процессе написания комментариев я затронул один момент, полезный с точки зрения разработчиков, кто захочет в дальнейшем дорабатывать приложение. Спешу поделится им.</p>
            <p>Чтобы вы представляли себе путь движения запроса по файлам и модулям сайта, нарисую его схему. Здесь стрелки вправо обозначают порядок загрузки файлов сайта и выполнения их методов, а стрелки влево - какие сущности декларировались загруженным файлом для использования в вашем приложении.</p>
            <pre>├─> .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 В БРАУЗЕР ПОЛЬЗОВАТЕЛЯ │                                                                 │
          └────────────────────────────────────────────────┘                                                                 └─> некийМетодПредставления()</pre>

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

            <nav>
                <a class="btn" href="<?php printSiteUrl ( ) ?>">
                    Главная
                </a>
            </nav>
            <?php
                mimimiModule ( 'snippets/footer.tpl' );
