diff --git a/public-legacy/auth/password.php b/public-legacy/auth/password.php
index 7090bbe8..7dc85aa8 100644
--- a/public-legacy/auth/password.php
+++ b/public-legacy/auth/password.php
@@ -71,7 +71,7 @@ while($canResetPassword) {
         $msz->usersCtx->passwords->updateUserPassword($userInfo, $passwordNew);
         $msz->usersCtx->totps->deleteUserTotp($userInfo);
 
-        $msz->createAuditLog('PASSWORD_RESET', [], $userInfo);
+        $msz->logsCtx->createUserLog($userInfo, 'PASSWORD_RESET');
 
         $msz->authCtx->recoveryTokens->invalidateToken($tokenInfo);
 
diff --git a/public-legacy/manage/changelog/change.php b/public-legacy/manage/changelog/change.php
index 1b31f76a..2b5e8313 100644
--- a/public-legacy/manage/changelog/change.php
+++ b/public-legacy/manage/changelog/change.php
@@ -38,7 +38,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
         Template::throwError(403);
 
     $msz->changelog->deleteChange($changeInfo);
-    $msz->createAuditLog('CHANGELOG_ENTRY_DELETE', [$changeInfo->id]);
+    $msz->logsCtx->createAuthedLog('CHANGELOG_ENTRY_DELETE', [$changeInfo->id]);
     Tools::redirect($msz->urls->format('manage-changelog-changes'));
     return;
 }
@@ -100,9 +100,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             }
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'CHANGELOG_ENTRY_CREATE' : 'CHANGELOG_ENTRY_EDIT',
-        [$changeInfo->id]
+        [$changeInfo->id],
     );
 
     Tools::redirect($msz->urls->format('manage-changelog-change', ['change' => $changeInfo->id]));
diff --git a/public-legacy/manage/changelog/tag.php b/public-legacy/manage/changelog/tag.php
index 1361e9de..75c96574 100644
--- a/public-legacy/manage/changelog/tag.php
+++ b/public-legacy/manage/changelog/tag.php
@@ -27,7 +27,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
         Template::throwError(403);
 
     $msz->changelog->deleteTag($tagInfo);
-    $msz->createAuditLog('CHANGELOG_TAG_DELETE', [$tagInfo->id]);
+    $msz->logsCtx->createAuthedLog('CHANGELOG_TAG_DELETE', [$tagInfo->id]);
     Tools::redirect($msz->urls->format('manage-changelog-tags'));
     return;
 }
@@ -51,9 +51,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $msz->changelog->updateTag($tagInfo, $name, $description, $archive);
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'CHANGELOG_TAG_CREATE' : 'CHANGELOG_TAG_EDIT',
-        [$tagInfo->id]
+        [$tagInfo->id],
     );
 
     if($isNew) {
diff --git a/public-legacy/manage/forum/redirs.php b/public-legacy/manage/forum/redirs.php
index 6e6f12cd..c0d380cd 100644
--- a/public-legacy/manage/forum/redirs.php
+++ b/public-legacy/manage/forum/redirs.php
@@ -14,7 +14,7 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
     $rTopicId = !empty($_POST['topic_redir_id']) && is_scalar($_POST['topic_redir_id']) ? trim((string)$_POST['topic_redir_id']) : '';
     $rTopicURL = !empty($_POST['topic_redir_url']) && is_scalar($_POST['topic_redir_url']) ? trim((string)$_POST['topic_redir_url']) : '';
 
-    $msz->createAuditLog('FORUM_TOPIC_REDIR_CREATE', [$rTopicId]);
+    $msz->logsCtx->createAuthedLog('FORUM_TOPIC_REDIR_CREATE', [$rTopicId]);
     $msz->forumCtx->topicRedirects->createTopicRedirect($rTopicId, $msz->authInfo->userInfo, $rTopicURL);
     Tools::redirect($msz->urls->format('manage-forum-topic-redirs'));
     return;
@@ -25,7 +25,7 @@ if(!empty($_GET['m']) && $_GET['m'] === 'explode') {
         throw new \Exception("Request verification failed.");
 
     $rTopicId = !empty($_GET['t']) && is_scalar($_GET['t']) ? (string)$_GET['t'] : '';
-    $msz->createAuditLog('FORUM_TOPIC_REDIR_REMOVE', [$rTopicId]);
+    $msz->logsCtx->createAuthedLog('FORUM_TOPIC_REDIR_REMOVE', [$rTopicId]);
     $msz->forumCtx->topicRedirects->deleteTopicRedirect($rTopicId);
     Tools::redirect($msz->urls->format('manage-forum-topic-redirs'));
     return;
diff --git a/public-legacy/manage/general/emoticon.php b/public-legacy/manage/general/emoticon.php
index 479e3f57..16e8e540 100644
--- a/public-legacy/manage/general/emoticon.php
+++ b/public-legacy/manage/general/emoticon.php
@@ -94,9 +94,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $sCurrent[] = $string;
         }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'EMOTICON_CREATE' : 'EMOTICON_EDIT',
-        [$emoteInfo->id]
+        [$emoteInfo->id],
     );
 
     Tools::redirect($msz->urls->format('manage-general-emoticon', ['emote' => $emoteInfo->id]));
diff --git a/public-legacy/manage/general/emoticons.php b/public-legacy/manage/general/emoticons.php
index 548a94a0..d670c583 100644
--- a/public-legacy/manage/general/emoticons.php
+++ b/public-legacy/manage/general/emoticons.php
@@ -20,20 +20,20 @@ if(CSRF::validateRequest() && !empty($_GET['emote'])) {
 
     if(!empty($_GET['delete'])) {
         $msz->emotesCtx->emotes->deleteEmote($emoteInfo);
-        $msz->createAuditLog('EMOTICON_DELETE', [$emoteInfo->id]);
+        $msz->logsCtx->createAuthedLog('EMOTICON_DELETE', [$emoteInfo->id]);
     } else {
         if(isset($_GET['order'])) {
             $order = !empty($_GET['order']) && is_scalar($_GET['order']) ? (string)$_GET['order'] : '';
             $offset = $order === 'i' ? 10 : ($order === 'd' ? -10 : 0);
             $msz->emotesCtx->emotes->updateEmoteOrderOffset($emoteInfo, $offset);
-            $msz->createAuditLog('EMOTICON_ORDER', [$emoteInfo->id]);
+            $msz->logsCtx->createAuthedLog('EMOTICON_ORDER', [$emoteInfo->id]);
         }
 
         if(isset($_GET['alias'])) {
             $alias = !empty($_GET['alias']) && is_scalar($_GET['alias']) ? (string)$_GET['alias'] : '';
             if($msz->emotesCtx->emotes->checkEmoteString($alias) === '') {
                 $msz->emotesCtx->emotes->addEmoteString($emoteInfo, $alias);
-                $msz->createAuditLog('EMOTICON_ALIAS', [$emoteInfo->id, $alias]);
+                $msz->logsCtx->createAuthedLog('EMOTICON_ALIAS', [$emoteInfo->id, $alias]);
             }
         }
     }
diff --git a/public-legacy/manage/general/logs.php b/public-legacy/manage/general/logs.php
index 12c3abaa..bc0c4bbb 100644
--- a/public-legacy/manage/general/logs.php
+++ b/public-legacy/manage/general/logs.php
@@ -9,11 +9,11 @@ if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
 if(!$msz->authInfo->getPerms('global')->check(Perm::G_LOGS_VIEW))
     Template::throwError(403);
 
-$pagination = Pagination::fromInput($msz->auditLog->countLogs(), 50);
+$pagination = Pagination::fromInput($msz->logsCtx->logs->countLogs(), 50);
 if(!$pagination->validOffset)
     Template::throwError(404);
 
-$logs = iterator_to_array($msz->auditLog->getLogs(pagination: $pagination));
+$logs = iterator_to_array($msz->logsCtx->logs->getLogs(pagination: $pagination));
 $userInfos = [];
 $userColours = [];
 
diff --git a/public-legacy/manage/general/setting-delete.php b/public-legacy/manage/general/setting-delete.php
index 0a5a8205..796e046f 100644
--- a/public-legacy/manage/general/setting-delete.php
+++ b/public-legacy/manage/general/setting-delete.php
@@ -12,7 +12,7 @@ if($valueInfo === null)
     Template::throwError(404);
 
 if($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
-    $msz->createAuditLog('CONFIG_DELETE', [$valueInfo->name]);
+    $msz->logsCtx->createAuthedLog('CONFIG_DELETE', [$valueInfo->name]);
     $msz->config->removeValues($valueInfo->name);
     Tools::redirect($msz->urls->format('manage-general-settings'));
     return;
diff --git a/public-legacy/manage/general/setting.php b/public-legacy/manage/general/setting.php
index 15aca438..116c9464 100644
--- a/public-legacy/manage/general/setting.php
+++ b/public-legacy/manage/general/setting.php
@@ -74,7 +74,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $applyFunc = $msz->config->setString(...);
     }
 
-    $msz->createAuditLog($isNew ? 'CONFIG_CREATE' : 'CONFIG_UPDATE', [$sName]);
+    $msz->logsCtx->createAuthedLog($isNew ? 'CONFIG_CREATE' : 'CONFIG_UPDATE', [$sName]);
     $applyFunc($sName, $sValue);
     Tools::redirect($msz->urls->format('manage-general-settings'));
     return;
diff --git a/public-legacy/manage/news/category.php b/public-legacy/manage/news/category.php
index 8a64f33d..4a848eea 100644
--- a/public-legacy/manage/news/category.php
+++ b/public-legacy/manage/news/category.php
@@ -27,7 +27,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
         Template::throwError(403);
 
     $msz->news->deleteCategory($categoryInfo);
-    $msz->createAuditLog('NEWS_CATEGORY_DELETE', [$categoryInfo->id]);
+    $msz->logsCtx->createAuthedLog('NEWS_CATEGORY_DELETE', [$categoryInfo->id]);
     Tools::redirect($msz->urls->format('manage-news-categories'));
     return;
 }
@@ -51,9 +51,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $msz->news->updateCategory($categoryInfo, $name, $description, $hidden);
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'NEWS_CATEGORY_CREATE' : 'NEWS_CATEGORY_EDIT',
-        [$categoryInfo->id]
+        [$categoryInfo->id],
     );
 
     if($isNew) {
diff --git a/public-legacy/manage/news/post.php b/public-legacy/manage/news/post.php
index bea405af..783ce36f 100644
--- a/public-legacy/manage/news/post.php
+++ b/public-legacy/manage/news/post.php
@@ -28,7 +28,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
         Template::throwError(403);
 
     $msz->news->deletePost($postInfo);
-    $msz->createAuditLog('NEWS_POST_DELETE', [$postInfo->id]);
+    $msz->logsCtx->createAuthedLog('NEWS_POST_DELETE', [$postInfo->id]);
     Tools::redirect($msz->urls->format('manage-news-posts'));
     return;
 }
@@ -55,9 +55,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $msz->news->updatePost($postInfo, $category, $title, $body, $featured);
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'NEWS_POST_CREATE' : 'NEWS_POST_EDIT',
-        [$postInfo->id]
+        [$postInfo->id],
     );
 
     if($isNew && $postInfo->featured) {
diff --git a/public-legacy/manage/users/ban.php b/public-legacy/manage/users/ban.php
index 1a2d05a5..5a4e4675 100644
--- a/public-legacy/manage/users/ban.php
+++ b/public-legacy/manage/users/ban.php
@@ -22,7 +22,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
     }
 
     $msz->usersCtx->bans->deleteBans($banInfo);
-    $msz->createAuditLog('BAN_DELETE', [$banInfo->id, $banInfo->userId]);
+    $msz->logsCtx->createAuthedLog('BAN_DELETE', [$banInfo->id, $banInfo->userId]);
     Tools::redirect($msz->urls->format('manage-users-bans', ['user' => $banInfo->userId]));
     return;
 }
@@ -67,7 +67,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
         severity: $severity, modInfo: $modInfo
     );
 
-    $msz->createAuditLog('BAN_CREATE', [$banInfo->id, $userInfo->id]);
+    $msz->logsCtx->createAuthedLog('BAN_CREATE', [$banInfo->id, $userInfo->id]);
     Tools::redirect($msz->urls->format('manage-users-bans', ['user' => $userInfo->id]));
     return;
 }
diff --git a/public-legacy/manage/users/note.php b/public-legacy/manage/users/note.php
index 0f8a3009..d72d4afd 100644
--- a/public-legacy/manage/users/note.php
+++ b/public-legacy/manage/users/note.php
@@ -39,7 +39,7 @@ if($hasUserId) {
             Template::throwError(403);
 
         $msz->usersCtx->modNotes->deleteNotes($noteInfo);
-        $msz->createAuditLog('MOD_NOTE_DELETE', [$noteInfo->id, $noteInfo->userId]);
+        $msz->logsCtx->createAuthedLog('MOD_NOTE_DELETE', [$noteInfo->id, $noteInfo->userId]);
         Tools::redirect($msz->urls->format('manage-users-notes', ['user' => $noteInfo->userId]));
         return;
     }
@@ -64,9 +64,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
             $msz->usersCtx->modNotes->updateNote($noteInfo, $title, $body);
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'MOD_NOTE_CREATE' : 'MOD_NOTE_UPDATE',
-        [$noteInfo->id, $userInfo->id]
+        [$noteInfo->id, $userInfo->id],
     );
 
     // this is easier
diff --git a/public-legacy/manage/users/role.php b/public-legacy/manage/users/role.php
index 28e7bf39..d0abf2cb 100644
--- a/public-legacy/manage/users/role.php
+++ b/public-legacy/manage/users/role.php
@@ -148,9 +148,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
         );
     }
 
-    $msz->createAuditLog(
+    $msz->logsCtx->createAuthedLog(
         $isNew ? 'ROLE_CREATE' : 'ROLE_UPDATE',
-        [$roleInfo->id]
+        [$roleInfo->id],
     );
 
     if($canEditPerms) {
diff --git a/public-legacy/manage/users/user.php b/public-legacy/manage/users/user.php
index b6a7a90e..a6402cdc 100644
--- a/public-legacy/manage/users/user.php
+++ b/public-legacy/manage/users/user.php
@@ -62,7 +62,7 @@ if(CSRF::validateRequest() && $canEdit) {
             }
 
             if($allowToImpersonate) {
-                $msz->createAuditLog('USER_IMPERSONATE', [$userInfo->id, $userInfo->name]);
+                $msz->logsCtx->createAuthedLog('USER_IMPERSONATE', [$userInfo->id, $userInfo->name]);
 
                 $tokenBuilder = $msz->authInfo->tokenInfo->toBuilder();
                 $tokenBuilder->setImpersonatedUserId($userInfo->id);
diff --git a/public-legacy/manage/users/warning.php b/public-legacy/manage/users/warning.php
index dfac1df1..0cfa810e 100644
--- a/public-legacy/manage/users/warning.php
+++ b/public-legacy/manage/users/warning.php
@@ -20,7 +20,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) {
     }
 
     $msz->usersCtx->warnings->deleteWarnings($warnInfo);
-    $msz->createAuditLog('WARN_DELETE', [$warnInfo->id, $warnInfo->userId]);
+    $msz->logsCtx->createAuthedLog('WARN_DELETE', [$warnInfo->id, $warnInfo->userId]);
     Tools::redirect($msz->urls->format('manage-users-warnings', ['user' => $warnInfo->userId]));
     return;
 }
@@ -41,7 +41,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
         $userInfo, $body, modInfo: $modInfo
     );
 
-    $msz->createAuditLog('WARN_CREATE', [$warnInfo->id, $userInfo->id]);
+    $msz->logsCtx->createAuthedLog('WARN_CREATE', [$warnInfo->id, $userInfo->id]);
     Tools::redirect($msz->urls->format('manage-users-warnings', ['user' => $userInfo->id]));
     return;
 }
diff --git a/public-legacy/settings/account.php b/public-legacy/settings/account.php
index 98a4e7d7..74a0472a 100644
--- a/public-legacy/settings/account.php
+++ b/public-legacy/settings/account.php
@@ -90,7 +90,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) {
                     $errors[] = $msz->usersCtx->users->validateEMailAddressText($checkMail);
                 } else {
                     $msz->usersCtx->users->updateUser(userInfo: $userInfo, emailAddr: $_POST['email']['new']);
-                    $msz->createAuditLog('PERSONAL_EMAIL_CHANGE', [$_POST['email']['new']]);
+                    $msz->logsCtx->createAuthedLog('PERSONAL_EMAIL_CHANGE', [$_POST['email']['new']]);
                 }
             }
         }
@@ -106,7 +106,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) {
                     $errors[] = UserPasswordsData::validateUserPasswordText($checkPassword);
                 } else {
                     $msz->usersCtx->passwords->updateUserPassword($userInfo, $_POST['password']['new']);
-                    $msz->createAuditLog('PERSONAL_PASSWORD_CHANGE');
+                    $msz->logsCtx->createAuthedLog('PERSONAL_PASSWORD_CHANGE');
                 }
             }
         }
diff --git a/public-legacy/settings/data.php b/public-legacy/settings/data.php
index cc805eb8..04b280f1 100644
--- a/public-legacy/settings/data.php
+++ b/public-legacy/settings/data.php
@@ -116,7 +116,7 @@ if(isset($_POST['action']) && is_string($_POST['action'])) {
         && ($msz->usersCtx->passwords->getUserPassword($userInfo)?->verifyPassword($_POST['password'] ?? ''))) {
         switch($_POST['action']) {
             case 'data':
-                $msz->createAuditLog('PERSONAL_DATA_DOWNLOAD');
+                $msz->logsCtx->createAuthedLog('PERSONAL_DATA_DOWNLOAD');
 
                 $timeStamp = floor(time() / 3600) * 3600;
                 $fileName = sprintf('msz-user-data-%d-%d.zip', $userInfo->id, $timeStamp);
diff --git a/public-legacy/settings/logs.php b/public-legacy/settings/logs.php
index 82f34f64..58ea08fd 100644
--- a/public-legacy/settings/logs.php
+++ b/public-legacy/settings/logs.php
@@ -11,10 +11,10 @@ if($currentUser === null)
     Template::throwError(401);
 
 $loginHistoryPagination = Pagination::fromInput($msz->authCtx->loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp');
-$accountLogPagination = Pagination::fromInput($msz->auditLog->countLogs(userInfo: $currentUser), 10, 'ap');
+$accountLogPagination = Pagination::fromInput($msz->logsCtx->logs->countLogs(userInfo: $currentUser), 10, 'ap');
 
 $loginHistory = iterator_to_array($msz->authCtx->loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination));
-$auditLogs = iterator_to_array($msz->auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination));
+$auditLogs = iterator_to_array($msz->logsCtx->logs->getLogs(userInfo: $currentUser, pagination: $accountLogPagination));
 
 Template::render('settings.logs', [
     'login_history_list' => $loginHistory,
diff --git a/public-legacy/settings/sessions.php b/public-legacy/settings/sessions.php
index 90be2cd1..43a90f26 100644
--- a/public-legacy/settings/sessions.php
+++ b/public-legacy/settings/sessions.php
@@ -20,7 +20,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
     if($sessionId === 'all') {
         $activeSessionKilled = true;
         $msz->authCtx->sessions->deleteSessions(userInfos: $currentUser);
-        $msz->createAuditLog('PERSONAL_SESSION_DESTROY_ALL');
+        $msz->logsCtx->createAuthedLog('PERSONAL_SESSION_DESTROY_ALL');
     } else {
         try {
             $sessionInfo = $msz->authCtx->sessions->getSession(sessionId: $sessionId);
@@ -33,7 +33,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
 
         $activeSessionKilled = $sessionInfo->id === $activeSessionId;
         $msz->authCtx->sessions->deleteSessions(sessionInfos: $sessionInfo);
-        $msz->createAuditLog('PERSONAL_SESSION_DESTROY', [$sessionInfo->id]);
+        $msz->logsCtx->createAuthedLog('PERSONAL_SESSION_DESTROY', [$sessionInfo->id]);
     }
 
     if($activeSessionKilled) {
diff --git a/public/index.php b/public/index.php
index 6afe51d8..289fb614 100644
--- a/public/index.php
+++ b/public/index.php
@@ -5,6 +5,8 @@ use RuntimeException;
 use Index\MediaType;
 use Index\Http\Content\MultipartFormContent;
 use Index\Http\Content\Multipart\ValueMultipartFormData;
+use Index\Http\Routing\Router;
+use Index\Http\Routing\Routes\RouteInfo;
 use Misuzu\Auth\{AuthTokenBuilder,AuthTokenCookie,AuthTokenInfo};
 
 require_once __DIR__ . '/../misuzu.php';
@@ -115,51 +117,6 @@ $router = $msz->createRouting($request);
 $msz->startTemplating();
 
 if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) {
-    // Reconstruct $_POST since PHP no longer makes it for us
-    if($request->getBody()->isReadable() && empty($_POST)) {
-        $mszRequestContent = (function($contentType, $stream) {
-            if($contentType->equals('application/x-www-form-urlencoded')) {
-                parse_str((string)$stream, $postVars);
-                return $postVars;
-            }
-
-            if($contentType->equals('multipart/form-data'))
-                try {
-                    return MultipartFormContent::parseStream($stream, $contentType->boundary);
-                } catch(RuntimeException $ex) {}
-
-            return null;
-        })(MediaType::parse($request->getHeaderLine('Content-Type')), $request->getBody());
-
-        $_POST = (function($requestContent) {
-            if(is_array($requestContent))
-                return $requestContent;
-
-            if($requestContent instanceof MultipartFormContent) {
-                $postVars = [];
-                foreach($requestContent->params as $name => $values) {
-                    if(count($values) === 0)
-                        $postVars[$name] = '';
-                    elseif(count($values) === 1)
-                        $postVars[$name] = $values[0] instanceof ValueMultipartFormData ? (string)$values[0] : '';
-                    else {
-                        $postVar = [];
-                        foreach($values as $value)
-                            $postVars[] = $value instanceof ValueMultipartFormData ? (string)$value : '';
-
-                        $postVars[$name] = $postVar;
-                    }
-                }
-
-                return $postVars;
-            }
-
-            return [];
-        })($mszRequestContent);
-
-        $_REQUEST = array_merge($_GET, $_POST);
-    }
-
     $mszRequestPath = substr($request->requestTarget, 1);
     $mszLegacyPathPrefix = Misuzu::PATH_PUBLIC_LEGACY . '/';
     $mszLegacyPath = $mszLegacyPathPrefix . $mszRequestPath;
@@ -167,6 +124,14 @@ if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) {
     if(str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) {
         $mszLegacyPathReal = realpath($mszLegacyPath);
         if($mszLegacyPath === $mszLegacyPathReal || $mszLegacyPath === $mszLegacyPathReal . '/') {
+            // this is here so filters can run...
+            $router->router->route(RouteInfo::exact($request->method, $request->requestTarget, function() {}));
+            $response = $router->router->handle($request);
+            if($response->getBody()->getSize() > 0) {
+                Router::output($response);
+                exit;
+            }
+
             if(str_starts_with($mszRequestPath, 'manage') && !$msz->hasManageAccess())
                 Template::throwError(403);
 
@@ -174,6 +139,51 @@ if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) {
                 $mszLegacyPath .= '/index.php';
 
             if(is_file($mszLegacyPath)) {
+                // Reconstruct $_POST since PHP no longer makes it for us
+                if($request->getBody()->isReadable() && empty($_POST)) {
+                    $mszRequestContent = (function($contentType, $stream) {
+                        if($contentType->equals('application/x-www-form-urlencoded')) {
+                            parse_str((string)$stream, $postVars);
+                            return $postVars;
+                        }
+
+                        if($contentType->equals('multipart/form-data'))
+                            try {
+                                return MultipartFormContent::parseStream($stream, $contentType->boundary);
+                            } catch(RuntimeException $ex) {}
+
+                        return null;
+                    })(MediaType::parse($request->getHeaderLine('Content-Type')), $request->getBody());
+
+                    $_POST = (function($requestContent) {
+                        if(is_array($requestContent))
+                            return $requestContent;
+
+                        if($requestContent instanceof MultipartFormContent) {
+                            $postVars = [];
+                            foreach($requestContent->params as $name => $values) {
+                                if(count($values) === 0)
+                                    $postVars[$name] = '';
+                                elseif(count($values) === 1)
+                                    $postVars[$name] = $values[0] instanceof ValueMultipartFormData ? (string)$values[0] : '';
+                                else {
+                                    $postVar = [];
+                                    foreach($values as $value)
+                                        $postVars[] = $value instanceof ValueMultipartFormData ? (string)$value : '';
+
+                                    $postVars[$name] = $postVar;
+                                }
+                            }
+
+                            return $postVars;
+                        }
+
+                        return [];
+                    })($mszRequestContent);
+
+                    $_REQUEST = array_merge($_GET, $_POST);
+                }
+
                 require_once $mszLegacyPath;
                 return;
             }
diff --git a/src/Forum/ForumPostsRoutes.php b/src/Forum/ForumPostsRoutes.php
index 077db87e..0080374e 100644
--- a/src/Forum/ForumPostsRoutes.php
+++ b/src/Forum/ForumPostsRoutes.php
@@ -7,8 +7,8 @@ use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
 use Index\Http\Routing\Routes\PatternRoute;
 use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
 use Misuzu\{CSRF,Perm};
-use Misuzu\AuditLog\AuditLogData;
 use Misuzu\Auth\AuthInfo;
+use Misuzu\Logs\LogsContext;
 use Misuzu\Users\UsersContext;
 
 class ForumPostsRoutes implements RouteHandler, UrlSource {
@@ -16,9 +16,9 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
 
     public function __construct(
         private UrlRegistry $urls,
-        private ForumContext $forum,
+        private ForumContext $forumCtx,
         private UsersContext $usersCtx,
-        private AuditLogData $auditLog,
+        private LogsContext $logsCtx,
         private AuthInfo $authInfo,
     ) {}
 
@@ -26,7 +26,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
     #[UrlFormat('forum-post', '/forum/posts/<post>')]
     public function getPost(HttpResponseBuilder $response, HttpRequest $request, string $postId): mixed {
         try {
-            $post = $this->forum->posts->getPost(postId: $postId);
+            $post = $this->forumCtx->posts->getPost(postId: $postId);
         } catch(RuntimeException $ex) {
             return 404;
         }
@@ -39,7 +39,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
         if($post->deleted && !$canDeleteAny)
             return 404;
 
-        $postsCount = $this->forum->posts->countPosts(
+        $postsCount = $this->forumCtx->posts->countPosts(
             topicInfo: $post->topicId,
             upToPostInfo: $post,
             deleted: $canDeleteAny ? null : false
@@ -76,7 +76,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
         }
 
         try {
-            $post = $this->forum->posts->getPost(
+            $post = $this->forumCtx->posts->getPost(
                 postId: $postId,
                 deleted: false,
             );
@@ -102,7 +102,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
         }
 
         if(!$perms->check(Perm::F_POST_DELETE_ANY)) {
-            $topic = $this->forum->topics->getTopic(postInfo: $post);
+            $topic = $this->forumCtx->topics->getTopic(postInfo: $post);
             if($topic->deleted) {
                 $response->statusCode = 404;
                 return [
@@ -156,7 +156,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             }
         }
 
-        $originalPost = $this->forum->posts->getPost(topicInfo: $post->topicId);
+        $originalPost = $this->forumCtx->posts->getPost(topicInfo: $post->topicId);
         if($originalPost->id === $post->id) {
             $response->statusCode = 403;
             return [
@@ -167,7 +167,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $category = $this->forum->categories->getCategory(postInfo: $post);
+        $category = $this->forumCtx->categories->getCategory(postInfo: $post);
         if($category->archived) {
             $response->statusCode = 400;
             return [
@@ -178,14 +178,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $this->forum->posts->deletePost($post);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_POST_DELETE',
-            [$post->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->forumCtx->posts->deletePost($post);
+        $this->logsCtx->createAuthedLog('FORUM_POST_DELETE', [$post->id]);
 
         return 204;
     }
@@ -211,7 +205,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
         }
 
         try {
-            $post = $this->forum->posts->getPost(
+            $post = $this->forumCtx->posts->getPost(
                 postId: $postId,
                 deleted: true,
             );
@@ -247,7 +241,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $category = $this->forum->categories->getCategory(postInfo: $post);
+        $category = $this->forumCtx->categories->getCategory(postInfo: $post);
         if($category->archived) {
             $response->statusCode = 400;
             return [
@@ -258,14 +252,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $this->forum->posts->nukePost($post);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_POST_NUKE',
-            [$post->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->forumCtx->posts->nukePost($post);
+        $this->logsCtx->createAuthedLog('FORUM_POST_NUKE', [$post->id]);
 
         return 204;
     }
@@ -291,7 +279,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
         }
 
         try {
-            $post = $this->forum->posts->getPost(
+            $post = $this->forumCtx->posts->getPost(
                 postId: $postId,
                 deleted: true,
             );
@@ -327,7 +315,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $category = $this->forum->categories->getCategory(postInfo: $post);
+        $category = $this->forumCtx->categories->getCategory(postInfo: $post);
         if($category->archived) {
             $response->statusCode = 400;
             return [
@@ -338,14 +326,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource {
             ];
         }
 
-        $this->forum->posts->restorePost($post);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_POST_RESTORE',
-            [$post->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->forumCtx->posts->restorePost($post);
+        $this->logsCtx->createAuthedLog('FORUM_POST_RESTORE', [$post->id]);
 
         return 204;
     }
diff --git a/src/Forum/ForumTopicsRoutes.php b/src/Forum/ForumTopicsRoutes.php
index 1643a144..f87ffe56 100644
--- a/src/Forum/ForumTopicsRoutes.php
+++ b/src/Forum/ForumTopicsRoutes.php
@@ -9,8 +9,8 @@ use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
 use Index\Http\Routing\Routes\PatternRoute;
 use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
 use Misuzu\{CSRF,Pagination,Perm,Template};
-use Misuzu\AuditLog\AuditLogData;
 use Misuzu\Auth\AuthInfo;
+use Misuzu\Logs\LogsContext;
 use Misuzu\Users\UsersContext;
 
 class ForumTopicsRoutes implements RouteHandler, UrlSource {
@@ -19,7 +19,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
     public function __construct(
         private ForumContext $forumCtx,
         private UsersContext $usersCtx,
-        private AuditLogData $auditLog,
+        private LogsContext $logsCtx,
         private AuthInfo $authInfo,
     ) {}
 
@@ -263,13 +263,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->deleteTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_DELETE',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_DELETE', [$topic->id]);
 
         return 204;
     }
@@ -343,13 +337,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->restoreTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_RESTORE',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_RESTORE', [$topic->id]);
 
         return 204;
     }
@@ -423,13 +411,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->nukeTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_NUKE',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_NUKE', [$topic->id]);
 
         return 204;
     }
@@ -503,13 +485,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->bumpTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_BUMP',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_BUMP', [$topic->id]);
 
         return 204;
     }
@@ -593,13 +569,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->lockTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_LOCK',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_LOCK', [$topic->id]);
 
         return 204;
     }
@@ -683,13 +653,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource {
         }
 
         $this->forumCtx->topics->unlockTopic($topic);
-        $this->auditLog->createLog(
-            $this->authInfo->userInfo,
-            'FORUM_TOPIC_UNLOCK',
-            [$topic->id],
-            $request->remoteAddress,
-            $request->countryCode
-        );
+        $this->logsCtx->createAuthedLog('FORUM_TOPIC_UNLOCK', [$topic->id]);
 
         return 204;
     }
diff --git a/src/AuditLog/AuditLogInfo.php b/src/Logs/LogInfo.php
similarity index 97%
rename from src/AuditLog/AuditLogInfo.php
rename to src/Logs/LogInfo.php
index 9f01a988..883fb002 100644
--- a/src/AuditLog/AuditLogInfo.php
+++ b/src/Logs/LogInfo.php
@@ -1,11 +1,11 @@
 <?php
-namespace Misuzu\AuditLog;
+namespace Misuzu\Logs;
 
 use ValueError;
 use Carbon\CarbonImmutable;
 use Index\Db\DbResult;
 
-class AuditLogInfo {
+class LogInfo {
     /** @param scalar[] $params */
     public function __construct(
         public private(set) string $id,
@@ -17,8 +17,8 @@ class AuditLogInfo {
         public private(set) string $countryCode,
     ) {}
 
-    public static function fromResult(DbResult $result): AuditLogInfo {
-        return new AuditLogInfo(
+    public static function fromResult(DbResult $result): LogInfo {
+        return new LogInfo(
             id: $result->getString(0),
             userId: $result->getStringOrNull(1),
             action: $result->getString(2),
diff --git a/src/Logs/LogsContext.php b/src/Logs/LogsContext.php
new file mode 100644
index 00000000..ddbf9d3f
--- /dev/null
+++ b/src/Logs/LogsContext.php
@@ -0,0 +1,60 @@
+<?php
+namespace Misuzu\Logs;
+
+use Index\Db\DbConnection;
+use Index\Http\HttpRequest;
+use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
+use Index\Http\Routing\Filters\PrefixFilter;
+use Misuzu\Auth\AuthInfo;
+use Misuzu\Users\UserInfo;
+
+class LogsContext implements RouteHandler {
+    use RouteHandlerCommon;
+
+    public private(set) LogsData $logs;
+
+    private ?HttpRequest $request = null;
+
+    public function __construct(
+        DbConnection $dbConn,
+        private AuthInfo $authInfo,
+    ) {
+        $this->logs = new LogsData($dbConn);
+    }
+
+    #[PrefixFilter('/')]
+    public function filterRequest(HttpRequest $request): void {
+        $this->request = $request;
+    }
+
+    /** @param mixed[] $params */
+    public function createSystemLog(string $action, array $params = []): void {
+        $this->logs->createLog(null, $action, $params, null, 'XS');
+    }
+
+    /** @param mixed[] $params */
+    public function createAuthedLog(string $action, array $params = []): void {
+        $this->logs->createLog(
+            $this->authInfo->userInfo,
+            $action,
+            $params,
+            $this->request?->remoteAddress,
+            $this->request->countryCode ?? 'XX',
+        );
+    }
+
+    /** @param mixed[] $params */
+    public function createUserLog(
+        UserInfo|string|null $userInfo,
+        string $action,
+        array $params = [],
+    ): void {
+        $this->logs->createLog(
+            $userInfo,
+            $action,
+            $params,
+            $this->request?->remoteAddress,
+            $this->request->countryCode ?? 'XX',
+        );
+    }
+}
diff --git a/src/AuditLog/AuditLogData.php b/src/Logs/LogsData.php
similarity index 74%
rename from src/AuditLog/AuditLogData.php
rename to src/Logs/LogsData.php
index 791b3ad7..c1c62453 100644
--- a/src/AuditLog/AuditLogData.php
+++ b/src/Logs/LogsData.php
@@ -1,12 +1,12 @@
 <?php
-namespace Misuzu\AuditLog;
+namespace Misuzu\Logs;
 
 use InvalidArgumentException;
 use Index\Db\{DbConnection,DbStatementCache};
 use Misuzu\Pagination;
 use Misuzu\Users\UserInfo;
 
-class AuditLogData {
+class LogsData {
     private DbStatementCache $cache;
 
     public function __construct(DbConnection $dbConn) {
@@ -15,13 +15,13 @@ class AuditLogData {
 
     public function countLogs(
         UserInfo|string|null $userInfo = null,
-        ?string $remoteAddr = null
+        string|null|false $remoteAddress = false,
     ): int {
         if($userInfo instanceof UserInfo)
             $userInfo = $userInfo->id;
 
         $hasUserInfo = $userInfo !== null;
-        $hasRemoteAddr = $remoteAddr !== null;
+        $hasRemoteAddr = $remoteAddress !== false;
 
         $args = 0;
         $query = 'SELECT COUNT(*) FROM msz_audit_log';
@@ -29,17 +29,19 @@ class AuditLogData {
             ++$args;
             $query .= ' WHERE user_id = ?';
         }
-        if($hasRemoteAddr) {
-            $query .= (++$args > 1 ? ' AND' : ' WHERE');
-            $query .= ' log_remote_addr = INET6_ATON(?)';
-        }
+        if($remoteAddress !== false)
+            $query .= sprintf(
+                ' %s log_remote_addr %s',
+                ++$args > 1 ? ' AND' : ' WHERE',
+                $remoteAddress === null ? 'IS NULL' : '= INET6_ATON(?)'
+            );
 
         $stmt = $this->cache->get($query);
 
         if($hasUserInfo)
             $stmt->nextParameter($userInfo);
-        if($hasRemoteAddr)
-            $stmt->nextParameter($remoteAddr);
+        if(is_string($remoteAddress))
+            $stmt->nextParameter($remoteAddress);
 
         $stmt->execute();
         $result = $stmt->getResult();
@@ -51,17 +53,16 @@ class AuditLogData {
         return $count;
     }
 
-    /** @return \Iterator<int, AuditLogInfo> */
+    /** @return \Iterator<int, LogInfo> */
     public function getLogs(
         UserInfo|string|null $userInfo = null,
-        ?string $remoteAddr = null,
+        string|null|false $remoteAddress = false,
         ?Pagination $pagination = null
     ): iterable {
         if($userInfo instanceof UserInfo)
             $userInfo = $userInfo->id;
 
         $hasUserInfo = $userInfo !== null;
-        $hasRemoteAddr = $remoteAddr !== null;
         $hasPagination = $pagination !== null;
 
         $args = 0;
@@ -76,10 +77,12 @@ class AuditLogData {
             ++$args;
             $query .= ' WHERE user_id = ?';
         }
-        if($hasRemoteAddr) {
-            $query .= (++$args > 1 ? ' AND' : ' WHERE');
-            $query .= ' log_remote_addr = INET6_ATON(?)';
-        }
+        if($remoteAddress !== false)
+            $query .= sprintf(
+                ' %s log_remote_addr %s',
+                ++$args > 1 ? ' AND' : ' WHERE',
+                $remoteAddress === null ? 'IS NULL' : '= INET6_ATON(?)'
+            );
         $query .= ' ORDER BY log_created DESC';
         if($hasPagination)
             $query .= ' LIMIT ? OFFSET ?';
@@ -88,14 +91,14 @@ class AuditLogData {
 
         if($hasUserInfo)
             $stmt->nextParameter($userInfo);
-        if($hasRemoteAddr)
-            $stmt->nextParameter($remoteAddr);
+        if(is_string($remoteAddress))
+            $stmt->nextParameter($remoteAddress);
         if($hasPagination)
             $pagination->addToStatement($stmt);
 
         $stmt->execute();
 
-        return $stmt->getResultIterator(AuditLogInfo::fromResult(...));
+        return $stmt->getResultIterator(LogInfo::fromResult(...));
     }
 
     /** @param mixed[] $params */
@@ -103,9 +106,9 @@ class AuditLogData {
         UserInfo|string|null $userInfo,
         string $action,
         array $params = [],
-        string $remoteAddr = '::1',
-        string $countryCode = 'XX'
-    ): void {
+        ?string $remoteAddress = null,
+        string $countryCode = 'XX',
+    ): string {
         if($userInfo instanceof UserInfo)
             $userInfo = $userInfo->id;
 
@@ -131,8 +134,10 @@ class AuditLogData {
         $stmt->nextParameter($userInfo);
         $stmt->nextParameter($action);
         $stmt->nextParameter($params);
-        $stmt->nextParameter($remoteAddr);
+        $stmt->nextParameter($remoteAddress);
         $stmt->nextParameter($countryCode);
         $stmt->execute();
+
+        return (string)$stmt->lastInsertId;
     }
 }
diff --git a/src/MisuzuContext.php b/src/MisuzuContext.php
index 35fa6e49..6b1e3d58 100644
--- a/src/MisuzuContext.php
+++ b/src/MisuzuContext.php
@@ -24,10 +24,8 @@ class MisuzuContext {
     public private(set) BinarySnowflake $sfBinary;
     public private(set) RandomSnowflake $sfRandom;
 
-    public private(set) AuditLog\AuditLogData $auditLog;
-    public private(set) Counters\CountersData $counters;
-
     public private(set) Changelog\ChangelogData $changelog;
+    public private(set) Counters\CountersData $counters;
     public private(set) News\NewsData $news;
 
     public private(set) DatabaseContext $dbCtx;
@@ -37,6 +35,7 @@ class MisuzuContext {
     public private(set) Comments\CommentsContext $commentsCtx;
     public private(set) Emoticons\EmotesContext $emotesCtx;
     public private(set) Forum\ForumContext $forumCtx;
+    public private(set) Logs\LogsContext $logsCtx;
     public private(set) Messages\MessagesContext $messagesCtx;
     public private(set) OAuth2\OAuth2Context $oauth2Ctx;
     public private(set) Profile\ProfileContext $profileCtx;
@@ -101,6 +100,7 @@ class MisuzuContext {
             Forum\ForumContext::class,
             config: $this->config->scopeTo('forum'),
         ));
+        $this->deps->register($this->logsCtx = $this->deps->constructLazy(Logs\LogsContext::class));
         $this->deps->register($this->messagesCtx = $this->deps->constructLazy(
             Messages\MessagesContext::class,
             config: $this->config->scopeTo('messages'),
@@ -116,7 +116,6 @@ class MisuzuContext {
             config: $this->config->scopeTo('redirects'),
         ));
 
-        $this->deps->register($this->auditLog = $this->deps->constructLazy(AuditLog\AuditLogData::class));
         $this->deps->register($this->changelog = $this->deps->constructLazy(Changelog\ChangelogData::class));
         $this->deps->register($this->counters = $this->deps->constructLazy(Counters\CountersData::class));
         $this->deps->register($this->news = $this->deps->constructLazy(News\NewsData::class));
@@ -132,20 +131,6 @@ class MisuzuContext {
         Mailer::init($this->config->scopeTo('mail'));
     }
 
-    /** @param mixed[] $params */
-    public function createAuditLog(string $action, array $params = [], UserInfo|string|null $userInfo = null): void {
-        if($userInfo === null && $this->authInfo->loggedIn)
-            $userInfo = $this->authInfo->userInfo;
-
-        $this->auditLog->createLog(
-            $userInfo,
-            $action,
-            $params,
-            $_SERVER['REMOTE_ADDR'] ?? '::1',
-            $_SERVER['COUNTRY_CODE'] ?? 'XX'
-        );
-    }
-
     private ?bool $hasManageAccess = null;
     public function hasManageAccess(): bool {
         $this->hasManageAccess ??= $this->authInfo->loggedIn
@@ -190,6 +175,7 @@ class MisuzuContext {
 
         $routingCtx = $this->deps->construct(RoutingContext::class);
         $this->deps->register($this->urls = $routingCtx->urls);
+        $routingCtx->register($this->logsCtx);
 
         if(in_array('main', $roles))
             $this->registerMainRoutes($routingCtx);