From 0c9b1014791f73fdd6c7425c12f3f90f8d92d2c9 Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Thu, 1 Jun 2023 07:24:49 +0900
Subject: [PATCH 01/66] switch position of social and recommended

---
 packages/client/src/pages/timeline.vue | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue
index a44f36c55..1947caaef 100644
--- a/packages/client/src/pages/timeline.vue
+++ b/packages/client/src/pages/timeline.vue
@@ -109,12 +109,12 @@ let timelines = ["home"];
 if (isLocalTimelineAvailable) {
 	timelines.push("local");
 }
-if (isRecommendedTimelineAvailable) {
-	timelines.push("recommended");
-}
 if (isLocalTimelineAvailable) {
 	timelines.push("social");
 }
+if (isRecommendedTimelineAvailable) {
+	timelines.push("recommended");
+}
 if (isGlobalTimelineAvailable) {
 	timelines.push("global");
 }
@@ -255,16 +255,6 @@ const headerTabs = $computed(() => [
 				},
 		  ]
 		: []),
-	...(isRecommendedTimelineAvailable
-		? [
-				{
-					key: "recommended",
-					title: i18n.ts._timelines.recommended,
-					icon: "ph-thumbs-up ph-bold ph-lg",
-					iconOnly: true,
-				},
-		  ]
-		: []),
 	...(isLocalTimelineAvailable
 		? [
 				{
@@ -275,6 +265,16 @@ const headerTabs = $computed(() => [
 				},
 		  ]
 		: []),
+	...(isRecommendedTimelineAvailable
+		? [
+				{
+					key: "recommended",
+					title: i18n.ts._timelines.recommended,
+					icon: "ph-thumbs-up ph-bold ph-lg",
+					iconOnly: true,
+				},
+		  ]
+		: []),
 	...(isGlobalTimelineAvailable
 		? [
 				{

From 6e09a56c2dc9a080fbfb44cc96e778870c8da028 Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Thu, 1 Jun 2023 07:29:54 +0900
Subject: [PATCH 02/66] no change, but more comfortable

---
 packages/client/src/pages/timeline.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue
index 1947caaef..5d96d6dfd 100644
--- a/packages/client/src/pages/timeline.vue
+++ b/packages/client/src/pages/timeline.vue
@@ -195,7 +195,7 @@ async function chooseAntenna(ev: MouseEvent): Promise<void> {
 }
 
 function saveSrc(
-	newSrc: "home" | "local" | "recommended" | "social" | "global"
+	newSrc: "home" | "local" | "social" | "recommended" | "global"
 ): void {
 	defaultStore.set("tl", {
 		...defaultStore.state.tl,

From d94c276a8c88857c6c37aa44c29867b8f6636fd6 Mon Sep 17 00:00:00 2001
From: mappi <mappi@mizuiromoon.com>
Date: Fri, 2 Jun 2023 16:31:25 +0900
Subject: [PATCH 03/66] fix: vue-plyr audio tag

Co-authored-by: mappi <mappi-pr@github.com>
---
 packages/client/src/components/MkNote.vue | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/packages/client/src/components/MkNote.vue b/packages/client/src/components/MkNote.vue
index 7eca22a73..1325809f3 100644
--- a/packages/client/src/components/MkNote.vue
+++ b/packages/client/src/components/MkNote.vue
@@ -381,6 +381,8 @@ const currentClipPage = inject<Ref<misskey.entities.Clip> | null>(
 function onContextmenu(ev: MouseEvent): void {
 	const isLink = (el: HTMLElement) => {
 		if (el.tagName === "A") return true;
+		// The Audio element's context menu is the browser default, such as for selecting playback speed.
+		if (el.tagName === 'AUDIO') return true;
 		if (el.parentElement) {
 			return isLink(el.parentElement);
 		}

From 5c305a85e6eb7509439edf70db9d1c0802ae53ba Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 20:06:04 -0700
Subject: [PATCH 04/66] chore: formatting

---
 packages/client/src/components/MkCheatSheetDialog.vue | 3 +--
 packages/client/src/components/MkNote.vue             | 2 +-
 packages/client/src/pages/mfm-cheat-sheet.vue         | 2 +-
 packages/client/src/pages/user/home.vue               | 6 +++++-
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/packages/client/src/components/MkCheatSheetDialog.vue b/packages/client/src/components/MkCheatSheetDialog.vue
index 519955d48..3b723cde5 100644
--- a/packages/client/src/components/MkCheatSheetDialog.vue
+++ b/packages/client/src/components/MkCheatSheetDialog.vue
@@ -6,7 +6,7 @@
 		@closed="$emit('closed')"
 	>
 		<template #header>{{ i18n.ts._mfm.cheatSheet }}</template>
-		<XCheatSheet :popup="true" style="background: var(--bg)"/>
+		<XCheatSheet :popup="true" style="background: var(--bg)" />
 	</XModalWindow>
 </template>
 
@@ -36,5 +36,4 @@ function close(res) {
 .fade-leave-to {
 	opacity: 0;
 }
-
 </style>
diff --git a/packages/client/src/components/MkNote.vue b/packages/client/src/components/MkNote.vue
index 1325809f3..ddf805fb3 100644
--- a/packages/client/src/components/MkNote.vue
+++ b/packages/client/src/components/MkNote.vue
@@ -382,7 +382,7 @@ function onContextmenu(ev: MouseEvent): void {
 	const isLink = (el: HTMLElement) => {
 		if (el.tagName === "A") return true;
 		// The Audio element's context menu is the browser default, such as for selecting playback speed.
-		if (el.tagName === 'AUDIO') return true;
+		if (el.tagName === "AUDIO") return true;
 		if (el.parentElement) {
 			return isLink(el.parentElement);
 		}
diff --git a/packages/client/src/pages/mfm-cheat-sheet.vue b/packages/client/src/pages/mfm-cheat-sheet.vue
index 1bbe36915..6c284bee0 100644
--- a/packages/client/src/pages/mfm-cheat-sheet.vue
+++ b/packages/client/src/pages/mfm-cheat-sheet.vue
@@ -450,7 +450,7 @@ import { i18n } from "@/i18n";
 import { instance } from "@/instance";
 
 defineProps<{
-	popup?: boolean
+	popup?: boolean;
 }>();
 
 let preview_mention = $ref("@example");
diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue
index 2ea4bc971..1926fee88 100644
--- a/packages/client/src/pages/user/home.vue
+++ b/packages/client/src/pages/user/home.vue
@@ -134,7 +134,11 @@
 						</div>
 						<div class="follow-container">
 							<div class="actions">
-								<button class="menu _button" @click="menu" v-tooltip="i18n.ts.menu">
+								<button
+									class="menu _button"
+									@click="menu"
+									v-tooltip="i18n.ts.menu"
+								>
 									<i
 										class="ph-dots-three-outline ph-bold ph-lg"
 									></i>

From 623f796ee930e4f0500f4348bd4abf26714b3f54 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 02:34:48 -0400
Subject: [PATCH 05/66] add entities and two schemas

---
 packages/backend/native-utils/.editorconfig   |   3 +
 packages/backend/native-utils/Cargo.toml      |   3 +
 packages/backend/native-utils/build.rs        |   2 +-
 .../native-utils/crates/model/Cargo.toml      |  17 +
 .../model/src/entity/abuse_user_report.rs     |  56 +++
 .../crates/model/src/entity/access_token.rs   |  70 +++
 .../crates/model/src/entity/ad.rs             |  27 ++
 .../crates/model/src/entity/announcement.rs   |  33 ++
 .../model/src/entity/announcement_read.rs     |  51 +++
 .../crates/model/src/entity/antenna.rs        |  93 ++++
 .../crates/model/src/entity/antenna_note.rs   |  50 +++
 .../crates/model/src/entity/app.rs            |  57 +++
 .../model/src/entity/attestation_challenge.rs |  38 ++
 .../crates/model/src/entity/auth_session.rs   |  52 +++
 .../crates/model/src/entity/blocking.rs       |  39 ++
 .../crates/model/src/entity/channel.rs        |  83 ++++
 .../model/src/entity/channel_following.rs     |  51 +++
 .../model/src/entity/channel_note_pining.rs   |  51 +++
 .../crates/model/src/entity/clip.rs           |  47 ++
 .../crates/model/src/entity/clip_note.rs      |  49 ++
 .../crates/model/src/entity/drive_file.rs     | 114 +++++
 .../crates/model/src/entity/drive_folder.rs   |  54 +++
 .../crates/model/src/entity/emoji.rs          |  31 ++
 .../crates/model/src/entity/follow_request.rs |  61 +++
 .../crates/model/src/entity/following.rs      |  51 +++
 .../crates/model/src/entity/gallery_like.rs   |  51 +++
 .../crates/model/src/entity/gallery_post.rs   |  54 +++
 .../crates/model/src/entity/hashtag.rs        |  41 ++
 .../crates/model/src/entity/instance.rs       |  59 +++
 .../model/src/entity/messaging_message.rs     |  76 ++++
 .../crates/model/src/entity/meta.rs           | 211 +++++++++
 .../crates/model/src/entity/migrations.rs     |  18 +
 .../crates/model/src/entity/mod.rs            |  75 ++++
 .../crates/model/src/entity/moderation_log.rs |  38 ++
 .../crates/model/src/entity/muted_note.rs     |  51 +++
 .../crates/model/src/entity/muting.rs         |  41 ++
 .../crates/model/src/entity/note.rs           | 235 ++++++++++
 .../crates/model/src/entity/note_edit.rs      |  40 ++
 .../crates/model/src/entity/note_favorite.rs  |  51 +++
 .../crates/model/src/entity/note_reaction.rs  |  52 +++
 .../model/src/entity/note_thread_muting.rs    |  37 ++
 .../crates/model/src/entity/note_unread.rs    |  57 +++
 .../crates/model/src/entity/note_watching.rs  |  53 +++
 .../crates/model/src/entity/notification.rs   | 115 +++++
 .../crates/model/src/entity/page.rs           |  90 ++++
 .../crates/model/src/entity/page_like.rs      |  51 +++
 .../src/entity/password_reset_request.rs      |  36 ++
 .../crates/model/src/entity/poll.rs           |  43 ++
 .../crates/model/src/entity/poll_vote.rs      |  52 +++
 .../crates/model/src/entity/prelude.rs        |  72 +++
 .../crates/model/src/entity/promo_note.rs     |  35 ++
 .../crates/model/src/entity/promo_read.rs     |  51 +++
 .../model/src/entity/registration_ticket.rs   |  19 +
 .../crates/model/src/entity/registry_item.rs  |  42 ++
 .../crates/model/src/entity/relay.rs          |  19 +
 .../crates/model/src/entity/renote_muting.rs  |  22 +
 .../crates/model/src/entity/reversi_game.rs   |  68 +++
 .../model/src/entity/reversi_matching.rs      |  39 ++
 .../model/src/entity/sea_orm_active_enums.rs  | 175 ++++++++
 .../crates/model/src/entity/signin.rs         |  39 ++
 .../model/src/entity/sw_subscription.rs       |  40 ++
 .../crates/model/src/entity/used_username.rs  |  18 +
 .../crates/model/src/entity/user.rs           | 425 ++++++++++++++++++
 .../crates/model/src/entity/user_group.rs     |  70 +++
 .../model/src/entity/user_group_invitation.rs |  59 +++
 .../model/src/entity/user_group_invite.rs     |  51 +++
 .../model/src/entity/user_group_joining.rs    |  59 +++
 .../crates/model/src/entity/user_ip.rs        |  21 +
 .../crates/model/src/entity/user_keypair.rs   |  35 ++
 .../crates/model/src/entity/user_list.rs      |  52 +++
 .../model/src/entity/user_list_joining.rs     |  51 +++
 .../model/src/entity/user_note_pining.rs      |  51 +++
 .../crates/model/src/entity/user_pending.rs   |  22 +
 .../crates/model/src/entity/user_profile.rs   | 111 +++++
 .../crates/model/src/entity/user_publickey.rs |  35 ++
 .../model/src/entity/user_security_key.rs     |  38 ++
 .../crates/model/src/entity/webhook.rs        |  44 ++
 .../native-utils/crates/model/src/lib.rs      |   3 +
 .../model/src/repository/abuse_user_report.rs |   1 +
 .../crates/model/src/repository/mod.rs        |   1 +
 .../crates/model/src/schema/antenna.rs        | 128 ++++++
 .../crates/model/src/schema/app.rs            | 108 +++++
 .../crates/model/src/schema/mod.rs            |  21 +
 packages/backend/native-utils/rustfmt.toml    |   2 -
 packages/backend/native-utils/src/lib.rs      |   1 -
 .../backend/native-utils/src/mastodon_api.rs  |  78 ++--
 86 files changed, 4873 insertions(+), 43 deletions(-)
 create mode 100644 packages/backend/native-utils/.editorconfig
 create mode 100644 packages/backend/native-utils/crates/model/Cargo.toml
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/access_token.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/ad.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/announcement.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/antenna.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/app.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/auth_session.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/blocking.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/channel.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/channel_following.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/clip.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/clip_note.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/drive_file.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/emoji.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/follow_request.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/following.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/hashtag.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/instance.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/meta.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/migrations.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/mod.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/muted_note.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/muting.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_edit.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_unread.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/note_watching.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/notification.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/page.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/page_like.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/poll.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/prelude.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/promo_note.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/promo_read.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/registry_item.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/relay.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/signin.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/used_username.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_group.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_ip.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_list.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_pending.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_profile.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/webhook.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/lib.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/repository/mod.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/schema/antenna.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/schema/app.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/schema/mod.rs
 delete mode 100644 packages/backend/native-utils/rustfmt.toml

diff --git a/packages/backend/native-utils/.editorconfig b/packages/backend/native-utils/.editorconfig
new file mode 100644
index 000000000..889b72e11
--- /dev/null
+++ b/packages/backend/native-utils/.editorconfig
@@ -0,0 +1,3 @@
+[*.rs]
+indent_style = space
+indent_size = 4
diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index 4f7fb4c39..6f3c0e23f 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -3,6 +3,9 @@ edition = "2021"
 name = "native-utils"
 version = "0.0.0"
 
+[workspace]
+members = ["crates/*"]
+
 [lib]
 crate-type = ["cdylib"]
 
diff --git a/packages/backend/native-utils/build.rs b/packages/backend/native-utils/build.rs
index 1f866b6a3..9fc236788 100644
--- a/packages/backend/native-utils/build.rs
+++ b/packages/backend/native-utils/build.rs
@@ -1,5 +1,5 @@
 extern crate napi_build;
 
 fn main() {
-  napi_build::setup();
+    napi_build::setup();
 }
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
new file mode 100644
index 000000000..7b492a89d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "model"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+chrono = "0.4.24"
+jsonschema = "0.17.0"
+once_cell = "1.17.1"
+schemars = { version = "0.8.12", features = ["chrono"] }
+sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls", "mock"] }
+serde = { version = "1.0.163", features = ["derive"] }
+serde_json = "1.0.96"
+tokio = { version = "1.28.1", features = ["sync"] }
+utoipa = "3.3.0"
diff --git a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
new file mode 100644
index 000000000..163a686ab
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
@@ -0,0 +1,56 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "abuse_user_report")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "targetUserId")]
+    pub target_user_id: String,
+    #[sea_orm(column_name = "reporterId")]
+    pub reporter_id: String,
+    #[sea_orm(column_name = "assigneeId")]
+    pub assignee_id: Option<String>,
+    pub resolved: bool,
+    pub comment: String,
+    #[sea_orm(column_name = "targetUserHost")]
+    pub target_user_host: Option<String>,
+    #[sea_orm(column_name = "reporterHost")]
+    pub reporter_host: Option<String>,
+    pub forwarded: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::ReporterId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User3,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::AssigneeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::TargetUserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/access_token.rs b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
new file mode 100644
index 000000000..ba3a43d64
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
@@ -0,0 +1,70 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "access_token")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub token: String,
+    pub hash: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "appId")]
+    pub app_id: Option<String>,
+    #[sea_orm(column_name = "lastUsedAt")]
+    pub last_used_at: Option<DateTimeWithTimeZone>,
+    pub session: Option<String>,
+    pub name: Option<String>,
+    pub description: Option<String>,
+    #[sea_orm(column_name = "iconUrl")]
+    pub icon_url: Option<String>,
+    pub permission: Vec<String>,
+    pub fetched: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::app::Entity",
+        from = "Column::AppId",
+        to = "super::app::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    App,
+    #[sea_orm(has_many = "super::notification::Entity")]
+    Notification,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::app::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::App.def()
+    }
+}
+
+impl Related<super::notification::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Notification.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/ad.rs b/packages/backend/native-utils/crates/model/src/entity/ad.rs
new file mode 100644
index 000000000..4e31c7b0d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/ad.rs
@@ -0,0 +1,27 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "ad")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "expiresAt")]
+    pub expires_at: DateTimeWithTimeZone,
+    pub place: String,
+    pub priority: String,
+    pub url: String,
+    #[sea_orm(column_name = "imageUrl")]
+    pub image_url: String,
+    pub memo: String,
+    pub ratio: i32,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement.rs b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
new file mode 100644
index 000000000..0f02a1ca9
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
@@ -0,0 +1,33 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "announcement")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub text: String,
+    pub title: String,
+    #[sea_orm(column_name = "imageUrl")]
+    pub image_url: Option<String>,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: Option<DateTimeWithTimeZone>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::announcement_read::Entity")]
+    AnnouncementRead,
+}
+
+impl Related<super::announcement_read::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AnnouncementRead.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
new file mode 100644
index 000000000..ad7dcc6f2
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "announcement_read")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "announcementId")]
+    pub announcement_id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::announcement::Entity",
+        from = "Column::AnnouncementId",
+        to = "super::announcement::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Announcement,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::announcement::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Announcement.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
new file mode 100644
index 000000000..f9c040b59
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -0,0 +1,93 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::AntennaSrcEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "antenna")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub name: String,
+    pub src: AntennaSrcEnum,
+    #[sea_orm(column_name = "userListId")]
+    pub user_list_id: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub keywords: Json,
+    #[sea_orm(column_name = "withFile")]
+    pub with_file: bool,
+    pub expression: Option<String>,
+    pub notify: bool,
+    #[sea_orm(column_name = "caseSensitive")]
+    pub case_sensitive: bool,
+    #[sea_orm(column_name = "withReplies")]
+    pub with_replies: bool,
+    #[sea_orm(column_name = "userGroupJoiningId")]
+    pub user_group_joining_id: Option<String>,
+    pub users: Vec<String>,
+    #[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")]
+    pub exclude_keywords: Json,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub instances: Json,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::antenna_note::Entity")]
+    AntennaNote,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(
+        belongs_to = "super::user_group_joining::Entity",
+        from = "Column::UserGroupJoiningId",
+        to = "super::user_group_joining::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroupJoining,
+    #[sea_orm(
+        belongs_to = "super::user_list::Entity",
+        from = "Column::UserListId",
+        to = "super::user_list::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserList,
+}
+
+impl Related<super::antenna_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AntennaNote.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_group_joining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupJoining.def()
+    }
+}
+
+impl Related<super::user_list::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserList.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
new file mode 100644
index 000000000..ecf7b88f7
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
@@ -0,0 +1,50 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "antenna_note")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_name = "antennaId")]
+    pub antenna_id: String,
+    pub read: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::antenna::Entity",
+        from = "Column::AntennaId",
+        to = "super::antenna::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Antenna,
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::antenna::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Antenna.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/app.rs b/packages/backend/native-utils/crates/model/src/entity/app.rs
new file mode 100644
index 000000000..bd6ae5acf
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/app.rs
@@ -0,0 +1,57 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "app")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: Option<String>,
+    pub secret: String,
+    pub name: String,
+    pub description: String,
+    pub permission: Vec<String>,
+    #[sea_orm(column_name = "callbackUrl")]
+    pub callback_url: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::access_token::Entity")]
+    AccessToken,
+    #[sea_orm(has_many = "super::auth_session::Entity")]
+    AuthSession,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    User,
+}
+
+impl Related<super::access_token::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AccessToken.def()
+    }
+}
+
+impl Related<super::auth_session::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AuthSession.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
new file mode 100644
index 000000000..25da1ae57
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
@@ -0,0 +1,38 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "attestation_challenge")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "userId", primary_key, auto_increment = false)]
+    pub user_id: String,
+    pub challenge: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "registrationChallenge")]
+    pub registration_challenge: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
new file mode 100644
index 000000000..c3b2fab54
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
@@ -0,0 +1,52 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "auth_session")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub token: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: Option<String>,
+    #[sea_orm(column_name = "appId")]
+    pub app_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::app::Entity",
+        from = "Column::AppId",
+        to = "super::app::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    App,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::app::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::App.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/blocking.rs b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
new file mode 100644
index 000000000..c9092e50d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
@@ -0,0 +1,39 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "blocking")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "blockeeId")]
+    pub blockee_id: String,
+    #[sea_orm(column_name = "blockerId")]
+    pub blocker_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::BlockerId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::BlockeeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel.rs b/packages/backend/native-utils/crates/model/src/entity/channel.rs
new file mode 100644
index 000000000..b39b57f56
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/channel.rs
@@ -0,0 +1,83 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "channel")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "lastNotedAt")]
+    pub last_noted_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: Option<String>,
+    pub name: String,
+    pub description: Option<String>,
+    #[sea_orm(column_name = "bannerId")]
+    pub banner_id: Option<String>,
+    #[sea_orm(column_name = "notesCount")]
+    pub notes_count: i32,
+    #[sea_orm(column_name = "usersCount")]
+    pub users_count: i32,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::channel_following::Entity")]
+    ChannelFollowing,
+    #[sea_orm(has_many = "super::channel_note_pining::Entity")]
+    ChannelNotePining,
+    #[sea_orm(
+        belongs_to = "super::drive_file::Entity",
+        from = "Column::BannerId",
+        to = "super::drive_file::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    DriveFile,
+    #[sea_orm(has_many = "super::note::Entity")]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    User,
+}
+
+impl Related<super::channel_following::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ChannelFollowing.def()
+    }
+}
+
+impl Related<super::channel_note_pining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ChannelNotePining.def()
+    }
+}
+
+impl Related<super::drive_file::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFile.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
new file mode 100644
index 000000000..a415b6c32
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "channel_following")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "followeeId")]
+    pub followee_id: String,
+    #[sea_orm(column_name = "followerId")]
+    pub follower_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::channel::Entity",
+        from = "Column::FolloweeId",
+        to = "super::channel::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Channel,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::FollowerId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::channel::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Channel.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
new file mode 100644
index 000000000..16f80b91d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "channel_note_pining")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "channelId")]
+    pub channel_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::channel::Entity",
+        from = "Column::ChannelId",
+        to = "super::channel::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Channel,
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::channel::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Channel.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip.rs b/packages/backend/native-utils/crates/model/src/entity/clip.rs
new file mode 100644
index 000000000..6cf1ac1c8
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/clip.rs
@@ -0,0 +1,47 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "clip")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub name: String,
+    #[sea_orm(column_name = "isPublic")]
+    pub is_public: bool,
+    pub description: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::clip_note::Entity")]
+    ClipNote,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::clip_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ClipNote.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
new file mode 100644
index 000000000..ba7114c3b
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
@@ -0,0 +1,49 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "clip_note")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_name = "clipId")]
+    pub clip_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::clip::Entity",
+        from = "Column::ClipId",
+        to = "super::clip::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Clip,
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::clip::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Clip.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
new file mode 100644
index 000000000..5b3d17b00
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
@@ -0,0 +1,114 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "drive_file")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: Option<String>,
+    #[sea_orm(column_name = "userHost")]
+    pub user_host: Option<String>,
+    pub md5: String,
+    pub name: String,
+    pub r#type: String,
+    pub size: i32,
+    pub comment: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub properties: Json,
+    #[sea_orm(column_name = "storedInternal")]
+    pub stored_internal: bool,
+    pub url: String,
+    #[sea_orm(column_name = "thumbnailUrl")]
+    pub thumbnail_url: Option<String>,
+    #[sea_orm(column_name = "webpublicUrl")]
+    pub webpublic_url: Option<String>,
+    #[sea_orm(column_name = "accessKey")]
+    pub access_key: Option<String>,
+    #[sea_orm(column_name = "thumbnailAccessKey")]
+    pub thumbnail_access_key: Option<String>,
+    #[sea_orm(column_name = "webpublicAccessKey")]
+    pub webpublic_access_key: Option<String>,
+    pub uri: Option<String>,
+    pub src: Option<String>,
+    #[sea_orm(column_name = "folderId")]
+    pub folder_id: Option<String>,
+    #[sea_orm(column_name = "isSensitive")]
+    pub is_sensitive: bool,
+    #[sea_orm(column_name = "isLink")]
+    pub is_link: bool,
+    pub blurhash: Option<String>,
+    #[sea_orm(column_name = "webpublicType")]
+    pub webpublic_type: Option<String>,
+    #[sea_orm(column_name = "requestHeaders", column_type = "JsonBinary", nullable)]
+    pub request_headers: Option<Json>,
+    #[sea_orm(column_name = "requestIp")]
+    pub request_ip: Option<String>,
+    #[sea_orm(column_name = "maybeSensitive")]
+    pub maybe_sensitive: bool,
+    #[sea_orm(column_name = "maybePorn")]
+    pub maybe_porn: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::channel::Entity")]
+    Channel,
+    #[sea_orm(
+        belongs_to = "super::drive_folder::Entity",
+        from = "Column::FolderId",
+        to = "super::drive_folder::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    DriveFolder,
+    #[sea_orm(has_many = "super::messaging_message::Entity")]
+    MessagingMessage,
+    #[sea_orm(has_many = "super::page::Entity")]
+    Page,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    User,
+}
+
+impl Related<super::channel::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Channel.def()
+    }
+}
+
+impl Related<super::drive_folder::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFolder.def()
+    }
+}
+
+impl Related<super::messaging_message::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::MessagingMessage.def()
+    }
+}
+
+impl Related<super::page::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Page.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
new file mode 100644
index 000000000..9756f7053
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
@@ -0,0 +1,54 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "drive_folder")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub name: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: Option<String>,
+    #[sea_orm(column_name = "parentId")]
+    pub parent_id: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::drive_file::Entity")]
+    DriveFile,
+    #[sea_orm(
+        belongs_to = "Entity",
+        from = "Column::ParentId",
+        to = "Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    SelfRef,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::drive_file::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFile.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/emoji.rs b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
new file mode 100644
index 000000000..9dff7c719
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
@@ -0,0 +1,31 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "emoji")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: Option<DateTimeWithTimeZone>,
+    pub name: String,
+    pub host: Option<String>,
+    #[sea_orm(column_name = "originalUrl")]
+    pub original_url: String,
+    pub uri: Option<String>,
+    pub r#type: Option<String>,
+    pub aliases: Vec<String>,
+    pub category: Option<String>,
+    #[sea_orm(column_name = "publicUrl")]
+    pub public_url: String,
+    pub license: Option<String>,
+    pub width: Option<i32>,
+    pub height: Option<i32>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
new file mode 100644
index 000000000..32e31a09d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
@@ -0,0 +1,61 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "follow_request")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "followeeId")]
+    pub followee_id: String,
+    #[sea_orm(column_name = "followerId")]
+    pub follower_id: String,
+    #[sea_orm(column_name = "requestId")]
+    pub request_id: Option<String>,
+    #[sea_orm(column_name = "followerHost")]
+    pub follower_host: Option<String>,
+    #[sea_orm(column_name = "followerInbox")]
+    pub follower_inbox: Option<String>,
+    #[sea_orm(column_name = "followerSharedInbox")]
+    pub follower_shared_inbox: Option<String>,
+    #[sea_orm(column_name = "followeeHost")]
+    pub followee_host: Option<String>,
+    #[sea_orm(column_name = "followeeInbox")]
+    pub followee_inbox: Option<String>,
+    #[sea_orm(column_name = "followeeSharedInbox")]
+    pub followee_shared_inbox: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::notification::Entity")]
+    Notification,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::FolloweeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::FollowerId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl Related<super::notification::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Notification.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/following.rs b/packages/backend/native-utils/crates/model/src/entity/following.rs
new file mode 100644
index 000000000..6f339e05d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/following.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "following")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "followeeId")]
+    pub followee_id: String,
+    #[sea_orm(column_name = "followerId")]
+    pub follower_id: String,
+    #[sea_orm(column_name = "followerHost")]
+    pub follower_host: Option<String>,
+    #[sea_orm(column_name = "followerInbox")]
+    pub follower_inbox: Option<String>,
+    #[sea_orm(column_name = "followerSharedInbox")]
+    pub follower_shared_inbox: Option<String>,
+    #[sea_orm(column_name = "followeeHost")]
+    pub followee_host: Option<String>,
+    #[sea_orm(column_name = "followeeInbox")]
+    pub followee_inbox: Option<String>,
+    #[sea_orm(column_name = "followeeSharedInbox")]
+    pub followee_shared_inbox: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::FolloweeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::FollowerId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
new file mode 100644
index 000000000..0fdbf07ef
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "gallery_like")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "postId")]
+    pub post_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::gallery_post::Entity",
+        from = "Column::PostId",
+        to = "super::gallery_post::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    GalleryPost,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::gallery_post::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::GalleryPost.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
new file mode 100644
index 000000000..a23ebbd8f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
@@ -0,0 +1,54 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "gallery_post")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: DateTimeWithTimeZone,
+    pub title: String,
+    pub description: Option<String>,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "fileIds")]
+    pub file_ids: Vec<String>,
+    #[sea_orm(column_name = "isSensitive")]
+    pub is_sensitive: bool,
+    #[sea_orm(column_name = "likedCount")]
+    pub liked_count: i32,
+    pub tags: Vec<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::gallery_like::Entity")]
+    GalleryLike,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::gallery_like::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::GalleryLike.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
new file mode 100644
index 000000000..a83ebbf29
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
@@ -0,0 +1,41 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "hashtag")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    pub name: String,
+    #[sea_orm(column_name = "mentionedUserIds")]
+    pub mentioned_user_ids: Vec<String>,
+    #[sea_orm(column_name = "mentionedUsersCount")]
+    pub mentioned_users_count: i32,
+    #[sea_orm(column_name = "mentionedLocalUserIds")]
+    pub mentioned_local_user_ids: Vec<String>,
+    #[sea_orm(column_name = "mentionedLocalUsersCount")]
+    pub mentioned_local_users_count: i32,
+    #[sea_orm(column_name = "mentionedRemoteUserIds")]
+    pub mentioned_remote_user_ids: Vec<String>,
+    #[sea_orm(column_name = "mentionedRemoteUsersCount")]
+    pub mentioned_remote_users_count: i32,
+    #[sea_orm(column_name = "attachedUserIds")]
+    pub attached_user_ids: Vec<String>,
+    #[sea_orm(column_name = "attachedUsersCount")]
+    pub attached_users_count: i32,
+    #[sea_orm(column_name = "attachedLocalUserIds")]
+    pub attached_local_user_ids: Vec<String>,
+    #[sea_orm(column_name = "attachedLocalUsersCount")]
+    pub attached_local_users_count: i32,
+    #[sea_orm(column_name = "attachedRemoteUserIds")]
+    pub attached_remote_user_ids: Vec<String>,
+    #[sea_orm(column_name = "attachedRemoteUsersCount")]
+    pub attached_remote_users_count: i32,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/instance.rs b/packages/backend/native-utils/crates/model/src/entity/instance.rs
new file mode 100644
index 000000000..405648efc
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/instance.rs
@@ -0,0 +1,59 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "instance")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "caughtAt")]
+    pub caught_at: DateTimeWithTimeZone,
+    pub host: String,
+    #[sea_orm(column_name = "usersCount")]
+    pub users_count: i32,
+    #[sea_orm(column_name = "notesCount")]
+    pub notes_count: i32,
+    #[sea_orm(column_name = "followingCount")]
+    pub following_count: i32,
+    #[sea_orm(column_name = "followersCount")]
+    pub followers_count: i32,
+    #[sea_orm(column_name = "latestRequestSentAt")]
+    pub latest_request_sent_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "latestStatus")]
+    pub latest_status: Option<i32>,
+    #[sea_orm(column_name = "latestRequestReceivedAt")]
+    pub latest_request_received_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "lastCommunicatedAt")]
+    pub last_communicated_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "isNotResponding")]
+    pub is_not_responding: bool,
+    #[sea_orm(column_name = "softwareName")]
+    pub software_name: Option<String>,
+    #[sea_orm(column_name = "softwareVersion")]
+    pub software_version: Option<String>,
+    #[sea_orm(column_name = "openRegistrations")]
+    pub open_registrations: Option<bool>,
+    pub name: Option<String>,
+    pub description: Option<String>,
+    #[sea_orm(column_name = "maintainerName")]
+    pub maintainer_name: Option<String>,
+    #[sea_orm(column_name = "maintainerEmail")]
+    pub maintainer_email: Option<String>,
+    #[sea_orm(column_name = "infoUpdatedAt")]
+    pub info_updated_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "isSuspended")]
+    pub is_suspended: bool,
+    #[sea_orm(column_name = "iconUrl")]
+    pub icon_url: Option<String>,
+    #[sea_orm(column_name = "themeColor")]
+    pub theme_color: Option<String>,
+    #[sea_orm(column_name = "faviconUrl")]
+    pub favicon_url: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
new file mode 100644
index 000000000..cfb896371
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
@@ -0,0 +1,76 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "messaging_message")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "recipientId")]
+    pub recipient_id: Option<String>,
+    pub text: Option<String>,
+    #[sea_orm(column_name = "isRead")]
+    pub is_read: bool,
+    #[sea_orm(column_name = "fileId")]
+    pub file_id: Option<String>,
+    #[sea_orm(column_name = "groupId")]
+    pub group_id: Option<String>,
+    pub reads: Vec<String>,
+    pub uri: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::drive_file::Entity",
+        from = "Column::FileId",
+        to = "super::drive_file::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    DriveFile,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::RecipientId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+    #[sea_orm(
+        belongs_to = "super::user_group::Entity",
+        from = "Column::GroupId",
+        to = "super::user_group::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroup,
+}
+
+impl Related<super::drive_file::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFile.def()
+    }
+}
+
+impl Related<super::user_group::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroup.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/meta.rs b/packages/backend/native-utils/crates/model/src/entity/meta.rs
new file mode 100644
index 000000000..768c725aa
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/meta.rs
@@ -0,0 +1,211 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::MetaSensitivemediadetectionEnum;
+use super::sea_orm_active_enums::MetaSensitivemediadetectionsensitivityEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "meta")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    pub name: Option<String>,
+    pub description: Option<String>,
+    #[sea_orm(column_name = "maintainerName")]
+    pub maintainer_name: Option<String>,
+    #[sea_orm(column_name = "maintainerEmail")]
+    pub maintainer_email: Option<String>,
+    #[sea_orm(column_name = "disableRegistration")]
+    pub disable_registration: bool,
+    #[sea_orm(column_name = "disableLocalTimeline")]
+    pub disable_local_timeline: bool,
+    #[sea_orm(column_name = "disableGlobalTimeline")]
+    pub disable_global_timeline: bool,
+    #[sea_orm(column_name = "useStarForReactionFallback")]
+    pub use_star_for_reaction_fallback: bool,
+    pub langs: Vec<String>,
+    #[sea_orm(column_name = "hiddenTags")]
+    pub hidden_tags: Vec<String>,
+    #[sea_orm(column_name = "blockedHosts")]
+    pub blocked_hosts: Vec<String>,
+    #[sea_orm(column_name = "mascotImageUrl")]
+    pub mascot_image_url: Option<String>,
+    #[sea_orm(column_name = "bannerUrl")]
+    pub banner_url: Option<String>,
+    #[sea_orm(column_name = "errorImageUrl")]
+    pub error_image_url: Option<String>,
+    #[sea_orm(column_name = "iconUrl")]
+    pub icon_url: Option<String>,
+    #[sea_orm(column_name = "cacheRemoteFiles")]
+    pub cache_remote_files: bool,
+    #[sea_orm(column_name = "enableRecaptcha")]
+    pub enable_recaptcha: bool,
+    #[sea_orm(column_name = "recaptchaSiteKey")]
+    pub recaptcha_site_key: Option<String>,
+    #[sea_orm(column_name = "recaptchaSecretKey")]
+    pub recaptcha_secret_key: Option<String>,
+    #[sea_orm(column_name = "localDriveCapacityMb")]
+    pub local_drive_capacity_mb: i32,
+    #[sea_orm(column_name = "remoteDriveCapacityMb")]
+    pub remote_drive_capacity_mb: i32,
+    #[sea_orm(column_name = "summalyProxy")]
+    pub summaly_proxy: Option<String>,
+    #[sea_orm(column_name = "enableEmail")]
+    pub enable_email: bool,
+    pub email: Option<String>,
+    #[sea_orm(column_name = "smtpSecure")]
+    pub smtp_secure: bool,
+    #[sea_orm(column_name = "smtpHost")]
+    pub smtp_host: Option<String>,
+    #[sea_orm(column_name = "smtpPort")]
+    pub smtp_port: Option<i32>,
+    #[sea_orm(column_name = "smtpUser")]
+    pub smtp_user: Option<String>,
+    #[sea_orm(column_name = "smtpPass")]
+    pub smtp_pass: Option<String>,
+    #[sea_orm(column_name = "enableServiceWorker")]
+    pub enable_service_worker: bool,
+    #[sea_orm(column_name = "swPublicKey")]
+    pub sw_public_key: Option<String>,
+    #[sea_orm(column_name = "swPrivateKey")]
+    pub sw_private_key: Option<String>,
+    #[sea_orm(column_name = "enableTwitterIntegration")]
+    pub enable_twitter_integration: bool,
+    #[sea_orm(column_name = "twitterConsumerKey")]
+    pub twitter_consumer_key: Option<String>,
+    #[sea_orm(column_name = "twitterConsumerSecret")]
+    pub twitter_consumer_secret: Option<String>,
+    #[sea_orm(column_name = "enableGithubIntegration")]
+    pub enable_github_integration: bool,
+    #[sea_orm(column_name = "githubClientId")]
+    pub github_client_id: Option<String>,
+    #[sea_orm(column_name = "githubClientSecret")]
+    pub github_client_secret: Option<String>,
+    #[sea_orm(column_name = "enableDiscordIntegration")]
+    pub enable_discord_integration: bool,
+    #[sea_orm(column_name = "discordClientId")]
+    pub discord_client_id: Option<String>,
+    #[sea_orm(column_name = "discordClientSecret")]
+    pub discord_client_secret: Option<String>,
+    #[sea_orm(column_name = "pinnedUsers")]
+    pub pinned_users: Vec<String>,
+    #[sea_orm(column_name = "ToSUrl")]
+    pub to_s_url: Option<String>,
+    #[sea_orm(column_name = "repositoryUrl")]
+    pub repository_url: String,
+    #[sea_orm(column_name = "feedbackUrl")]
+    pub feedback_url: Option<String>,
+    #[sea_orm(column_name = "useObjectStorage")]
+    pub use_object_storage: bool,
+    #[sea_orm(column_name = "objectStorageBucket")]
+    pub object_storage_bucket: Option<String>,
+    #[sea_orm(column_name = "objectStoragePrefix")]
+    pub object_storage_prefix: Option<String>,
+    #[sea_orm(column_name = "objectStorageBaseUrl")]
+    pub object_storage_base_url: Option<String>,
+    #[sea_orm(column_name = "objectStorageEndpoint")]
+    pub object_storage_endpoint: Option<String>,
+    #[sea_orm(column_name = "objectStorageRegion")]
+    pub object_storage_region: Option<String>,
+    #[sea_orm(column_name = "objectStorageAccessKey")]
+    pub object_storage_access_key: Option<String>,
+    #[sea_orm(column_name = "objectStorageSecretKey")]
+    pub object_storage_secret_key: Option<String>,
+    #[sea_orm(column_name = "objectStoragePort")]
+    pub object_storage_port: Option<i32>,
+    #[sea_orm(column_name = "objectStorageUseSSL")]
+    pub object_storage_use_ssl: bool,
+    #[sea_orm(column_name = "proxyAccountId")]
+    pub proxy_account_id: Option<String>,
+    #[sea_orm(column_name = "objectStorageUseProxy")]
+    pub object_storage_use_proxy: bool,
+    #[sea_orm(column_name = "enableHcaptcha")]
+    pub enable_hcaptcha: bool,
+    #[sea_orm(column_name = "hcaptchaSiteKey")]
+    pub hcaptcha_site_key: Option<String>,
+    #[sea_orm(column_name = "hcaptchaSecretKey")]
+    pub hcaptcha_secret_key: Option<String>,
+    #[sea_orm(column_name = "objectStorageSetPublicRead")]
+    pub object_storage_set_public_read: bool,
+    #[sea_orm(column_name = "pinnedPages")]
+    pub pinned_pages: Vec<String>,
+    #[sea_orm(column_name = "backgroundImageUrl")]
+    pub background_image_url: Option<String>,
+    #[sea_orm(column_name = "logoImageUrl")]
+    pub logo_image_url: Option<String>,
+    #[sea_orm(column_name = "pinnedClipId")]
+    pub pinned_clip_id: Option<String>,
+    #[sea_orm(column_name = "objectStorageS3ForcePathStyle")]
+    pub object_storage_s3_force_path_style: bool,
+    #[sea_orm(column_name = "allowedHosts")]
+    pub allowed_hosts: Option<Vec<String>>,
+    #[sea_orm(column_name = "secureMode")]
+    pub secure_mode: Option<bool>,
+    #[sea_orm(column_name = "privateMode")]
+    pub private_mode: Option<bool>,
+    #[sea_orm(column_name = "deeplAuthKey")]
+    pub deepl_auth_key: Option<String>,
+    #[sea_orm(column_name = "deeplIsPro")]
+    pub deepl_is_pro: bool,
+    #[sea_orm(column_name = "emailRequiredForSignup")]
+    pub email_required_for_signup: bool,
+    #[sea_orm(column_name = "themeColor")]
+    pub theme_color: Option<String>,
+    #[sea_orm(column_name = "defaultLightTheme")]
+    pub default_light_theme: Option<String>,
+    #[sea_orm(column_name = "defaultDarkTheme")]
+    pub default_dark_theme: Option<String>,
+    #[sea_orm(column_name = "sensitiveMediaDetection")]
+    pub sensitive_media_detection: MetaSensitivemediadetectionEnum,
+    #[sea_orm(column_name = "sensitiveMediaDetectionSensitivity")]
+    pub sensitive_media_detection_sensitivity: MetaSensitivemediadetectionsensitivityEnum,
+    #[sea_orm(column_name = "setSensitiveFlagAutomatically")]
+    pub set_sensitive_flag_automatically: bool,
+    #[sea_orm(column_name = "enableIpLogging")]
+    pub enable_ip_logging: bool,
+    #[sea_orm(column_name = "enableSensitiveMediaDetectionForVideos")]
+    pub enable_sensitive_media_detection_for_videos: bool,
+    #[sea_orm(column_name = "enableActiveEmailValidation")]
+    pub enable_active_email_validation: bool,
+    #[sea_orm(column_name = "customMOTD")]
+    pub custom_motd: Vec<String>,
+    #[sea_orm(column_name = "customSplashIcons")]
+    pub custom_splash_icons: Vec<String>,
+    #[sea_orm(column_name = "disableRecommendedTimeline")]
+    pub disable_recommended_timeline: bool,
+    #[sea_orm(column_name = "recommendedInstances")]
+    pub recommended_instances: Vec<String>,
+    #[sea_orm(column_name = "enableGuestTimeline")]
+    pub enable_guest_timeline: bool,
+    #[sea_orm(column_name = "defaultReaction")]
+    pub default_reaction: String,
+    #[sea_orm(column_name = "libreTranslateApiUrl")]
+    pub libre_translate_api_url: Option<String>,
+    #[sea_orm(column_name = "libreTranslateApiKey")]
+    pub libre_translate_api_key: Option<String>,
+    #[sea_orm(column_name = "silencedHosts")]
+    pub silenced_hosts: Vec<String>,
+    #[sea_orm(column_name = "experimentalFeatures", column_type = "JsonBinary")]
+    pub experimental_features: Json,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::ProxyAccountId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/migrations.rs b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
new file mode 100644
index 000000000..c53c3fc89
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
@@ -0,0 +1,18 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "migrations")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    pub timestamp: i64,
+    pub name: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/mod.rs b/packages/backend/native-utils/crates/model/src/entity/mod.rs
new file mode 100644
index 000000000..077f9fa6e
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/mod.rs
@@ -0,0 +1,75 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+pub mod prelude;
+
+pub mod abuse_user_report;
+pub mod access_token;
+pub mod ad;
+pub mod announcement;
+pub mod announcement_read;
+pub mod antenna;
+pub mod antenna_note;
+pub mod app;
+pub mod attestation_challenge;
+pub mod auth_session;
+pub mod blocking;
+pub mod channel;
+pub mod channel_following;
+pub mod channel_note_pining;
+pub mod clip;
+pub mod clip_note;
+pub mod drive_file;
+pub mod drive_folder;
+pub mod emoji;
+pub mod follow_request;
+pub mod following;
+pub mod gallery_like;
+pub mod gallery_post;
+pub mod hashtag;
+pub mod instance;
+pub mod messaging_message;
+pub mod meta;
+pub mod migrations;
+pub mod moderation_log;
+pub mod muted_note;
+pub mod muting;
+pub mod note;
+pub mod note_edit;
+pub mod note_favorite;
+pub mod note_reaction;
+pub mod note_thread_muting;
+pub mod note_unread;
+pub mod note_watching;
+pub mod notification;
+pub mod page;
+pub mod page_like;
+pub mod password_reset_request;
+pub mod poll;
+pub mod poll_vote;
+pub mod promo_note;
+pub mod promo_read;
+pub mod registration_ticket;
+pub mod registry_item;
+pub mod relay;
+pub mod renote_muting;
+pub mod reversi_game;
+pub mod reversi_matching;
+pub mod sea_orm_active_enums;
+pub mod signin;
+pub mod sw_subscription;
+pub mod used_username;
+pub mod user;
+pub mod user_group;
+pub mod user_group_invitation;
+pub mod user_group_invite;
+pub mod user_group_joining;
+pub mod user_ip;
+pub mod user_keypair;
+pub mod user_list;
+pub mod user_list_joining;
+pub mod user_note_pining;
+pub mod user_pending;
+pub mod user_profile;
+pub mod user_publickey;
+pub mod user_security_key;
+pub mod webhook;
diff --git a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
new file mode 100644
index 000000000..eb49d4f15
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
@@ -0,0 +1,38 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "moderation_log")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub r#type: String,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub info: Json,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
new file mode 100644
index 000000000..17328a829
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::MutedNoteReasonEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "muted_note")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub reason: MutedNoteReasonEnum,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/muting.rs b/packages/backend/native-utils/crates/model/src/entity/muting.rs
new file mode 100644
index 000000000..60020b60b
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/muting.rs
@@ -0,0 +1,41 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "muting")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "muteeId")]
+    pub mutee_id: String,
+    #[sea_orm(column_name = "muterId")]
+    pub muter_id: String,
+    #[sea_orm(column_name = "expiresAt")]
+    pub expires_at: Option<DateTimeWithTimeZone>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::MuterId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::MuteeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note.rs b/packages/backend/native-utils/crates/model/src/entity/note.rs
new file mode 100644
index 000000000..cc3ec289f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note.rs
@@ -0,0 +1,235 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::NoteVisibilityEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "replyId")]
+    pub reply_id: Option<String>,
+    #[sea_orm(column_name = "renoteId")]
+    pub renote_id: Option<String>,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub text: Option<String>,
+    pub name: Option<String>,
+    pub cw: Option<String>,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "localOnly")]
+    pub local_only: bool,
+    #[sea_orm(column_name = "renoteCount")]
+    pub renote_count: i16,
+    #[sea_orm(column_name = "repliesCount")]
+    pub replies_count: i16,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub reactions: Json,
+    pub visibility: NoteVisibilityEnum,
+    pub uri: Option<String>,
+    pub score: i32,
+    #[sea_orm(column_name = "fileIds")]
+    pub file_ids: Vec<String>,
+    #[sea_orm(column_name = "attachedFileTypes")]
+    pub attached_file_types: Vec<String>,
+    #[sea_orm(column_name = "visibleUserIds")]
+    pub visible_user_ids: Vec<String>,
+    pub mentions: Vec<String>,
+    #[sea_orm(column_name = "mentionedRemoteUsers", column_type = "Text")]
+    pub mentioned_remote_users: String,
+    pub emojis: Vec<String>,
+    pub tags: Vec<String>,
+    #[sea_orm(column_name = "hasPoll")]
+    pub has_poll: bool,
+    #[sea_orm(column_name = "userHost")]
+    pub user_host: Option<String>,
+    #[sea_orm(column_name = "replyUserId")]
+    pub reply_user_id: Option<String>,
+    #[sea_orm(column_name = "replyUserHost")]
+    pub reply_user_host: Option<String>,
+    #[sea_orm(column_name = "renoteUserId")]
+    pub renote_user_id: Option<String>,
+    #[sea_orm(column_name = "renoteUserHost")]
+    pub renote_user_host: Option<String>,
+    pub url: Option<String>,
+    #[sea_orm(column_name = "channelId")]
+    pub channel_id: Option<String>,
+    #[sea_orm(column_name = "threadId")]
+    pub thread_id: Option<String>,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: Option<DateTimeWithTimeZone>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::antenna_note::Entity")]
+    AntennaNote,
+    #[sea_orm(
+        belongs_to = "super::channel::Entity",
+        from = "Column::ChannelId",
+        to = "super::channel::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Channel,
+    #[sea_orm(has_many = "super::channel_note_pining::Entity")]
+    ChannelNotePining,
+    #[sea_orm(has_many = "super::clip_note::Entity")]
+    ClipNote,
+    #[sea_orm(has_many = "super::muted_note::Entity")]
+    MutedNote,
+    #[sea_orm(
+        belongs_to = "Entity",
+        from = "Column::ReplyId",
+        to = "Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    SelfRef2,
+    #[sea_orm(
+        belongs_to = "Entity",
+        from = "Column::RenoteId",
+        to = "Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    SelfRef1,
+    #[sea_orm(has_many = "super::note_edit::Entity")]
+    NoteEdit,
+    #[sea_orm(has_many = "super::note_favorite::Entity")]
+    NoteFavorite,
+    #[sea_orm(has_many = "super::note_reaction::Entity")]
+    NoteReaction,
+    #[sea_orm(has_many = "super::note_unread::Entity")]
+    NoteUnread,
+    #[sea_orm(has_many = "super::note_watching::Entity")]
+    NoteWatching,
+    #[sea_orm(has_many = "super::notification::Entity")]
+    Notification,
+    #[sea_orm(has_one = "super::poll::Entity")]
+    Poll,
+    #[sea_orm(has_many = "super::poll_vote::Entity")]
+    PollVote,
+    #[sea_orm(has_one = "super::promo_note::Entity")]
+    PromoNote,
+    #[sea_orm(has_many = "super::promo_read::Entity")]
+    PromoRead,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(has_many = "super::user_note_pining::Entity")]
+    UserNotePining,
+}
+
+impl Related<super::antenna_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AntennaNote.def()
+    }
+}
+
+impl Related<super::channel::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Channel.def()
+    }
+}
+
+impl Related<super::channel_note_pining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ChannelNotePining.def()
+    }
+}
+
+impl Related<super::clip_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ClipNote.def()
+    }
+}
+
+impl Related<super::muted_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::MutedNote.def()
+    }
+}
+
+impl Related<super::note_edit::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteEdit.def()
+    }
+}
+
+impl Related<super::note_favorite::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteFavorite.def()
+    }
+}
+
+impl Related<super::note_reaction::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteReaction.def()
+    }
+}
+
+impl Related<super::note_unread::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteUnread.def()
+    }
+}
+
+impl Related<super::note_watching::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteWatching.def()
+    }
+}
+
+impl Related<super::notification::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Notification.def()
+    }
+}
+
+impl Related<super::poll::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Poll.def()
+    }
+}
+
+impl Related<super::poll_vote::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PollVote.def()
+    }
+}
+
+impl Related<super::promo_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PromoNote.def()
+    }
+}
+
+impl Related<super::promo_read::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PromoRead.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_note_pining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserNotePining.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
new file mode 100644
index 000000000..7b87613dd
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
@@ -0,0 +1,40 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_edit")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub text: Option<String>,
+    pub cw: Option<String>,
+    #[sea_orm(column_name = "fileIds")]
+    pub file_ids: Vec<String>,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: DateTimeWithTimeZone,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
new file mode 100644
index 000000000..b5c96a9a6
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_favorite")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
new file mode 100644
index 000000000..52526aa9f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
@@ -0,0 +1,52 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_reaction")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    pub reaction: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
new file mode 100644
index 000000000..572a03750
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
@@ -0,0 +1,37 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_thread_muting")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "threadId")]
+    pub thread_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
new file mode 100644
index 000000000..80fae4335
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
@@ -0,0 +1,57 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_unread")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_name = "noteUserId")]
+    pub note_user_id: String,
+    #[sea_orm(column_name = "isSpecified")]
+    pub is_specified: bool,
+    #[sea_orm(column_name = "isMentioned")]
+    pub is_mentioned: bool,
+    #[sea_orm(column_name = "noteChannelId")]
+    pub note_channel_id: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
new file mode 100644
index 000000000..1ff7af52e
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
@@ -0,0 +1,53 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "note_watching")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    #[sea_orm(column_name = "noteUserId")]
+    pub note_user_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/notification.rs b/packages/backend/native-utils/crates/model/src/entity/notification.rs
new file mode 100644
index 000000000..c2d9115f3
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/notification.rs
@@ -0,0 +1,115 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::NotificationTypeEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "notification")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "notifieeId")]
+    pub notifiee_id: String,
+    #[sea_orm(column_name = "notifierId")]
+    pub notifier_id: Option<String>,
+    #[sea_orm(column_name = "isRead")]
+    pub is_read: bool,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: Option<String>,
+    pub reaction: Option<String>,
+    pub choice: Option<i32>,
+    #[sea_orm(column_name = "followRequestId")]
+    pub follow_request_id: Option<String>,
+    pub r#type: NotificationTypeEnum,
+    #[sea_orm(column_name = "userGroupInvitationId")]
+    pub user_group_invitation_id: Option<String>,
+    #[sea_orm(column_name = "customBody")]
+    pub custom_body: Option<String>,
+    #[sea_orm(column_name = "customHeader")]
+    pub custom_header: Option<String>,
+    #[sea_orm(column_name = "customIcon")]
+    pub custom_icon: Option<String>,
+    #[sea_orm(column_name = "appAccessTokenId")]
+    pub app_access_token_id: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::access_token::Entity",
+        from = "Column::AppAccessTokenId",
+        to = "super::access_token::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    AccessToken,
+    #[sea_orm(
+        belongs_to = "super::follow_request::Entity",
+        from = "Column::FollowRequestId",
+        to = "super::follow_request::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    FollowRequest,
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::NotifierId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::NotifieeId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+    #[sea_orm(
+        belongs_to = "super::user_group_invitation::Entity",
+        from = "Column::UserGroupInvitationId",
+        to = "super::user_group_invitation::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroupInvitation,
+}
+
+impl Related<super::access_token::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AccessToken.def()
+    }
+}
+
+impl Related<super::follow_request::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::FollowRequest.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user_group_invitation::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupInvitation.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/page.rs b/packages/backend/native-utils/crates/model/src/entity/page.rs
new file mode 100644
index 000000000..32f082daf
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/page.rs
@@ -0,0 +1,90 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::PageVisibilityEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "page")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: DateTimeWithTimeZone,
+    pub title: String,
+    pub name: String,
+    pub summary: Option<String>,
+    #[sea_orm(column_name = "alignCenter")]
+    pub align_center: bool,
+    pub font: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "eyeCatchingImageId")]
+    pub eye_catching_image_id: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub content: Json,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub variables: Json,
+    pub visibility: PageVisibilityEnum,
+    #[sea_orm(column_name = "visibleUserIds")]
+    pub visible_user_ids: Vec<String>,
+    #[sea_orm(column_name = "likedCount")]
+    pub liked_count: i32,
+    #[sea_orm(column_name = "hideTitleWhenPinned")]
+    pub hide_title_when_pinned: bool,
+    pub script: String,
+    #[sea_orm(column_name = "isPublic")]
+    pub is_public: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::drive_file::Entity",
+        from = "Column::EyeCatchingImageId",
+        to = "super::drive_file::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    DriveFile,
+    #[sea_orm(has_many = "super::page_like::Entity")]
+    PageLike,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(has_one = "super::user_profile::Entity")]
+    UserProfile,
+}
+
+impl Related<super::drive_file::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFile.def()
+    }
+}
+
+impl Related<super::page_like::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PageLike.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_profile::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserProfile.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/page_like.rs b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
new file mode 100644
index 000000000..e9de78eb6
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "page_like")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "pageId")]
+    pub page_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::page::Entity",
+        from = "Column::PageId",
+        to = "super::page::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Page,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::page::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Page.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
new file mode 100644
index 000000000..472b93db9
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
@@ -0,0 +1,36 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "password_reset_request")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub token: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll.rs b/packages/backend/native-utils/crates/model/src/entity/poll.rs
new file mode 100644
index 000000000..0facabd9a
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/poll.rs
@@ -0,0 +1,43 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::PollNotevisibilityEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "poll")]
+pub struct Model {
+    #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
+    pub note_id: String,
+    #[sea_orm(column_name = "expiresAt")]
+    pub expires_at: Option<DateTimeWithTimeZone>,
+    pub multiple: bool,
+    pub choices: Vec<String>,
+    pub votes: Vec<i32>,
+    #[sea_orm(column_name = "noteVisibility")]
+    pub note_visibility: PollNotevisibilityEnum,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "userHost")]
+    pub user_host: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
new file mode 100644
index 000000000..29b6928ef
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
@@ -0,0 +1,52 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "poll_vote")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+    pub choice: i32,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/prelude.rs b/packages/backend/native-utils/crates/model/src/entity/prelude.rs
new file mode 100644
index 000000000..7cab688bb
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/prelude.rs
@@ -0,0 +1,72 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+pub use super::abuse_user_report::Entity as AbuseUserReport;
+pub use super::access_token::Entity as AccessToken;
+pub use super::ad::Entity as Ad;
+pub use super::announcement::Entity as Announcement;
+pub use super::announcement_read::Entity as AnnouncementRead;
+pub use super::antenna::Entity as Antenna;
+pub use super::antenna_note::Entity as AntennaNote;
+pub use super::app::Entity as App;
+pub use super::attestation_challenge::Entity as AttestationChallenge;
+pub use super::auth_session::Entity as AuthSession;
+pub use super::blocking::Entity as Blocking;
+pub use super::channel::Entity as Channel;
+pub use super::channel_following::Entity as ChannelFollowing;
+pub use super::channel_note_pining::Entity as ChannelNotePining;
+pub use super::clip::Entity as Clip;
+pub use super::clip_note::Entity as ClipNote;
+pub use super::drive_file::Entity as DriveFile;
+pub use super::drive_folder::Entity as DriveFolder;
+pub use super::emoji::Entity as Emoji;
+pub use super::follow_request::Entity as FollowRequest;
+pub use super::following::Entity as Following;
+pub use super::gallery_like::Entity as GalleryLike;
+pub use super::gallery_post::Entity as GalleryPost;
+pub use super::hashtag::Entity as Hashtag;
+pub use super::instance::Entity as Instance;
+pub use super::messaging_message::Entity as MessagingMessage;
+pub use super::meta::Entity as Meta;
+pub use super::migrations::Entity as Migrations;
+pub use super::moderation_log::Entity as ModerationLog;
+pub use super::muted_note::Entity as MutedNote;
+pub use super::muting::Entity as Muting;
+pub use super::note::Entity as Note;
+pub use super::note_edit::Entity as NoteEdit;
+pub use super::note_favorite::Entity as NoteFavorite;
+pub use super::note_reaction::Entity as NoteReaction;
+pub use super::note_thread_muting::Entity as NoteThreadMuting;
+pub use super::note_unread::Entity as NoteUnread;
+pub use super::note_watching::Entity as NoteWatching;
+pub use super::notification::Entity as Notification;
+pub use super::page::Entity as Page;
+pub use super::page_like::Entity as PageLike;
+pub use super::password_reset_request::Entity as PasswordResetRequest;
+pub use super::poll::Entity as Poll;
+pub use super::poll_vote::Entity as PollVote;
+pub use super::promo_note::Entity as PromoNote;
+pub use super::promo_read::Entity as PromoRead;
+pub use super::registration_ticket::Entity as RegistrationTicket;
+pub use super::registry_item::Entity as RegistryItem;
+pub use super::relay::Entity as Relay;
+pub use super::renote_muting::Entity as RenoteMuting;
+pub use super::reversi_game::Entity as ReversiGame;
+pub use super::reversi_matching::Entity as ReversiMatching;
+pub use super::signin::Entity as Signin;
+pub use super::sw_subscription::Entity as SwSubscription;
+pub use super::used_username::Entity as UsedUsername;
+pub use super::user::Entity as User;
+pub use super::user_group::Entity as UserGroup;
+pub use super::user_group_invitation::Entity as UserGroupInvitation;
+pub use super::user_group_invite::Entity as UserGroupInvite;
+pub use super::user_group_joining::Entity as UserGroupJoining;
+pub use super::user_ip::Entity as UserIp;
+pub use super::user_keypair::Entity as UserKeypair;
+pub use super::user_list::Entity as UserList;
+pub use super::user_list_joining::Entity as UserListJoining;
+pub use super::user_note_pining::Entity as UserNotePining;
+pub use super::user_pending::Entity as UserPending;
+pub use super::user_profile::Entity as UserProfile;
+pub use super::user_publickey::Entity as UserPublickey;
+pub use super::user_security_key::Entity as UserSecurityKey;
+pub use super::webhook::Entity as Webhook;
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
new file mode 100644
index 000000000..6e8de9866
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
@@ -0,0 +1,35 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "promo_note")]
+pub struct Model {
+    #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
+    pub note_id: String,
+    #[sea_orm(column_name = "expiresAt")]
+    pub expires_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
new file mode 100644
index 000000000..807ad4a27
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "promo_read")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
new file mode 100644
index 000000000..8d7e4ba8d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
@@ -0,0 +1,19 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "registration_ticket")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub code: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
new file mode 100644
index 000000000..8aa188210
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
@@ -0,0 +1,42 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "registry_item")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub key: String,
+    pub scope: Vec<String>,
+    pub domain: Option<String>,
+    #[sea_orm(column_type = "JsonBinary", nullable)]
+    pub value: Option<Json>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/relay.rs b/packages/backend/native-utils/crates/model/src/entity/relay.rs
new file mode 100644
index 000000000..731d12e8c
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/relay.rs
@@ -0,0 +1,19 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::RelayStatusEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "relay")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    pub inbox: String,
+    pub status: RelayStatusEnum,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
new file mode 100644
index 000000000..b63c989a6
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
@@ -0,0 +1,22 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "renote_muting")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "muteeId")]
+    pub mutee_id: String,
+    #[sea_orm(column_name = "muterId")]
+    pub muter_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
new file mode 100644
index 000000000..56f83e543
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
@@ -0,0 +1,68 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "reversi_game")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "startedAt")]
+    pub started_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "user1Id")]
+    pub user1_id: String,
+    #[sea_orm(column_name = "user2Id")]
+    pub user2_id: String,
+    #[sea_orm(column_name = "user1Accepted")]
+    pub user1_accepted: bool,
+    #[sea_orm(column_name = "user2Accepted")]
+    pub user2_accepted: bool,
+    pub black: Option<i32>,
+    #[sea_orm(column_name = "isStarted")]
+    pub is_started: bool,
+    #[sea_orm(column_name = "isEnded")]
+    pub is_ended: bool,
+    #[sea_orm(column_name = "winnerId")]
+    pub winner_id: Option<String>,
+    pub surrendered: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub logs: Json,
+    pub map: Vec<String>,
+    pub bw: String,
+    #[sea_orm(column_name = "isLlotheo")]
+    pub is_llotheo: bool,
+    #[sea_orm(column_name = "canPutEverywhere")]
+    pub can_put_everywhere: bool,
+    #[sea_orm(column_name = "loopedBoard")]
+    pub looped_board: bool,
+    #[sea_orm(column_type = "JsonBinary", nullable)]
+    pub form1: Option<Json>,
+    #[sea_orm(column_type = "JsonBinary", nullable)]
+    pub form2: Option<Json>,
+    pub crc32: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::User2Id",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::User1Id",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
new file mode 100644
index 000000000..9261b6482
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
@@ -0,0 +1,39 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "reversi_matching")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "parentId")]
+    pub parent_id: String,
+    #[sea_orm(column_name = "childId")]
+    pub child_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::ParentId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User2,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::ChildId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User1,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
new file mode 100644
index 000000000..747cd953a
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
@@ -0,0 +1,175 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
+pub enum AntennaSrcEnum {
+    #[sea_orm(string_value = "all")]
+    All,
+    #[sea_orm(string_value = "group")]
+    Group,
+    #[sea_orm(string_value = "home")]
+    Home,
+    #[sea_orm(string_value = "instances")]
+    Instances,
+    #[sea_orm(string_value = "list")]
+    List,
+    #[sea_orm(string_value = "users")]
+    Users,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "meta_sensitivemediadetection_enum"
+)]
+pub enum MetaSensitivemediadetectionEnum {
+    #[sea_orm(string_value = "all")]
+    All,
+    #[sea_orm(string_value = "local")]
+    Local,
+    #[sea_orm(string_value = "none")]
+    None,
+    #[sea_orm(string_value = "remote")]
+    Remote,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "meta_sensitivemediadetectionsensitivity_enum"
+)]
+pub enum MetaSensitivemediadetectionsensitivityEnum {
+    #[sea_orm(string_value = "high")]
+    High,
+    #[sea_orm(string_value = "low")]
+    Low,
+    #[sea_orm(string_value = "medium")]
+    Medium,
+    #[sea_orm(string_value = "veryHigh")]
+    VeryHigh,
+    #[sea_orm(string_value = "veryLow")]
+    VeryLow,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "muted_note_reason_enum"
+)]
+pub enum MutedNoteReasonEnum {
+    #[sea_orm(string_value = "manual")]
+    Manual,
+    #[sea_orm(string_value = "other")]
+    Other,
+    #[sea_orm(string_value = "spam")]
+    Spam,
+    #[sea_orm(string_value = "word")]
+    Word,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "note_visibility_enum"
+)]
+pub enum NoteVisibilityEnum {
+    #[sea_orm(string_value = "followers")]
+    Followers,
+    #[sea_orm(string_value = "hidden")]
+    Hidden,
+    #[sea_orm(string_value = "home")]
+    Home,
+    #[sea_orm(string_value = "public")]
+    Public,
+    #[sea_orm(string_value = "specified")]
+    Specified,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "notification_type_enum"
+)]
+pub enum NotificationTypeEnum {
+    #[sea_orm(string_value = "app")]
+    App,
+    #[sea_orm(string_value = "follow")]
+    Follow,
+    #[sea_orm(string_value = "followRequestAccepted")]
+    FollowRequestAccepted,
+    #[sea_orm(string_value = "groupInvited")]
+    GroupInvited,
+    #[sea_orm(string_value = "mention")]
+    Mention,
+    #[sea_orm(string_value = "pollEnded")]
+    PollEnded,
+    #[sea_orm(string_value = "pollVote")]
+    PollVote,
+    #[sea_orm(string_value = "quote")]
+    Quote,
+    #[sea_orm(string_value = "reaction")]
+    Reaction,
+    #[sea_orm(string_value = "receiveFollowRequest")]
+    ReceiveFollowRequest,
+    #[sea_orm(string_value = "renote")]
+    Renote,
+    #[sea_orm(string_value = "reply")]
+    Reply,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "page_visibility_enum"
+)]
+pub enum PageVisibilityEnum {
+    #[sea_orm(string_value = "followers")]
+    Followers,
+    #[sea_orm(string_value = "public")]
+    Public,
+    #[sea_orm(string_value = "specified")]
+    Specified,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "poll_notevisibility_enum"
+)]
+pub enum PollNotevisibilityEnum {
+    #[sea_orm(string_value = "followers")]
+    Followers,
+    #[sea_orm(string_value = "home")]
+    Home,
+    #[sea_orm(string_value = "public")]
+    Public,
+    #[sea_orm(string_value = "specified")]
+    Specified,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
+pub enum RelayStatusEnum {
+    #[sea_orm(string_value = "accepted")]
+    Accepted,
+    #[sea_orm(string_value = "rejected")]
+    Rejected,
+    #[sea_orm(string_value = "requesting")]
+    Requesting,
+}
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = "Enum",
+    enum_name = "user_profile_ffvisibility_enum"
+)]
+pub enum UserProfileFfvisibilityEnum {
+    #[sea_orm(string_value = "followers")]
+    Followers,
+    #[sea_orm(string_value = "private")]
+    Private,
+    #[sea_orm(string_value = "public")]
+    Public,
+}
diff --git a/packages/backend/native-utils/crates/model/src/entity/signin.rs b/packages/backend/native-utils/crates/model/src/entity/signin.rs
new file mode 100644
index 000000000..d6f730892
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/signin.rs
@@ -0,0 +1,39 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "signin")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub ip: String,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub headers: Json,
+    pub success: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
new file mode 100644
index 000000000..0d2ac26d9
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
@@ -0,0 +1,40 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "sw_subscription")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub endpoint: String,
+    pub auth: String,
+    pub publickey: String,
+    #[sea_orm(column_name = "sendReadMessage")]
+    pub send_read_message: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/used_username.rs b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
new file mode 100644
index 000000000..cf325cfa5
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
@@ -0,0 +1,18 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "used_username")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub username: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user.rs b/packages/backend/native-utils/crates/model/src/entity/user.rs
new file mode 100644
index 000000000..cd1153994
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user.rs
@@ -0,0 +1,425 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "updatedAt")]
+    pub updated_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "lastFetchedAt")]
+    pub last_fetched_at: Option<DateTimeWithTimeZone>,
+    pub username: String,
+    #[sea_orm(column_name = "usernameLower")]
+    pub username_lower: String,
+    pub name: Option<String>,
+    #[sea_orm(column_name = "followersCount")]
+    pub followers_count: i32,
+    #[sea_orm(column_name = "followingCount")]
+    pub following_count: i32,
+    #[sea_orm(column_name = "notesCount")]
+    pub notes_count: i32,
+    #[sea_orm(column_name = "avatarId", unique)]
+    pub avatar_id: Option<String>,
+    #[sea_orm(column_name = "bannerId", unique)]
+    pub banner_id: Option<String>,
+    pub tags: Vec<String>,
+    #[sea_orm(column_name = "isSuspended")]
+    pub is_suspended: bool,
+    #[sea_orm(column_name = "isSilenced")]
+    pub is_silenced: bool,
+    #[sea_orm(column_name = "isLocked")]
+    pub is_locked: bool,
+    #[sea_orm(column_name = "isBot")]
+    pub is_bot: bool,
+    #[sea_orm(column_name = "isCat")]
+    pub is_cat: bool,
+    #[sea_orm(column_name = "isAdmin")]
+    pub is_admin: bool,
+    #[sea_orm(column_name = "isModerator")]
+    pub is_moderator: bool,
+    pub emojis: Vec<String>,
+    pub host: Option<String>,
+    pub inbox: Option<String>,
+    #[sea_orm(column_name = "sharedInbox")]
+    pub shared_inbox: Option<String>,
+    pub featured: Option<String>,
+    pub uri: Option<String>,
+    #[sea_orm(unique)]
+    pub token: Option<String>,
+    #[sea_orm(column_name = "isExplorable")]
+    pub is_explorable: bool,
+    #[sea_orm(column_name = "followersUri")]
+    pub followers_uri: Option<String>,
+    #[sea_orm(column_name = "lastActiveDate")]
+    pub last_active_date: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "hideOnlineStatus")]
+    pub hide_online_status: bool,
+    #[sea_orm(column_name = "isDeleted")]
+    pub is_deleted: bool,
+    #[sea_orm(column_name = "showTimelineReplies")]
+    pub show_timeline_replies: bool,
+    #[sea_orm(column_name = "driveCapacityOverrideMb")]
+    pub drive_capacity_override_mb: Option<i32>,
+    #[sea_orm(column_name = "movedToUri")]
+    pub moved_to_uri: Option<String>,
+    #[sea_orm(column_name = "alsoKnownAs", column_type = "Text", nullable)]
+    pub also_known_as: Option<String>,
+    #[sea_orm(column_name = "speakAsCat")]
+    pub speak_as_cat: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::access_token::Entity")]
+    AccessToken,
+    #[sea_orm(has_many = "super::announcement_read::Entity")]
+    AnnouncementRead,
+    #[sea_orm(has_many = "super::antenna::Entity")]
+    Antenna,
+    #[sea_orm(has_many = "super::app::Entity")]
+    App,
+    #[sea_orm(has_many = "super::attestation_challenge::Entity")]
+    AttestationChallenge,
+    #[sea_orm(has_many = "super::auth_session::Entity")]
+    AuthSession,
+    #[sea_orm(has_many = "super::channel::Entity")]
+    Channel,
+    #[sea_orm(has_many = "super::channel_following::Entity")]
+    ChannelFollowing,
+    #[sea_orm(has_many = "super::clip::Entity")]
+    Clip,
+    #[sea_orm(
+        belongs_to = "super::drive_file::Entity",
+        from = "Column::AvatarId",
+        to = "super::drive_file::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    DriveFile2,
+    #[sea_orm(
+        belongs_to = "super::drive_file::Entity",
+        from = "Column::BannerId",
+        to = "super::drive_file::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    DriveFile1,
+    #[sea_orm(has_many = "super::drive_folder::Entity")]
+    DriveFolder,
+    #[sea_orm(has_many = "super::gallery_like::Entity")]
+    GalleryLike,
+    #[sea_orm(has_many = "super::gallery_post::Entity")]
+    GalleryPost,
+    #[sea_orm(has_many = "super::meta::Entity")]
+    Meta,
+    #[sea_orm(has_many = "super::moderation_log::Entity")]
+    ModerationLog,
+    #[sea_orm(has_many = "super::muted_note::Entity")]
+    MutedNote,
+    #[sea_orm(has_many = "super::note::Entity")]
+    Note,
+    #[sea_orm(has_many = "super::note_favorite::Entity")]
+    NoteFavorite,
+    #[sea_orm(has_many = "super::note_reaction::Entity")]
+    NoteReaction,
+    #[sea_orm(has_many = "super::note_thread_muting::Entity")]
+    NoteThreadMuting,
+    #[sea_orm(has_many = "super::note_unread::Entity")]
+    NoteUnread,
+    #[sea_orm(has_many = "super::note_watching::Entity")]
+    NoteWatching,
+    #[sea_orm(has_many = "super::page::Entity")]
+    Page,
+    #[sea_orm(has_many = "super::page_like::Entity")]
+    PageLike,
+    #[sea_orm(has_many = "super::password_reset_request::Entity")]
+    PasswordResetRequest,
+    #[sea_orm(has_many = "super::poll_vote::Entity")]
+    PollVote,
+    #[sea_orm(has_many = "super::promo_read::Entity")]
+    PromoRead,
+    #[sea_orm(has_many = "super::registry_item::Entity")]
+    RegistryItem,
+    #[sea_orm(has_many = "super::signin::Entity")]
+    Signin,
+    #[sea_orm(has_many = "super::sw_subscription::Entity")]
+    SwSubscription,
+    #[sea_orm(has_many = "super::user_group::Entity")]
+    UserGroup,
+    #[sea_orm(has_many = "super::user_group_invitation::Entity")]
+    UserGroupInvitation,
+    #[sea_orm(has_many = "super::user_group_invite::Entity")]
+    UserGroupInvite,
+    #[sea_orm(has_many = "super::user_group_joining::Entity")]
+    UserGroupJoining,
+    #[sea_orm(has_one = "super::user_keypair::Entity")]
+    UserKeypair,
+    #[sea_orm(has_many = "super::user_list::Entity")]
+    UserList,
+    #[sea_orm(has_many = "super::user_list_joining::Entity")]
+    UserListJoining,
+    #[sea_orm(has_many = "super::user_note_pining::Entity")]
+    UserNotePining,
+    #[sea_orm(has_one = "super::user_profile::Entity")]
+    UserProfile,
+    #[sea_orm(has_one = "super::user_publickey::Entity")]
+    UserPublickey,
+    #[sea_orm(has_many = "super::user_security_key::Entity")]
+    UserSecurityKey,
+    #[sea_orm(has_many = "super::webhook::Entity")]
+    Webhook,
+}
+
+impl Related<super::access_token::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AccessToken.def()
+    }
+}
+
+impl Related<super::announcement_read::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AnnouncementRead.def()
+    }
+}
+
+impl Related<super::antenna::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Antenna.def()
+    }
+}
+
+impl Related<super::app::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::App.def()
+    }
+}
+
+impl Related<super::attestation_challenge::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AttestationChallenge.def()
+    }
+}
+
+impl Related<super::auth_session::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::AuthSession.def()
+    }
+}
+
+impl Related<super::channel::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Channel.def()
+    }
+}
+
+impl Related<super::channel_following::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ChannelFollowing.def()
+    }
+}
+
+impl Related<super::clip::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Clip.def()
+    }
+}
+
+impl Related<super::drive_folder::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::DriveFolder.def()
+    }
+}
+
+impl Related<super::gallery_like::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::GalleryLike.def()
+    }
+}
+
+impl Related<super::gallery_post::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::GalleryPost.def()
+    }
+}
+
+impl Related<super::meta::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Meta.def()
+    }
+}
+
+impl Related<super::moderation_log::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::ModerationLog.def()
+    }
+}
+
+impl Related<super::muted_note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::MutedNote.def()
+    }
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::note_favorite::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteFavorite.def()
+    }
+}
+
+impl Related<super::note_reaction::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteReaction.def()
+    }
+}
+
+impl Related<super::note_thread_muting::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteThreadMuting.def()
+    }
+}
+
+impl Related<super::note_unread::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteUnread.def()
+    }
+}
+
+impl Related<super::note_watching::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::NoteWatching.def()
+    }
+}
+
+impl Related<super::page::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Page.def()
+    }
+}
+
+impl Related<super::page_like::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PageLike.def()
+    }
+}
+
+impl Related<super::password_reset_request::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PasswordResetRequest.def()
+    }
+}
+
+impl Related<super::poll_vote::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PollVote.def()
+    }
+}
+
+impl Related<super::promo_read::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::PromoRead.def()
+    }
+}
+
+impl Related<super::registry_item::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::RegistryItem.def()
+    }
+}
+
+impl Related<super::signin::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Signin.def()
+    }
+}
+
+impl Related<super::sw_subscription::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::SwSubscription.def()
+    }
+}
+
+impl Related<super::user_group::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroup.def()
+    }
+}
+
+impl Related<super::user_group_invitation::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupInvitation.def()
+    }
+}
+
+impl Related<super::user_group_invite::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupInvite.def()
+    }
+}
+
+impl Related<super::user_group_joining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupJoining.def()
+    }
+}
+
+impl Related<super::user_keypair::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserKeypair.def()
+    }
+}
+
+impl Related<super::user_list::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserList.def()
+    }
+}
+
+impl Related<super::user_list_joining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserListJoining.def()
+    }
+}
+
+impl Related<super::user_note_pining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserNotePining.def()
+    }
+}
+
+impl Related<super::user_profile::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserProfile.def()
+    }
+}
+
+impl Related<super::user_publickey::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserPublickey.def()
+    }
+}
+
+impl Related<super::user_security_key::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserSecurityKey.def()
+    }
+}
+
+impl Related<super::webhook::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Webhook.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group.rs b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
new file mode 100644
index 000000000..278e9997d
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
@@ -0,0 +1,70 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_group")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub name: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "isPrivate")]
+    pub is_private: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::messaging_message::Entity")]
+    MessagingMessage,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(has_many = "super::user_group_invitation::Entity")]
+    UserGroupInvitation,
+    #[sea_orm(has_many = "super::user_group_invite::Entity")]
+    UserGroupInvite,
+    #[sea_orm(has_many = "super::user_group_joining::Entity")]
+    UserGroupJoining,
+}
+
+impl Related<super::messaging_message::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::MessagingMessage.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_group_invitation::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupInvitation.def()
+    }
+}
+
+impl Related<super::user_group_invite::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupInvite.def()
+    }
+}
+
+impl Related<super::user_group_joining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroupJoining.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
new file mode 100644
index 000000000..62538db37
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
@@ -0,0 +1,59 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_group_invitation")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "userGroupId")]
+    pub user_group_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::notification::Entity")]
+    Notification,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(
+        belongs_to = "super::user_group::Entity",
+        from = "Column::UserGroupId",
+        to = "super::user_group::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroup,
+}
+
+impl Related<super::notification::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Notification.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_group::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroup.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
new file mode 100644
index 000000000..7ddfa021f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_group_invite")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "userGroupId")]
+    pub user_group_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(
+        belongs_to = "super::user_group::Entity",
+        from = "Column::UserGroupId",
+        to = "super::user_group::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroup,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_group::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroup.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
new file mode 100644
index 000000000..65cb000df
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
@@ -0,0 +1,59 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_group_joining")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "userGroupId")]
+    pub user_group_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::antenna::Entity")]
+    Antenna,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(
+        belongs_to = "super::user_group::Entity",
+        from = "Column::UserGroupId",
+        to = "super::user_group::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserGroup,
+}
+
+impl Related<super::antenna::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Antenna.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_group::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserGroup.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
new file mode 100644
index 000000000..d108b29fe
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
@@ -0,0 +1,21 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_ip")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub ip: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
new file mode 100644
index 000000000..a9a07b1d9
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
@@ -0,0 +1,35 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_keypair")]
+pub struct Model {
+    #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
+    pub user_id: String,
+    #[sea_orm(column_name = "publicKey")]
+    pub public_key: String,
+    #[sea_orm(column_name = "privateKey")]
+    pub private_key: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list.rs b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
new file mode 100644
index 000000000..6a2f93241
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
@@ -0,0 +1,52 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_list")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub name: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::antenna::Entity")]
+    Antenna,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(has_many = "super::user_list_joining::Entity")]
+    UserListJoining,
+}
+
+impl Related<super::antenna::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Antenna.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_list_joining::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserListJoining.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
new file mode 100644
index 000000000..fddcfdb54
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_list_joining")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "userListId")]
+    pub user_list_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+    #[sea_orm(
+        belongs_to = "super::user_list::Entity",
+        from = "Column::UserListId",
+        to = "super::user_list::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    UserList,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl Related<super::user_list::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::UserList.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
new file mode 100644
index 000000000..24e976e22
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
@@ -0,0 +1,51 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_note_pining")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "noteId")]
+    pub note_id: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::note::Entity",
+        from = "Column::NoteId",
+        to = "super::note::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    Note,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::note::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Note.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
new file mode 100644
index 000000000..e9134d9ee
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
@@ -0,0 +1,22 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_pending")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    pub code: String,
+    pub username: String,
+    pub email: String,
+    pub password: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
new file mode 100644
index 000000000..d22dcbebf
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
@@ -0,0 +1,111 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use super::sea_orm_active_enums::UserProfileFfvisibilityEnum;
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_profile")]
+pub struct Model {
+    #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
+    pub user_id: String,
+    pub location: Option<String>,
+    pub birthday: Option<String>,
+    pub description: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub fields: Json,
+    pub url: Option<String>,
+    pub email: Option<String>,
+    #[sea_orm(column_name = "emailVerifyCode")]
+    pub email_verify_code: Option<String>,
+    #[sea_orm(column_name = "emailVerified")]
+    pub email_verified: bool,
+    #[sea_orm(column_name = "twoFactorTempSecret")]
+    pub two_factor_temp_secret: Option<String>,
+    #[sea_orm(column_name = "twoFactorSecret")]
+    pub two_factor_secret: Option<String>,
+    #[sea_orm(column_name = "twoFactorEnabled")]
+    pub two_factor_enabled: bool,
+    pub password: Option<String>,
+    #[sea_orm(column_name = "clientData", column_type = "JsonBinary")]
+    pub client_data: Json,
+    #[sea_orm(column_name = "autoAcceptFollowed")]
+    pub auto_accept_followed: bool,
+    #[sea_orm(column_name = "alwaysMarkNsfw")]
+    pub always_mark_nsfw: bool,
+    #[sea_orm(column_name = "carefulBot")]
+    pub careful_bot: bool,
+    #[sea_orm(column_name = "userHost")]
+    pub user_host: Option<String>,
+    #[sea_orm(column_name = "securityKeysAvailable")]
+    pub security_keys_available: bool,
+    #[sea_orm(column_name = "usePasswordLessLogin")]
+    pub use_password_less_login: bool,
+    #[sea_orm(column_name = "pinnedPageId", unique)]
+    pub pinned_page_id: Option<String>,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub room: Json,
+    #[sea_orm(column_type = "JsonBinary")]
+    pub integrations: Json,
+    #[sea_orm(column_name = "injectFeaturedNote")]
+    pub inject_featured_note: bool,
+    #[sea_orm(column_name = "enableWordMute")]
+    pub enable_word_mute: bool,
+    #[sea_orm(column_name = "mutedWords", column_type = "JsonBinary")]
+    pub muted_words: Json,
+    #[sea_orm(column_name = "mutingNotificationTypes")]
+    pub muting_notification_types: Vec<String>,
+    #[sea_orm(column_name = "noCrawle")]
+    pub no_crawle: bool,
+    #[sea_orm(column_name = "receiveAnnouncementEmail")]
+    pub receive_announcement_email: bool,
+    #[sea_orm(column_name = "emailNotificationTypes", column_type = "JsonBinary")]
+    pub email_notification_types: Json,
+    pub lang: Option<String>,
+    #[sea_orm(column_name = "mutedInstances", column_type = "JsonBinary")]
+    pub muted_instances: Json,
+    #[sea_orm(column_name = "publicReactions")]
+    pub public_reactions: bool,
+    #[sea_orm(column_name = "ffVisibility")]
+    pub ff_visibility: UserProfileFfvisibilityEnum,
+    #[sea_orm(column_name = "autoSensitive")]
+    pub auto_sensitive: bool,
+    #[sea_orm(column_name = "moderationNote")]
+    pub moderation_note: String,
+    #[sea_orm(column_name = "preventAiLearning")]
+    pub prevent_ai_learning: bool,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::page::Entity",
+        from = "Column::PinnedPageId",
+        to = "super::page::Column::Id",
+        on_update = "NoAction",
+        on_delete = "SetNull"
+    )]
+    Page,
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::page::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::Page.def()
+    }
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
new file mode 100644
index 000000000..5cf6857e2
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
@@ -0,0 +1,35 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_publickey")]
+pub struct Model {
+    #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
+    pub user_id: String,
+    #[sea_orm(column_name = "keyId")]
+    pub key_id: String,
+    #[sea_orm(column_name = "keyPem")]
+    pub key_pem: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
new file mode 100644
index 000000000..531b59ab8
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
@@ -0,0 +1,38 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "user_security_key")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    #[sea_orm(column_name = "publicKey")]
+    pub public_key: String,
+    #[sea_orm(column_name = "lastUsed")]
+    pub last_used: DateTimeWithTimeZone,
+    pub name: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/webhook.rs b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
new file mode 100644
index 000000000..39508f7fa
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
@@ -0,0 +1,44 @@
+//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "webhook")]
+pub struct Model {
+    #[sea_orm(primary_key, auto_increment = false)]
+    pub id: String,
+    #[sea_orm(column_name = "createdAt")]
+    pub created_at: DateTimeWithTimeZone,
+    #[sea_orm(column_name = "userId")]
+    pub user_id: String,
+    pub name: String,
+    pub on: Vec<String>,
+    pub url: String,
+    pub secret: String,
+    pub active: bool,
+    #[sea_orm(column_name = "latestSentAt")]
+    pub latest_sent_at: Option<DateTimeWithTimeZone>,
+    #[sea_orm(column_name = "latestStatus")]
+    pub latest_status: Option<i32>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::user::Entity",
+        from = "Column::UserId",
+        to = "super::user::Column::Id",
+        on_update = "NoAction",
+        on_delete = "Cascade"
+    )]
+    User,
+}
+
+impl Related<super::user::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::User.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/lib.rs b/packages/backend/native-utils/crates/model/src/lib.rs
new file mode 100644
index 000000000..b14d29c34
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/lib.rs
@@ -0,0 +1,3 @@
+pub mod entity;
+pub mod repository;
+pub mod schema;
diff --git a/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs b/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
@@ -0,0 +1 @@
+
diff --git a/packages/backend/native-utils/crates/model/src/repository/mod.rs b/packages/backend/native-utils/crates/model/src/repository/mod.rs
new file mode 100644
index 000000000..f7a590081
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/repository/mod.rs
@@ -0,0 +1 @@
+pub mod abuse_user_report;
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
new file mode 100644
index 000000000..3bffe4f5f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -0,0 +1,128 @@
+use jsonschema::JSONSchema;
+use once_cell::sync::Lazy;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use utoipa::ToSchema;
+
+use super::Schema;
+
+#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct Antenna {
+    pub id: String,
+    pub created_at: chrono::DateTime<chrono::Utc>,
+    pub name: String,
+    pub keywords: Vec<Vec<String>>,
+    pub exclude_keywords: Vec<Vec<String>>,
+    #[schema(inline)]
+    pub src: AntennaSrcEnum,
+    pub user_list_id: Option<String>,
+    pub user_group_id: Option<String>,
+    pub users: Vec<String>,
+    pub instances: Vec<String>,
+    #[serde(default)]
+    pub case_sensitive: bool,
+    #[serde(default)]
+    pub notify: bool,
+    #[serde(default)]
+    pub with_replies: bool,
+    #[serde(default)]
+    pub with_file: bool,
+    #[serde(default)]
+    pub has_unread_note: bool,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[serde(rename_all = "lowercase")]
+pub enum AntennaSrcEnum {
+    Home,
+    All,
+    Users,
+    List,
+    Group,
+    Instances,
+}
+
+impl Schema<Self> for Antenna {}
+
+pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
+
+#[cfg(test)]
+mod tests {
+    use serde_json::json;
+
+    use super::VALIDATOR;
+
+    #[test]
+    fn valid() {
+        let instance = json!({
+            "id": "9f4x0bkx1u",
+            "createdAt": "2023-05-24T06:56:14.323Z",
+            "name": "Valid Antenna",
+            "keywords": [["first", "keyword"], ["second"]],
+            "excludeKeywords": [["excluding", "keywrods"], ["from", "antenna"]],
+            "src": "users",
+            // "userListId" and "userGroupId" can be null or be omitted
+            "userListId": null,
+            "users": ["9f4yjw6m13", "9f4yk2cp6d"],
+            "instances": [],
+            // "caseSensitive", "notify", "withReplies", "withFile", and
+            // "hasUnreadNote" are false if ommited
+            "notify": false,
+            "withReplies": false,
+            "withFile": false,
+            "hasUnreadNote": false,
+        });
+
+        assert!(VALIDATOR.is_valid(&instance));
+    }
+
+    #[test]
+    fn invalid() {
+        let instance = json!({
+            // "id" is required
+            "id": null,
+            // trailing "Z" is missing
+            "createdAt": "2023-05-24T07:36:34.389",
+            // "name" is required
+            // "keywords" must be an array
+            "keywords": "invalid keyword",
+            // "excludeKeywords" is required
+            "excludeKeywords": null,
+            // "src" should be one of "home", "all", "users", "list", "group", and
+            // "instances"
+            "src": "invalid_src",
+            // "userListId" is string
+            "userListId": ["9f4ziiqfxw"],
+            // "users" must be an array of strings
+            "users": [1, "9f4ykyuza6"],
+            "instances": ["9f4ykyuybo"],
+            // "caseSensitive" is boolean
+            "caseSensitive": 0,
+            "notify": true,
+            "withReplies": true,
+            "withFile": true,
+            "hasUnreadNote": true,
+        });
+
+        let result = VALIDATOR
+            .validate(&instance)
+            .expect_err("validation must fail");
+        let mut paths: Vec<String> = result.map(|e| e.schema_path.to_string()).collect();
+        paths.sort();
+        assert_eq!(
+            paths,
+            vec![
+                "/properties/caseSensitive/type",
+                "/properties/createdAt/format",
+                "/properties/excludeKeywords/type",
+                "/properties/id/type",
+                "/properties/keywords/type",
+                "/properties/src/enum",
+                "/properties/userListId/type",
+                "/properties/users/items/type",
+                "/required"
+            ]
+        );
+    }
+}
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/crates/model/src/schema/app.rs
new file mode 100644
index 000000000..861bdc48a
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/schema/app.rs
@@ -0,0 +1,108 @@
+use jsonschema::JSONSchema;
+use once_cell::sync::Lazy;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use utoipa::ToSchema;
+
+use super::Schema;
+
+#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct App {
+    pub id: String,
+    pub name: String,
+    #[schemars(url)]
+    pub callback_url: Option<String>,
+    #[schema(inline)]
+    pub permission: Vec<Permission>,
+    pub secret: Option<String>,
+    pub is_authorized: Option<bool>,
+}
+
+/// This represents `permissions` in `packages/calckey-js/src/consts.ts`.
+#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+pub enum Permission {
+    #[serde(rename = "read:account")]
+    ReadAccount,
+    #[serde(rename = "write:account")]
+    WriteAccount,
+    #[serde(rename = "read:blocks")]
+    ReadBlocks,
+    #[serde(rename = "write:blocks")]
+    WriteBlocks,
+    #[serde(rename = "read:drive")]
+    ReadDrive,
+    #[serde(rename = "write:drive")]
+    WriteDrive,
+    #[serde(rename = "read:favorites")]
+    ReadFavorites,
+    #[serde(rename = "write:favorites")]
+    WriteFavorites,
+    #[serde(rename = "read:following")]
+    ReadFollowing,
+    #[serde(rename = "write:following")]
+    WriteFollowing,
+    #[serde(rename = "read:messaging")]
+    ReadMessaging,
+    #[serde(rename = "write:messaging")]
+    WriteMessaging,
+    #[serde(rename = "read:mutes")]
+    ReadMutes,
+    #[serde(rename = "write:mutes")]
+    WriteMutes,
+    #[serde(rename = "read:notes")]
+    ReadNotes,
+    #[serde(rename = "write:notes")]
+    WriteNotes,
+    #[serde(rename = "read:notifications")]
+    ReadNotifications,
+    #[serde(rename = "write:notifications")]
+    WriteNotifications,
+    #[serde(rename = "read:reactions")]
+    ReadReactions,
+    #[serde(rename = "write:reactions")]
+    WriteReactions,
+    #[serde(rename = "write:votes")]
+    WriteVotes,
+    #[serde(rename = "read:pages")]
+    ReadPages,
+    #[serde(rename = "write:pages")]
+    WritePages,
+    #[serde(rename = "read:page-likes")]
+    ReadPageLikes,
+    #[serde(rename = "write:page-likes")]
+    WritePageLikes,
+    #[serde(rename = "read:user-groups")]
+    ReadUserGroups,
+    #[serde(rename = "write:user-groups")]
+    WriteUserGroups,
+    #[serde(rename = "read:channels")]
+    ReadChannels,
+    #[serde(rename = "write:channels")]
+    WriteChannels,
+    #[serde(rename = "read:gallery")]
+    ReadGallery,
+    #[serde(rename = "write:gallery")]
+    WriteGallery,
+    #[serde(rename = "read:gallery-likes")]
+    ReadGalleryLikes,
+    #[serde(rename = "write:gallery-likes")]
+    WriteGalleryLikes,
+}
+
+impl Schema<Self> for App {}
+
+pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| App::validator());
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn valid() {
+        todo!();
+    }
+
+    #[test]
+    fn invalid() {
+        todo!();
+    }
+}
diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema/mod.rs
new file mode 100644
index 000000000..cc495aac1
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/schema/mod.rs
@@ -0,0 +1,21 @@
+pub mod antenna;
+pub mod app;
+
+use jsonschema::JSONSchema;
+use schemars::{schema_for, JsonSchema};
+
+/// Structs of schema defitions implement this trait in order to
+/// provide the JSON Schema validator [`jsonschema::JSONSchema`].
+trait Schema<T: JsonSchema> {
+    /// Returns the validator of [JSON Schema Draft
+    /// 7](https://json-schema.org/specification-links.html#draft-7) with the
+    /// default settings of [`schemars::gen::SchemaSettings`].
+    fn validator() -> JSONSchema {
+        let root = schema_for!(T);
+        let schema = serde_json::to_value(&root).expect("Schema definition invalid");
+        JSONSchema::options()
+            .with_draft(jsonschema::Draft::Draft7)
+            .compile(&schema)
+            .expect("Unable to compile schema")
+    }
+}
diff --git a/packages/backend/native-utils/rustfmt.toml b/packages/backend/native-utils/rustfmt.toml
deleted file mode 100644
index cab5731ed..000000000
--- a/packages/backend/native-utils/rustfmt.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-tab_spaces = 2
-edition = "2021"
diff --git a/packages/backend/native-utils/src/lib.rs b/packages/backend/native-utils/src/lib.rs
index bc5b9fc7c..e13190140 100644
--- a/packages/backend/native-utils/src/lib.rs
+++ b/packages/backend/native-utils/src/lib.rs
@@ -1,2 +1 @@
-
 pub mod mastodon_api;
diff --git a/packages/backend/native-utils/src/mastodon_api.rs b/packages/backend/native-utils/src/mastodon_api.rs
index 36b4eb984..7a3ea455a 100644
--- a/packages/backend/native-utils/src/mastodon_api.rs
+++ b/packages/backend/native-utils/src/mastodon_api.rs
@@ -7,64 +7,64 @@ static CHAR_COLLECTION: &str = "0123456789abcdefghijklmnopqrstuvwxyz";
 
 #[napi]
 pub enum IdConvertType {
-  MastodonId,
-  CalckeyId,
+    MastodonId,
+    CalckeyId,
 }
 
 #[napi]
 pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> {
-  use IdConvertType::*;
-  match id_convert_type {
-    MastodonId => {
-      let mut out: i64 = 0;
-      for (i, c) in in_id.to_lowercase().chars().rev().enumerate() {
-        out += num_from_char(c)? as i64 * 36_i64.pow(i as u32);
-      }
+    use IdConvertType::*;
+    match id_convert_type {
+        MastodonId => {
+            let mut out: i64 = 0;
+            for (i, c) in in_id.to_lowercase().chars().rev().enumerate() {
+                out += num_from_char(c)? as i64 * 36_i64.pow(i as u32);
+            }
 
-      Ok(out.to_string())
-    }
-    CalckeyId => {
-      let mut input: i64 = match in_id.parse() {
-        Ok(s) => s,
-        Err(_) => {
-          return Err(Error::new(
-            Status::InvalidArg,
-            "Unable to parse ID as MasstodonId",
-          ))
+            Ok(out.to_string())
         }
-      };
-      let mut out = String::new();
+        CalckeyId => {
+            let mut input: i64 = match in_id.parse() {
+                Ok(s) => s,
+                Err(_) => {
+                    return Err(Error::new(
+                        Status::InvalidArg,
+                        "Unable to parse ID as MasstodonId",
+                    ))
+                }
+            };
+            let mut out = String::new();
 
-      while input != 0 {
-        out.insert(0, char_from_num((input % 36) as u8)?);
-        input /= 36;
-      }
+            while input != 0 {
+                out.insert(0, char_from_num((input % 36) as u8)?);
+                input /= 36;
+            }
 
-      Ok(out)
+            Ok(out)
+        }
     }
-  }
 }
 
 // -- end --
 
 #[inline(always)]
 fn num_from_char(character: char) -> napi::Result<u8> {
-  for (i, c) in CHAR_COLLECTION.chars().enumerate() {
-    if c == character {
-      return Ok(i as u8);
+    for (i, c) in CHAR_COLLECTION.chars().enumerate() {
+        if c == character {
+            return Ok(i as u8);
+        }
     }
-  }
 
-  Err(Error::new(
-    Status::InvalidArg,
-    "Invalid character in parsed base36 id",
-  ))
+    Err(Error::new(
+        Status::InvalidArg,
+        "Invalid character in parsed base36 id",
+    ))
 }
 
 #[inline(always)]
 fn char_from_num(number: u8) -> napi::Result<char> {
-  CHAR_COLLECTION
-    .chars()
-    .nth(number as usize)
-    .ok_or(Error::from_status(Status::Unknown))
+    CHAR_COLLECTION
+        .chars()
+        .nth(number as usize)
+        .ok_or(Error::from_status(Status::Unknown))
 }

From de3eb6589a21355f34187172ce7ba9498a03dfb4 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 08:55:20 -0400
Subject: [PATCH 06/66] add repository trait

---
 .../native-utils/crates/database/Cargo.toml   | 15 ++++++
 .../native-utils/crates/database/src/error.rs |  9 ++++
 .../native-utils/crates/database/src/lib.rs   | 18 +++++++
 .../native-utils/crates/model/Cargo.toml      |  4 ++
 .../native-utils/crates/model/src/error.rs    |  9 ++++
 .../native-utils/crates/model/src/lib.rs      |  3 +-
 .../model/src/repository/abuse_user_report.rs |  1 -
 .../crates/model/src/repository/antenna.rs    | 47 +++++++++++++++++++
 .../crates/model/src/repository/mod.rs        | 12 ++++-
 .../crates/model/src/schema/antenna.rs        | 33 ++++++++-----
 .../crates/model/src/schema/app.rs            |  5 +-
 .../crates/model/src/schema/mod.rs            | 30 ++++++++++++
 12 files changed, 169 insertions(+), 17 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/database/Cargo.toml
 create mode 100644 packages/backend/native-utils/crates/database/src/error.rs
 create mode 100644 packages/backend/native-utils/crates/database/src/lib.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/error.rs
 delete mode 100644 packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/repository/antenna.rs

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
new file mode 100644
index 000000000..69e0c73f7
--- /dev/null
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "database"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[features]
+default = ["napi"]
+napi = []
+
+[dependencies]
+once_cell = "1.17.1"
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
+thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/database/src/error.rs b/packages/backend/native-utils/crates/database/src/error.rs
new file mode 100644
index 000000000..b70964f2e
--- /dev/null
+++ b/packages/backend/native-utils/crates/database/src/error.rs
@@ -0,0 +1,9 @@
+use sea_orm::error::DbErr;
+
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+    #[error("The database connections have not been initialized yet")]
+    Uninitialized,
+    #[error("ORM error: {0}")]
+    OrmError(#[from] DbErr),
+}
diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
new file mode 100644
index 000000000..3c9db912b
--- /dev/null
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -0,0 +1,18 @@
+pub mod error;
+
+use once_cell::sync::OnceCell;
+use sea_orm::{Database, DatabaseConnection};
+
+use crate::error::Error;
+
+static DB_CONN: OnceCell<DatabaseConnection> = OnceCell::new();
+
+pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
+    let conn = Database::connect(connection_uri.into()).await?;
+    DB_CONN.get_or_init(move || conn);
+    Ok(())
+}
+
+pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
+    DB_CONN.get().ok_or(Error::Uninitialized)
+}
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 7b492a89d..832375ec7 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -6,12 +6,16 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+async-trait = "0.1.68"
 chrono = "0.4.24"
+database = { path = "../database" }
 jsonschema = "0.17.0"
 once_cell = "1.17.1"
+parse-display = "0.8.0"
 schemars = { version = "0.8.12", features = ["chrono"] }
 sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls", "mock"] }
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
+thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["sync"] }
 utoipa = "3.3.0"
diff --git a/packages/backend/native-utils/crates/model/src/error.rs b/packages/backend/native-utils/crates/model/src/error.rs
new file mode 100644
index 000000000..f75c0119a
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/error.rs
@@ -0,0 +1,9 @@
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+    #[error("Failed to parse string")]
+    ParseError(#[from] parse_display::ParseError),
+    #[error("Failed to get database connection")]
+    DatabaseConnectionError(#[from] database::error::Error),
+    #[error("Database operation error: {0}")]
+    DatabaseOperationError(#[from] sea_orm::DbErr),
+}
diff --git a/packages/backend/native-utils/crates/model/src/lib.rs b/packages/backend/native-utils/crates/model/src/lib.rs
index b14d29c34..61ba77a59 100644
--- a/packages/backend/native-utils/crates/model/src/lib.rs
+++ b/packages/backend/native-utils/crates/model/src/lib.rs
@@ -1,3 +1,4 @@
 pub mod entity;
-pub mod repository;
+pub mod error;
 pub mod schema;
+pub mod repository;
diff --git a/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs b/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/packages/backend/native-utils/crates/model/src/repository/abuse_user_report.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
new file mode 100644
index 000000000..32e17e244
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -0,0 +1,47 @@
+use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
+use async_trait::async_trait;
+
+use crate::entity::{antenna, antenna_note, user_group_joining};
+use crate::error::Error;
+use crate::schema::{antenna::Antenna, json_to_keyword, json_to_string_list};
+
+use super::Repository;
+
+#[async_trait]
+impl Repository<Antenna> for antenna::Model {
+    async fn pack(self) -> Result<Antenna, Error> {
+        let db = database::get_database()?;
+        let has_unread_note = antenna_note::Entity::find()
+            .filter(antenna_note::Column::AntennaId.eq(self.id.to_owned()))
+            .filter(antenna_note::Column::Read.eq(false))
+            .one(db)
+            .await?
+            .is_some();
+        let user_group_joining = match self.user_group_joining_id {
+            None => None,
+            Some(id) => user_group_joining::Entity::find_by_id(id).one(db).await?,
+        };
+        let user_group_id = match user_group_joining {
+            None => None,
+            Some(m) => Some(m.user_group_id),
+        };
+
+        Ok(Antenna {
+            id: self.id,
+            created_at: self.created_at.into(),
+            name: self.name,
+            keywords: json_to_keyword(&self.keywords),
+            exclude_keywords: json_to_keyword(&self.exclude_keywords),
+            src: self.src.try_into()?,
+            user_list_id: self.user_list_id,
+            user_group_id,
+            users: self.users,
+            instances: json_to_string_list(&self.instances),
+            case_sensitive: self.case_sensitive,
+            notify: self.notify,
+            with_replies: self.with_replies,
+            with_file: self.with_file,
+            has_unread_note,
+        })
+    }
+}
diff --git a/packages/backend/native-utils/crates/model/src/repository/mod.rs b/packages/backend/native-utils/crates/model/src/repository/mod.rs
index f7a590081..b720d1d48 100644
--- a/packages/backend/native-utils/crates/model/src/repository/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/mod.rs
@@ -1 +1,11 @@
-pub mod abuse_user_report;
+pub mod antenna;
+
+use async_trait::async_trait;
+use schemars::JsonSchema;
+
+use crate::error::Error;
+
+#[async_trait]
+trait Repository<T: JsonSchema> {
+    async fn pack(self) -> Result<T, Error>;
+}
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index 3bffe4f5f..a8065d09e 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -1,25 +1,26 @@
 use jsonschema::JSONSchema;
 use once_cell::sync::Lazy;
+use parse_display::FromStr;
 use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
 use utoipa::ToSchema;
 
-use super::Schema;
+use super::{Keyword, Schema, StringList};
+use crate::entity::sea_orm_active_enums::AntennaSrcEnum;
 
-#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[derive(Debug, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
 pub struct Antenna {
     pub id: String,
     pub created_at: chrono::DateTime<chrono::Utc>,
     pub name: String,
-    pub keywords: Vec<Vec<String>>,
-    pub exclude_keywords: Vec<Vec<String>>,
+    pub keywords: Keyword,
+    pub exclude_keywords: Keyword,
     #[schema(inline)]
-    pub src: AntennaSrcEnum,
+    pub src: AntennaSrc,
     pub user_list_id: Option<String>,
     pub user_group_id: Option<String>,
-    pub users: Vec<String>,
-    pub instances: Vec<String>,
+    pub users: StringList,
+    pub instances: StringList,
     #[serde(default)]
     pub case_sensitive: bool,
     #[serde(default)]
@@ -32,9 +33,10 @@ pub struct Antenna {
     pub has_unread_note: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[derive(Debug, FromStr, JsonSchema, ToSchema)]
 #[serde(rename_all = "lowercase")]
-pub enum AntennaSrcEnum {
+#[display(style = "lowercase")]
+pub enum AntennaSrc {
     Home,
     All,
     Users,
@@ -43,9 +45,18 @@ pub enum AntennaSrcEnum {
     Instances,
 }
 
-impl Schema<Self> for Antenna {}
+impl TryFrom<AntennaSrcEnum> for AntennaSrc {
+    type Error = parse_display::ParseError;
 
+    fn try_from(value: AntennaSrcEnum) -> Result<Self, Self::Error> {
+        value.to_string().parse()
+    }
+}
+
+// ---- TODO: could be macro
+impl Schema<Self> for Antenna {}
 pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
+// ----
 
 #[cfg(test)]
 mod tests {
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/crates/model/src/schema/app.rs
index 861bdc48a..adc404eb9 100644
--- a/packages/backend/native-utils/crates/model/src/schema/app.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/app.rs
@@ -1,12 +1,11 @@
 use jsonschema::JSONSchema;
 use once_cell::sync::Lazy;
 use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
 use utoipa::ToSchema;
 
 use super::Schema;
 
-#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[derive(Debug, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
 pub struct App {
     pub id: String,
@@ -20,7 +19,7 @@ pub struct App {
 }
 
 /// This represents `permissions` in `packages/calckey-js/src/consts.ts`.
-#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
+#[derive(Debug, JsonSchema, ToSchema)]
 pub enum Permission {
     #[serde(rename = "read:account")]
     ReadAccount,
diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema/mod.rs
index cc495aac1..2a0853814 100644
--- a/packages/backend/native-utils/crates/model/src/schema/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/mod.rs
@@ -3,6 +3,10 @@ pub mod app;
 
 use jsonschema::JSONSchema;
 use schemars::{schema_for, JsonSchema};
+use serde_json::Value;
+
+type Keyword = Vec<Vec<String>>;
+type StringList = Vec<String>;
 
 /// Structs of schema defitions implement this trait in order to
 /// provide the JSON Schema validator [`jsonschema::JSONSchema`].
@@ -19,3 +23,29 @@ trait Schema<T: JsonSchema> {
             .expect("Unable to compile schema")
     }
 }
+
+pub(crate) fn json_to_keyword(value: &Value) -> Keyword {
+    match value.as_array() {
+        None => vec![vec![]],
+        Some(or_vec) => or_vec
+            .iter()
+            .map(|and_val| match and_val.as_array() {
+                None => vec![],
+                Some(and_vec) => and_vec
+                    .iter()
+                    .map(|word| word.as_str().unwrap_or_default().to_string())
+                    .collect(),
+            })
+            .collect(),
+    }
+}
+
+pub(crate) fn json_to_string_list(value: &Value) -> StringList {
+    match value.as_array() {
+        None => vec![],
+        Some(v) => v
+            .iter()
+            .map(|s| s.as_str().unwrap_or_default().to_string())
+            .collect(),
+    }
+}

From 36436991e2de36a27633fb97cce2bdfd301f043e Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 08:55:41 -0400
Subject: [PATCH 07/66] remove unused serde

---
 .../model/src/entity/abuse_user_report.rs     |  3 +--
 .../crates/model/src/entity/access_token.rs   |  3 +--
 .../crates/model/src/entity/ad.rs             |  3 +--
 .../crates/model/src/entity/announcement.rs   |  3 +--
 .../model/src/entity/announcement_read.rs     |  3 +--
 .../crates/model/src/entity/antenna.rs        |  3 +--
 .../crates/model/src/entity/antenna_note.rs   |  3 +--
 .../crates/model/src/entity/app.rs            |  3 +--
 .../model/src/entity/attestation_challenge.rs |  3 +--
 .../crates/model/src/entity/auth_session.rs   |  3 +--
 .../crates/model/src/entity/blocking.rs       |  3 +--
 .../crates/model/src/entity/channel.rs        |  3 +--
 .../model/src/entity/channel_following.rs     |  3 +--
 .../model/src/entity/channel_note_pining.rs   |  3 +--
 .../crates/model/src/entity/clip.rs           |  3 +--
 .../crates/model/src/entity/clip_note.rs      |  3 +--
 .../crates/model/src/entity/drive_file.rs     |  3 +--
 .../crates/model/src/entity/drive_folder.rs   |  3 +--
 .../crates/model/src/entity/emoji.rs          |  3 +--
 .../crates/model/src/entity/follow_request.rs |  3 +--
 .../crates/model/src/entity/following.rs      |  3 +--
 .../crates/model/src/entity/gallery_like.rs   |  3 +--
 .../crates/model/src/entity/gallery_post.rs   |  3 +--
 .../crates/model/src/entity/hashtag.rs        |  3 +--
 .../crates/model/src/entity/instance.rs       |  3 +--
 .../model/src/entity/messaging_message.rs     |  3 +--
 .../crates/model/src/entity/meta.rs           |  3 +--
 .../crates/model/src/entity/migrations.rs     |  3 +--
 .../crates/model/src/entity/moderation_log.rs |  3 +--
 .../crates/model/src/entity/muted_note.rs     |  3 +--
 .../crates/model/src/entity/muting.rs         |  3 +--
 .../crates/model/src/entity/note.rs           |  3 +--
 .../crates/model/src/entity/note_edit.rs      |  3 +--
 .../crates/model/src/entity/note_favorite.rs  |  3 +--
 .../crates/model/src/entity/note_reaction.rs  |  3 +--
 .../model/src/entity/note_thread_muting.rs    |  3 +--
 .../crates/model/src/entity/note_unread.rs    |  3 +--
 .../crates/model/src/entity/note_watching.rs  |  3 +--
 .../crates/model/src/entity/notification.rs   |  3 +--
 .../crates/model/src/entity/page.rs           |  3 +--
 .../crates/model/src/entity/page_like.rs      |  3 +--
 .../src/entity/password_reset_request.rs      |  3 +--
 .../crates/model/src/entity/poll.rs           |  3 +--
 .../crates/model/src/entity/poll_vote.rs      |  3 +--
 .../crates/model/src/entity/promo_note.rs     |  3 +--
 .../crates/model/src/entity/promo_read.rs     |  3 +--
 .../model/src/entity/registration_ticket.rs   |  3 +--
 .../crates/model/src/entity/registry_item.rs  |  3 +--
 .../crates/model/src/entity/relay.rs          |  3 +--
 .../crates/model/src/entity/renote_muting.rs  |  3 +--
 .../crates/model/src/entity/reversi_game.rs   |  3 +--
 .../model/src/entity/reversi_matching.rs      |  3 +--
 .../model/src/entity/sea_orm_active_enums.rs  | 21 +++++++++----------
 .../crates/model/src/entity/signin.rs         |  3 +--
 .../model/src/entity/sw_subscription.rs       |  3 +--
 .../crates/model/src/entity/used_username.rs  |  3 +--
 .../crates/model/src/entity/user.rs           |  3 +--
 .../crates/model/src/entity/user_group.rs     |  3 +--
 .../model/src/entity/user_group_invitation.rs |  3 +--
 .../model/src/entity/user_group_invite.rs     |  3 +--
 .../model/src/entity/user_group_joining.rs    |  3 +--
 .../crates/model/src/entity/user_ip.rs        |  3 +--
 .../crates/model/src/entity/user_keypair.rs   |  3 +--
 .../crates/model/src/entity/user_list.rs      |  3 +--
 .../model/src/entity/user_list_joining.rs     |  3 +--
 .../model/src/entity/user_note_pining.rs      |  3 +--
 .../crates/model/src/entity/user_pending.rs   |  3 +--
 .../crates/model/src/entity/user_profile.rs   |  3 +--
 .../crates/model/src/entity/user_publickey.rs |  3 +--
 .../model/src/entity/user_security_key.rs     |  3 +--
 .../crates/model/src/entity/webhook.rs        |  3 +--
 71 files changed, 80 insertions(+), 151 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
index 163a686ab..270837973 100644
--- a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "abuse_user_report")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/access_token.rs b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
index ba3a43d64..fa9894414 100644
--- a/packages/backend/native-utils/crates/model/src/entity/access_token.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "access_token")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/ad.rs b/packages/backend/native-utils/crates/model/src/entity/ad.rs
index 4e31c7b0d..708ed69ce 100644
--- a/packages/backend/native-utils/crates/model/src/entity/ad.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/ad.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "ad")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement.rs b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
index 0f02a1ca9..3e9b91687 100644
--- a/packages/backend/native-utils/crates/model/src/entity/announcement.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "announcement")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
index ad7dcc6f2..7fc51d475 100644
--- a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "announcement_read")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
index f9c040b59..513d15e83 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::AntennaSrcEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "antenna")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
index ecf7b88f7..d4c850bfc 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "antenna_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/app.rs b/packages/backend/native-utils/crates/model/src/entity/app.rs
index bd6ae5acf..5f3d5d131 100644
--- a/packages/backend/native-utils/crates/model/src/entity/app.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/app.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "app")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
index 25da1ae57..135a4f1fb 100644
--- a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "attestation_challenge")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
index c3b2fab54..83aecbaa6 100644
--- a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "auth_session")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/blocking.rs b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
index c9092e50d..4667e60c6 100644
--- a/packages/backend/native-utils/crates/model/src/entity/blocking.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "blocking")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel.rs b/packages/backend/native-utils/crates/model/src/entity/channel.rs
index b39b57f56..9132d9d4e 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "channel")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
index a415b6c32..bd1b16dce 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "channel_following")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
index 16f80b91d..2c9089ac4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "channel_note_pining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip.rs b/packages/backend/native-utils/crates/model/src/entity/clip.rs
index 6cf1ac1c8..209bd047e 100644
--- a/packages/backend/native-utils/crates/model/src/entity/clip.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/clip.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "clip")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
index ba7114c3b..953c5511c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "clip_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
index 5b3d17b00..abc191ba3 100644
--- a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "drive_file")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
index 9756f7053..f0b716283 100644
--- a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "drive_folder")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/emoji.rs b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
index 9dff7c719..a89f0b22d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/emoji.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "emoji")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
index 32e31a09d..af763baa6 100644
--- a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "follow_request")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/following.rs b/packages/backend/native-utils/crates/model/src/entity/following.rs
index 6f339e05d..087ca270b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/following.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/following.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "following")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
index 0fdbf07ef..186c92703 100644
--- a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "gallery_like")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
index a23ebbd8f..bb68eda62 100644
--- a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "gallery_post")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
index a83ebbf29..9a6e44623 100644
--- a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "hashtag")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/instance.rs b/packages/backend/native-utils/crates/model/src/entity/instance.rs
index 405648efc..3f3af2a5d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/instance.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/instance.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "instance")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
index cfb896371..0fbfc1ffb 100644
--- a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "messaging_message")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/meta.rs b/packages/backend/native-utils/crates/model/src/entity/meta.rs
index 768c725aa..33ab911ba 100644
--- a/packages/backend/native-utils/crates/model/src/entity/meta.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/meta.rs
@@ -3,9 +3,8 @@
 use super::sea_orm_active_enums::MetaSensitivemediadetectionEnum;
 use super::sea_orm_active_enums::MetaSensitivemediadetectionsensitivityEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "meta")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/migrations.rs b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
index c53c3fc89..c03df1180 100644
--- a/packages/backend/native-utils/crates/model/src/entity/migrations.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "migrations")]
 pub struct Model {
     #[sea_orm(primary_key)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
index eb49d4f15..330685392 100644
--- a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "moderation_log")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
index 17328a829..1740e9078 100644
--- a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::MutedNoteReasonEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "muted_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/muting.rs b/packages/backend/native-utils/crates/model/src/entity/muting.rs
index 60020b60b..83885034c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/muting.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note.rs b/packages/backend/native-utils/crates/model/src/entity/note.rs
index cc3ec289f..2e733edae 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::NoteVisibilityEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
index 7b87613dd..5e98b3da4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_edit")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
index b5c96a9a6..42f3c400f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_favorite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
index 52526aa9f..c740d994f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_reaction")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
index 572a03750..f1dbfb598 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_thread_muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
index 80fae4335..746815611 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_unread")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
index 1ff7af52e..4a87a4495 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_watching")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/notification.rs b/packages/backend/native-utils/crates/model/src/entity/notification.rs
index c2d9115f3..4500e59d9 100644
--- a/packages/backend/native-utils/crates/model/src/entity/notification.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/notification.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::NotificationTypeEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "notification")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/page.rs b/packages/backend/native-utils/crates/model/src/entity/page.rs
index 32f082daf..efb794944 100644
--- a/packages/backend/native-utils/crates/model/src/entity/page.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/page.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::PageVisibilityEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "page")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/page_like.rs b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
index e9de78eb6..3d3d2f3ac 100644
--- a/packages/backend/native-utils/crates/model/src/entity/page_like.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "page_like")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
index 472b93db9..3b24d70d9 100644
--- a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "password_reset_request")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll.rs b/packages/backend/native-utils/crates/model/src/entity/poll.rs
index 0facabd9a..a4d9e2df1 100644
--- a/packages/backend/native-utils/crates/model/src/entity/poll.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/poll.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::PollNotevisibilityEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "poll")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
index 29b6928ef..1b8b3ba1c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "poll_vote")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
index 6e8de9866..aa5eb2f3d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "promo_note")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
index 807ad4a27..d7dcacfb8 100644
--- a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "promo_read")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
index 8d7e4ba8d..f71c87327 100644
--- a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "registration_ticket")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
index 8aa188210..6de0c740f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "registry_item")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/relay.rs b/packages/backend/native-utils/crates/model/src/entity/relay.rs
index 731d12e8c..736b48b78 100644
--- a/packages/backend/native-utils/crates/model/src/entity/relay.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/relay.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::RelayStatusEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "relay")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
index b63c989a6..b5e7d38f2 100644
--- a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "renote_muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
index 56f83e543..1e5359280 100644
--- a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "reversi_game")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
index 9261b6482..aafdf13f6 100644
--- a/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "reversi_matching")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
index 747cd953a..14ef7002a 100644
--- a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
 pub enum AntennaSrcEnum {
     #[sea_orm(string_value = "all")]
@@ -19,7 +18,7 @@ pub enum AntennaSrcEnum {
     #[sea_orm(string_value = "users")]
     Users,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -35,7 +34,7 @@ pub enum MetaSensitivemediadetectionEnum {
     #[sea_orm(string_value = "remote")]
     Remote,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -53,7 +52,7 @@ pub enum MetaSensitivemediadetectionsensitivityEnum {
     #[sea_orm(string_value = "veryLow")]
     VeryLow,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -69,7 +68,7 @@ pub enum MutedNoteReasonEnum {
     #[sea_orm(string_value = "word")]
     Word,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -87,7 +86,7 @@ pub enum NoteVisibilityEnum {
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -119,7 +118,7 @@ pub enum NotificationTypeEnum {
     #[sea_orm(string_value = "reply")]
     Reply,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -133,7 +132,7 @@ pub enum PageVisibilityEnum {
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -149,7 +148,7 @@ pub enum PollNotevisibilityEnum {
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
 pub enum RelayStatusEnum {
     #[sea_orm(string_value = "accepted")]
@@ -159,7 +158,7 @@ pub enum RelayStatusEnum {
     #[sea_orm(string_value = "requesting")]
     Requesting,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
diff --git a/packages/backend/native-utils/crates/model/src/entity/signin.rs b/packages/backend/native-utils/crates/model/src/entity/signin.rs
index d6f730892..6220973c1 100644
--- a/packages/backend/native-utils/crates/model/src/entity/signin.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/signin.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "signin")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
index 0d2ac26d9..eaa332d8c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "sw_subscription")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/used_username.rs b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
index cf325cfa5..e9e8eb097 100644
--- a/packages/backend/native-utils/crates/model/src/entity/used_username.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "used_username")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user.rs b/packages/backend/native-utils/crates/model/src/entity/user.rs
index cd1153994..79b9fa692 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group.rs b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
index 278e9997d..680f78b9e 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_group")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
index 62538db37..5a6f6f4a1 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_group_invitation")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
index 7ddfa021f..786dd1f31 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_group_invite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
index 65cb000df..2baa0b9a7 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_group_joining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
index d108b29fe..872cfd860 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_ip")]
 pub struct Model {
     #[sea_orm(primary_key)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
index a9a07b1d9..df23b506b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_keypair")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list.rs b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
index 6a2f93241..ff05f2c44 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_list.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_list")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
index fddcfdb54..27899a8c5 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_list_joining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
index 24e976e22..bcb3ec8b0 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_note_pining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
index e9134d9ee..1fb3b4fdc 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_pending")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
index d22dcbebf..3a12469d8 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
@@ -2,9 +2,8 @@
 
 use super::sea_orm_active_enums::UserProfileFfvisibilityEnum;
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_profile")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
index 5cf6857e2..c3c6dbf1f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_publickey")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
index 531b59ab8..cbb31e1b0 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_security_key")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/webhook.rs b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
index 39508f7fa..952dcbadb 100644
--- a/packages/backend/native-utils/crates/model/src/entity/webhook.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
@@ -1,9 +1,8 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
 use sea_orm::entity::prelude::*;
-use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "webhook")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]

From c4e41e3d327254f8e97fd8ae673b6f35d3279d9c Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 08:56:57 -0400
Subject: [PATCH 08/66] format

---
 packages/backend/native-utils/crates/model/src/lib.rs           | 2 +-
 .../backend/native-utils/crates/model/src/repository/antenna.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/lib.rs b/packages/backend/native-utils/crates/model/src/lib.rs
index 61ba77a59..6e86ec052 100644
--- a/packages/backend/native-utils/crates/model/src/lib.rs
+++ b/packages/backend/native-utils/crates/model/src/lib.rs
@@ -1,4 +1,4 @@
 pub mod entity;
 pub mod error;
-pub mod schema;
 pub mod repository;
+pub mod schema;
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
index 32e17e244..dc6cb5a01 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -1,5 +1,5 @@
-use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 use async_trait::async_trait;
+use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
 use crate::entity::{antenna, antenna_note, user_group_joining};
 use crate::error::Error;

From f50c3c906b67df2bfc01567cca9e323a45b6b1a5 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 09:23:26 -0400
Subject: [PATCH 09/66] remove unused feature

---
 packages/backend/native-utils/crates/database/Cargo.toml | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
index 69e0c73f7..b88f9b324 100644
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -5,10 +5,6 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
-[features]
-default = ["napi"]
-napi = []
-
 [dependencies]
 once_cell = "1.17.1"
 sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }

From ea20db46942f3eee35e21b54327e32858e582a3c Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 09:42:59 -0400
Subject: [PATCH 10/66] add mock database

---
 .../native-utils/crates/database/Cargo.toml   |  2 +-
 .../native-utils/crates/database/src/lib.rs   | 22 ++++++++++++++++---
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
index b88f9b324..8498f52f2 100644
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
 
 [dependencies]
 once_cell = "1.17.1"
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls", "mock"] }
 thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 3c9db912b..e92d6bcfc 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -1,11 +1,13 @@
 pub mod error;
 
-use once_cell::sync::OnceCell;
-use sea_orm::{Database, DatabaseConnection};
+use once_cell::sync::{Lazy, OnceCell};
+use sea_orm::{Database, DatabaseBackend, DatabaseConnection, MockDatabase};
 
 use crate::error::Error;
 
 static DB_CONN: OnceCell<DatabaseConnection> = OnceCell::new();
+static DB_MOCK: Lazy<DatabaseConnection> =
+    Lazy::new(|| MockDatabase::new(DatabaseBackend::Postgres).into_connection());
 
 pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
     let conn = Database::connect(connection_uri.into()).await?;
@@ -14,5 +16,19 @@ pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Erro
 }
 
 pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
-    DB_CONN.get().ok_or(Error::Uninitialized)
+    if cfg!(test) {
+        Ok(&DB_MOCK)
+    } else {
+        DB_CONN.get().ok_or(Error::Uninitialized)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::get_database;
+
+    #[test]
+    fn can_get_mock_without_initialization() {
+        assert!(get_database().is_ok());
+    }
 }

From 0ad9f00cacaf6290ab0d3983c8aa9067fb19fa95 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 12:11:59 -0400
Subject: [PATCH 11/66] add utility crate

---
 .../native-utils/crates/database/src/lib.rs   |  4 +--
 .../native-utils/crates/util/Cargo.toml       | 11 +++++++
 .../native-utils/crates/util/src/id.rs        | 31 +++++++++++++++++++
 .../native-utils/crates/util/src/lib.rs       |  1 +
 4 files changed, 45 insertions(+), 2 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/util/Cargo.toml
 create mode 100644 packages/backend/native-utils/crates/util/src/id.rs
 create mode 100644 packages/backend/native-utils/crates/util/src/lib.rs

diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index e92d6bcfc..5506c702a 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -28,7 +28,7 @@ mod tests {
     use super::get_database;
 
     #[test]
-    fn can_get_mock_without_initialization() {
-        assert!(get_database().is_ok());
+    fn can_get_mock() {
+        get_database().unwrap().as_mock_connection();
     }
 }
diff --git a/packages/backend/native-utils/crates/util/Cargo.toml b/packages/backend/native-utils/crates/util/Cargo.toml
new file mode 100644
index 000000000..8010d27f4
--- /dev/null
+++ b/packages/backend/native-utils/crates/util/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "util"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+chrono = "0.4.24"
+radix_fmt = "1.0.0"
+rand = "0.8.5"
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/crates/util/src/id.rs
new file mode 100644
index 000000000..3dc713668
--- /dev/null
+++ b/packages/backend/native-utils/crates/util/src/id.rs
@@ -0,0 +1,31 @@
+use chrono::{DateTime, Utc};
+use radix_fmt::radix_36;
+
+const TIME_2000: i64 = 946_684_800_000;
+
+/// FIXME: Should we continue aid, or use other (more secure and scalable) guids
+/// such as [Cuid2](https://github.com/paralleldrive/cuid2)?
+pub fn create_aid(date: DateTime<Utc>) -> String {
+    let time = date.timestamp_millis() - TIME_2000;
+    let time = if time < 0 { 0 } else { time };
+    let num: i16 = rand::random();
+    let mut noise = format!("{:0>2}", radix_36(num).to_string());
+    let noise = noise.split_off(noise.len() - 2);
+    format!("{:0>8}{}", radix_36(time).to_string(), noise,)
+}
+
+#[cfg(test)]
+mod tests {
+    use chrono::{TimeZone, Utc};
+
+    use super::create_aid;
+
+    #[test]
+    fn generate_aid() {
+        let date = Utc.with_ymd_and_hms(2023, 5, 25, 11, 49, 37).unwrap();
+        let aid = create_aid(date);
+        assert_eq!(aid.len(), 10);
+        assert!(aid.starts_with("9f6mynag"));
+        assert_ne!(create_aid(Utc::now()), create_aid(Utc::now()));
+    }
+}
diff --git a/packages/backend/native-utils/crates/util/src/lib.rs b/packages/backend/native-utils/crates/util/src/lib.rs
new file mode 100644
index 000000000..fd6bb6c43
--- /dev/null
+++ b/packages/backend/native-utils/crates/util/src/lib.rs
@@ -0,0 +1 @@
+pub mod id;

From ab58f69c311f0f49d19cbc0a875c3fbb3eadd0ff Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 21:40:04 -0400
Subject: [PATCH 12/66] return mock db when mock feature is enabled

---
 .../native-utils/crates/database/Cargo.toml   |  9 ++++-
 .../native-utils/crates/database/src/error.rs |  2 +-
 .../native-utils/crates/database/src/lib.rs   | 33 ++++++++++++-------
 .../native-utils/crates/model/Cargo.toml      |  7 +++-
 .../native-utils/crates/model/src/error.rs    |  2 +-
 5 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
index 8498f52f2..e4c60623e 100644
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -5,7 +5,14 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+[features]
+mock = []
+
 [dependencies]
 once_cell = "1.17.1"
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls", "mock"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
 thiserror = "1.0.40"
+tokio = { version = "1.28.1", features = ["macros"] }
+
+[dev-dependencies]
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "sqlx-sqlite", "runtime-tokio-rustls", "mock"] }
diff --git a/packages/backend/native-utils/crates/database/src/error.rs b/packages/backend/native-utils/crates/database/src/error.rs
index b70964f2e..babdd6831 100644
--- a/packages/backend/native-utils/crates/database/src/error.rs
+++ b/packages/backend/native-utils/crates/database/src/error.rs
@@ -1,6 +1,6 @@
 use sea_orm::error::DbErr;
 
-#[derive(thiserror::Error, Debug)]
+#[derive(thiserror::Error, Debug, PartialEq, Eq)]
 pub enum Error {
     #[error("The database connections have not been initialized yet")]
     Uninitialized,
diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 5506c702a..756be123e 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -1,13 +1,15 @@
 pub mod error;
 
-use once_cell::sync::{Lazy, OnceCell};
-use sea_orm::{Database, DatabaseBackend, DatabaseConnection, MockDatabase};
+use sea_orm::{Database, DatabaseConnection};
 
 use crate::error::Error;
 
-static DB_CONN: OnceCell<DatabaseConnection> = OnceCell::new();
-static DB_MOCK: Lazy<DatabaseConnection> =
-    Lazy::new(|| MockDatabase::new(DatabaseBackend::Postgres).into_connection());
+static DB_CONN: once_cell::sync::OnceCell<DatabaseConnection> = once_cell::sync::OnceCell::new();
+
+#[cfg(feature = "mock")]
+static DB_MOCK: once_cell::sync::Lazy<DatabaseConnection> = once_cell::sync::Lazy::new(|| {
+    sea_orm::MockDatabase::new(sea_orm::DatabaseBackend::Postgres).into_connection()
+});
 
 pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
     let conn = Database::connect(connection_uri.into()).await?;
@@ -16,19 +18,26 @@ pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Erro
 }
 
 pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
-    if cfg!(test) {
-        Ok(&DB_MOCK)
-    } else {
-        DB_CONN.get().ok_or(Error::Uninitialized)
-    }
+    #[cfg(feature = "mock")]
+    return Ok(&DB_MOCK);
+    #[cfg(not(feature = "mock"))]
+    DB_CONN.get().ok_or(Error::Uninitialized)
 }
 
 #[cfg(test)]
 mod tests {
     use super::get_database;
+    use crate::{error::Error, init_database};
 
     #[test]
-    fn can_get_mock() {
-        get_database().unwrap().as_mock_connection();
+    fn error_uninitialized() {
+        assert_eq!(get_database().unwrap_err(), Error::Uninitialized);
+    }
+
+    #[tokio::test]
+    async fn connect_in_memory_sqlite() -> Result<(), Error> {
+        init_database("sqlite::memory:").await?;
+        get_database()?;
+        Ok(())
     }
 }
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 832375ec7..8714afdb4 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -13,9 +13,14 @@ jsonschema = "0.17.0"
 once_cell = "1.17.1"
 parse-display = "0.8.0"
 schemars = { version = "0.8.12", features = ["chrono"] }
-sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls", "mock"] }
+sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls"] }
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
 thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["sync"] }
+util = { path = "../util" }
 utoipa = "3.3.0"
+
+[dev-dependencies]
+database = { path = "../database", features = ["mock"] }
+sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls", "mock"] }
diff --git a/packages/backend/native-utils/crates/model/src/error.rs b/packages/backend/native-utils/crates/model/src/error.rs
index f75c0119a..379ecb784 100644
--- a/packages/backend/native-utils/crates/model/src/error.rs
+++ b/packages/backend/native-utils/crates/model/src/error.rs
@@ -1,4 +1,4 @@
-#[derive(thiserror::Error, Debug)]
+#[derive(thiserror::Error, Debug, PartialEq, Eq)]
 pub enum Error {
     #[error("Failed to parse string")]
     ParseError(#[from] parse_display::ParseError),

From 3b6692cdf09a73056a1637b5b1020a9d99d215f6 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 25 May 2023 21:49:50 -0400
Subject: [PATCH 13/66] fix features

---
 packages/backend/native-utils/crates/database/Cargo.toml | 4 ++--
 packages/backend/native-utils/crates/model/Cargo.toml    | 1 -
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
index e4c60623e..4ff4da2b7 100644
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [features]
-mock = []
+mock = ["sea-orm/mock"]
 
 [dependencies]
 once_cell = "1.17.1"
@@ -15,4 +15,4 @@ thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["macros"] }
 
 [dev-dependencies]
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "sqlx-sqlite", "runtime-tokio-rustls", "mock"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-sqlite"] }
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 8714afdb4..63f53c630 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -23,4 +23,3 @@ utoipa = "3.3.0"
 
 [dev-dependencies]
 database = { path = "../database", features = ["mock"] }
-sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls", "mock"] }

From 1601b8985c618c091ef9dcd4d96ab797547f8ccc Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 26 May 2023 04:00:09 -0400
Subject: [PATCH 14/66] change aid to cuid2

---
 .../native-utils/crates/util/Cargo.toml       |  6 +--
 .../native-utils/crates/util/src/id.rs        | 48 +++++++++++--------
 2 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/packages/backend/native-utils/crates/util/Cargo.toml b/packages/backend/native-utils/crates/util/Cargo.toml
index 8010d27f4..3c28e248f 100644
--- a/packages/backend/native-utils/crates/util/Cargo.toml
+++ b/packages/backend/native-utils/crates/util/Cargo.toml
@@ -6,6 +6,6 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-chrono = "0.4.24"
-radix_fmt = "1.0.0"
-rand = "0.8.5"
+cuid2 = "0.1.0"
+once_cell = "1.17.1"
+thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/crates/util/src/id.rs
index 3dc713668..f82b64652 100644
--- a/packages/backend/native-utils/crates/util/src/id.rs
+++ b/packages/backend/native-utils/crates/util/src/id.rs
@@ -1,31 +1,39 @@
-use chrono::{DateTime, Utc};
-use radix_fmt::radix_36;
+//! ID generation utility based on [cuid2]
 
-const TIME_2000: i64 = 946_684_800_000;
+use cuid2::CuidConstructor;
+use once_cell::sync::OnceCell;
 
-/// FIXME: Should we continue aid, or use other (more secure and scalable) guids
-/// such as [Cuid2](https://github.com/paralleldrive/cuid2)?
-pub fn create_aid(date: DateTime<Utc>) -> String {
-    let time = date.timestamp_millis() - TIME_2000;
-    let time = if time < 0 { 0 } else { time };
-    let num: i16 = rand::random();
-    let mut noise = format!("{:0>2}", radix_36(num).to_string());
-    let noise = noise.split_off(noise.len() - 2);
-    format!("{:0>8}{}", radix_36(time).to_string(), noise,)
+#[derive(thiserror::Error, Debug, PartialEq, Eq)]
+#[error("ID generator has not been initialized yet")]
+pub struct ErrorUninitialized;
+
+static GENERATOR: OnceCell<CuidConstructor> = OnceCell::new();
+
+pub fn init_id(length: u16) {
+    GENERATOR.get_or_init(move || CuidConstructor::new().with_length(length));
+}
+
+pub fn create_id() -> Result<String, ErrorUninitialized> {
+    match GENERATOR.get() {
+        None => Err(ErrorUninitialized),
+        Some(gen) => Ok(gen.create_id()),
+    }
 }
 
 #[cfg(test)]
 mod tests {
-    use chrono::{TimeZone, Utc};
+    use std::thread;
 
-    use super::create_aid;
+    use crate::id;
 
     #[test]
-    fn generate_aid() {
-        let date = Utc.with_ymd_and_hms(2023, 5, 25, 11, 49, 37).unwrap();
-        let aid = create_aid(date);
-        assert_eq!(aid.len(), 10);
-        assert!(aid.starts_with("9f6mynag"));
-        assert_ne!(create_aid(Utc::now()), create_aid(Utc::now()));
+    fn can_generate() {
+        assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
+        id::init_id(12);
+        assert_eq!(id::create_id().unwrap().len(), 12);
+        assert_ne!(id::create_id().unwrap(), id::create_id().unwrap());
+        let id1 = thread::spawn(|| id::create_id().unwrap());
+        let id2 = thread::spawn(|| id::create_id().unwrap());
+        assert_ne!(id1.join().unwrap(), id2.join().unwrap())
     }
 }

From a42d6e2e2df7d4100ec410d3247bd6e78573c22b Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 02:37:34 -0400
Subject: [PATCH 15/66] add random string generator

---
 .../native-utils/crates/util/Cargo.toml       |  1 +
 .../native-utils/crates/util/src/lib.rs       |  1 +
 .../native-utils/crates/util/src/random.rs    | 25 +++++++++++++++++++
 3 files changed, 27 insertions(+)
 create mode 100644 packages/backend/native-utils/crates/util/src/random.rs

diff --git a/packages/backend/native-utils/crates/util/Cargo.toml b/packages/backend/native-utils/crates/util/Cargo.toml
index 3c28e248f..ad5486b4b 100644
--- a/packages/backend/native-utils/crates/util/Cargo.toml
+++ b/packages/backend/native-utils/crates/util/Cargo.toml
@@ -8,4 +8,5 @@ edition = "2021"
 [dependencies]
 cuid2 = "0.1.0"
 once_cell = "1.17.1"
+rand = "0.8.5"
 thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/util/src/lib.rs b/packages/backend/native-utils/crates/util/src/lib.rs
index fd6bb6c43..1be5a7fd1 100644
--- a/packages/backend/native-utils/crates/util/src/lib.rs
+++ b/packages/backend/native-utils/crates/util/src/lib.rs
@@ -1 +1,2 @@
 pub mod id;
+pub mod random;
diff --git a/packages/backend/native-utils/crates/util/src/random.rs b/packages/backend/native-utils/crates/util/src/random.rs
new file mode 100644
index 000000000..fb2f02147
--- /dev/null
+++ b/packages/backend/native-utils/crates/util/src/random.rs
@@ -0,0 +1,25 @@
+use rand::{distributions::Alphanumeric, thread_rng, Rng};
+
+pub fn gen_string(length: u16) -> String {
+    thread_rng()
+        .sample_iter(Alphanumeric)
+        .take(length.into())
+        .map(char::from)
+        .collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use std::thread;
+
+    use super::gen_string;
+
+    #[test]
+    fn can_generate_string() {
+        assert_eq!(gen_string(16).len(), 16);
+        assert_ne!(gen_string(16), gen_string(16));
+        let s1 = thread::spawn(|| gen_string(16));
+        let s2 = thread::spawn(|| gen_string(16));
+        assert_ne!(s1.join().unwrap(), s2.join().unwrap());
+    }
+}

From 9c832d00f9e42e6e3a8581d99b0fc2fd00042951 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 03:35:09 -0400
Subject: [PATCH 16/66] remove mock database

---
 packages/backend/native-utils/crates/database/Cargo.toml | 6 ------
 packages/backend/native-utils/crates/database/src/lib.rs | 8 --------
 packages/backend/native-utils/crates/model/Cargo.toml    | 3 ---
 3 files changed, 17 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
index 4ff4da2b7..440a76cf5 100644
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ b/packages/backend/native-utils/crates/database/Cargo.toml
@@ -5,14 +5,8 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
-[features]
-mock = ["sea-orm/mock"]
-
 [dependencies]
 once_cell = "1.17.1"
 sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
 thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["macros"] }
-
-[dev-dependencies]
-sea-orm = { version = "0.11.3", features = ["sqlx-sqlite"] }
diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 756be123e..d0e7b2577 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -6,11 +6,6 @@ use crate::error::Error;
 
 static DB_CONN: once_cell::sync::OnceCell<DatabaseConnection> = once_cell::sync::OnceCell::new();
 
-#[cfg(feature = "mock")]
-static DB_MOCK: once_cell::sync::Lazy<DatabaseConnection> = once_cell::sync::Lazy::new(|| {
-    sea_orm::MockDatabase::new(sea_orm::DatabaseBackend::Postgres).into_connection()
-});
-
 pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
     let conn = Database::connect(connection_uri.into()).await?;
     DB_CONN.get_or_init(move || conn);
@@ -18,9 +13,6 @@ pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Erro
 }
 
 pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
-    #[cfg(feature = "mock")]
-    return Ok(&DB_MOCK);
-    #[cfg(not(feature = "mock"))]
     DB_CONN.get().ok_or(Error::Uninitialized)
 }
 
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 63f53c630..87f712aa7 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -20,6 +20,3 @@ thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["sync"] }
 util = { path = "../util" }
 utoipa = "3.3.0"
-
-[dev-dependencies]
-database = { path = "../database", features = ["mock"] }

From ba95b61b7fc90e9780322335d3b5c4407a9ed2b7 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 05:50:07 -0400
Subject: [PATCH 17/66] add integration test in model

---
 .../native-utils/crates/database/src/lib.rs   |  4 +-
 .../crates/model/src/repository/mod.rs        |  2 +-
 .../crates/model/src/schema/antenna.rs        | 21 +++--
 .../crates/model/src/schema/app.rs            |  8 +-
 .../native-utils/crates/model/tests/common.rs | 88 +++++++++++++++++++
 .../crates/model/tests/repository/antenna.rs  | 60 +++++++++++++
 .../crates/model/tests/repository/mod.rs      |  1 +
 .../native-utils/crates/util/src/id.rs        |  2 +-
 .../native-utils/crates/util/src/random.rs    |  2 +-
 9 files changed, 173 insertions(+), 15 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/model/tests/common.rs
 create mode 100644 packages/backend/native-utils/crates/model/tests/repository/antenna.rs
 create mode 100644 packages/backend/native-utils/crates/model/tests/repository/mod.rs

diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index d0e7b2577..36d4a532a 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -22,12 +22,12 @@ mod tests {
     use crate::{error::Error, init_database};
 
     #[test]
-    fn error_uninitialized() {
+    fn unit_lib_error_uninitialized() {
         assert_eq!(get_database().unwrap_err(), Error::Uninitialized);
     }
 
     #[tokio::test]
-    async fn connect_in_memory_sqlite() -> Result<(), Error> {
+    async fn unit_lib_connect_in_memory_sqlite() -> Result<(), Error> {
         init_database("sqlite::memory:").await?;
         get_database()?;
         Ok(())
diff --git a/packages/backend/native-utils/crates/model/src/repository/mod.rs b/packages/backend/native-utils/crates/model/src/repository/mod.rs
index b720d1d48..01e11412d 100644
--- a/packages/backend/native-utils/crates/model/src/repository/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/mod.rs
@@ -6,6 +6,6 @@ use schemars::JsonSchema;
 use crate::error::Error;
 
 #[async_trait]
-trait Repository<T: JsonSchema> {
+pub trait Repository<T: JsonSchema> {
     async fn pack(self) -> Result<T, Error>;
 }
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index a8065d09e..3f4c40ccb 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -7,7 +7,7 @@ use utoipa::ToSchema;
 use super::{Keyword, Schema, StringList};
 use crate::entity::sea_orm_active_enums::AntennaSrcEnum;
 
-#[derive(Debug, JsonSchema, ToSchema)]
+#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
 pub struct Antenna {
     pub id: String,
@@ -33,9 +33,10 @@ pub struct Antenna {
     pub has_unread_note: bool,
 }
 
-#[derive(Debug, FromStr, JsonSchema, ToSchema)]
-#[serde(rename_all = "lowercase")]
-#[display(style = "lowercase")]
+#[derive(Clone, Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
+#[serde(rename_all = "camelCase")]
+#[display(style = "camelCase")]
+#[display("'{}'")]
 pub enum AntennaSrc {
     Home,
     All,
@@ -62,10 +63,18 @@ pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
 mod tests {
     use serde_json::json;
 
+    use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::antenna::AntennaSrc};
+
     use super::VALIDATOR;
 
     #[test]
-    fn valid() {
+    fn unit_schema_src_from_active_enum() {
+        let src = AntennaSrc::try_from(AntennaSrcEnum::All).unwrap();
+        assert_eq!(src, AntennaSrc::All);
+    }
+
+    #[test]
+    fn unit_schema_antenna_valid() {
         let instance = json!({
             "id": "9f4x0bkx1u",
             "createdAt": "2023-05-24T06:56:14.323Z",
@@ -89,7 +98,7 @@ mod tests {
     }
 
     #[test]
-    fn invalid() {
+    fn unit_schema_antenna_invalid() {
         let instance = json!({
             // "id" is required
             "id": null,
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/crates/model/src/schema/app.rs
index adc404eb9..0b18ebeda 100644
--- a/packages/backend/native-utils/crates/model/src/schema/app.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/app.rs
@@ -5,7 +5,7 @@ use utoipa::ToSchema;
 
 use super::Schema;
 
-#[derive(Debug, JsonSchema, ToSchema)]
+#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
 pub struct App {
     pub id: String,
@@ -19,7 +19,7 @@ pub struct App {
 }
 
 /// This represents `permissions` in `packages/calckey-js/src/consts.ts`.
-#[derive(Debug, JsonSchema, ToSchema)]
+#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 pub enum Permission {
     #[serde(rename = "read:account")]
     ReadAccount,
@@ -96,12 +96,12 @@ pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| App::validator());
 #[cfg(test)]
 mod tests {
     #[test]
-    fn valid() {
+    fn unit_schema_app_valid() {
         todo!();
     }
 
     #[test]
-    fn invalid() {
+    fn unit_shcmea_app_invalid() {
         todo!();
     }
 }
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
new file mode 100644
index 000000000..9fd8815d3
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -0,0 +1,88 @@
+extern crate model;
+
+mod repository;
+
+use chrono::Utc;
+use model::entity::{antenna, sea_orm_active_enums::AntennaSrcEnum, user};
+use sea_orm::{
+    ActiveModelTrait, ActiveValue::Set, DatabaseConnection, DbErr, EntityTrait, TransactionTrait,
+};
+use serde_json::json;
+use std::env;
+use util::{
+    id::{create_id, init_id},
+    random::gen_string,
+};
+
+/// Insert predefined entries in the database.
+async fn prepare() {
+    let conn_uri = env::var("DATABASE_URL")
+        .unwrap_or("postgres://calckey:calckey@localhost/calckey".to_string());
+    database::init_database(conn_uri)
+        .await
+        .expect("Unable to initialize database connection");
+    let db = database::get_database().expect("Unable to get database connection from pool");
+    setup_model(db).await;
+}
+
+/// Delete all entries in the database.
+async fn cleanup() {
+    let db = database::get_database().unwrap();
+    db.transaction::<_, (), DbErr>(|txn| {
+        Box::pin(async move {
+            user::Entity::delete_many().exec(txn).await.unwrap();
+            antenna::Entity::delete_many().exec(txn).await.unwrap();
+
+            Ok(())
+        })
+    })
+    .await
+    .expect("Unable to delete predefined models");
+}
+
+async fn setup_model(db: &DatabaseConnection) {
+    init_id(12);
+
+    db.transaction::<_, (), DbErr>(|txn| {
+        Box::pin(async move {
+            let user_id = create_id().unwrap();
+            let name = "Alice";
+            let user_model = user::ActiveModel {
+                id: Set(user_id.to_owned()),
+                created_at: Set(Utc::now().into()),
+                username: Set(name.to_lowercase().to_string()),
+                username_lower: Set(name.to_lowercase().to_string()),
+                name: Set(Some(name.to_string())),
+                token: Set(Some(gen_string(16))),
+                is_admin: Set(true),
+                ..Default::default()
+            };
+            user_model.insert(txn).await?;
+            let antenna_model = antenna::ActiveModel {
+                id: Set(create_id().unwrap()),
+                created_at: Set(Utc::now().into()),
+                user_id: Set(user_id.to_owned()),
+                name: Set("Test Antenna".to_string()),
+                src: Set(AntennaSrcEnum::All),
+                keywords: Set(json!([["foo", "bar"], ["foobar"]])),
+                exclude_keywords: Set(json!([["abc"], ["def", "ghi"]])),
+                with_file: Set(false),
+                notify: Set(true),
+                case_sensitive: Set(true),
+                with_replies: Set(false),
+                ..Default::default()
+            };
+            antenna_model.insert(txn).await?;
+
+            Ok(())
+        })
+    })
+    .await
+    .expect("Unable to setup predefined models");
+}
+
+#[tokio::test]
+async fn inte_common_prepare_and_cleanup() {
+    prepare().await;
+    cleanup().await;
+}
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
new file mode 100644
index 000000000..42fd3b4bd
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -0,0 +1,60 @@
+use model::{
+    entity::{antenna, user},
+    repository::Repository,
+    schema,
+};
+use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
+
+use crate::{cleanup, prepare};
+
+#[tokio::test]
+async fn inte_repository_antenna_can_pack() {
+    prepare().await;
+
+    let db = database::get_database().unwrap();
+
+    let alice_antenna = user::Entity::find()
+        .filter(user::Column::Username.eq("alice"))
+        .find_also_related(antenna::Entity)
+        .one(db)
+        .await
+        .unwrap()
+        .expect("alice not found")
+        .1
+        .expect("alice's antenna not found");
+
+    let packed = alice_antenna
+        .to_owned()
+        .pack()
+        .await
+        .expect("Unable to pack");
+
+    assert_eq!(
+        packed,
+        schema::antenna::Antenna {
+            id: alice_antenna.id,
+            created_at: alice_antenna.created_at.into(),
+            name: "Test Antenna".to_string(),
+            keywords: vec![
+                vec!["foo".to_string(), "bar".to_string()],
+                vec!["foobar".to_string()]
+            ],
+            exclude_keywords: vec![
+                vec!["abc".to_string()],
+                vec!["def".to_string(), "ghi".to_string()]
+            ],
+            src: schema::antenna::AntennaSrc::All,
+            user_list_id: None,
+            user_group_id: None,
+            users: vec![],
+            instances: vec![],
+            case_sensitive: true,
+            notify: true,
+            with_replies: false,
+            with_file: false,
+            has_unread_note: false,
+        }
+    );
+
+    cleanup().await;
+}
diff --git a/packages/backend/native-utils/crates/model/tests/repository/mod.rs b/packages/backend/native-utils/crates/model/tests/repository/mod.rs
new file mode 100644
index 000000000..c11ef7687
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/tests/repository/mod.rs
@@ -0,0 +1 @@
+mod antenna;
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/crates/util/src/id.rs
index f82b64652..94f20a847 100644
--- a/packages/backend/native-utils/crates/util/src/id.rs
+++ b/packages/backend/native-utils/crates/util/src/id.rs
@@ -27,7 +27,7 @@ mod tests {
     use crate::id;
 
     #[test]
-    fn can_generate() {
+    fn unit_id_can_generate() {
         assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
         id::init_id(12);
         assert_eq!(id::create_id().unwrap().len(), 12);
diff --git a/packages/backend/native-utils/crates/util/src/random.rs b/packages/backend/native-utils/crates/util/src/random.rs
index fb2f02147..c197298c7 100644
--- a/packages/backend/native-utils/crates/util/src/random.rs
+++ b/packages/backend/native-utils/crates/util/src/random.rs
@@ -15,7 +15,7 @@ mod tests {
     use super::gen_string;
 
     #[test]
-    fn can_generate_string() {
+    fn unit_random_can_generate_string() {
         assert_eq!(gen_string(16).len(), 16);
         assert_ne!(gen_string(16), gen_string(16));
         let s1 = thread::spawn(|| gen_string(16));

From 4e4280e02eb5a3fcd0d692919af7168349af2308 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 06:28:27 -0400
Subject: [PATCH 18/66] add tests

---
 packages/backend/native-utils/crates/database/src/lib.rs | 9 +--------
 packages/backend/native-utils/package.json               | 4 +++-
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 36d4a532a..28c0a6ed4 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -19,17 +19,10 @@ pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
 #[cfg(test)]
 mod tests {
     use super::get_database;
-    use crate::{error::Error, init_database};
+    use crate::error::Error;
 
     #[test]
     fn unit_lib_error_uninitialized() {
         assert_eq!(get_database().unwrap_err(), Error::Uninitialized);
     }
-
-    #[tokio::test]
-    async fn unit_lib_connect_in_memory_sqlite() -> Result<(), Error> {
-        init_database("sqlite::memory:").await?;
-        get_database()?;
-        Ok(())
-    }
 }
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 787d1bd89..c82826d69 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -39,6 +39,8 @@
     "prepublishOnly": "napi prepublish -t npm",
     "test": "ava",
     "universal": "napi universal",
-    "version": "napi version"
+    "version": "napi version",
+    "cargo:unit": "cargo test --workspace unit",
+    "cargo:integration": "cargo test --workspace inte -- --test-threads=1"
   }
 }

From f851bc8f406b56d6393eb2a0bab5aaef657c3038 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 06:52:15 -0400
Subject: [PATCH 19/66] rename test modules

---
 .../native-utils/crates/database/src/lib.rs   |   4 +-
 .../crates/model/src/schema/antenna.rs        |   8 +-
 .../crates/model/src/schema/app.rs            |   6 +-
 .../native-utils/crates/model/tests/common.rs |  12 +-
 .../crates/model/tests/repository/antenna.rs  | 106 +++++++++---------
 .../native-utils/crates/util/src/id.rs        |   4 +-
 .../native-utils/crates/util/src/random.rs    |   4 +-
 packages/backend/native-utils/package.json    |   4 +-
 8 files changed, 77 insertions(+), 71 deletions(-)

diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 28c0a6ed4..6907a1281 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -17,12 +17,12 @@ pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
 }
 
 #[cfg(test)]
-mod tests {
+mod unit_test {
     use super::get_database;
     use crate::error::Error;
 
     #[test]
-    fn unit_lib_error_uninitialized() {
+    fn error_uninitialized() {
         assert_eq!(get_database().unwrap_err(), Error::Uninitialized);
     }
 }
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index 3f4c40ccb..d5f19a96f 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -60,7 +60,7 @@ pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
 // ----
 
 #[cfg(test)]
-mod tests {
+mod unit_test {
     use serde_json::json;
 
     use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::antenna::AntennaSrc};
@@ -68,13 +68,13 @@ mod tests {
     use super::VALIDATOR;
 
     #[test]
-    fn unit_schema_src_from_active_enum() {
+    fn src_from_active_enum() {
         let src = AntennaSrc::try_from(AntennaSrcEnum::All).unwrap();
         assert_eq!(src, AntennaSrc::All);
     }
 
     #[test]
-    fn unit_schema_antenna_valid() {
+    fn antenna_valid() {
         let instance = json!({
             "id": "9f4x0bkx1u",
             "createdAt": "2023-05-24T06:56:14.323Z",
@@ -98,7 +98,7 @@ mod tests {
     }
 
     #[test]
-    fn unit_schema_antenna_invalid() {
+    fn antenna_invalid() {
         let instance = json!({
             // "id" is required
             "id": null,
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/crates/model/src/schema/app.rs
index 0b18ebeda..b45cad6d6 100644
--- a/packages/backend/native-utils/crates/model/src/schema/app.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/app.rs
@@ -94,14 +94,14 @@ impl Schema<Self> for App {}
 pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| App::validator());
 
 #[cfg(test)]
-mod tests {
+mod unit_test {
     #[test]
-    fn unit_schema_app_valid() {
+    fn valid() {
         todo!();
     }
 
     #[test]
-    fn unit_shcmea_app_invalid() {
+    fn invalid() {
         todo!();
     }
 }
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index 9fd8815d3..38c616071 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -81,8 +81,12 @@ async fn setup_model(db: &DatabaseConnection) {
     .expect("Unable to setup predefined models");
 }
 
-#[tokio::test]
-async fn inte_common_prepare_and_cleanup() {
-    prepare().await;
-    cleanup().await;
+mod it_test {
+    use super::{cleanup, prepare};
+
+    #[tokio::test]
+    async fn can_prepare_and_cleanup() {
+        prepare().await;
+        cleanup().await;
+    }
 }
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index 42fd3b4bd..7f3aac74d 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -1,60 +1,62 @@
-use model::{
-    entity::{antenna, user},
-    repository::Repository,
-    schema,
-};
-use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
+mod it_test {
+    use model::{
+        entity::{antenna, user},
+        repository::Repository,
+        schema,
+    };
+    use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
-use crate::{cleanup, prepare};
+    use crate::{cleanup, prepare};
 
-#[tokio::test]
-async fn inte_repository_antenna_can_pack() {
-    prepare().await;
+    #[tokio::test]
+    async fn can_pack() {
+        prepare().await;
 
-    let db = database::get_database().unwrap();
+        let db = database::get_database().unwrap();
 
-    let alice_antenna = user::Entity::find()
-        .filter(user::Column::Username.eq("alice"))
-        .find_also_related(antenna::Entity)
-        .one(db)
-        .await
-        .unwrap()
-        .expect("alice not found")
-        .1
-        .expect("alice's antenna not found");
+        let alice_antenna = user::Entity::find()
+            .filter(user::Column::Username.eq("alice"))
+            .find_also_related(antenna::Entity)
+            .one(db)
+            .await
+            .unwrap()
+            .expect("alice not found")
+            .1
+            .expect("alice's antenna not found");
 
-    let packed = alice_antenna
-        .to_owned()
-        .pack()
-        .await
-        .expect("Unable to pack");
+        let packed = alice_antenna
+            .to_owned()
+            .pack()
+            .await
+            .expect("Unable to pack");
 
-    assert_eq!(
-        packed,
-        schema::antenna::Antenna {
-            id: alice_antenna.id,
-            created_at: alice_antenna.created_at.into(),
-            name: "Test Antenna".to_string(),
-            keywords: vec![
-                vec!["foo".to_string(), "bar".to_string()],
-                vec!["foobar".to_string()]
-            ],
-            exclude_keywords: vec![
-                vec!["abc".to_string()],
-                vec!["def".to_string(), "ghi".to_string()]
-            ],
-            src: schema::antenna::AntennaSrc::All,
-            user_list_id: None,
-            user_group_id: None,
-            users: vec![],
-            instances: vec![],
-            case_sensitive: true,
-            notify: true,
-            with_replies: false,
-            with_file: false,
-            has_unread_note: false,
-        }
-    );
+        assert_eq!(
+            packed,
+            schema::antenna::Antenna {
+                id: alice_antenna.id,
+                created_at: alice_antenna.created_at.into(),
+                name: "Test Antenna".to_string(),
+                keywords: vec![
+                    vec!["foo".to_string(), "bar".to_string()],
+                    vec!["foobar".to_string()]
+                ],
+                exclude_keywords: vec![
+                    vec!["abc".to_string()],
+                    vec!["def".to_string(), "ghi".to_string()]
+                ],
+                src: schema::antenna::AntennaSrc::All,
+                user_list_id: None,
+                user_group_id: None,
+                users: vec![],
+                instances: vec![],
+                case_sensitive: true,
+                notify: true,
+                with_replies: false,
+                with_file: false,
+                has_unread_note: false,
+            }
+        );
 
-    cleanup().await;
+        cleanup().await;
+    }
 }
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/crates/util/src/id.rs
index 94f20a847..2831ef79d 100644
--- a/packages/backend/native-utils/crates/util/src/id.rs
+++ b/packages/backend/native-utils/crates/util/src/id.rs
@@ -21,13 +21,13 @@ pub fn create_id() -> Result<String, ErrorUninitialized> {
 }
 
 #[cfg(test)]
-mod tests {
+mod unit_test {
     use std::thread;
 
     use crate::id;
 
     #[test]
-    fn unit_id_can_generate() {
+    fn can_generate_unique_ids() {
         assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
         id::init_id(12);
         assert_eq!(id::create_id().unwrap().len(), 12);
diff --git a/packages/backend/native-utils/crates/util/src/random.rs b/packages/backend/native-utils/crates/util/src/random.rs
index c197298c7..1c4a20d50 100644
--- a/packages/backend/native-utils/crates/util/src/random.rs
+++ b/packages/backend/native-utils/crates/util/src/random.rs
@@ -9,13 +9,13 @@ pub fn gen_string(length: u16) -> String {
 }
 
 #[cfg(test)]
-mod tests {
+mod unit_test {
     use std::thread;
 
     use super::gen_string;
 
     #[test]
-    fn unit_random_can_generate_string() {
+    fn can_generate_unique_strings() {
         assert_eq!(gen_string(16).len(), 16);
         assert_ne!(gen_string(16), gen_string(16));
         let s1 = thread::spawn(|| gen_string(16));
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index c82826d69..60f14260d 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -40,7 +40,7 @@
     "test": "ava",
     "universal": "napi universal",
     "version": "napi version",
-    "cargo:unit": "cargo test --workspace unit",
-    "cargo:integration": "cargo test --workspace inte -- --test-threads=1"
+    "cargo:unit": "cargo test --workspace unit_test",
+    "cargo:integration": "cargo test --workspace it_test -- --test-threads=1"
   }
 }

From bc69e2df8733ba6d33926023e89ad6084517952b Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 27 May 2023 07:02:10 -0400
Subject: [PATCH 20/66] todo unread note check

---
 .../native-utils/crates/model/tests/repository/antenna.rs   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index 7f3aac74d..a7e490733 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -11,7 +11,6 @@ mod it_test {
     #[tokio::test]
     async fn can_pack() {
         prepare().await;
-
         let db = database::get_database().unwrap();
 
         let alice_antenna = user::Entity::find()
@@ -59,4 +58,9 @@ mod it_test {
 
         cleanup().await;
     }
+
+    #[tokio::test]
+    async fn unread_note() {
+        todo!();
+    }
 }

From 29e914c9c3aaa4e4bf88c7bb6767a8a9811f6849 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Wed, 31 May 2023 12:09:30 -0400
Subject: [PATCH 21/66] add newtype

---
 .../native-utils/crates/model/Cargo.toml      |  1 +
 .../crates/model/src/entity/antenna.rs        | 10 ++--
 .../crates/model/src/entity/mod.rs            |  1 +
 .../crates/model/src/entity/newtype/macros.rs | 51 +++++++++++++++++++
 .../crates/model/src/entity/newtype/mod.rs    | 17 +++++++
 .../crates/model/src/repository/antenna.rs    |  8 +--
 .../crates/model/src/schema/antenna.rs        | 12 ++---
 .../crates/model/src/schema/mod.rs            | 30 -----------
 .../native-utils/crates/model/tests/common.rs | 13 +++--
 .../crates/model/tests/repository/antenna.rs  | 10 ++--
 10 files changed, 101 insertions(+), 52 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs

diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 87f712aa7..47d2e1553 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2021"
 async-trait = "0.1.68"
 chrono = "0.4.24"
 database = { path = "../database" }
+derive_more = "0.99.17"
 jsonschema = "0.17.0"
 once_cell = "1.17.1"
 parse-display = "0.8.0"
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
index 513d15e83..5e514576b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -1,6 +1,6 @@
 //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
 
-use super::sea_orm_active_enums::AntennaSrcEnum;
+use super::{newtype, sea_orm_active_enums::AntennaSrcEnum};
 use sea_orm::entity::prelude::*;
 
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
@@ -17,7 +17,7 @@ pub struct Model {
     #[sea_orm(column_name = "userListId")]
     pub user_list_id: Option<String>,
     #[sea_orm(column_type = "JsonBinary")]
-    pub keywords: Json,
+    pub keywords: newtype::Keyword,
     #[sea_orm(column_name = "withFile")]
     pub with_file: bool,
     pub expression: Option<String>,
@@ -28,11 +28,11 @@ pub struct Model {
     pub with_replies: bool,
     #[sea_orm(column_name = "userGroupJoiningId")]
     pub user_group_joining_id: Option<String>,
-    pub users: Vec<String>,
+    pub users: newtype::StringVec,
     #[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")]
-    pub exclude_keywords: Json,
+    pub exclude_keywords: newtype::Keyword,
     #[sea_orm(column_type = "JsonBinary")]
-    pub instances: Json,
+    pub instances: newtype::StringVec,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/mod.rs b/packages/backend/native-utils/crates/model/src/entity/mod.rs
index 077f9fa6e..6105b0555 100644
--- a/packages/backend/native-utils/crates/model/src/entity/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/mod.rs
@@ -33,6 +33,7 @@ pub mod migrations;
 pub mod moderation_log;
 pub mod muted_note;
 pub mod muting;
+pub mod newtype;
 pub mod note;
 pub mod note_edit;
 pub mod note_favorite;
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
new file mode 100644
index 000000000..0266e80c8
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
@@ -0,0 +1,51 @@
+#[macro_export]
+macro_rules! impl_json_newtype {
+    ($a:tt) => {
+        impl From<$a> for Value {
+            fn from(source: $a) -> Self {
+                Value::Json(serde_json::to_value(source).ok().map(Box::new))
+            }
+        }
+
+        impl TryGetable for $a {
+            fn try_get_by<I: sea_orm::ColIdx>(
+                res: &QueryResult,
+                idx: I,
+            ) -> Result<Self, TryGetError> {
+                let json_value: serde_json::Value =
+                    res.try_get_by(idx).map_err(TryGetError::DbErr)?;
+                serde_json::from_value(json_value)
+                    .map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string())))
+            }
+        }
+
+        impl sea_query::ValueType for $a {
+            fn try_from(v: Value) -> Result<Self, sea_query::ValueTypeErr> {
+                match v {
+                    Value::Json(Some(x)) => Ok($a(
+                        serde_json::from_value(*x).map_err(|_| sea_query::ValueTypeErr)?
+                    )),
+                    _ => Err(sea_query::ValueTypeErr),
+                }
+            }
+
+            fn type_name() -> String {
+                stringify!($a).to_owned()
+            }
+
+            fn array_type() -> sea_orm::sea_query::ArrayType {
+                sea_orm::sea_query::ArrayType::Json
+            }
+
+            fn column_type() -> sea_query::ColumnType {
+                sea_query::ColumnType::Json
+            }
+        }
+
+        impl sea_query::Nullable for $a {
+            fn null() -> Value {
+                Value::Json(None)
+            }
+        }
+    };
+}
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
new file mode 100644
index 000000000..714f3dafb
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -0,0 +1,17 @@
+mod macros;
+
+use derive_more::From;
+use schemars::JsonSchema;
+use sea_orm::{sea_query, DbErr, QueryResult, TryGetError, TryGetable, Value};
+use serde::{Deserialize, Serialize};
+
+use crate::impl_json_newtype;
+
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
+pub struct Keyword(pub Vec<Vec<String>>);
+impl_json_newtype!(Keyword);
+
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
+
+pub struct StringVec(pub Vec<String>);
+impl_json_newtype!(StringVec);
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
index dc6cb5a01..9a6882b59 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -3,7 +3,7 @@ use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
 use crate::entity::{antenna, antenna_note, user_group_joining};
 use crate::error::Error;
-use crate::schema::{antenna::Antenna, json_to_keyword, json_to_string_list};
+use crate::schema::antenna::Antenna;
 
 use super::Repository;
 
@@ -30,13 +30,13 @@ impl Repository<Antenna> for antenna::Model {
             id: self.id,
             created_at: self.created_at.into(),
             name: self.name,
-            keywords: json_to_keyword(&self.keywords),
-            exclude_keywords: json_to_keyword(&self.exclude_keywords),
+            keywords: self.keywords,
+            exclude_keywords: self.exclude_keywords,
             src: self.src.try_into()?,
             user_list_id: self.user_list_id,
             user_group_id,
             users: self.users,
-            instances: json_to_string_list(&self.instances),
+            instances: self.instances,
             case_sensitive: self.case_sensitive,
             notify: self.notify,
             with_replies: self.with_replies,
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index d5f19a96f..035dca344 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -4,8 +4,8 @@ use parse_display::FromStr;
 use schemars::JsonSchema;
 use utoipa::ToSchema;
 
-use super::{Keyword, Schema, StringList};
-use crate::entity::sea_orm_active_enums::AntennaSrcEnum;
+use super::Schema;
+use crate::entity::{newtype, sea_orm_active_enums::AntennaSrcEnum};
 
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
@@ -13,14 +13,14 @@ pub struct Antenna {
     pub id: String,
     pub created_at: chrono::DateTime<chrono::Utc>,
     pub name: String,
-    pub keywords: Keyword,
-    pub exclude_keywords: Keyword,
+    pub keywords: newtype::Keyword,
+    pub exclude_keywords: newtype::Keyword,
     #[schema(inline)]
     pub src: AntennaSrc,
     pub user_list_id: Option<String>,
     pub user_group_id: Option<String>,
-    pub users: StringList,
-    pub instances: StringList,
+    pub users: newtype::StringVec,
+    pub instances: newtype::StringVec,
     #[serde(default)]
     pub case_sensitive: bool,
     #[serde(default)]
diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema/mod.rs
index 2a0853814..cc495aac1 100644
--- a/packages/backend/native-utils/crates/model/src/schema/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/mod.rs
@@ -3,10 +3,6 @@ pub mod app;
 
 use jsonschema::JSONSchema;
 use schemars::{schema_for, JsonSchema};
-use serde_json::Value;
-
-type Keyword = Vec<Vec<String>>;
-type StringList = Vec<String>;
 
 /// Structs of schema defitions implement this trait in order to
 /// provide the JSON Schema validator [`jsonschema::JSONSchema`].
@@ -23,29 +19,3 @@ trait Schema<T: JsonSchema> {
             .expect("Unable to compile schema")
     }
 }
-
-pub(crate) fn json_to_keyword(value: &Value) -> Keyword {
-    match value.as_array() {
-        None => vec![vec![]],
-        Some(or_vec) => or_vec
-            .iter()
-            .map(|and_val| match and_val.as_array() {
-                None => vec![],
-                Some(and_vec) => and_vec
-                    .iter()
-                    .map(|word| word.as_str().unwrap_or_default().to_string())
-                    .collect(),
-            })
-            .collect(),
-    }
-}
-
-pub(crate) fn json_to_string_list(value: &Value) -> StringList {
-    match value.as_array() {
-        None => vec![],
-        Some(v) => v
-            .iter()
-            .map(|s| s.as_str().unwrap_or_default().to_string())
-            .collect(),
-    }
-}
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index 38c616071..6a54ca414 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -7,7 +7,6 @@ use model::entity::{antenna, sea_orm_active_enums::AntennaSrcEnum, user};
 use sea_orm::{
     ActiveModelTrait, ActiveValue::Set, DatabaseConnection, DbErr, EntityTrait, TransactionTrait,
 };
-use serde_json::json;
 use std::env;
 use util::{
     id::{create_id, init_id},
@@ -64,8 +63,16 @@ async fn setup_model(db: &DatabaseConnection) {
                 user_id: Set(user_id.to_owned()),
                 name: Set("Test Antenna".to_string()),
                 src: Set(AntennaSrcEnum::All),
-                keywords: Set(json!([["foo", "bar"], ["foobar"]])),
-                exclude_keywords: Set(json!([["abc"], ["def", "ghi"]])),
+                keywords: Set(vec![
+                    vec!["foo".to_string(), "bar".to_string()],
+                    vec!["foobar".to_string()],
+                ]
+                .into()),
+                exclude_keywords: Set(vec![
+                    vec!["abc".to_string()],
+                    vec!["def".to_string(), "ghi".to_string()],
+                ]
+                .into()),
                 with_file: Set(false),
                 notify: Set(true),
                 case_sensitive: Set(true),
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index a7e490733..73ddc6505 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -38,16 +38,18 @@ mod it_test {
                 keywords: vec![
                     vec!["foo".to_string(), "bar".to_string()],
                     vec!["foobar".to_string()]
-                ],
+                ]
+                .into(),
                 exclude_keywords: vec![
                     vec!["abc".to_string()],
                     vec!["def".to_string(), "ghi".to_string()]
-                ],
+                ]
+                .into(),
                 src: schema::antenna::AntennaSrc::All,
                 user_list_id: None,
                 user_group_id: None,
-                users: vec![],
-                instances: vec![],
+                users: vec![].into(),
+                instances: vec![].into(),
                 case_sensitive: true,
                 notify: true,
                 with_replies: false,

From 516d5460f0009eb61890e64554b6ea6c99da3eb3 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Wed, 31 May 2023 12:24:02 -0400
Subject: [PATCH 22/66] fix varchar array

---
 .../native-utils/crates/model/src/entity/antenna.rs       | 8 ++++----
 .../native-utils/crates/model/src/entity/newtype/mod.rs   | 8 ++++----
 .../native-utils/crates/model/src/schema/antenna.rs       | 8 ++++----
 .../backend/native-utils/crates/model/tests/common.rs     | 2 +-
 .../native-utils/crates/model/tests/repository/antenna.rs | 2 +-
 packages/backend/native-utils/package.json                | 2 +-
 6 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
index 5e514576b..ccff0aab4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -17,7 +17,7 @@ pub struct Model {
     #[sea_orm(column_name = "userListId")]
     pub user_list_id: Option<String>,
     #[sea_orm(column_type = "JsonBinary")]
-    pub keywords: newtype::Keyword,
+    pub keywords: newtype::JsonKeyword,
     #[sea_orm(column_name = "withFile")]
     pub with_file: bool,
     pub expression: Option<String>,
@@ -28,11 +28,11 @@ pub struct Model {
     pub with_replies: bool,
     #[sea_orm(column_name = "userGroupJoiningId")]
     pub user_group_joining_id: Option<String>,
-    pub users: newtype::StringVec,
+    pub users: Vec<String>,
     #[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")]
-    pub exclude_keywords: newtype::Keyword,
+    pub exclude_keywords: newtype::JsonKeyword,
     #[sea_orm(column_type = "JsonBinary")]
-    pub instances: newtype::StringVec,
+    pub instances: newtype::JsonStringVec,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index 714f3dafb..f7e3c3d43 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -8,10 +8,10 @@ use serde::{Deserialize, Serialize};
 use crate::impl_json_newtype;
 
 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
-pub struct Keyword(pub Vec<Vec<String>>);
-impl_json_newtype!(Keyword);
+pub struct JsonKeyword(pub Vec<Vec<String>>);
+impl_json_newtype!(JsonKeyword);
 
 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
 
-pub struct StringVec(pub Vec<String>);
-impl_json_newtype!(StringVec);
+pub struct JsonStringVec(pub Vec<String>);
+impl_json_newtype!(JsonStringVec);
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index 035dca344..4a71982f7 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -13,14 +13,14 @@ pub struct Antenna {
     pub id: String,
     pub created_at: chrono::DateTime<chrono::Utc>,
     pub name: String,
-    pub keywords: newtype::Keyword,
-    pub exclude_keywords: newtype::Keyword,
+    pub keywords: newtype::JsonKeyword,
+    pub exclude_keywords: newtype::JsonKeyword,
     #[schema(inline)]
     pub src: AntennaSrc,
     pub user_list_id: Option<String>,
     pub user_group_id: Option<String>,
-    pub users: newtype::StringVec,
-    pub instances: newtype::StringVec,
+    pub users: Vec<String>,
+    pub instances: newtype::JsonStringVec,
     #[serde(default)]
     pub case_sensitive: bool,
     #[serde(default)]
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index 6a54ca414..d459056f3 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -88,7 +88,7 @@ async fn setup_model(db: &DatabaseConnection) {
     .expect("Unable to setup predefined models");
 }
 
-mod it_test {
+mod int_test {
     use super::{cleanup, prepare};
 
     #[tokio::test]
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index 73ddc6505..e07a16c07 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -1,4 +1,4 @@
-mod it_test {
+mod int_test {
     use model::{
         entity::{antenna, user},
         repository::Repository,
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 60f14260d..aa194bad3 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -41,6 +41,6 @@
     "universal": "napi universal",
     "version": "napi version",
     "cargo:unit": "cargo test --workspace unit_test",
-    "cargo:integration": "cargo test --workspace it_test -- --test-threads=1"
+    "cargo:integration": "cargo test --workspace int_test -- --test-threads=1"
   }
 }

From 128a354b83c0348b1bb5fab715eeb1ebba022cf0 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Wed, 31 May 2023 18:12:59 -0400
Subject: [PATCH 23/66] add abstraction of string array type

---
 .../native-utils/crates/database/src/lib.rs   |  6 +-
 .../native-utils/crates/migration/Cargo.toml  | 25 +++++++
 .../native-utils/crates/migration/README.md   | 41 ++++++++++
 .../native-utils/crates/migration/src/lib.rs  | 12 +++
 .../src/m20230531_180824_stringvec.rs         | 74 +++++++++++++++++++
 .../native-utils/crates/migration/src/main.rs |  6 ++
 .../native-utils/crates/model/Cargo.toml      |  6 +-
 .../crates/model/src/entity/antenna.rs        |  2 +-
 .../crates/model/src/entity/newtype/macros.rs |  6 +-
 .../crates/model/src/entity/newtype/mod.rs    | 17 +++--
 .../native-utils/crates/model/src/error.rs    |  2 +-
 .../crates/model/src/repository/antenna.rs    |  8 +-
 .../crates/model/src/schema/antenna.rs        |  8 +-
 .../native-utils/crates/model/tests/common.rs | 24 +++++-
 14 files changed, 213 insertions(+), 24 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/migration/Cargo.toml
 create mode 100644 packages/backend/native-utils/crates/migration/README.md
 create mode 100644 packages/backend/native-utils/crates/migration/src/lib.rs
 create mode 100644 packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
 create mode 100644 packages/backend/native-utils/crates/migration/src/main.rs

diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/crates/database/src/lib.rs
index 6907a1281..0012d2292 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/crates/database/src/lib.rs
@@ -1,10 +1,10 @@
 pub mod error;
 
-use sea_orm::{Database, DatabaseConnection};
+use sea_orm::{Database, DbConn};
 
 use crate::error::Error;
 
-static DB_CONN: once_cell::sync::OnceCell<DatabaseConnection> = once_cell::sync::OnceCell::new();
+static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
 
 pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
     let conn = Database::connect(connection_uri.into()).await?;
@@ -12,7 +12,7 @@ pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Erro
     Ok(())
 }
 
-pub fn get_database() -> Result<&'static DatabaseConnection, Error> {
+pub fn get_database() -> Result<&'static DbConn, Error> {
     DB_CONN.get().ok_or(Error::Uninitialized)
 }
 
diff --git a/packages/backend/native-utils/crates/migration/Cargo.toml b/packages/backend/native-utils/crates/migration/Cargo.toml
new file mode 100644
index 000000000..46108c68c
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "migration"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+name = "migration"
+path = "src/lib.rs"
+
+[dependencies]
+async-std = { version = "1", features = ["attributes", "tokio1"] }
+serde_json = "1.0.96"
+model = { path = "../model" }
+
+[dependencies.sea-orm-migration]
+version = "0.11.0"
+features = [
+  # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
+  # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
+  # e.g.
+  "runtime-tokio-rustls",  # `ASYNC_RUNTIME` feature
+  "sqlx-postgres",         # `DATABASE_DRIVER` feature
+	"sqlx-sqlite",
+]
diff --git a/packages/backend/native-utils/crates/migration/README.md b/packages/backend/native-utils/crates/migration/README.md
new file mode 100644
index 000000000..b3ea53eb4
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/README.md
@@ -0,0 +1,41 @@
+# Running Migrator CLI
+
+- Generate a new migration file
+    ```sh
+    cargo run -- migrate generate MIGRATION_NAME
+    ```
+- Apply all pending migrations
+    ```sh
+    cargo run
+    ```
+    ```sh
+    cargo run -- up
+    ```
+- Apply first 10 pending migrations
+    ```sh
+    cargo run -- up -n 10
+    ```
+- Rollback last applied migrations
+    ```sh
+    cargo run -- down
+    ```
+- Rollback last 10 applied migrations
+    ```sh
+    cargo run -- down -n 10
+    ```
+- Drop all tables from the database, then reapply all migrations
+    ```sh
+    cargo run -- fresh
+    ```
+- Rollback all applied migrations, then reapply all migrations
+    ```sh
+    cargo run -- refresh
+    ```
+- Rollback all applied migrations
+    ```sh
+    cargo run -- reset
+    ```
+- Check the status of all migrations
+    ```sh
+    cargo run -- status
+    ```
diff --git a/packages/backend/native-utils/crates/migration/src/lib.rs b/packages/backend/native-utils/crates/migration/src/lib.rs
new file mode 100644
index 000000000..a2a1b932f
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/src/lib.rs
@@ -0,0 +1,12 @@
+pub use sea_orm_migration::prelude::*;
+
+mod m20230531_180824_stringvec;
+
+pub struct Migrator;
+
+#[async_trait::async_trait]
+impl MigratorTrait for Migrator {
+    fn migrations() -> Vec<Box<dyn MigrationTrait>> {
+        vec![Box::new(m20230531_180824_stringvec::Migration)]
+    }
+}
diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
new file mode 100644
index 000000000..ba1fc257d
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
@@ -0,0 +1,74 @@
+use model::entity::{antenna, newtype::StringVec};
+use sea_orm_migration::{
+    prelude::*,
+    sea_orm::{DbBackend, EntityTrait, Statement},
+};
+use serde_json::json;
+
+#[derive(DeriveMigrationName)]
+pub struct Migration;
+
+#[async_trait::async_trait]
+impl MigrationTrait for Migration {
+    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        if manager.get_database_backend() == DbBackend::Sqlite {
+            return Ok(());
+        }
+
+        let db = manager.get_connection();
+        let query = Query::select()
+            .column(Antenna::Id)
+            .column(Antenna::Users)
+            .from(Antenna::Table)
+            .to_string(PostgresQueryBuilder);
+        let res: Vec<(String, Vec<String>)> = db
+            .query_all(Statement::from_string(DbBackend::Postgres, query))
+            .await?
+            .iter()
+            .filter_map(|r| r.try_get_many_by_index().ok())
+            .collect();
+
+        manager
+            .alter_table(
+                Table::alter()
+                    .table(Antenna::Table)
+                    .drop_column(Antenna::Users)
+                    .add_column(
+                        ColumnDef::new(Antenna::Users)
+                            .json_binary()
+                            .not_null()
+                            .default(json!([])),
+                    )
+                    .to_owned(),
+            )
+            .await?;
+
+        let models: Vec<antenna::ActiveModel> = res
+            .iter()
+            .map(|(id, users)| antenna::ActiveModel {
+                id: sea_orm::Set(id.to_owned()),
+                users: sea_orm::Set(StringVec::from(users.to_owned())),
+                ..Default::default()
+            })
+            .collect();
+
+        for model in models {
+            antenna::Entity::update(model).exec(db).await?;
+        }
+
+        Ok(())
+    }
+
+    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
+        // Replace the sample below with your own migration scripts
+        Ok(())
+    }
+}
+
+/// Learn more at https://docs.rs/sea-query#iden
+#[derive(Iden)]
+enum Antenna {
+    Table,
+    Id,
+    Users,
+}
diff --git a/packages/backend/native-utils/crates/migration/src/main.rs b/packages/backend/native-utils/crates/migration/src/main.rs
new file mode 100644
index 000000000..c6b6e48db
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/src/main.rs
@@ -0,0 +1,6 @@
+use sea_orm_migration::prelude::*;
+
+#[async_std::main]
+async fn main() {
+    cli::run_cli(migration::Migrator).await;
+}
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 47d2e1553..4f121a1e1 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -4,9 +4,13 @@ version = "0.1.0"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[features]
+default = ["compat"]
+compat = ["sea-orm/postgres-array"]
 
 [dependencies]
 async-trait = "0.1.68"
+cfg-if = "1.0.0"
 chrono = "0.4.24"
 database = { path = "../database" }
 derive_more = "0.99.17"
@@ -14,7 +18,7 @@ jsonschema = "0.17.0"
 once_cell = "1.17.1"
 parse-display = "0.8.0"
 schemars = { version = "0.8.12", features = ["chrono"] }
-sea-orm = { version = "0.11.3", features = ["postgres-array", "sqlx-postgres", "runtime-tokio-rustls"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "sqlx-sqlite", "runtime-tokio-rustls"] }
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
 thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
index ccff0aab4..0ebd1cf45 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -28,7 +28,7 @@ pub struct Model {
     pub with_replies: bool,
     #[sea_orm(column_name = "userGroupJoiningId")]
     pub user_group_joining_id: Option<String>,
-    pub users: Vec<String>,
+    pub users: newtype::StringVec,
     #[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")]
     pub exclude_keywords: newtype::JsonKeyword,
     #[sea_orm(column_type = "JsonBinary")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
index 0266e80c8..4b05c2c99 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
@@ -33,12 +33,12 @@ macro_rules! impl_json_newtype {
                 stringify!($a).to_owned()
             }
 
-            fn array_type() -> sea_orm::sea_query::ArrayType {
-                sea_orm::sea_query::ArrayType::Json
+            fn array_type() -> sea_query::ArrayType {
+                sea_query::ArrayType::Json
             }
 
             fn column_type() -> sea_query::ColumnType {
-                sea_query::ColumnType::Json
+                sea_query::ColumnType::JsonBinary
             }
         }
 
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index f7e3c3d43..2b11c5f21 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -1,17 +1,24 @@
 mod macros;
 
-use derive_more::From;
-use schemars::JsonSchema;
+use cfg_if::cfg_if;
+use derive_more::{From, Into};
 use sea_orm::{sea_query, DbErr, QueryResult, TryGetError, TryGetable, Value};
 use serde::{Deserialize, Serialize};
 
 use crate::impl_json_newtype;
 
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
 pub struct JsonKeyword(pub Vec<Vec<String>>);
 impl_json_newtype!(JsonKeyword);
 
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)]
-
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
 pub struct JsonStringVec(pub Vec<String>);
 impl_json_newtype!(JsonStringVec);
+
+cfg_if! {
+    if #[cfg(feature = "compat")] {
+        pub type StringVec = Vec<String>;
+    } else {
+        pub type StringVec = JsonStringVec;
+    }
+}
diff --git a/packages/backend/native-utils/crates/model/src/error.rs b/packages/backend/native-utils/crates/model/src/error.rs
index 379ecb784..7686312ec 100644
--- a/packages/backend/native-utils/crates/model/src/error.rs
+++ b/packages/backend/native-utils/crates/model/src/error.rs
@@ -3,7 +3,7 @@ pub enum Error {
     #[error("Failed to parse string")]
     ParseError(#[from] parse_display::ParseError),
     #[error("Failed to get database connection")]
-    DatabaseConnectionError(#[from] database::error::Error),
+    DbConnError(#[from] database::error::Error),
     #[error("Database operation error: {0}")]
     DatabaseOperationError(#[from] sea_orm::DbErr),
 }
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
index 9a6882b59..f9ef012a6 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -30,13 +30,13 @@ impl Repository<Antenna> for antenna::Model {
             id: self.id,
             created_at: self.created_at.into(),
             name: self.name,
-            keywords: self.keywords,
-            exclude_keywords: self.exclude_keywords,
+            keywords: self.keywords.into(),
+            exclude_keywords: self.exclude_keywords.into(),
             src: self.src.try_into()?,
             user_list_id: self.user_list_id,
             user_group_id,
-            users: self.users,
-            instances: self.instances,
+            users: self.users.into(),
+            instances: self.instances.into(),
             case_sensitive: self.case_sensitive,
             notify: self.notify,
             with_replies: self.with_replies,
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index 4a71982f7..fa7902b92 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -5,7 +5,7 @@ use schemars::JsonSchema;
 use utoipa::ToSchema;
 
 use super::Schema;
-use crate::entity::{newtype, sea_orm_active_enums::AntennaSrcEnum};
+use crate::entity::sea_orm_active_enums::AntennaSrcEnum;
 
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
@@ -13,14 +13,14 @@ pub struct Antenna {
     pub id: String,
     pub created_at: chrono::DateTime<chrono::Utc>,
     pub name: String,
-    pub keywords: newtype::JsonKeyword,
-    pub exclude_keywords: newtype::JsonKeyword,
+    pub keywords: Vec<Vec<String>>,
+    pub exclude_keywords: Vec<Vec<String>>,
     #[schema(inline)]
     pub src: AntennaSrc,
     pub user_list_id: Option<String>,
     pub user_group_id: Option<String>,
     pub users: Vec<String>,
-    pub instances: newtype::JsonStringVec,
+    pub instances: Vec<String>,
     #[serde(default)]
     pub case_sensitive: bool,
     #[serde(default)]
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index d459056f3..f05c4432d 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -5,7 +5,8 @@ mod repository;
 use chrono::Utc;
 use model::entity::{antenna, sea_orm_active_enums::AntennaSrcEnum, user};
 use sea_orm::{
-    ActiveModelTrait, ActiveValue::Set, DatabaseConnection, DbErr, EntityTrait, TransactionTrait,
+    ActiveModelTrait, ActiveValue::Set, ConnectionTrait, DbBackend, DbConn, DbErr, EntityTrait,
+    TransactionTrait,
 };
 use std::env;
 use util::{
@@ -24,6 +25,15 @@ async fn prepare() {
     setup_model(db).await;
 }
 
+async fn setup_schema(db: DbConn) {
+    // Setup Schema helper
+    let schema = sea_orm::Schema::new(DbBackend::Sqlite);
+    let stmt = schema.create_table_from_entity(antenna::Entity);
+    db.execute(db.get_database_backend().build(&stmt))
+        .await
+        .expect("Unable to initialize in-memoty sqlite");
+}
+
 /// Delete all entries in the database.
 async fn cleanup() {
     let db = database::get_database().unwrap();
@@ -39,7 +49,7 @@ async fn cleanup() {
     .expect("Unable to delete predefined models");
 }
 
-async fn setup_model(db: &DatabaseConnection) {
+async fn setup_model(db: &DbConn) {
     init_id(12);
 
     db.transaction::<_, (), DbErr>(|txn| {
@@ -89,6 +99,10 @@ async fn setup_model(db: &DatabaseConnection) {
 }
 
 mod int_test {
+    use sea_orm::Database;
+
+    use crate::setup_schema;
+
     use super::{cleanup, prepare};
 
     #[tokio::test]
@@ -96,4 +110,10 @@ mod int_test {
         prepare().await;
         cleanup().await;
     }
+
+    #[tokio::test]
+    async fn can_setup_sqlite_schema() {
+        let db = Database::connect("sqlite::memory:").await.unwrap();
+        setup_schema(db).await;
+    }
 }

From 968943c7c0c12347b24d6d17ea224e61604c9e9d Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Wed, 31 May 2023 18:21:57 -0400
Subject: [PATCH 24/66] make sqlite compat

---
 packages/backend/native-utils/crates/model/Cargo.toml         | 4 ++--
 .../native-utils/crates/model/src/entity/newtype/mod.rs       | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index 4f121a1e1..e99f8b561 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [features]
-default = ["compat"]
-compat = ["sea-orm/postgres-array"]
+default = ["legacy"]
+legacy = ["sea-orm/postgres-array"]
 
 [dependencies]
 async-trait = "0.1.68"
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index 2b11c5f21..65eba72d7 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -16,7 +16,7 @@ pub struct JsonStringVec(pub Vec<String>);
 impl_json_newtype!(JsonStringVec);
 
 cfg_if! {
-    if #[cfg(feature = "compat")] {
+    if #[cfg(feature = "legacy")] {
         pub type StringVec = Vec<String>;
     } else {
         pub type StringVec = JsonStringVec;

From 099f9e042afebd86dad1757f2586392df54fbe47 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 00:18:50 -0400
Subject: [PATCH 25/66] use vec newtype

---
 .../crates/model/src/entity/access_token.rs   |  4 +++-
 .../crates/model/src/entity/app.rs            |  4 +++-
 .../crates/model/src/entity/emoji.rs          |  4 +++-
 .../crates/model/src/entity/gallery_post.rs   |  6 +++--
 .../crates/model/src/entity/hashtag.rs        | 14 +++++++-----
 .../model/src/entity/messaging_message.rs     |  4 +++-
 .../crates/model/src/entity/meta.rs           | 22 ++++++++++---------
 .../crates/model/src/entity/newtype/mod.rs    |  6 +++++
 .../crates/model/src/entity/note.rs           | 14 +++++++-----
 .../crates/model/src/entity/note_edit.rs      |  4 +++-
 .../crates/model/src/entity/page.rs           |  4 +++-
 .../crates/model/src/entity/poll.rs           |  6 +++--
 .../crates/model/src/entity/registry_item.rs  |  4 +++-
 .../crates/model/src/entity/reversi_game.rs   |  4 +++-
 .../crates/model/src/entity/user.rs           |  6 +++--
 .../crates/model/src/entity/user_profile.rs   |  4 +++-
 .../crates/model/src/entity/webhook.rs        |  4 +++-
 17 files changed, 76 insertions(+), 38 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/entity/access_token.rs b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
index fa9894414..f84971605 100644
--- a/packages/backend/native-utils/crates/model/src/entity/access_token.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "access_token")]
 pub struct Model {
@@ -22,7 +24,7 @@ pub struct Model {
     pub description: Option<String>,
     #[sea_orm(column_name = "iconUrl")]
     pub icon_url: Option<String>,
-    pub permission: Vec<String>,
+    pub permission: StringVec,
     pub fetched: bool,
 }
 
diff --git a/packages/backend/native-utils/crates/model/src/entity/app.rs b/packages/backend/native-utils/crates/model/src/entity/app.rs
index 5f3d5d131..310294568 100644
--- a/packages/backend/native-utils/crates/model/src/entity/app.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/app.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "app")]
 pub struct Model {
@@ -14,7 +16,7 @@ pub struct Model {
     pub secret: String,
     pub name: String,
     pub description: String,
-    pub permission: Vec<String>,
+    pub permission: StringVec,
     #[sea_orm(column_name = "callbackUrl")]
     pub callback_url: Option<String>,
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/emoji.rs b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
index a89f0b22d..fdb99a2c3 100644
--- a/packages/backend/native-utils/crates/model/src/entity/emoji.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "emoji")]
 pub struct Model {
@@ -15,7 +17,7 @@ pub struct Model {
     pub original_url: String,
     pub uri: Option<String>,
     pub r#type: Option<String>,
-    pub aliases: Vec<String>,
+    pub aliases: StringVec,
     pub category: Option<String>,
     #[sea_orm(column_name = "publicUrl")]
     pub public_url: String,
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
index bb68eda62..875d3af58 100644
--- a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "gallery_post")]
 pub struct Model {
@@ -16,12 +18,12 @@ pub struct Model {
     #[sea_orm(column_name = "userId")]
     pub user_id: String,
     #[sea_orm(column_name = "fileIds")]
-    pub file_ids: Vec<String>,
+    pub file_ids: StringVec,
     #[sea_orm(column_name = "isSensitive")]
     pub is_sensitive: bool,
     #[sea_orm(column_name = "likedCount")]
     pub liked_count: i32,
-    pub tags: Vec<String>,
+    pub tags: StringVec,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
index 9a6e44623..917f4ea1b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "hashtag")]
 pub struct Model {
@@ -9,27 +11,27 @@ pub struct Model {
     pub id: String,
     pub name: String,
     #[sea_orm(column_name = "mentionedUserIds")]
-    pub mentioned_user_ids: Vec<String>,
+    pub mentioned_user_ids: StringVec,
     #[sea_orm(column_name = "mentionedUsersCount")]
     pub mentioned_users_count: i32,
     #[sea_orm(column_name = "mentionedLocalUserIds")]
-    pub mentioned_local_user_ids: Vec<String>,
+    pub mentioned_local_user_ids: StringVec,
     #[sea_orm(column_name = "mentionedLocalUsersCount")]
     pub mentioned_local_users_count: i32,
     #[sea_orm(column_name = "mentionedRemoteUserIds")]
-    pub mentioned_remote_user_ids: Vec<String>,
+    pub mentioned_remote_user_ids: StringVec,
     #[sea_orm(column_name = "mentionedRemoteUsersCount")]
     pub mentioned_remote_users_count: i32,
     #[sea_orm(column_name = "attachedUserIds")]
-    pub attached_user_ids: Vec<String>,
+    pub attached_user_ids: StringVec,
     #[sea_orm(column_name = "attachedUsersCount")]
     pub attached_users_count: i32,
     #[sea_orm(column_name = "attachedLocalUserIds")]
-    pub attached_local_user_ids: Vec<String>,
+    pub attached_local_user_ids: StringVec,
     #[sea_orm(column_name = "attachedLocalUsersCount")]
     pub attached_local_users_count: i32,
     #[sea_orm(column_name = "attachedRemoteUserIds")]
-    pub attached_remote_user_ids: Vec<String>,
+    pub attached_remote_user_ids: StringVec,
     #[sea_orm(column_name = "attachedRemoteUsersCount")]
     pub attached_remote_users_count: i32,
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
index 0fbfc1ffb..b66c01fc9 100644
--- a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "messaging_message")]
 pub struct Model {
@@ -20,7 +22,7 @@ pub struct Model {
     pub file_id: Option<String>,
     #[sea_orm(column_name = "groupId")]
     pub group_id: Option<String>,
-    pub reads: Vec<String>,
+    pub reads: StringVec,
     pub uri: Option<String>,
 }
 
diff --git a/packages/backend/native-utils/crates/model/src/entity/meta.rs b/packages/backend/native-utils/crates/model/src/entity/meta.rs
index 33ab911ba..a97cb89c4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/meta.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/meta.rs
@@ -4,6 +4,8 @@ use super::sea_orm_active_enums::MetaSensitivemediadetectionEnum;
 use super::sea_orm_active_enums::MetaSensitivemediadetectionsensitivityEnum;
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "meta")]
 pub struct Model {
@@ -23,11 +25,11 @@ pub struct Model {
     pub disable_global_timeline: bool,
     #[sea_orm(column_name = "useStarForReactionFallback")]
     pub use_star_for_reaction_fallback: bool,
-    pub langs: Vec<String>,
+    pub langs: StringVec,
     #[sea_orm(column_name = "hiddenTags")]
-    pub hidden_tags: Vec<String>,
+    pub hidden_tags: StringVec,
     #[sea_orm(column_name = "blockedHosts")]
-    pub blocked_hosts: Vec<String>,
+    pub blocked_hosts: StringVec,
     #[sea_orm(column_name = "mascotImageUrl")]
     pub mascot_image_url: Option<String>,
     #[sea_orm(column_name = "bannerUrl")]
@@ -88,7 +90,7 @@ pub struct Model {
     #[sea_orm(column_name = "discordClientSecret")]
     pub discord_client_secret: Option<String>,
     #[sea_orm(column_name = "pinnedUsers")]
-    pub pinned_users: Vec<String>,
+    pub pinned_users: StringVec,
     #[sea_orm(column_name = "ToSUrl")]
     pub to_s_url: Option<String>,
     #[sea_orm(column_name = "repositoryUrl")]
@@ -128,7 +130,7 @@ pub struct Model {
     #[sea_orm(column_name = "objectStorageSetPublicRead")]
     pub object_storage_set_public_read: bool,
     #[sea_orm(column_name = "pinnedPages")]
-    pub pinned_pages: Vec<String>,
+    pub pinned_pages: StringVec,
     #[sea_orm(column_name = "backgroundImageUrl")]
     pub background_image_url: Option<String>,
     #[sea_orm(column_name = "logoImageUrl")]
@@ -138,7 +140,7 @@ pub struct Model {
     #[sea_orm(column_name = "objectStorageS3ForcePathStyle")]
     pub object_storage_s3_force_path_style: bool,
     #[sea_orm(column_name = "allowedHosts")]
-    pub allowed_hosts: Option<Vec<String>>,
+    pub allowed_hosts: Option<StringVec>,
     #[sea_orm(column_name = "secureMode")]
     pub secure_mode: Option<bool>,
     #[sea_orm(column_name = "privateMode")]
@@ -168,13 +170,13 @@ pub struct Model {
     #[sea_orm(column_name = "enableActiveEmailValidation")]
     pub enable_active_email_validation: bool,
     #[sea_orm(column_name = "customMOTD")]
-    pub custom_motd: Vec<String>,
+    pub custom_motd: StringVec,
     #[sea_orm(column_name = "customSplashIcons")]
-    pub custom_splash_icons: Vec<String>,
+    pub custom_splash_icons: StringVec,
     #[sea_orm(column_name = "disableRecommendedTimeline")]
     pub disable_recommended_timeline: bool,
     #[sea_orm(column_name = "recommendedInstances")]
-    pub recommended_instances: Vec<String>,
+    pub recommended_instances: StringVec,
     #[sea_orm(column_name = "enableGuestTimeline")]
     pub enable_guest_timeline: bool,
     #[sea_orm(column_name = "defaultReaction")]
@@ -184,7 +186,7 @@ pub struct Model {
     #[sea_orm(column_name = "libreTranslateApiKey")]
     pub libre_translate_api_key: Option<String>,
     #[sea_orm(column_name = "silencedHosts")]
-    pub silenced_hosts: Vec<String>,
+    pub silenced_hosts: StringVec,
     #[sea_orm(column_name = "experimentalFeatures", column_type = "JsonBinary")]
     pub experimental_features: Json,
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index 65eba72d7..bd4302441 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -15,10 +15,16 @@ impl_json_newtype!(JsonKeyword);
 pub struct JsonStringVec(pub Vec<String>);
 impl_json_newtype!(JsonStringVec);
 
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
+pub struct JsonI32Vec(pub Vec<i32>);
+impl_json_newtype!(JsonI32Vec);
+
 cfg_if! {
     if #[cfg(feature = "legacy")] {
         pub type StringVec = Vec<String>;
+        pub type I32Vec = Vec<i32>;
     } else {
         pub type StringVec = JsonStringVec;
+        pub type I32Vec = JsonI32Vec;
     }
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/note.rs b/packages/backend/native-utils/crates/model/src/entity/note.rs
index 2e733edae..c2f20c11b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note.rs
@@ -3,6 +3,8 @@
 use super::sea_orm_active_enums::NoteVisibilityEnum;
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note")]
 pub struct Model {
@@ -32,16 +34,16 @@ pub struct Model {
     pub uri: Option<String>,
     pub score: i32,
     #[sea_orm(column_name = "fileIds")]
-    pub file_ids: Vec<String>,
+    pub file_ids: StringVec,
     #[sea_orm(column_name = "attachedFileTypes")]
-    pub attached_file_types: Vec<String>,
+    pub attached_file_types: StringVec,
     #[sea_orm(column_name = "visibleUserIds")]
-    pub visible_user_ids: Vec<String>,
-    pub mentions: Vec<String>,
+    pub visible_user_ids: StringVec,
+    pub mentions: StringVec,
     #[sea_orm(column_name = "mentionedRemoteUsers", column_type = "Text")]
     pub mentioned_remote_users: String,
-    pub emojis: Vec<String>,
-    pub tags: Vec<String>,
+    pub emojis: StringVec,
+    pub tags: StringVec,
     #[sea_orm(column_name = "hasPoll")]
     pub has_poll: bool,
     #[sea_orm(column_name = "userHost")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
index 5e98b3da4..4e8f42083 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "note_edit")]
 pub struct Model {
@@ -13,7 +15,7 @@ pub struct Model {
     pub text: Option<String>,
     pub cw: Option<String>,
     #[sea_orm(column_name = "fileIds")]
-    pub file_ids: Vec<String>,
+    pub file_ids: StringVec,
     #[sea_orm(column_name = "updatedAt")]
     pub updated_at: DateTimeWithTimeZone,
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/page.rs b/packages/backend/native-utils/crates/model/src/entity/page.rs
index efb794944..c3d09fa8c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/page.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/page.rs
@@ -3,6 +3,8 @@
 use super::sea_orm_active_enums::PageVisibilityEnum;
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "page")]
 pub struct Model {
@@ -28,7 +30,7 @@ pub struct Model {
     pub variables: Json,
     pub visibility: PageVisibilityEnum,
     #[sea_orm(column_name = "visibleUserIds")]
-    pub visible_user_ids: Vec<String>,
+    pub visible_user_ids: StringVec,
     #[sea_orm(column_name = "likedCount")]
     pub liked_count: i32,
     #[sea_orm(column_name = "hideTitleWhenPinned")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll.rs b/packages/backend/native-utils/crates/model/src/entity/poll.rs
index a4d9e2df1..81953cfba 100644
--- a/packages/backend/native-utils/crates/model/src/entity/poll.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/poll.rs
@@ -3,6 +3,8 @@
 use super::sea_orm_active_enums::PollNotevisibilityEnum;
 use sea_orm::entity::prelude::*;
 
+use super::newtype::{I32Vec, StringVec};
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "poll")]
 pub struct Model {
@@ -11,8 +13,8 @@ pub struct Model {
     #[sea_orm(column_name = "expiresAt")]
     pub expires_at: Option<DateTimeWithTimeZone>,
     pub multiple: bool,
-    pub choices: Vec<String>,
-    pub votes: Vec<i32>,
+    pub choices: StringVec,
+    pub votes: I32Vec,
     #[sea_orm(column_name = "noteVisibility")]
     pub note_visibility: PollNotevisibilityEnum,
     #[sea_orm(column_name = "userId")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
index 6de0c740f..54d72d5d8 100644
--- a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "registry_item")]
 pub struct Model {
@@ -14,7 +16,7 @@ pub struct Model {
     #[sea_orm(column_name = "userId")]
     pub user_id: String,
     pub key: String,
-    pub scope: Vec<String>,
+    pub scope: StringVec,
     pub domain: Option<String>,
     #[sea_orm(column_type = "JsonBinary", nullable)]
     pub value: Option<Json>,
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
index 1e5359280..0c82fccf7 100644
--- a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "reversi_game")]
 pub struct Model {
@@ -29,7 +31,7 @@ pub struct Model {
     pub surrendered: Option<String>,
     #[sea_orm(column_type = "JsonBinary")]
     pub logs: Json,
-    pub map: Vec<String>,
+    pub map: StringVec,
     pub bw: String,
     #[sea_orm(column_name = "isLlotheo")]
     pub is_llotheo: bool,
diff --git a/packages/backend/native-utils/crates/model/src/entity/user.rs b/packages/backend/native-utils/crates/model/src/entity/user.rs
index 79b9fa692..1cf6ac6b7 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user")]
 pub struct Model {
@@ -27,7 +29,7 @@ pub struct Model {
     pub avatar_id: Option<String>,
     #[sea_orm(column_name = "bannerId", unique)]
     pub banner_id: Option<String>,
-    pub tags: Vec<String>,
+    pub tags: StringVec,
     #[sea_orm(column_name = "isSuspended")]
     pub is_suspended: bool,
     #[sea_orm(column_name = "isSilenced")]
@@ -42,7 +44,7 @@ pub struct Model {
     pub is_admin: bool,
     #[sea_orm(column_name = "isModerator")]
     pub is_moderator: bool,
-    pub emojis: Vec<String>,
+    pub emojis: StringVec,
     pub host: Option<String>,
     pub inbox: Option<String>,
     #[sea_orm(column_name = "sharedInbox")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
index 3a12469d8..d62607f16 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
@@ -3,6 +3,8 @@
 use super::sea_orm_active_enums::UserProfileFfvisibilityEnum;
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "user_profile")]
 pub struct Model {
@@ -53,7 +55,7 @@ pub struct Model {
     #[sea_orm(column_name = "mutedWords", column_type = "JsonBinary")]
     pub muted_words: Json,
     #[sea_orm(column_name = "mutingNotificationTypes")]
-    pub muting_notification_types: Vec<String>,
+    pub muting_notification_types: StringVec,
     #[sea_orm(column_name = "noCrawle")]
     pub no_crawle: bool,
     #[sea_orm(column_name = "receiveAnnouncementEmail")]
diff --git a/packages/backend/native-utils/crates/model/src/entity/webhook.rs b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
index 952dcbadb..dd3c3c738 100644
--- a/packages/backend/native-utils/crates/model/src/entity/webhook.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
@@ -2,6 +2,8 @@
 
 use sea_orm::entity::prelude::*;
 
+use super::newtype::StringVec;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
 #[sea_orm(table_name = "webhook")]
 pub struct Model {
@@ -12,7 +14,7 @@ pub struct Model {
     #[sea_orm(column_name = "userId")]
     pub user_id: String,
     pub name: String,
-    pub on: Vec<String>,
+    pub on: StringVec,
     pub url: String,
     pub secret: String,
     pub active: bool,

From 239dfeec9f1333ef9e7d916759e3ba2727d60090 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 04:01:25 -0400
Subject: [PATCH 26/66] add migration to convert array to jsonb

---
 .../src/m20230531_180824_stringvec.rs         | 395 ++++++++++++++++--
 .../native-utils/crates/model/Cargo.toml      |   6 +-
 .../crates/model/src/entity/mod.rs            |   2 -
 .../crates/model/src/entity/prelude.rs        |   2 -
 .../crates/model/src/entity/reversi_game.rs   |  69 ---
 .../model/src/entity/reversi_matching.rs      |  38 --
 .../native-utils/crates/model/tests/common.rs |   6 +-
 7 files changed, 365 insertions(+), 153 deletions(-)
 delete mode 100644 packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
 delete mode 100644 packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs

diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
index ba1fc257d..b7c0a70b3 100644
--- a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
+++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
@@ -1,7 +1,11 @@
-use model::entity::{antenna, newtype::StringVec};
+use model::entity::{
+    access_token, antenna, app, emoji, gallery_post, hashtag, messaging_message, meta,
+    newtype::{I32Vec, StringVec},
+    note, note_edit, poll, registry_item, user, user_profile, webhook,
+};
 use sea_orm_migration::{
     prelude::*,
-    sea_orm::{DbBackend, EntityTrait, Statement},
+    sea_orm::{DbBackend, EntityTrait, Statement, TryGetable},
 };
 use serde_json::json;
 
@@ -11,50 +15,220 @@ pub struct Migration;
 #[async_trait::async_trait]
 impl MigrationTrait for Migration {
     async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        manager
+            .drop_table(Table::drop().table(Alias::new("reversi_game")).to_owned())
+            .await?;
+
+        manager
+            .drop_table(
+                Table::drop()
+                    .table(Alias::new("reversi_matching"))
+                    .to_owned(),
+            )
+            .await?;
+
         if manager.get_database_backend() == DbBackend::Sqlite {
             return Ok(());
         }
 
         let db = manager.get_connection();
-        let query = Query::select()
-            .column(Antenna::Id)
-            .column(Antenna::Users)
-            .from(Antenna::Table)
-            .to_string(PostgresQueryBuilder);
-        let res: Vec<(String, Vec<String>)> = db
-            .query_all(Statement::from_string(DbBackend::Postgres, query))
-            .await?
-            .iter()
-            .filter_map(|r| r.try_get_many_by_index().ok())
-            .collect();
 
-        manager
-            .alter_table(
-                Table::alter()
-                    .table(Antenna::Table)
-                    .drop_column(Antenna::Users)
-                    .add_column(
-                        ColumnDef::new(Antenna::Users)
-                            .json_binary()
-                            .not_null()
-                            .default(json!([])),
-                    )
-                    .to_owned(),
-            )
-            .await?;
+        macro_rules! copy_data {
+            ($data:ident, $ent:ident, $col:tt) => {
+                let models: Vec<$ent::ActiveModel> = $data
+                    .iter()
+                    .map(|(id, r)| $ent::ActiveModel {
+                        id: sea_orm::Set(id.to_owned()),
+                        $col: sea_orm::Set(StringVec::from(r.to_owned())),
+                        ..Default::default()
+                    })
+                    .collect();
+                for model in models {
+                    $ent::Entity::update(model).exec(db).await?;
+                }
+            };
+        }
 
-        let models: Vec<antenna::ActiveModel> = res
+        macro_rules! convert_to_stringvec_json {
+            ($table:expr, $id:expr, $col:expr, $ent:ident, $col_name:tt) => {
+                let query = select_query($table, $id, $col);
+                let res = get_vec::<Vec<String>>(db, query).await?;
+                convert_col(manager, $table, $col).await?;
+                copy_data!(res, $ent, $col_name);
+            };
+        }
+
+        convert_to_stringvec_json!(
+            AccessToken::Table,
+            AccessToken::Id,
+            AccessToken::Permission,
+            access_token,
+            permission
+        );
+        convert_to_stringvec_json!(Antenna::Table, Antenna::Id, Antenna::Users, antenna, users);
+        convert_to_stringvec_json!(App::Table, App::Id, App::Permission, app, permission);
+        convert_to_stringvec_json!(Emoji::Table, Emoji::Id, Emoji::Aliases, emoji, aliases);
+        convert_to_stringvec_json!(
+            GalleryPost::Table,
+            GalleryPost::Id,
+            GalleryPost::FileIds,
+            gallery_post,
+            file_ids
+        );
+        convert_to_stringvec_json!(
+            GalleryPost::Table,
+            GalleryPost::Id,
+            GalleryPost::Tags,
+            gallery_post,
+            tags
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedUserIds,
+            hashtag,
+            mentioned_user_ids
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedLocalUserIds,
+            hashtag,
+            mentioned_local_user_ids
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedRemoteUserIds,
+            hashtag,
+            mentioned_remote_user_ids
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedUserIds,
+            hashtag,
+            attached_user_ids
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedLocalUserIds,
+            hashtag,
+            attached_local_user_ids
+        );
+        convert_to_stringvec_json!(
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedRemoteUserIds,
+            hashtag,
+            attached_remote_user_ids
+        );
+        convert_to_stringvec_json!(
+            MessagingMessage::Table,
+            MessagingMessage::Id,
+            MessagingMessage::Reads,
+            messaging_message,
+            reads
+        );
+        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::Langs, meta, langs);
+        convert_to_stringvec_json!(
+            Meta::Table,
+            Meta::Id,
+            Meta::BlockedHosts,
+            meta,
+            blocked_hosts
+        );
+        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::HiddenTags, meta, hidden_tags);
+        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedUsers, meta, pinned_users);
+        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedPages, meta, pinned_pages);
+        convert_to_stringvec_json!(
+            Meta::Table,
+            Meta::Id,
+            Meta::RecommendedInstances,
+            meta,
+            recommended_instances
+        );
+        convert_to_stringvec_json!(
+            Meta::Table,
+            Meta::Id,
+            Meta::SilencedHosts,
+            meta,
+            silenced_hosts
+        );
+        convert_to_stringvec_json!(Note::Table, Note::Id, Note::FileIds, note, file_ids);
+        convert_to_stringvec_json!(
+            Note::Table,
+            Note::Id,
+            Note::AttachedFileTypes,
+            note,
+            attached_file_types
+        );
+        convert_to_stringvec_json!(
+            Note::Table,
+            Note::Id,
+            Note::VisibleUserIds,
+            note,
+            visible_user_ids
+        );
+        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Mentions, note, mentions);
+        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Emojis, note, emojis);
+        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Tags, note, tags);
+        convert_to_stringvec_json!(
+            NoteEdit::Table,
+            NoteEdit::Id,
+            NoteEdit::FileIds,
+            note_edit,
+            file_ids
+        );
+
+        // Convert poll here because its primary key is not id, but note_id.
+        let query = select_query(Poll::Table, Poll::NoteId, Poll::Choices);
+        let res = get_vec::<Vec<String>>(db, query).await?;
+        convert_col(manager, Poll::Table, Poll::Choices).await?;
+        let poll_models: Vec<poll::ActiveModel> = res
             .iter()
-            .map(|(id, users)| antenna::ActiveModel {
-                id: sea_orm::Set(id.to_owned()),
-                users: sea_orm::Set(StringVec::from(users.to_owned())),
+            .map(|(id, r)| poll::ActiveModel {
+                note_id: sea_orm::Set(id.to_owned()),
+                choices: sea_orm::Set(StringVec::from(r.to_owned())),
                 ..Default::default()
             })
             .collect();
-
-        for model in models {
-            antenna::Entity::update(model).exec(db).await?;
+        for model in poll_models {
+            poll::Entity::update(model).exec(db).await?;
         }
+        let query = select_query(Poll::Table, Poll::NoteId, Poll::Votes);
+        let res = get_vec::<Vec<i32>>(db, query).await?;
+        convert_col(manager, Poll::Table, Poll::Votes).await?;
+        let poll_models: Vec<poll::ActiveModel> = res
+            .iter()
+            .map(|(id, r)| poll::ActiveModel {
+                note_id: sea_orm::Set(id.to_owned()),
+                votes: sea_orm::Set(I32Vec::from(r.to_owned())),
+                ..Default::default()
+            })
+            .collect();
+        for model in poll_models {
+            poll::Entity::update(model).exec(db).await?;
+        }
+
+        convert_to_stringvec_json!(
+            RegistryItem::Table,
+            RegistryItem::Id,
+            RegistryItem::Scope,
+            registry_item,
+            scope
+        );
+        convert_to_stringvec_json!(User::Table, User::Id, User::Tags, user, tags);
+        convert_to_stringvec_json!(User::Table, User::Id, User::Emojis, user, emojis);
+        convert_to_stringvec_json!(
+            UserProfile::Table,
+            UserProfile::Id,
+            UserProfile::MutingNotificationTypes,
+            user_profile,
+            muting_notification_types
+        );
+        convert_to_stringvec_json!(Webhook::Table, Webhook::Id, Webhook::On, webhook, on);
 
         Ok(())
     }
@@ -66,9 +240,160 @@ impl MigrationTrait for Migration {
 }
 
 /// Learn more at https://docs.rs/sea-query#iden
-#[derive(Iden)]
+#[derive(Iden, Clone)]
 enum Antenna {
     Table,
     Id,
     Users,
 }
+#[derive(Iden, Clone)]
+enum AccessToken {
+    Table,
+    Id,
+    Permission,
+}
+#[derive(Iden, Clone)]
+enum App {
+    Table,
+    Id,
+    Permission,
+}
+#[derive(Iden, Clone)]
+enum Emoji {
+    Table,
+    Id,
+    Aliases,
+}
+#[derive(Iden, Clone)]
+enum GalleryPost {
+    Table,
+    Id,
+    FileIds,
+    Tags,
+}
+#[derive(Iden, Clone)]
+enum Hashtag {
+    Table,
+    Id,
+    MentionedUserIds,
+    MentionedLocalUserIds,
+    MentionedRemoteUserIds,
+    AttachedUserIds,
+    AttachedLocalUserIds,
+    AttachedRemoteUserIds,
+}
+#[derive(Iden, Clone)]
+enum MessagingMessage {
+    Table,
+    Id,
+    Reads,
+}
+#[derive(Iden, Clone)]
+enum Meta {
+    Table,
+    Id,
+    Langs,
+    HiddenTags,
+    BlockedHosts,
+    PinnedUsers,
+    PinnedPages,
+    RecommendedInstances,
+    SilencedHosts,
+}
+#[derive(Iden, Clone)]
+enum Note {
+    Table,
+    Id,
+    FileIds,
+    AttachedFileTypes,
+    VisibleUserIds,
+    Mentions,
+    Emojis,
+    Tags,
+}
+#[derive(Iden, Clone)]
+enum NoteEdit {
+    Table,
+    Id,
+    FileIds,
+}
+#[derive(Iden, Clone)]
+enum Page {
+    Table,
+    Id,
+    VisibleUserIds,
+}
+#[derive(Iden, Clone)]
+enum Poll {
+    Table,
+    NoteId,
+    Choices,
+    Votes, // I32Vec
+}
+#[derive(Iden, Clone)]
+enum RegistryItem {
+    Table,
+    Id,
+    Scope,
+}
+#[derive(Iden, Clone)]
+enum User {
+    Table,
+    Id,
+    Tags,
+    Emojis,
+}
+#[derive(Iden, Clone)]
+enum UserProfile {
+    Table,
+    Id,
+    MutingNotificationTypes,
+}
+#[derive(Iden, Clone)]
+enum Webhook {
+    Table,
+    Id,
+    On,
+}
+
+fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
+    Query::select()
+        .column(id)
+        .column(col)
+        .from(table)
+        .to_string(PostgresQueryBuilder)
+}
+
+async fn get_vec<'a, T: TryGetable>(
+    db: &SchemaManagerConnection<'a>,
+    query: String,
+) -> Result<Vec<(String, T)>, DbErr> {
+    let res: Vec<(String, T)> = db
+        .query_all(Statement::from_string(DbBackend::Postgres, query))
+        .await?
+        .iter()
+        .filter_map(|r| r.try_get_many_by_index().ok())
+        .collect();
+    Ok(res)
+}
+
+async fn convert_col<'a, T: Iden + Clone + 'static>(
+    manager: &SchemaManager<'a>,
+    table: T,
+    col: T,
+) -> Result<(), DbErr> {
+    manager
+        .alter_table(
+            Table::alter()
+                .table(table)
+                .drop_column(col.to_owned())
+                .add_column(
+                    ColumnDef::new(col.to_owned())
+                        .json_binary()
+                        .not_null()
+                        .default(json!([])),
+                )
+                .to_owned(),
+        )
+        .await
+}
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index e99f8b561..a511e6e99 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [features]
-default = ["legacy"]
-legacy = ["sea-orm/postgres-array"]
+default = []
+legacy = []
 
 [dependencies]
 async-trait = "0.1.68"
@@ -18,7 +18,7 @@ jsonschema = "0.17.0"
 once_cell = "1.17.1"
 parse-display = "0.8.0"
 schemars = { version = "0.8.12", features = ["chrono"] }
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "sqlx-sqlite", "runtime-tokio-rustls"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "postgres-array", "sqlx-sqlite", "runtime-tokio-rustls"] }
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
 thiserror = "1.0.40"
diff --git a/packages/backend/native-utils/crates/model/src/entity/mod.rs b/packages/backend/native-utils/crates/model/src/entity/mod.rs
index 6105b0555..d71057fde 100644
--- a/packages/backend/native-utils/crates/model/src/entity/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/mod.rs
@@ -53,8 +53,6 @@ pub mod registration_ticket;
 pub mod registry_item;
 pub mod relay;
 pub mod renote_muting;
-pub mod reversi_game;
-pub mod reversi_matching;
 pub mod sea_orm_active_enums;
 pub mod signin;
 pub mod sw_subscription;
diff --git a/packages/backend/native-utils/crates/model/src/entity/prelude.rs b/packages/backend/native-utils/crates/model/src/entity/prelude.rs
index 7cab688bb..8be696cb4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/prelude.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/prelude.rs
@@ -50,8 +50,6 @@ pub use super::registration_ticket::Entity as RegistrationTicket;
 pub use super::registry_item::Entity as RegistryItem;
 pub use super::relay::Entity as Relay;
 pub use super::renote_muting::Entity as RenoteMuting;
-pub use super::reversi_game::Entity as ReversiGame;
-pub use super::reversi_matching::Entity as ReversiMatching;
 pub use super::signin::Entity as Signin;
 pub use super::sw_subscription::Entity as SwSubscription;
 pub use super::used_username::Entity as UsedUsername;
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
deleted file mode 100644
index 0c82fccf7..000000000
--- a/packages/backend/native-utils/crates/model/src/entity/reversi_game.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
-
-use sea_orm::entity::prelude::*;
-
-use super::newtype::StringVec;
-
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
-#[sea_orm(table_name = "reversi_game")]
-pub struct Model {
-    #[sea_orm(primary_key, auto_increment = false)]
-    pub id: String,
-    #[sea_orm(column_name = "createdAt")]
-    pub created_at: DateTimeWithTimeZone,
-    #[sea_orm(column_name = "startedAt")]
-    pub started_at: Option<DateTimeWithTimeZone>,
-    #[sea_orm(column_name = "user1Id")]
-    pub user1_id: String,
-    #[sea_orm(column_name = "user2Id")]
-    pub user2_id: String,
-    #[sea_orm(column_name = "user1Accepted")]
-    pub user1_accepted: bool,
-    #[sea_orm(column_name = "user2Accepted")]
-    pub user2_accepted: bool,
-    pub black: Option<i32>,
-    #[sea_orm(column_name = "isStarted")]
-    pub is_started: bool,
-    #[sea_orm(column_name = "isEnded")]
-    pub is_ended: bool,
-    #[sea_orm(column_name = "winnerId")]
-    pub winner_id: Option<String>,
-    pub surrendered: Option<String>,
-    #[sea_orm(column_type = "JsonBinary")]
-    pub logs: Json,
-    pub map: StringVec,
-    pub bw: String,
-    #[sea_orm(column_name = "isLlotheo")]
-    pub is_llotheo: bool,
-    #[sea_orm(column_name = "canPutEverywhere")]
-    pub can_put_everywhere: bool,
-    #[sea_orm(column_name = "loopedBoard")]
-    pub looped_board: bool,
-    #[sea_orm(column_type = "JsonBinary", nullable)]
-    pub form1: Option<Json>,
-    #[sea_orm(column_type = "JsonBinary", nullable)]
-    pub form2: Option<Json>,
-    pub crc32: Option<String>,
-}
-
-#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
-pub enum Relation {
-    #[sea_orm(
-        belongs_to = "super::user::Entity",
-        from = "Column::User2Id",
-        to = "super::user::Column::Id",
-        on_update = "NoAction",
-        on_delete = "Cascade"
-    )]
-    User2,
-    #[sea_orm(
-        belongs_to = "super::user::Entity",
-        from = "Column::User1Id",
-        to = "super::user::Column::Id",
-        on_update = "NoAction",
-        on_delete = "Cascade"
-    )]
-    User1,
-}
-
-impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs b/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
deleted file mode 100644
index aafdf13f6..000000000
--- a/packages/backend/native-utils/crates/model/src/entity/reversi_matching.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
-
-use sea_orm::entity::prelude::*;
-
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
-#[sea_orm(table_name = "reversi_matching")]
-pub struct Model {
-    #[sea_orm(primary_key, auto_increment = false)]
-    pub id: String,
-    #[sea_orm(column_name = "createdAt")]
-    pub created_at: DateTimeWithTimeZone,
-    #[sea_orm(column_name = "parentId")]
-    pub parent_id: String,
-    #[sea_orm(column_name = "childId")]
-    pub child_id: String,
-}
-
-#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
-pub enum Relation {
-    #[sea_orm(
-        belongs_to = "super::user::Entity",
-        from = "Column::ParentId",
-        to = "super::user::Column::Id",
-        on_update = "NoAction",
-        on_delete = "Cascade"
-    )]
-    User2,
-    #[sea_orm(
-        belongs_to = "super::user::Entity",
-        from = "Column::ChildId",
-        to = "super::user::Column::Id",
-        on_update = "NoAction",
-        on_delete = "Cascade"
-    )]
-    User1,
-}
-
-impl ActiveModelBehavior for ActiveModel {}
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index f05c4432d..0fd32d8f9 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -31,7 +31,7 @@ async fn setup_schema(db: DbConn) {
     let stmt = schema.create_table_from_entity(antenna::Entity);
     db.execute(db.get_database_backend().build(&stmt))
         .await
-        .expect("Unable to initialize in-memoty sqlite");
+        .expect("Unable to setup schemas for in-memoty sqlite");
 }
 
 /// Delete all entries in the database.
@@ -101,9 +101,7 @@ async fn setup_model(db: &DbConn) {
 mod int_test {
     use sea_orm::Database;
 
-    use crate::setup_schema;
-
-    use super::{cleanup, prepare};
+    use super::{cleanup, prepare, setup_schema};
 
     #[tokio::test]
     async fn can_prepare_and_cleanup() {

From d533734575c4c5070fd5cd9b93c4fb564048e06d Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 04:06:31 -0400
Subject: [PATCH 27/66] fix primary key specifier

---
 .../src/m20230531_180824_stringvec.rs         | 104 +++++++++++-------
 1 file changed, 64 insertions(+), 40 deletions(-)

diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
index b7c0a70b3..d9c54fd74 100644
--- a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
+++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
@@ -1,7 +1,7 @@
 use model::entity::{
     access_token, antenna, app, emoji, gallery_post, hashtag, messaging_message, meta,
     newtype::{I32Vec, StringVec},
-    note, note_edit, poll, registry_item, user, user_profile, webhook,
+    note, note_edit, page, poll, registry_item, user, user_profile, webhook,
 };
 use sea_orm_migration::{
     prelude::*,
@@ -181,37 +181,13 @@ impl MigrationTrait for Migration {
             note_edit,
             file_ids
         );
-
-        // Convert poll here because its primary key is not id, but note_id.
-        let query = select_query(Poll::Table, Poll::NoteId, Poll::Choices);
-        let res = get_vec::<Vec<String>>(db, query).await?;
-        convert_col(manager, Poll::Table, Poll::Choices).await?;
-        let poll_models: Vec<poll::ActiveModel> = res
-            .iter()
-            .map(|(id, r)| poll::ActiveModel {
-                note_id: sea_orm::Set(id.to_owned()),
-                choices: sea_orm::Set(StringVec::from(r.to_owned())),
-                ..Default::default()
-            })
-            .collect();
-        for model in poll_models {
-            poll::Entity::update(model).exec(db).await?;
-        }
-        let query = select_query(Poll::Table, Poll::NoteId, Poll::Votes);
-        let res = get_vec::<Vec<i32>>(db, query).await?;
-        convert_col(manager, Poll::Table, Poll::Votes).await?;
-        let poll_models: Vec<poll::ActiveModel> = res
-            .iter()
-            .map(|(id, r)| poll::ActiveModel {
-                note_id: sea_orm::Set(id.to_owned()),
-                votes: sea_orm::Set(I32Vec::from(r.to_owned())),
-                ..Default::default()
-            })
-            .collect();
-        for model in poll_models {
-            poll::Entity::update(model).exec(db).await?;
-        }
-
+        convert_to_stringvec_json!(
+            Page::Table,
+            Page::Id,
+            Page::VisibleUserIds,
+            page,
+            visible_user_ids
+        );
         convert_to_stringvec_json!(
             RegistryItem::Table,
             RegistryItem::Id,
@@ -221,15 +197,63 @@ impl MigrationTrait for Migration {
         );
         convert_to_stringvec_json!(User::Table, User::Id, User::Tags, user, tags);
         convert_to_stringvec_json!(User::Table, User::Id, User::Emojis, user, emojis);
-        convert_to_stringvec_json!(
-            UserProfile::Table,
-            UserProfile::Id,
-            UserProfile::MutingNotificationTypes,
-            user_profile,
-            muting_notification_types
-        );
         convert_to_stringvec_json!(Webhook::Table, Webhook::Id, Webhook::On, webhook, on);
 
+        // Convert poll here because its primary key is not id, but note_id.
+        let query = select_query(Poll::Table, Poll::NoteId, Poll::Choices);
+        let res = get_vec::<Vec<String>>(db, query).await?;
+        convert_col(manager, Poll::Table, Poll::Choices).await?;
+        let models: Vec<poll::ActiveModel> = res
+            .iter()
+            .map(|(id, r)| poll::ActiveModel {
+                note_id: sea_orm::Set(id.to_owned()),
+                choices: sea_orm::Set(StringVec::from(r.to_owned())),
+                ..Default::default()
+            })
+            .collect();
+        for model in models {
+            poll::Entity::update(model).exec(db).await?;
+        }
+        let query = select_query(Poll::Table, Poll::NoteId, Poll::Votes);
+        let res = get_vec::<Vec<i32>>(db, query).await?;
+        convert_col(manager, Poll::Table, Poll::Votes).await?;
+        let models: Vec<poll::ActiveModel> = res
+            .iter()
+            .map(|(id, r)| poll::ActiveModel {
+                note_id: sea_orm::Set(id.to_owned()),
+                votes: sea_orm::Set(I32Vec::from(r.to_owned())),
+                ..Default::default()
+            })
+            .collect();
+        for model in models {
+            poll::Entity::update(model).exec(db).await?;
+        }
+
+        // Convert user_profile here because its primary key is not id, but user_id.
+        let query = select_query(
+            UserProfile::Table,
+            UserProfile::UserId,
+            UserProfile::MutingNotificationTypes,
+        );
+        let res = get_vec::<Vec<String>>(db, query).await?;
+        convert_col(
+            manager,
+            UserProfile::Table,
+            UserProfile::MutingNotificationTypes,
+        )
+        .await?;
+        let models: Vec<user_profile::ActiveModel> = res
+            .iter()
+            .map(|(id, r)| user_profile::ActiveModel {
+                user_id: sea_orm::Set(id.to_owned()),
+                muting_notification_types: sea_orm::Set(StringVec::from(r.to_owned())),
+                ..Default::default()
+            })
+            .collect();
+        for model in models {
+            user_profile::Entity::update(model).exec(db).await?;
+        }
+
         Ok(())
     }
 
@@ -346,7 +370,7 @@ enum User {
 #[derive(Iden, Clone)]
 enum UserProfile {
     Table,
-    Id,
+    UserId,
     MutingNotificationTypes,
 }
 #[derive(Iden, Clone)]

From a98093bd61b1d5055694d3a6ad01db31c25ee302 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 04:24:45 -0400
Subject: [PATCH 28/66] use iden enum

---
 .../src/m20230531_180824_stringvec.rs          | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
index d9c54fd74..e561e18d5 100644
--- a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
+++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
@@ -16,13 +16,19 @@ pub struct Migration;
 impl MigrationTrait for Migration {
     async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
         manager
-            .drop_table(Table::drop().table(Alias::new("reversi_game")).to_owned())
+            .drop_table(
+                Table::drop()
+                    .if_exists()
+                    .table(ReversiGame::Table)
+                    .to_owned(),
+            )
             .await?;
 
         manager
             .drop_table(
                 Table::drop()
-                    .table(Alias::new("reversi_matching"))
+                    .if_exists()
+                    .table(ReversiMatching::Table)
                     .to_owned(),
             )
             .await?;
@@ -379,6 +385,14 @@ enum Webhook {
     Id,
     On,
 }
+#[derive(Iden)]
+enum ReversiGame {
+    Table,
+}
+#[derive(Iden)]
+enum ReversiMatching {
+    Table,
+}
 
 fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
     Query::select()

From d059dc53c0f6b83b675cef833798431916d76003 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 12:32:15 -0400
Subject: [PATCH 29/66] use thread to copy data

---
 .../native-utils/crates/migration/Cargo.toml  |   7 +
 .../native-utils/crates/migration/src/lib.rs  |   4 +-
 .../src/m20230531_180824_drop_reversi.rs      |  49 ++
 .../src/m20230531_180824_stringvec.rs         | 437 ------------------
 .../native-utils/crates/migration/src/main.rs |   5 +
 .../crates/migration/src/vec_to_json.rs       | 279 +++++++++++
 6 files changed, 342 insertions(+), 439 deletions(-)
 create mode 100644 packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs
 delete mode 100644 packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
 create mode 100644 packages/backend/native-utils/crates/migration/src/vec_to_json.rs

diff --git a/packages/backend/native-utils/crates/migration/Cargo.toml b/packages/backend/native-utils/crates/migration/Cargo.toml
index 46108c68c..49accc9a2 100644
--- a/packages/backend/native-utils/crates/migration/Cargo.toml
+++ b/packages/backend/native-utils/crates/migration/Cargo.toml
@@ -8,10 +8,17 @@ publish = false
 name = "migration"
 path = "src/lib.rs"
 
+[features]
+default = []
+convert = []
+
 [dependencies]
 async-std = { version = "1", features = ["attributes", "tokio1"] }
 serde_json = "1.0.96"
 model = { path = "../model" }
+indicatif = { version = "0.17.4", features = ["tokio"] }
+tokio = { version = "1.28.2", features = ["full"] }
+futures = "0.3.28"
 
 [dependencies.sea-orm-migration]
 version = "0.11.0"
diff --git a/packages/backend/native-utils/crates/migration/src/lib.rs b/packages/backend/native-utils/crates/migration/src/lib.rs
index a2a1b932f..4835c2d3d 100644
--- a/packages/backend/native-utils/crates/migration/src/lib.rs
+++ b/packages/backend/native-utils/crates/migration/src/lib.rs
@@ -1,12 +1,12 @@
 pub use sea_orm_migration::prelude::*;
 
-mod m20230531_180824_stringvec;
+mod m20230531_180824_drop_reversi;
 
 pub struct Migrator;
 
 #[async_trait::async_trait]
 impl MigratorTrait for Migrator {
     fn migrations() -> Vec<Box<dyn MigrationTrait>> {
-        vec![Box::new(m20230531_180824_stringvec::Migration)]
+        vec![Box::new(m20230531_180824_drop_reversi::Migration)]
     }
 }
diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs
new file mode 100644
index 000000000..c2726dd76
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs
@@ -0,0 +1,49 @@
+use sea_orm_migration::{
+    prelude::*,
+    sea_orm::{DbBackend, Statement},
+};
+
+#[derive(DeriveMigrationName)]
+pub struct Migration;
+
+#[async_trait::async_trait]
+impl MigrationTrait for Migration {
+    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        if manager.get_database_backend() == DbBackend::Sqlite {
+            return Ok(());
+        }
+
+        let db = manager.get_connection();
+        db.query_one(Statement::from_string(
+            DbBackend::Postgres,
+            Table::drop()
+                .table(ReversiGame::Table)
+                .to_string(PostgresQueryBuilder),
+        ))
+        .await?;
+        db.query_one(Statement::from_string(
+            DbBackend::Postgres,
+            Table::drop()
+                .table(ReversiMatching::Table)
+                .to_string(PostgresQueryBuilder),
+        ))
+        .await?;
+
+        Ok(())
+    }
+
+    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
+        // Replace the sample below with your own migration scripts
+        Ok(())
+    }
+}
+
+/// Learn more at https://docs.rs/sea-query#iden
+#[derive(Iden)]
+enum ReversiGame {
+    Table,
+}
+#[derive(Iden)]
+enum ReversiMatching {
+    Table,
+}
diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
deleted file mode 100644
index e561e18d5..000000000
--- a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs
+++ /dev/null
@@ -1,437 +0,0 @@
-use model::entity::{
-    access_token, antenna, app, emoji, gallery_post, hashtag, messaging_message, meta,
-    newtype::{I32Vec, StringVec},
-    note, note_edit, page, poll, registry_item, user, user_profile, webhook,
-};
-use sea_orm_migration::{
-    prelude::*,
-    sea_orm::{DbBackend, EntityTrait, Statement, TryGetable},
-};
-use serde_json::json;
-
-#[derive(DeriveMigrationName)]
-pub struct Migration;
-
-#[async_trait::async_trait]
-impl MigrationTrait for Migration {
-    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
-        manager
-            .drop_table(
-                Table::drop()
-                    .if_exists()
-                    .table(ReversiGame::Table)
-                    .to_owned(),
-            )
-            .await?;
-
-        manager
-            .drop_table(
-                Table::drop()
-                    .if_exists()
-                    .table(ReversiMatching::Table)
-                    .to_owned(),
-            )
-            .await?;
-
-        if manager.get_database_backend() == DbBackend::Sqlite {
-            return Ok(());
-        }
-
-        let db = manager.get_connection();
-
-        macro_rules! copy_data {
-            ($data:ident, $ent:ident, $col:tt) => {
-                let models: Vec<$ent::ActiveModel> = $data
-                    .iter()
-                    .map(|(id, r)| $ent::ActiveModel {
-                        id: sea_orm::Set(id.to_owned()),
-                        $col: sea_orm::Set(StringVec::from(r.to_owned())),
-                        ..Default::default()
-                    })
-                    .collect();
-                for model in models {
-                    $ent::Entity::update(model).exec(db).await?;
-                }
-            };
-        }
-
-        macro_rules! convert_to_stringvec_json {
-            ($table:expr, $id:expr, $col:expr, $ent:ident, $col_name:tt) => {
-                let query = select_query($table, $id, $col);
-                let res = get_vec::<Vec<String>>(db, query).await?;
-                convert_col(manager, $table, $col).await?;
-                copy_data!(res, $ent, $col_name);
-            };
-        }
-
-        convert_to_stringvec_json!(
-            AccessToken::Table,
-            AccessToken::Id,
-            AccessToken::Permission,
-            access_token,
-            permission
-        );
-        convert_to_stringvec_json!(Antenna::Table, Antenna::Id, Antenna::Users, antenna, users);
-        convert_to_stringvec_json!(App::Table, App::Id, App::Permission, app, permission);
-        convert_to_stringvec_json!(Emoji::Table, Emoji::Id, Emoji::Aliases, emoji, aliases);
-        convert_to_stringvec_json!(
-            GalleryPost::Table,
-            GalleryPost::Id,
-            GalleryPost::FileIds,
-            gallery_post,
-            file_ids
-        );
-        convert_to_stringvec_json!(
-            GalleryPost::Table,
-            GalleryPost::Id,
-            GalleryPost::Tags,
-            gallery_post,
-            tags
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::MentionedUserIds,
-            hashtag,
-            mentioned_user_ids
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::MentionedLocalUserIds,
-            hashtag,
-            mentioned_local_user_ids
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::MentionedRemoteUserIds,
-            hashtag,
-            mentioned_remote_user_ids
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::AttachedUserIds,
-            hashtag,
-            attached_user_ids
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::AttachedLocalUserIds,
-            hashtag,
-            attached_local_user_ids
-        );
-        convert_to_stringvec_json!(
-            Hashtag::Table,
-            Hashtag::Id,
-            Hashtag::AttachedRemoteUserIds,
-            hashtag,
-            attached_remote_user_ids
-        );
-        convert_to_stringvec_json!(
-            MessagingMessage::Table,
-            MessagingMessage::Id,
-            MessagingMessage::Reads,
-            messaging_message,
-            reads
-        );
-        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::Langs, meta, langs);
-        convert_to_stringvec_json!(
-            Meta::Table,
-            Meta::Id,
-            Meta::BlockedHosts,
-            meta,
-            blocked_hosts
-        );
-        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::HiddenTags, meta, hidden_tags);
-        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedUsers, meta, pinned_users);
-        convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedPages, meta, pinned_pages);
-        convert_to_stringvec_json!(
-            Meta::Table,
-            Meta::Id,
-            Meta::RecommendedInstances,
-            meta,
-            recommended_instances
-        );
-        convert_to_stringvec_json!(
-            Meta::Table,
-            Meta::Id,
-            Meta::SilencedHosts,
-            meta,
-            silenced_hosts
-        );
-        convert_to_stringvec_json!(Note::Table, Note::Id, Note::FileIds, note, file_ids);
-        convert_to_stringvec_json!(
-            Note::Table,
-            Note::Id,
-            Note::AttachedFileTypes,
-            note,
-            attached_file_types
-        );
-        convert_to_stringvec_json!(
-            Note::Table,
-            Note::Id,
-            Note::VisibleUserIds,
-            note,
-            visible_user_ids
-        );
-        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Mentions, note, mentions);
-        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Emojis, note, emojis);
-        convert_to_stringvec_json!(Note::Table, Note::Id, Note::Tags, note, tags);
-        convert_to_stringvec_json!(
-            NoteEdit::Table,
-            NoteEdit::Id,
-            NoteEdit::FileIds,
-            note_edit,
-            file_ids
-        );
-        convert_to_stringvec_json!(
-            Page::Table,
-            Page::Id,
-            Page::VisibleUserIds,
-            page,
-            visible_user_ids
-        );
-        convert_to_stringvec_json!(
-            RegistryItem::Table,
-            RegistryItem::Id,
-            RegistryItem::Scope,
-            registry_item,
-            scope
-        );
-        convert_to_stringvec_json!(User::Table, User::Id, User::Tags, user, tags);
-        convert_to_stringvec_json!(User::Table, User::Id, User::Emojis, user, emojis);
-        convert_to_stringvec_json!(Webhook::Table, Webhook::Id, Webhook::On, webhook, on);
-
-        // Convert poll here because its primary key is not id, but note_id.
-        let query = select_query(Poll::Table, Poll::NoteId, Poll::Choices);
-        let res = get_vec::<Vec<String>>(db, query).await?;
-        convert_col(manager, Poll::Table, Poll::Choices).await?;
-        let models: Vec<poll::ActiveModel> = res
-            .iter()
-            .map(|(id, r)| poll::ActiveModel {
-                note_id: sea_orm::Set(id.to_owned()),
-                choices: sea_orm::Set(StringVec::from(r.to_owned())),
-                ..Default::default()
-            })
-            .collect();
-        for model in models {
-            poll::Entity::update(model).exec(db).await?;
-        }
-        let query = select_query(Poll::Table, Poll::NoteId, Poll::Votes);
-        let res = get_vec::<Vec<i32>>(db, query).await?;
-        convert_col(manager, Poll::Table, Poll::Votes).await?;
-        let models: Vec<poll::ActiveModel> = res
-            .iter()
-            .map(|(id, r)| poll::ActiveModel {
-                note_id: sea_orm::Set(id.to_owned()),
-                votes: sea_orm::Set(I32Vec::from(r.to_owned())),
-                ..Default::default()
-            })
-            .collect();
-        for model in models {
-            poll::Entity::update(model).exec(db).await?;
-        }
-
-        // Convert user_profile here because its primary key is not id, but user_id.
-        let query = select_query(
-            UserProfile::Table,
-            UserProfile::UserId,
-            UserProfile::MutingNotificationTypes,
-        );
-        let res = get_vec::<Vec<String>>(db, query).await?;
-        convert_col(
-            manager,
-            UserProfile::Table,
-            UserProfile::MutingNotificationTypes,
-        )
-        .await?;
-        let models: Vec<user_profile::ActiveModel> = res
-            .iter()
-            .map(|(id, r)| user_profile::ActiveModel {
-                user_id: sea_orm::Set(id.to_owned()),
-                muting_notification_types: sea_orm::Set(StringVec::from(r.to_owned())),
-                ..Default::default()
-            })
-            .collect();
-        for model in models {
-            user_profile::Entity::update(model).exec(db).await?;
-        }
-
-        Ok(())
-    }
-
-    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
-        // Replace the sample below with your own migration scripts
-        Ok(())
-    }
-}
-
-/// Learn more at https://docs.rs/sea-query#iden
-#[derive(Iden, Clone)]
-enum Antenna {
-    Table,
-    Id,
-    Users,
-}
-#[derive(Iden, Clone)]
-enum AccessToken {
-    Table,
-    Id,
-    Permission,
-}
-#[derive(Iden, Clone)]
-enum App {
-    Table,
-    Id,
-    Permission,
-}
-#[derive(Iden, Clone)]
-enum Emoji {
-    Table,
-    Id,
-    Aliases,
-}
-#[derive(Iden, Clone)]
-enum GalleryPost {
-    Table,
-    Id,
-    FileIds,
-    Tags,
-}
-#[derive(Iden, Clone)]
-enum Hashtag {
-    Table,
-    Id,
-    MentionedUserIds,
-    MentionedLocalUserIds,
-    MentionedRemoteUserIds,
-    AttachedUserIds,
-    AttachedLocalUserIds,
-    AttachedRemoteUserIds,
-}
-#[derive(Iden, Clone)]
-enum MessagingMessage {
-    Table,
-    Id,
-    Reads,
-}
-#[derive(Iden, Clone)]
-enum Meta {
-    Table,
-    Id,
-    Langs,
-    HiddenTags,
-    BlockedHosts,
-    PinnedUsers,
-    PinnedPages,
-    RecommendedInstances,
-    SilencedHosts,
-}
-#[derive(Iden, Clone)]
-enum Note {
-    Table,
-    Id,
-    FileIds,
-    AttachedFileTypes,
-    VisibleUserIds,
-    Mentions,
-    Emojis,
-    Tags,
-}
-#[derive(Iden, Clone)]
-enum NoteEdit {
-    Table,
-    Id,
-    FileIds,
-}
-#[derive(Iden, Clone)]
-enum Page {
-    Table,
-    Id,
-    VisibleUserIds,
-}
-#[derive(Iden, Clone)]
-enum Poll {
-    Table,
-    NoteId,
-    Choices,
-    Votes, // I32Vec
-}
-#[derive(Iden, Clone)]
-enum RegistryItem {
-    Table,
-    Id,
-    Scope,
-}
-#[derive(Iden, Clone)]
-enum User {
-    Table,
-    Id,
-    Tags,
-    Emojis,
-}
-#[derive(Iden, Clone)]
-enum UserProfile {
-    Table,
-    UserId,
-    MutingNotificationTypes,
-}
-#[derive(Iden, Clone)]
-enum Webhook {
-    Table,
-    Id,
-    On,
-}
-#[derive(Iden)]
-enum ReversiGame {
-    Table,
-}
-#[derive(Iden)]
-enum ReversiMatching {
-    Table,
-}
-
-fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
-    Query::select()
-        .column(id)
-        .column(col)
-        .from(table)
-        .to_string(PostgresQueryBuilder)
-}
-
-async fn get_vec<'a, T: TryGetable>(
-    db: &SchemaManagerConnection<'a>,
-    query: String,
-) -> Result<Vec<(String, T)>, DbErr> {
-    let res: Vec<(String, T)> = db
-        .query_all(Statement::from_string(DbBackend::Postgres, query))
-        .await?
-        .iter()
-        .filter_map(|r| r.try_get_many_by_index().ok())
-        .collect();
-    Ok(res)
-}
-
-async fn convert_col<'a, T: Iden + Clone + 'static>(
-    manager: &SchemaManager<'a>,
-    table: T,
-    col: T,
-) -> Result<(), DbErr> {
-    manager
-        .alter_table(
-            Table::alter()
-                .table(table)
-                .drop_column(col.to_owned())
-                .add_column(
-                    ColumnDef::new(col.to_owned())
-                        .json_binary()
-                        .not_null()
-                        .default(json!([])),
-                )
-                .to_owned(),
-        )
-        .await
-}
diff --git a/packages/backend/native-utils/crates/migration/src/main.rs b/packages/backend/native-utils/crates/migration/src/main.rs
index c6b6e48db..31a72026e 100644
--- a/packages/backend/native-utils/crates/migration/src/main.rs
+++ b/packages/backend/native-utils/crates/migration/src/main.rs
@@ -1,6 +1,11 @@
 use sea_orm_migration::prelude::*;
 
+mod vec_to_json;
+
 #[async_std::main]
 async fn main() {
     cli::run_cli(migration::Migrator).await;
+
+    #[cfg(feature = "convert")]
+    vec_to_json::convert().await;
 }
diff --git a/packages/backend/native-utils/crates/migration/src/vec_to_json.rs b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs
new file mode 100644
index 000000000..eccd80114
--- /dev/null
+++ b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs
@@ -0,0 +1,279 @@
+#![allow(dead_code)]
+
+use sea_orm_migration::{prelude::*, sea_orm::{DbConn, DbBackend, Statement, TryGetable, Database}};
+use serde_json::json;
+use std::time::Duration;
+use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
+use model::entity::newtype::{I32Vec, StringVec};
+use std::env;
+
+pub async fn convert() {
+    let uri = env::var("DATABASE_URL").expect("Environment variable 'DATABASE_URL' not set");
+
+    let db = Database::connect(uri).await.expect("Unable to connect");
+    let mp = MultiProgress::new();
+
+    let handlers = vec![
+        tokio::spawn(to_json::<AccessToken, Vec<String>, StringVec>(db.clone(), mp.clone(), AccessToken::Table, AccessToken::Id, AccessToken::Permission)),
+        tokio::spawn(to_json::<Antenna, Vec<String>, StringVec>(db.clone(), mp.clone(), Antenna::Table, Antenna::Id, Antenna::Users)),
+        tokio::spawn(to_json::<App, Vec<String>, StringVec>(db.clone(), mp.clone(), App::Table, App::Id, App::Permission)),
+        tokio::spawn(to_json::<Emoji, Vec<String>, StringVec>(db.clone(), mp.clone(), Emoji::Table, Emoji::Id, Emoji::Aliases)),
+        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::FileIds)),
+        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::Tags)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedUserIds)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedLocalUserIds)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedRemoteUserIds)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedUserIds)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedLocalUserIds)),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedRemoteUserIds)),
+        tokio::spawn(to_json::<MessagingMessage, Vec<String>, StringVec>(db.clone(), mp.clone(), MessagingMessage::Table, MessagingMessage::Id, MessagingMessage::Reads)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::Langs)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::BlockedHosts)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::HiddenTags)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedUsers)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedPages)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::RecommendedInstances)),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::SilencedHosts)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::FileIds)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::AttachedFileTypes)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::VisibleUserIds)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Mentions)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Emojis)),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Tags)),
+        tokio::spawn(to_json::<NoteEdit, Vec<String>, StringVec>(db.clone(), mp.clone(), NoteEdit::Table, NoteEdit::Id, NoteEdit::FileIds)),
+        tokio::spawn(to_json::<Page, Vec<String>, StringVec>(db.clone(), mp.clone(), Page::Table, Page::Id, Page::VisibleUserIds)),
+        tokio::spawn(to_json::<RegistryItem, Vec<String>, StringVec>(db.clone(), mp.clone(), RegistryItem::Table, RegistryItem::Id, RegistryItem::Scope)),
+        tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Tags)),
+        tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Emojis)),
+        tokio::spawn(to_json::<Webhook, Vec<String>, StringVec>(db.clone(), mp.clone(), Webhook::Table, Webhook::Id, Webhook::On)),
+        tokio::spawn(to_json::<Poll, Vec<String>, StringVec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Choices)),
+        tokio::spawn(to_json::<Poll, Vec<i32>, I32Vec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Votes)),
+        tokio::spawn(to_json::<UserProfile, Vec<String>, StringVec>(db.clone(), mp.clone(), UserProfile::Table, UserProfile::UserId, UserProfile::MutingNotificationTypes)),
+    ];
+
+    futures::future::join_all(handlers).await;
+}
+
+fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
+    Query::select()
+        .column(id)
+        .column(col)
+        .from(table)
+        .to_string(PostgresQueryBuilder)
+}
+
+async fn get_vec<T: TryGetable>(
+    db: &DbConn,
+    query: String,
+) -> Result<Vec<(String, T)>, DbErr> {
+    let res: Vec<(String, T)> = db
+        .query_all(Statement::from_string(DbBackend::Postgres, query))
+        .await?
+        .iter()
+        .filter_map(|r| r.try_get_many_by_index().ok())
+        .collect();
+    Ok(res)
+}
+
+async fn convert_col<T: Iden + Clone + 'static>(
+    db: &DbConn,
+    table: T,
+    col: T,
+) -> Result<(), DbErr> {
+    let stmt = Table::alter()
+                .table(table)
+                .drop_column(col.to_owned())
+                .add_column(
+                    ColumnDef::new(col.to_owned())
+                        .json_binary()
+                        .not_null()
+                        .default(json!([])),
+                ).to_string(PostgresQueryBuilder);
+    db.query_one(Statement::from_string(DbBackend::Postgres, stmt)).await?;
+    Ok(())
+}
+
+async fn to_json<T, U, V>(
+    db: DbConn,
+    mp: MultiProgress,
+    table: T,
+    id: T,
+    col: T,
+) -> Result<(), DbErr>
+where
+    T: Iden + Clone + 'static,
+    U: TryGetable + Clone,
+    V: From<U> + Into<SimpleExpr>,
+{
+    let query = select_query(table.clone(), id.clone(), col.clone());
+    let loading = ProgressBar::new_spinner()
+        .with_style(ProgressStyle::with_template("{prefix} {msg} {spinner}").unwrap())
+        .with_prefix("[-]")
+        .with_message(format!("Loading data from {}.{}", table.to_string(), col.to_string()));
+    loading.enable_steady_tick(Duration::from_millis(100));
+    let loading = mp.add(loading);
+    let res = get_vec::<U>(&db, query).await?;
+    let models: Vec<(String, V)> = res
+        .iter()
+        .map(|(id, r)| (id.clone(), <V>::from(r.clone())))
+        .collect();
+    loading.finish_and_clear();
+    convert_col(&db, table.clone(), col.clone()).await?;
+
+    let progress = ProgressBar::new(models.len() as u64)
+        .with_style(ProgressStyle::with_template("{prefix} {msg} {wide_bar} {pos}/{len}").unwrap().progress_chars("##-"))
+        .with_prefix("[*]")
+        .with_message(format!("Copying {}.{}", table.to_string(), col.to_string()));
+    let progress = mp.add(progress);
+
+    for model in models {
+        progress.inc(1);
+        let q = Query::update()
+            .table(table.clone())
+            .values([(col.clone(), model.1.into())])
+            .and_where(Expr::col(id.clone()).eq(model.0))
+            .to_string(PostgresQueryBuilder);
+        db.query_one(Statement::from_string(DbBackend::Postgres, q))
+            .await?;
+    }
+    progress.finish_with_message(format!("Complete {}.{}", table.to_string(), col.to_string()));
+
+    Ok(())
+}
+
+#[derive(Iden, Clone)]
+enum AccessToken {
+    Table,
+    Id,
+    Permission,
+}
+#[derive(Iden, Clone)]
+enum Antenna {
+    Table,
+    Id,
+    Users,
+}
+#[derive(Iden, Clone)]
+enum App {
+    Table,
+    Id,
+    Permission,
+}
+#[derive(Iden, Clone)]
+enum Emoji {
+    Table,
+    Id,
+    Aliases,
+}
+#[derive(Iden, Clone)]
+enum GalleryPost {
+    Table,
+    Id,
+    #[iden = "fileIds"]
+    FileIds,
+    Tags,
+}
+#[derive(Iden, Clone)]
+enum Hashtag {
+    Table,
+    Id,
+    #[iden = "mentionedUserIds"]
+    MentionedUserIds,
+    #[iden = "mentionedLocalUserIds"]
+    MentionedLocalUserIds,
+    #[iden = "mentionedRemoteUserIds"]
+    MentionedRemoteUserIds,
+    #[iden = "attachedUserIds"]
+    AttachedUserIds,
+    #[iden = "attachedLocalUserIds"]
+    AttachedLocalUserIds,
+    #[iden = "attachedRemoteUserIds"]
+    AttachedRemoteUserIds,
+}
+#[derive(Iden, Clone)]
+enum MessagingMessage {
+    Table,
+    Id,
+    Reads,
+}
+#[derive(Iden, Clone)]
+enum Meta {
+    Table,
+    Id,
+    Langs,
+    #[iden = "hiddenTags"]
+    HiddenTags,
+    #[iden = "blockedHosts"]
+    BlockedHosts,
+    #[iden = "pinnedUsers"]
+    PinnedUsers,
+    #[iden = "pinnedPages"]
+    PinnedPages,
+    #[iden = "recommendedInstances"]
+    RecommendedInstances,
+    #[iden = "silencedHosts"]
+    SilencedHosts,
+}
+#[derive(Iden, Clone)]
+enum Note {
+    Table,
+    Id,
+    #[iden = "fileIds"]
+    FileIds,
+    #[iden = "attachedFileTypes"]
+    AttachedFileTypes,
+    #[iden = "visibleUserIds"]
+    VisibleUserIds,
+    Mentions,
+    Emojis,
+    Tags,
+}
+#[derive(Iden, Clone)]
+enum NoteEdit {
+    Table,
+    Id,
+    #[iden = "fileIds"]
+    FileIds,
+}
+#[derive(Iden, Clone)]
+enum Page {
+    Table,
+    Id,
+    #[iden = "visibleUserIds"]
+    VisibleUserIds,
+}
+#[derive(Iden, Clone)]
+enum Poll {
+    Table,
+    #[iden = "noteId"]
+    NoteId,
+    Choices,
+    Votes, // I32Vec
+}
+#[derive(Iden, Clone)]
+enum RegistryItem {
+    Table,
+    Id,
+    Scope,
+}
+#[derive(Iden, Clone)]
+enum User {
+    Table,
+    Id,
+    Tags,
+    Emojis,
+}
+#[derive(Iden, Clone)]
+enum UserProfile {
+    Table,
+    #[iden = "userId"]
+    UserId,
+    #[iden = "mutingNotificationTypes"]
+    MutingNotificationTypes,
+}
+#[derive(Iden, Clone)]
+enum Webhook {
+    Table,
+    Id,
+    On,
+}

From ed8122ea8c7b70d450565b838b9b083b61ee38a2 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Thu, 1 Jun 2023 12:56:23 -0400
Subject: [PATCH 30/66] skip empty array

---
 .../crates/migration/src/vec_to_json.rs       | 335 +++++++++++++++---
 1 file changed, 278 insertions(+), 57 deletions(-)

diff --git a/packages/backend/native-utils/crates/migration/src/vec_to_json.rs b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs
index eccd80114..c762dcf1c 100644
--- a/packages/backend/native-utils/crates/migration/src/vec_to_json.rs
+++ b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs
@@ -1,11 +1,14 @@
 #![allow(dead_code)]
 
-use sea_orm_migration::{prelude::*, sea_orm::{DbConn, DbBackend, Statement, TryGetable, Database}};
-use serde_json::json;
-use std::time::Duration;
-use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
+use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
 use model::entity::newtype::{I32Vec, StringVec};
+use sea_orm_migration::{
+    prelude::*,
+    sea_orm::{Database, DbBackend, DbConn, Statement, TryGetable},
+};
+use serde_json::json;
 use std::env;
+use std::time::Duration;
 
 pub async fn convert() {
     let uri = env::var("DATABASE_URL").expect("Environment variable 'DATABASE_URL' not set");
@@ -14,41 +17,251 @@ pub async fn convert() {
     let mp = MultiProgress::new();
 
     let handlers = vec![
-        tokio::spawn(to_json::<AccessToken, Vec<String>, StringVec>(db.clone(), mp.clone(), AccessToken::Table, AccessToken::Id, AccessToken::Permission)),
-        tokio::spawn(to_json::<Antenna, Vec<String>, StringVec>(db.clone(), mp.clone(), Antenna::Table, Antenna::Id, Antenna::Users)),
-        tokio::spawn(to_json::<App, Vec<String>, StringVec>(db.clone(), mp.clone(), App::Table, App::Id, App::Permission)),
-        tokio::spawn(to_json::<Emoji, Vec<String>, StringVec>(db.clone(), mp.clone(), Emoji::Table, Emoji::Id, Emoji::Aliases)),
-        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::FileIds)),
-        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::Tags)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedUserIds)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedLocalUserIds)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedRemoteUserIds)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedUserIds)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedLocalUserIds)),
-        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedRemoteUserIds)),
-        tokio::spawn(to_json::<MessagingMessage, Vec<String>, StringVec>(db.clone(), mp.clone(), MessagingMessage::Table, MessagingMessage::Id, MessagingMessage::Reads)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::Langs)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::BlockedHosts)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::HiddenTags)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedUsers)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedPages)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::RecommendedInstances)),
-        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::SilencedHosts)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::FileIds)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::AttachedFileTypes)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::VisibleUserIds)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Mentions)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Emojis)),
-        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Tags)),
-        tokio::spawn(to_json::<NoteEdit, Vec<String>, StringVec>(db.clone(), mp.clone(), NoteEdit::Table, NoteEdit::Id, NoteEdit::FileIds)),
-        tokio::spawn(to_json::<Page, Vec<String>, StringVec>(db.clone(), mp.clone(), Page::Table, Page::Id, Page::VisibleUserIds)),
-        tokio::spawn(to_json::<RegistryItem, Vec<String>, StringVec>(db.clone(), mp.clone(), RegistryItem::Table, RegistryItem::Id, RegistryItem::Scope)),
-        tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Tags)),
-        tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Emojis)),
-        tokio::spawn(to_json::<Webhook, Vec<String>, StringVec>(db.clone(), mp.clone(), Webhook::Table, Webhook::Id, Webhook::On)),
-        tokio::spawn(to_json::<Poll, Vec<String>, StringVec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Choices)),
-        tokio::spawn(to_json::<Poll, Vec<i32>, I32Vec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Votes)),
-        tokio::spawn(to_json::<UserProfile, Vec<String>, StringVec>(db.clone(), mp.clone(), UserProfile::Table, UserProfile::UserId, UserProfile::MutingNotificationTypes)),
+        tokio::spawn(to_json::<AccessToken, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            AccessToken::Table,
+            AccessToken::Id,
+            AccessToken::Permission,
+        )),
+        tokio::spawn(to_json::<Antenna, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Antenna::Table,
+            Antenna::Id,
+            Antenna::Users,
+        )),
+        tokio::spawn(to_json::<App, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            App::Table,
+            App::Id,
+            App::Permission,
+        )),
+        tokio::spawn(to_json::<Emoji, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Emoji::Table,
+            Emoji::Id,
+            Emoji::Aliases,
+        )),
+        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            GalleryPost::Table,
+            GalleryPost::Id,
+            GalleryPost::FileIds,
+        )),
+        tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            GalleryPost::Table,
+            GalleryPost::Id,
+            GalleryPost::Tags,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedUserIds,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedLocalUserIds,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::MentionedRemoteUserIds,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedUserIds,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedLocalUserIds,
+        )),
+        tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Hashtag::Table,
+            Hashtag::Id,
+            Hashtag::AttachedRemoteUserIds,
+        )),
+        tokio::spawn(to_json::<MessagingMessage, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            MessagingMessage::Table,
+            MessagingMessage::Id,
+            MessagingMessage::Reads,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::Langs,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::BlockedHosts,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::HiddenTags,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::PinnedUsers,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::PinnedPages,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::RecommendedInstances,
+        )),
+        tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Meta::Table,
+            Meta::Id,
+            Meta::SilencedHosts,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::FileIds,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::AttachedFileTypes,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::VisibleUserIds,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::Mentions,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::Emojis,
+        )),
+        tokio::spawn(to_json::<Note, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Note::Table,
+            Note::Id,
+            Note::Tags,
+        )),
+        tokio::spawn(to_json::<NoteEdit, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            NoteEdit::Table,
+            NoteEdit::Id,
+            NoteEdit::FileIds,
+        )),
+        tokio::spawn(to_json::<Page, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Page::Table,
+            Page::Id,
+            Page::VisibleUserIds,
+        )),
+        tokio::spawn(to_json::<RegistryItem, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            RegistryItem::Table,
+            RegistryItem::Id,
+            RegistryItem::Scope,
+        )),
+        tokio::spawn(to_json::<User, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            User::Table,
+            User::Id,
+            User::Tags,
+        )),
+        tokio::spawn(to_json::<User, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            User::Table,
+            User::Id,
+            User::Emojis,
+        )),
+        tokio::spawn(to_json::<Webhook, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Webhook::Table,
+            Webhook::Id,
+            Webhook::On,
+        )),
+        tokio::spawn(to_json::<Poll, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            Poll::Table,
+            Poll::NoteId,
+            Poll::Choices,
+        )),
+        tokio::spawn(to_json::<Poll, Vec<i32>, I32Vec>(
+            db.clone(),
+            mp.clone(),
+            Poll::Table,
+            Poll::NoteId,
+            Poll::Votes,
+        )),
+        tokio::spawn(to_json::<UserProfile, Vec<String>, StringVec>(
+            db.clone(),
+            mp.clone(),
+            UserProfile::Table,
+            UserProfile::UserId,
+            UserProfile::MutingNotificationTypes,
+        )),
     ];
 
     futures::future::join_all(handlers).await;
@@ -62,10 +275,7 @@ fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
         .to_string(PostgresQueryBuilder)
 }
 
-async fn get_vec<T: TryGetable>(
-    db: &DbConn,
-    query: String,
-) -> Result<Vec<(String, T)>, DbErr> {
+async fn get_vec<T: TryGetable>(db: &DbConn, query: String) -> Result<Vec<(String, T)>, DbErr> {
     let res: Vec<(String, T)> = db
         .query_all(Statement::from_string(DbBackend::Postgres, query))
         .await?
@@ -81,15 +291,17 @@ async fn convert_col<T: Iden + Clone + 'static>(
     col: T,
 ) -> Result<(), DbErr> {
     let stmt = Table::alter()
-                .table(table)
-                .drop_column(col.to_owned())
-                .add_column(
-                    ColumnDef::new(col.to_owned())
-                        .json_binary()
-                        .not_null()
-                        .default(json!([])),
-                ).to_string(PostgresQueryBuilder);
-    db.query_one(Statement::from_string(DbBackend::Postgres, stmt)).await?;
+        .table(table)
+        .drop_column(col.to_owned())
+        .add_column(
+            ColumnDef::new(col.to_owned())
+                .json_binary()
+                .not_null()
+                .default(json!([])),
+        )
+        .to_string(PostgresQueryBuilder);
+    db.query_one(Statement::from_string(DbBackend::Postgres, stmt))
+        .await?;
     Ok(())
 }
 
@@ -102,26 +314,35 @@ async fn to_json<T, U, V>(
 ) -> Result<(), DbErr>
 where
     T: Iden + Clone + 'static,
-    U: TryGetable + Clone,
+    U: TryGetable + IntoIterator + Clone,
     V: From<U> + Into<SimpleExpr>,
 {
     let query = select_query(table.clone(), id.clone(), col.clone());
     let loading = ProgressBar::new_spinner()
         .with_style(ProgressStyle::with_template("{prefix} {msg} {spinner}").unwrap())
         .with_prefix("[-]")
-        .with_message(format!("Loading data from {}.{}", table.to_string(), col.to_string()));
-    loading.enable_steady_tick(Duration::from_millis(100));
+        .with_message(format!(
+            "Loading data from {}.{}",
+            table.to_string(),
+            col.to_string()
+        ));
     let loading = mp.add(loading);
+    loading.enable_steady_tick(Duration::from_millis(100));
     let res = get_vec::<U>(&db, query).await?;
     let models: Vec<(String, V)> = res
         .iter()
+        .filter(|(_, r)| r.clone().into_iter().count() > 0)
         .map(|(id, r)| (id.clone(), <V>::from(r.clone())))
         .collect();
     loading.finish_and_clear();
     convert_col(&db, table.clone(), col.clone()).await?;
 
     let progress = ProgressBar::new(models.len() as u64)
-        .with_style(ProgressStyle::with_template("{prefix} {msg} {wide_bar} {pos}/{len}").unwrap().progress_chars("##-"))
+        .with_style(
+            ProgressStyle::with_template("{prefix} {msg} {wide_bar} {pos}/{len}")
+                .unwrap()
+                .progress_chars("##-"),
+        )
         .with_prefix("[*]")
         .with_message(format!("Copying {}.{}", table.to_string(), col.to_string()));
     let progress = mp.add(progress);
@@ -136,7 +357,7 @@ where
         db.query_one(Statement::from_string(DbBackend::Postgres, q))
             .await?;
     }
-    progress.finish_with_message(format!("Complete {}.{}", table.to_string(), col.to_string()));
+    progress.finish_with_message(format!("Done {}.{}", table.to_string(), col.to_string()));
 
     Ok(())
 }

From a2e6c78f090be79fbc0c8d29c7ad63f5feb28197 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 01:10:23 -0400
Subject: [PATCH 31/66] rename feature

---
 packages/backend/native-utils/crates/migration/Cargo.toml | 2 +-
 packages/backend/native-utils/crates/model/Cargo.toml     | 2 +-
 .../native-utils/crates/model/src/entity/newtype/mod.rs   | 8 ++++----
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/packages/backend/native-utils/crates/migration/Cargo.toml b/packages/backend/native-utils/crates/migration/Cargo.toml
index 49accc9a2..dbfd41be6 100644
--- a/packages/backend/native-utils/crates/migration/Cargo.toml
+++ b/packages/backend/native-utils/crates/migration/Cargo.toml
@@ -10,7 +10,7 @@ path = "src/lib.rs"
 
 [features]
 default = []
-convert = []
+convert = ["model/noarray"]
 
 [dependencies]
 async-std = { version = "1", features = ["attributes", "tokio1"] }
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index a511e6e99..e9a3260c4 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [features]
 default = []
-legacy = []
+noarray = []
 
 [dependencies]
 async-trait = "0.1.68"
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index bd4302441..45aa17540 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -20,11 +20,11 @@ pub struct JsonI32Vec(pub Vec<i32>);
 impl_json_newtype!(JsonI32Vec);
 
 cfg_if! {
-    if #[cfg(feature = "legacy")] {
-        pub type StringVec = Vec<String>;
-        pub type I32Vec = Vec<i32>;
-    } else {
+    if #[cfg(feature = "noarray")] {
         pub type StringVec = JsonStringVec;
         pub type I32Vec = JsonI32Vec;
+    } else {
+        pub type StringVec = Vec<String>;
+        pub type I32Vec = Vec<i32>;
     }
 }

From e79d34e1edf4372502b3eb00d2b7715c5dbb8c37 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 03:39:52 -0400
Subject: [PATCH 32/66] add default values

---
 .../model/src/entity/abuse_user_report.rs     |   2 +-
 .../crates/model/src/entity/access_token.rs   |   2 +-
 .../crates/model/src/entity/ad.rs             |   2 +-
 .../crates/model/src/entity/announcement.rs   |   2 +-
 .../model/src/entity/announcement_read.rs     |   2 +-
 .../crates/model/src/entity/antenna.rs        |   2 +-
 .../crates/model/src/entity/antenna_note.rs   |   2 +-
 .../crates/model/src/entity/app.rs            |   2 +-
 .../model/src/entity/attestation_challenge.rs |   2 +-
 .../crates/model/src/entity/auth_session.rs   |   2 +-
 .../crates/model/src/entity/blocking.rs       |   2 +-
 .../crates/model/src/entity/channel.rs        |   2 +-
 .../model/src/entity/channel_following.rs     |   2 +-
 .../model/src/entity/channel_note_pining.rs   |   2 +-
 .../crates/model/src/entity/clip.rs           |   2 +-
 .../crates/model/src/entity/clip_note.rs      |   2 +-
 .../crates/model/src/entity/drive_file.rs     |   2 +-
 .../crates/model/src/entity/drive_folder.rs   |   2 +-
 .../crates/model/src/entity/emoji.rs          |   2 +-
 .../crates/model/src/entity/follow_request.rs |   2 +-
 .../crates/model/src/entity/following.rs      |   2 +-
 .../crates/model/src/entity/gallery_like.rs   |   2 +-
 .../crates/model/src/entity/gallery_post.rs   |   2 +-
 .../crates/model/src/entity/hashtag.rs        |   2 +-
 .../crates/model/src/entity/instance.rs       |   2 +-
 .../model/src/entity/messaging_message.rs     |   2 +-
 .../crates/model/src/entity/meta.rs           |   2 +-
 .../crates/model/src/entity/migrations.rs     |   2 +-
 .../crates/model/src/entity/moderation_log.rs |   2 +-
 .../crates/model/src/entity/muted_note.rs     |   2 +-
 .../crates/model/src/entity/muting.rs         |   2 +-
 .../crates/model/src/entity/newtype/mod.rs    |   6 +-
 .../crates/model/src/entity/note.rs           |   2 +-
 .../crates/model/src/entity/note_edit.rs      |   2 +-
 .../crates/model/src/entity/note_favorite.rs  |   2 +-
 .../crates/model/src/entity/note_reaction.rs  |   2 +-
 .../model/src/entity/note_thread_muting.rs    |   2 +-
 .../crates/model/src/entity/note_unread.rs    |   2 +-
 .../crates/model/src/entity/note_watching.rs  |   2 +-
 .../crates/model/src/entity/notification.rs   |   2 +-
 .../crates/model/src/entity/page.rs           |   2 +-
 .../crates/model/src/entity/page_like.rs      |   2 +-
 .../src/entity/password_reset_request.rs      |   2 +-
 .../crates/model/src/entity/poll.rs           |   2 +-
 .../crates/model/src/entity/poll_vote.rs      |   2 +-
 .../crates/model/src/entity/promo_note.rs     |   2 +-
 .../crates/model/src/entity/promo_read.rs     |   2 +-
 .../model/src/entity/registration_ticket.rs   |   2 +-
 .../crates/model/src/entity/registry_item.rs  |   2 +-
 .../crates/model/src/entity/relay.rs          |   2 +-
 .../crates/model/src/entity/renote_muting.rs  |   2 +-
 .../model/src/entity/sea_orm_active_enums.rs  |  30 ++-
 .../crates/model/src/entity/signin.rs         |   2 +-
 .../model/src/entity/sw_subscription.rs       |   2 +-
 .../crates/model/src/entity/used_username.rs  |   2 +-
 .../crates/model/src/entity/user.rs           |   2 +-
 .../crates/model/src/entity/user_group.rs     |   2 +-
 .../model/src/entity/user_group_invitation.rs |   2 +-
 .../model/src/entity/user_group_invite.rs     |   2 +-
 .../model/src/entity/user_group_joining.rs    |   2 +-
 .../crates/model/src/entity/user_ip.rs        |   2 +-
 .../crates/model/src/entity/user_keypair.rs   |   2 +-
 .../crates/model/src/entity/user_list.rs      |   2 +-
 .../model/src/entity/user_list_joining.rs     |   2 +-
 .../model/src/entity/user_note_pining.rs      |   2 +-
 .../crates/model/src/entity/user_pending.rs   |   2 +-
 .../crates/model/src/entity/user_profile.rs   |   2 +-
 .../crates/model/src/entity/user_publickey.rs |   2 +-
 .../model/src/entity/user_security_key.rs     |   2 +-
 .../crates/model/src/entity/webhook.rs        |   2 +-
 .../native-utils/crates/model/tests/common.rs | 184 +++++++++++++-----
 71 files changed, 226 insertions(+), 130 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
index 270837973..24230b394 100644
--- a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "abuse_user_report")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/access_token.rs b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
index f84971605..dd9289224 100644
--- a/packages/backend/native-utils/crates/model/src/entity/access_token.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/access_token.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "access_token")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/ad.rs b/packages/backend/native-utils/crates/model/src/entity/ad.rs
index 708ed69ce..2cf7a6fc8 100644
--- a/packages/backend/native-utils/crates/model/src/entity/ad.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/ad.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "ad")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement.rs b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
index 3e9b91687..e8a2a28aa 100644
--- a/packages/backend/native-utils/crates/model/src/entity/announcement.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "announcement")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
index 7fc51d475..53ff8d6ce 100644
--- a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "announcement_read")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
index 0ebd1cf45..85bdfbfea 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs
@@ -3,7 +3,7 @@
 use super::{newtype, sea_orm_active_enums::AntennaSrcEnum};
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "antenna")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
index d4c850bfc..c86fb349d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "antenna_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/app.rs b/packages/backend/native-utils/crates/model/src/entity/app.rs
index 310294568..6400d0b24 100644
--- a/packages/backend/native-utils/crates/model/src/entity/app.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/app.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "app")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
index 135a4f1fb..5217b2796 100644
--- a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "attestation_challenge")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
index 83aecbaa6..8ced191c3 100644
--- a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/auth_session.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "auth_session")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/blocking.rs b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
index 4667e60c6..4f326f6fa 100644
--- a/packages/backend/native-utils/crates/model/src/entity/blocking.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/blocking.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "blocking")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel.rs b/packages/backend/native-utils/crates/model/src/entity/channel.rs
index 9132d9d4e..abc79b4f5 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "channel")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
index bd1b16dce..93739459a 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_following.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "channel_following")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
index 2c9089ac4..50ec1ecef 100644
--- a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "channel_note_pining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip.rs b/packages/backend/native-utils/crates/model/src/entity/clip.rs
index 209bd047e..a51ef720e 100644
--- a/packages/backend/native-utils/crates/model/src/entity/clip.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/clip.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "clip")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
index 953c5511c..a8bfd4564 100644
--- a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/clip_note.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "clip_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
index abc191ba3..7c42b9881 100644
--- a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_file.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "drive_file")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
index f0b716283..98a9f8901 100644
--- a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "drive_folder")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/emoji.rs b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
index fdb99a2c3..00fc6184a 100644
--- a/packages/backend/native-utils/crates/model/src/entity/emoji.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/emoji.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "emoji")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
index af763baa6..6f8b00b79 100644
--- a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/follow_request.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "follow_request")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/following.rs b/packages/backend/native-utils/crates/model/src/entity/following.rs
index 087ca270b..641e41530 100644
--- a/packages/backend/native-utils/crates/model/src/entity/following.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/following.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "following")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
index 186c92703..e90dfedb3 100644
--- a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "gallery_like")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
index 875d3af58..7e53e6bf3 100644
--- a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "gallery_post")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
index 917f4ea1b..7a8722a5f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/hashtag.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "hashtag")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/instance.rs b/packages/backend/native-utils/crates/model/src/entity/instance.rs
index 3f3af2a5d..fc9c5bf8b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/instance.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/instance.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "instance")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
index b66c01fc9..8d7c7b8cc 100644
--- a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "messaging_message")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/meta.rs b/packages/backend/native-utils/crates/model/src/entity/meta.rs
index a97cb89c4..2c0dc315c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/meta.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/meta.rs
@@ -6,7 +6,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "meta")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/migrations.rs b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
index c03df1180..54e44f2fd 100644
--- a/packages/backend/native-utils/crates/model/src/entity/migrations.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/migrations.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "migrations")]
 pub struct Model {
     #[sea_orm(primary_key)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
index 330685392..eb882b896 100644
--- a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "moderation_log")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
index 1740e9078..238898549 100644
--- a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/muted_note.rs
@@ -3,7 +3,7 @@
 use super::sea_orm_active_enums::MutedNoteReasonEnum;
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "muted_note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/muting.rs b/packages/backend/native-utils/crates/model/src/entity/muting.rs
index 83885034c..7b46a0b24 100644
--- a/packages/backend/native-utils/crates/model/src/entity/muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/muting.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
index 45aa17540..3dc2d7553 100644
--- a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
@@ -7,15 +7,15 @@ use serde::{Deserialize, Serialize};
 
 use crate::impl_json_newtype;
 
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into, Default)]
 pub struct JsonKeyword(pub Vec<Vec<String>>);
 impl_json_newtype!(JsonKeyword);
 
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into, Default)]
 pub struct JsonStringVec(pub Vec<String>);
 impl_json_newtype!(JsonStringVec);
 
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, From, Into, Default)]
 pub struct JsonI32Vec(pub Vec<i32>);
 impl_json_newtype!(JsonI32Vec);
 
diff --git a/packages/backend/native-utils/crates/model/src/entity/note.rs b/packages/backend/native-utils/crates/model/src/entity/note.rs
index c2f20c11b..077841e48 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note.rs
@@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
index 4e8f42083..ea9b9eabd 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_edit.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_edit")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
index 42f3c400f..470ad55d2 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_favorite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
index c740d994f..a4e9f490d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_reaction")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
index f1dbfb598..51688a088 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_thread_muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
index 746815611..a444eb35d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_unread.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_unread")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
index 4a87a4495..962ef081e 100644
--- a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/note_watching.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "note_watching")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/notification.rs b/packages/backend/native-utils/crates/model/src/entity/notification.rs
index 4500e59d9..896b6c2da 100644
--- a/packages/backend/native-utils/crates/model/src/entity/notification.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/notification.rs
@@ -3,7 +3,7 @@
 use super::sea_orm_active_enums::NotificationTypeEnum;
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "notification")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/page.rs b/packages/backend/native-utils/crates/model/src/entity/page.rs
index c3d09fa8c..dabb5c9f0 100644
--- a/packages/backend/native-utils/crates/model/src/entity/page.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/page.rs
@@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "page")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/page_like.rs b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
index 3d3d2f3ac..108b6b929 100644
--- a/packages/backend/native-utils/crates/model/src/entity/page_like.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/page_like.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "page_like")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
index 3b24d70d9..45cc3de10 100644
--- a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "password_reset_request")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll.rs b/packages/backend/native-utils/crates/model/src/entity/poll.rs
index 81953cfba..4d64594c7 100644
--- a/packages/backend/native-utils/crates/model/src/entity/poll.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/poll.rs
@@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::{I32Vec, StringVec};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "poll")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
index 1b8b3ba1c..bf26bf5dd 100644
--- a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "poll_vote")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
index aa5eb2f3d..288a0ea81 100644
--- a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_note.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "promo_note")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
index d7dcacfb8..4e6224cf2 100644
--- a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/promo_read.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "promo_read")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
index f71c87327..798f19586 100644
--- a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "registration_ticket")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
index 54d72d5d8..904c43abf 100644
--- a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/registry_item.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "registry_item")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/relay.rs b/packages/backend/native-utils/crates/model/src/entity/relay.rs
index 736b48b78..bed89c849 100644
--- a/packages/backend/native-utils/crates/model/src/entity/relay.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/relay.rs
@@ -3,7 +3,7 @@
 use super::sea_orm_active_enums::RelayStatusEnum;
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "relay")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
index b5e7d38f2..44751c14c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "renote_muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
index 14ef7002a..f26995224 100644
--- a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
@@ -2,9 +2,10 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
 pub enum AntennaSrcEnum {
+    #[default]
     #[sea_orm(string_value = "all")]
     All,
     #[sea_orm(string_value = "group")]
@@ -18,13 +19,14 @@ pub enum AntennaSrcEnum {
     #[sea_orm(string_value = "users")]
     Users,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
     enum_name = "meta_sensitivemediadetection_enum"
 )]
 pub enum MetaSensitivemediadetectionEnum {
+    #[default]
     #[sea_orm(string_value = "all")]
     All,
     #[sea_orm(string_value = "local")]
@@ -34,7 +36,7 @@ pub enum MetaSensitivemediadetectionEnum {
     #[sea_orm(string_value = "remote")]
     Remote,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -45,6 +47,7 @@ pub enum MetaSensitivemediadetectionsensitivityEnum {
     High,
     #[sea_orm(string_value = "low")]
     Low,
+    #[default]
     #[sea_orm(string_value = "medium")]
     Medium,
     #[sea_orm(string_value = "veryHigh")]
@@ -52,13 +55,14 @@ pub enum MetaSensitivemediadetectionsensitivityEnum {
     #[sea_orm(string_value = "veryLow")]
     VeryLow,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
     enum_name = "muted_note_reason_enum"
 )]
 pub enum MutedNoteReasonEnum {
+    #[default]
     #[sea_orm(string_value = "manual")]
     Manual,
     #[sea_orm(string_value = "other")]
@@ -68,7 +72,7 @@ pub enum MutedNoteReasonEnum {
     #[sea_orm(string_value = "word")]
     Word,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -81,12 +85,13 @@ pub enum NoteVisibilityEnum {
     Hidden,
     #[sea_orm(string_value = "home")]
     Home,
+    #[default]
     #[sea_orm(string_value = "public")]
     Public,
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -115,10 +120,11 @@ pub enum NotificationTypeEnum {
     ReceiveFollowRequest,
     #[sea_orm(string_value = "renote")]
     Renote,
+    #[default]
     #[sea_orm(string_value = "reply")]
     Reply,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -127,12 +133,13 @@ pub enum NotificationTypeEnum {
 pub enum PageVisibilityEnum {
     #[sea_orm(string_value = "followers")]
     Followers,
+    #[default]
     #[sea_orm(string_value = "public")]
     Public,
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -143,22 +150,24 @@ pub enum PollNotevisibilityEnum {
     Followers,
     #[sea_orm(string_value = "home")]
     Home,
+    #[default]
     #[sea_orm(string_value = "public")]
     Public,
     #[sea_orm(string_value = "specified")]
     Specified,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
 pub enum RelayStatusEnum {
     #[sea_orm(string_value = "accepted")]
     Accepted,
     #[sea_orm(string_value = "rejected")]
     Rejected,
+    #[default]
     #[sea_orm(string_value = "requesting")]
     Requesting,
 }
-#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default)]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -169,6 +178,7 @@ pub enum UserProfileFfvisibilityEnum {
     Followers,
     #[sea_orm(string_value = "private")]
     Private,
+    #[default]
     #[sea_orm(string_value = "public")]
     Public,
 }
diff --git a/packages/backend/native-utils/crates/model/src/entity/signin.rs b/packages/backend/native-utils/crates/model/src/entity/signin.rs
index 6220973c1..60bbc33d2 100644
--- a/packages/backend/native-utils/crates/model/src/entity/signin.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/signin.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "signin")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
index eaa332d8c..1be9e046a 100644
--- a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "sw_subscription")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/used_username.rs b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
index e9e8eb097..620950b64 100644
--- a/packages/backend/native-utils/crates/model/src/entity/used_username.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/used_username.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "used_username")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user.rs b/packages/backend/native-utils/crates/model/src/entity/user.rs
index 1cf6ac6b7..f30fd8ace 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group.rs b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
index 680f78b9e..74ee4f22f 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_group")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
index 5a6f6f4a1..baa6fea83 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_group_invitation")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
index 786dd1f31..dbbc055f0 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_group_invite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
index 2baa0b9a7..e7741520c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_group_joining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
index 872cfd860..ce0af264d 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_ip.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_ip")]
 pub struct Model {
     #[sea_orm(primary_key)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
index df23b506b..0382d5d76 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_keypair")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list.rs b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
index ff05f2c44..7cc972133 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_list.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_list")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
index 27899a8c5..4f28a21db 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_list_joining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
index bcb3ec8b0..e657fcb53 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_note_pining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
index 1fb3b4fdc..297fe553c 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_pending.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_pending")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
index d62607f16..4c2f903d4 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_profile.rs
@@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_profile")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
index c3c6dbf1f..b1f426c5b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_publickey")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
index cbb31e1b0..4bc976336 100644
--- a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
@@ -2,7 +2,7 @@
 
 use sea_orm::entity::prelude::*;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "user_security_key")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/src/entity/webhook.rs b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
index dd3c3c738..06ea1516b 100644
--- a/packages/backend/native-utils/crates/model/src/entity/webhook.rs
+++ b/packages/backend/native-utils/crates/model/src/entity/webhook.rs
@@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*;
 
 use super::newtype::StringVec;
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
 #[sea_orm(table_name = "webhook")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index 0fd32d8f9..add8c12b2 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -3,12 +3,12 @@ extern crate model;
 mod repository;
 
 use chrono::Utc;
-use model::entity::{antenna, sea_orm_active_enums::AntennaSrcEnum, user};
+use model::entity;
+use model::entity::sea_orm_active_enums::AntennaSrcEnum;
 use sea_orm::{
-    ActiveModelTrait, ActiveValue::Set, ConnectionTrait, DbBackend, DbConn, DbErr, EntityTrait,
-    TransactionTrait,
+    sea_query::TableCreateStatement, ActiveModelTrait, ConnectionTrait, DbBackend, DbConn, DbErr,
+    EntityTrait, IntoActiveModel, TransactionTrait,
 };
-use std::env;
 use util::{
     id::{create_id, init_id},
     random::gen_string,
@@ -16,31 +16,119 @@ use util::{
 
 /// Insert predefined entries in the database.
 async fn prepare() {
-    let conn_uri = env::var("DATABASE_URL")
-        .unwrap_or("postgres://calckey:calckey@localhost/calckey".to_string());
-    database::init_database(conn_uri)
+    database::init_database("sqlite::memory:")
         .await
         .expect("Unable to initialize database connection");
     let db = database::get_database().expect("Unable to get database connection from pool");
+    setup_schema(db).await;
     setup_model(db).await;
 }
 
-async fn setup_schema(db: DbConn) {
-    // Setup Schema helper
+/// Setup schemas in the database.
+async fn setup_schema(db: &DbConn) {
     let schema = sea_orm::Schema::new(DbBackend::Sqlite);
-    let stmt = schema.create_table_from_entity(antenna::Entity);
-    db.execute(db.get_database_backend().build(&stmt))
-        .await
-        .expect("Unable to setup schemas for in-memoty sqlite");
+    let mut stmts: Vec<TableCreateStatement> = Vec::new();
+    macro_rules! create_table_statement {
+        ($a:tt) => {
+            stmts.push(schema.create_table_from_entity(entity::$a::Entity).if_not_exists().to_owned());
+        };
+        ($a:tt, $($b:tt),+) => {
+            create_table_statement!($a);
+            create_table_statement!($($b),+);
+        };
+    }
+    create_table_statement!(
+        abuse_user_report,
+        access_token,
+        ad,
+        announcement_read,
+        announcement,
+        antenna_note,
+        antenna,
+        app,
+        attestation_challenge,
+        auth_session,
+        blocking,
+        channel_following,
+        channel_note_pining,
+        channel,
+        clip_note,
+        clip,
+        drive_file,
+        drive_folder,
+        emoji,
+        following,
+        follow_request,
+        gallery_like,
+        gallery_post,
+        hashtag,
+        instance,
+        messaging_message,
+        meta,
+        migrations,
+        moderation_log,
+        muted_note,
+        muting,
+        note_edit,
+        note_favorite,
+        note_reaction,
+        note,
+        note_thread_muting,
+        note_unread,
+        note_watching,
+        notification,
+        page_like,
+        page,
+        password_reset_request,
+        poll,
+        poll_vote,
+        promo_note,
+        promo_read,
+        registration_ticket,
+        registry_item,
+        relay,
+        renote_muting,
+        signin,
+        sw_subscription,
+        used_username,
+        user_group_invitation,
+        user_group_invite,
+        user_group_joining,
+        user_group,
+        user_ip,
+        user_keypair,
+        user_list_joining,
+        user_list,
+        user_note_pining,
+        user_pending,
+        user_profile,
+        user_publickey,
+        user,
+        user_security_key,
+        webhook
+    );
+    db.transaction::<_, (), DbErr>(|txn| {
+        Box::pin(async move {
+            for stmt in stmts {
+                txn.execute(txn.get_database_backend().build(&stmt)).await?;
+            }
+            Ok(())
+        })
+    })
+    .await
+    .expect("Unable to setup schemas");
 }
 
 /// Delete all entries in the database.
 async fn cleanup() {
-    let db = database::get_database().unwrap();
+    let db = database::get_database().expect("Unable to get database connection from pool");
     db.transaction::<_, (), DbErr>(|txn| {
         Box::pin(async move {
-            user::Entity::delete_many().exec(txn).await.unwrap();
-            antenna::Entity::delete_many().exec(txn).await.unwrap();
+            entity::user::Entity::delete_many().exec(txn).await.unwrap();
+            entity::antenna::Entity::delete_many()
+                .exec(txn)
+                .await
+                .unwrap();
 
             Ok(())
         })
@@ -56,40 +144,46 @@ async fn setup_model(db: &DbConn) {
         Box::pin(async move {
             let user_id = create_id().unwrap();
             let name = "Alice";
-            let user_model = user::ActiveModel {
-                id: Set(user_id.to_owned()),
-                created_at: Set(Utc::now().into()),
-                username: Set(name.to_lowercase().to_string()),
-                username_lower: Set(name.to_lowercase().to_string()),
-                name: Set(Some(name.to_string())),
-                token: Set(Some(gen_string(16))),
-                is_admin: Set(true),
+            let user_model = entity::user::Model {
+                id: user_id.to_owned(),
+                created_at: Utc::now().into(),
+                username: name.to_lowercase().to_string(),
+                username_lower: name.to_lowercase().to_string(),
+                name: Some(name.to_string()),
+                token: Some(gen_string(16)),
+                is_admin: true,
                 ..Default::default()
             };
-            user_model.insert(txn).await?;
-            let antenna_model = antenna::ActiveModel {
-                id: Set(create_id().unwrap()),
-                created_at: Set(Utc::now().into()),
-                user_id: Set(user_id.to_owned()),
-                name: Set("Test Antenna".to_string()),
-                src: Set(AntennaSrcEnum::All),
-                keywords: Set(vec![
+            user_model
+                .into_active_model()
+                .reset_all()
+                .insert(txn)
+                .await?;
+            let antenna_model = entity::antenna::Model {
+                id: create_id().unwrap(),
+                created_at: Utc::now().into(),
+                user_id: user_id.to_owned(),
+                name: "Test Antenna".to_string(),
+                src: AntennaSrcEnum::All,
+                keywords: vec![
                     vec!["foo".to_string(), "bar".to_string()],
                     vec!["foobar".to_string()],
                 ]
-                .into()),
-                exclude_keywords: Set(vec![
+                .into(),
+                exclude_keywords: vec![
                     vec!["abc".to_string()],
                     vec!["def".to_string(), "ghi".to_string()],
                 ]
-                .into()),
-                with_file: Set(false),
-                notify: Set(true),
-                case_sensitive: Set(true),
-                with_replies: Set(false),
+                .into(),
+                notify: true,
+                case_sensitive: true,
                 ..Default::default()
             };
-            antenna_model.insert(txn).await?;
+            antenna_model
+                .into_active_model()
+                .reset_all()
+                .insert(txn)
+                .await?;
 
             Ok(())
         })
@@ -99,19 +193,11 @@ async fn setup_model(db: &DbConn) {
 }
 
 mod int_test {
-    use sea_orm::Database;
-
-    use super::{cleanup, prepare, setup_schema};
+    use super::{cleanup, prepare};
 
     #[tokio::test]
     async fn can_prepare_and_cleanup() {
         prepare().await;
         cleanup().await;
     }
-
-    #[tokio::test]
-    async fn can_setup_sqlite_schema() {
-        let db = Database::connect("sqlite::memory:").await.unwrap();
-        setup_schema(db).await;
-    }
 }

From 3dd44d146f3f66e22311b0924bcb5e76130aec60 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 04:34:49 -0400
Subject: [PATCH 33/66] add pack_by_id

---
 .../native-utils/crates/model/src/error.rs    |  4 +-
 .../crates/model/src/repository/antenna.rs    |  5 ++
 .../crates/model/src/repository/mod.rs        | 14 +++++
 .../crates/model/src/schema/mod.rs            |  2 +-
 .../crates/model/tests/repository/antenna.rs  | 60 ++++++++++---------
 5 files changed, 55 insertions(+), 30 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/src/error.rs b/packages/backend/native-utils/crates/model/src/error.rs
index 7686312ec..c90f3f5a3 100644
--- a/packages/backend/native-utils/crates/model/src/error.rs
+++ b/packages/backend/native-utils/crates/model/src/error.rs
@@ -5,5 +5,7 @@ pub enum Error {
     #[error("Failed to get database connection")]
     DbConnError(#[from] database::error::Error),
     #[error("Database operation error: {0}")]
-    DatabaseOperationError(#[from] sea_orm::DbErr),
+    DbOperationError(#[from] sea_orm::DbErr),
+    #[error("Requested entity not found")]
+    NotFound,
 }
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
index f9ef012a6..d3ad6ecec 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -5,6 +5,7 @@ use crate::entity::{antenna, antenna_note, user_group_joining};
 use crate::error::Error;
 use crate::schema::antenna::Antenna;
 
+use super::macros::impl_pack_by_id;
 use super::Repository;
 
 #[async_trait]
@@ -44,4 +45,8 @@ impl Repository<Antenna> for antenna::Model {
             has_unread_note,
         })
     }
+
+    async fn pack_by_id(id: String) -> Result<Antenna, Error> {
+        impl_pack_by_id!(antenna::Entity, id)
+    }
 }
diff --git a/packages/backend/native-utils/crates/model/src/repository/mod.rs b/packages/backend/native-utils/crates/model/src/repository/mod.rs
index 01e11412d..83573ab16 100644
--- a/packages/backend/native-utils/crates/model/src/repository/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/mod.rs
@@ -8,4 +8,18 @@ use crate::error::Error;
 #[async_trait]
 pub trait Repository<T: JsonSchema> {
     async fn pack(self) -> Result<T, Error>;
+    async fn pack_by_id(id: String) -> Result<T, Error>;
+}
+
+mod macros {
+    macro_rules! impl_pack_by_id {
+        ($a:ty, $b:ident) => {
+            match <$a>::find_by_id($b).one(database::get_database()?).await? {
+                None => Err(Error::NotFound),
+                Some(m) => m.pack().await,
+            }
+        };
+    }
+
+    pub(crate) use impl_pack_by_id;
 }
diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema/mod.rs
index cc495aac1..a64751020 100644
--- a/packages/backend/native-utils/crates/model/src/schema/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/mod.rs
@@ -6,7 +6,7 @@ use schemars::{schema_for, JsonSchema};
 
 /// Structs of schema defitions implement this trait in order to
 /// provide the JSON Schema validator [`jsonschema::JSONSchema`].
-trait Schema<T: JsonSchema> {
+pub trait Schema<T: JsonSchema> {
     /// Returns the validator of [JSON Schema Draft
     /// 7](https://json-schema.org/specification-links.html#draft-7) with the
     /// default settings of [`schemars::gen::SchemaSettings`].
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index e07a16c07..193efcba2 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -29,34 +29,38 @@ mod int_test {
             .await
             .expect("Unable to pack");
 
-        assert_eq!(
-            packed,
-            schema::antenna::Antenna {
-                id: alice_antenna.id,
-                created_at: alice_antenna.created_at.into(),
-                name: "Test Antenna".to_string(),
-                keywords: vec![
-                    vec!["foo".to_string(), "bar".to_string()],
-                    vec!["foobar".to_string()]
-                ]
-                .into(),
-                exclude_keywords: vec![
-                    vec!["abc".to_string()],
-                    vec!["def".to_string(), "ghi".to_string()]
-                ]
-                .into(),
-                src: schema::antenna::AntennaSrc::All,
-                user_list_id: None,
-                user_group_id: None,
-                users: vec![].into(),
-                instances: vec![].into(),
-                case_sensitive: true,
-                notify: true,
-                with_replies: false,
-                with_file: false,
-                has_unread_note: false,
-            }
-        );
+        let packed_by_id = antenna::Model::pack_by_id(alice_antenna.id.to_owned())
+            .await
+            .expect("Unable to pack");
+
+        let result = schema::antenna::Antenna {
+            id: alice_antenna.id,
+            created_at: alice_antenna.created_at.into(),
+            name: "Test Antenna".to_string(),
+            keywords: vec![
+                vec!["foo".to_string(), "bar".to_string()],
+                vec!["foobar".to_string()],
+            ]
+            .into(),
+            exclude_keywords: vec![
+                vec!["abc".to_string()],
+                vec!["def".to_string(), "ghi".to_string()],
+            ]
+            .into(),
+            src: schema::antenna::AntennaSrc::All,
+            user_list_id: None,
+            user_group_id: None,
+            users: vec![].into(),
+            instances: vec![].into(),
+            case_sensitive: true,
+            notify: true,
+            with_replies: false,
+            with_file: false,
+            has_unread_note: false,
+        };
+
+        assert_eq!(packed, result);
+        assert_eq!(packed_by_id, result);
 
         cleanup().await;
     }

From 993ece47555641c99c37e6ea7d9851e3203bf2e7 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 06:22:09 -0400
Subject: [PATCH 34/66] add napi schema

---
 .../native-utils/crates/model/Cargo.toml      |  5 ++
 .../model/src/{entity/mod.rs => entity.rs}    |  0
 .../src/{repository/mod.rs => repository.rs}  |  0
 .../crates/model/src/repository/antenna.rs    | 13 ++++-
 .../model/src/{schema/mod.rs => schema.rs}    | 12 +++++
 .../crates/model/src/schema/antenna.rs        |  6 +--
 .../crates/model/src/schema/napi.rs           |  1 +
 .../crates/model/src/schema/napi/antenna.rs   | 47 +++++++++++++++++++
 .../native-utils/crates/model/tests/common.rs |  2 +
 .../crates/model/tests/repository/antenna.rs  |  4 +-
 10 files changed, 83 insertions(+), 7 deletions(-)
 rename packages/backend/native-utils/crates/model/src/{entity/mod.rs => entity.rs} (100%)
 rename packages/backend/native-utils/crates/model/src/{repository/mod.rs => repository.rs} (100%)
 rename packages/backend/native-utils/crates/model/src/{schema/mod.rs => schema.rs} (75%)
 create mode 100644 packages/backend/native-utils/crates/model/src/schema/napi.rs
 create mode 100644 packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs

diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index e9a3260c4..c2002443d 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 [features]
 default = []
 noarray = []
+napi = ["dep:napi", "dep:napi-derive"]
 
 [dependencies]
 async-trait = "0.1.68"
@@ -25,3 +26,7 @@ thiserror = "1.0.40"
 tokio = { version = "1.28.1", features = ["sync"] }
 util = { path = "../util" }
 utoipa = "3.3.0"
+
+# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
+napi = { version = "2.12.0", default-features = false, features = ["napi4"], optional = true }
+napi-derive = { version = "2.12.0", optional = true }
diff --git a/packages/backend/native-utils/crates/model/src/entity/mod.rs b/packages/backend/native-utils/crates/model/src/entity.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/mod.rs
rename to packages/backend/native-utils/crates/model/src/entity.rs
diff --git a/packages/backend/native-utils/crates/model/src/repository/mod.rs b/packages/backend/native-utils/crates/model/src/repository.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/repository/mod.rs
rename to packages/backend/native-utils/crates/model/src/repository.rs
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
index d3ad6ecec..c8324edd3 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs
@@ -1,9 +1,10 @@
 use async_trait::async_trait;
+use cfg_if::cfg_if;
 use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
 use crate::entity::{antenna, antenna_note, user_group_joining};
 use crate::error::Error;
-use crate::schema::antenna::Antenna;
+use crate::schema::Antenna;
 
 use super::macros::impl_pack_by_id;
 use super::Repository;
@@ -27,9 +28,17 @@ impl Repository<Antenna> for antenna::Model {
             Some(m) => Some(m.user_group_id),
         };
 
+        cfg_if! {
+            if #[cfg(feature = "napi")] {
+                let created_at: String = self.created_at.to_rfc3339();
+            } else {
+                let created_at: chrono::DateTime<chrono::Utc> = self.created_at.into();
+            }
+        }
+
         Ok(Antenna {
             id: self.id,
-            created_at: self.created_at.into(),
+            created_at,
             name: self.name,
             keywords: self.keywords.into(),
             exclude_keywords: self.exclude_keywords.into(),
diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema.rs
similarity index 75%
rename from packages/backend/native-utils/crates/model/src/schema/mod.rs
rename to packages/backend/native-utils/crates/model/src/schema.rs
index a64751020..78a0887fe 100644
--- a/packages/backend/native-utils/crates/model/src/schema/mod.rs
+++ b/packages/backend/native-utils/crates/model/src/schema.rs
@@ -1,9 +1,21 @@
 pub mod antenna;
 pub mod app;
 
+use cfg_if::cfg_if;
 use jsonschema::JSONSchema;
 use schemars::{schema_for, JsonSchema};
 
+cfg_if! {
+    if #[cfg(feature = "napi")] {
+        mod napi;
+        pub use napi::antenna::Antenna;
+        pub use napi::antenna::AntennaSrc;
+    } else {
+        pub use antenna::Antenna;
+        pub use antenna::AntennaSrc;
+    }
+}
+
 /// Structs of schema defitions implement this trait in order to
 /// provide the JSON Schema validator [`jsonschema::JSONSchema`].
 pub trait Schema<T: JsonSchema> {
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index fa7902b92..2f13a563d 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -47,10 +47,10 @@ pub enum AntennaSrc {
 }
 
 impl TryFrom<AntennaSrcEnum> for AntennaSrc {
-    type Error = parse_display::ParseError;
+    type Error = crate::error::Error;
 
     fn try_from(value: AntennaSrcEnum) -> Result<Self, Self::Error> {
-        value.to_string().parse()
+        value.to_string().parse().map_err(crate::error::Error::from)
     }
 }
 
@@ -63,7 +63,7 @@ pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
 mod unit_test {
     use serde_json::json;
 
-    use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::antenna::AntennaSrc};
+    use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::AntennaSrc};
 
     use super::VALIDATOR;
 
diff --git a/packages/backend/native-utils/crates/model/src/schema/napi.rs b/packages/backend/native-utils/crates/model/src/schema/napi.rs
new file mode 100644
index 000000000..16130e4cc
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/schema/napi.rs
@@ -0,0 +1 @@
+pub mod antenna;
diff --git a/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
new file mode 100644
index 000000000..cfba50d7f
--- /dev/null
+++ b/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
@@ -0,0 +1,47 @@
+use parse_display::FromStr;
+use schemars::JsonSchema;
+use utoipa::ToSchema;
+
+use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
+use napi_derive::napi;
+
+#[napi]
+#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct Antenna {
+    pub id: String,
+    pub created_at: String,
+    pub name: String,
+    pub keywords: Vec<Vec<String>>,
+    pub exclude_keywords: Vec<Vec<String>>,
+    #[schema(inline)]
+    pub src: AntennaSrc,
+    pub user_list_id: Option<String>,
+    pub user_group_id: Option<String>,
+    pub users: Vec<String>,
+    pub instances: Vec<String>,
+    #[serde(default)]
+    pub case_sensitive: bool,
+    #[serde(default)]
+    pub notify: bool,
+    #[serde(default)]
+    pub with_replies: bool,
+    #[serde(default)]
+    pub with_file: bool,
+    #[serde(default)]
+    pub has_unread_note: bool,
+}
+
+#[napi]
+#[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
+#[serde(rename_all = "camelCase")]
+#[display(style = "camelCase")]
+#[display("'{}'")]
+pub enum AntennaSrc {
+    Home,
+    All,
+    Users,
+    List,
+    Group,
+    Instances,
+}
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs
index add8c12b2..554a8ca73 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/crates/model/tests/common.rs
@@ -1,3 +1,5 @@
+#![cfg(not(feature = "napi"))]
+
 extern crate model;
 
 mod repository;
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index 193efcba2..90732130a 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -33,7 +33,7 @@ mod int_test {
             .await
             .expect("Unable to pack");
 
-        let result = schema::antenna::Antenna {
+        let result = schema::Antenna {
             id: alice_antenna.id,
             created_at: alice_antenna.created_at.into(),
             name: "Test Antenna".to_string(),
@@ -47,7 +47,7 @@ mod int_test {
                 vec!["def".to_string(), "ghi".to_string()],
             ]
             .into(),
-            src: schema::antenna::AntennaSrc::All,
+            src: schema::AntennaSrc::All,
             user_list_id: None,
             user_group_id: None,
             users: vec![].into(),

From 1c34915018e81874185bf04579686fa667300702 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 07:08:58 -0400
Subject: [PATCH 35/66] fix unit test

---
 .../native-utils/crates/model/Cargo.toml      |  5 +++-
 .../native-utils/crates/model/src/schema.rs   |  6 ++--
 .../crates/model/src/schema/antenna.rs        | 30 +++++++++++--------
 .../crates/model/src/schema/app.rs            |  4 +--
 .../crates/model/src/schema/napi/antenna.rs   |  5 ++--
 .../crates/model/tests/repository/antenna.rs  |  1 +
 .../native-utils/crates/util/Cargo.toml       |  3 ++
 .../native-utils/crates/util/src/id.rs        |  1 +
 .../native-utils/crates/util/src/random.rs    |  1 +
 9 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
index c2002443d..4925fb702 100644
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ b/packages/backend/native-utils/crates/model/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [features]
-default = []
+default = ["napi"]
 noarray = []
 napi = ["dep:napi", "dep:napi-derive"]
 
@@ -30,3 +30,6 @@ utoipa = "3.3.0"
 # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
 napi = { version = "2.12.0", default-features = false, features = ["napi4"], optional = true }
 napi-derive = { version = "2.12.0", optional = true }
+
+[dev-dependencies]
+pretty_assertions = "1.3.0"
diff --git a/packages/backend/native-utils/crates/model/src/schema.rs b/packages/backend/native-utils/crates/model/src/schema.rs
index 78a0887fe..71f9348b3 100644
--- a/packages/backend/native-utils/crates/model/src/schema.rs
+++ b/packages/backend/native-utils/crates/model/src/schema.rs
@@ -8,11 +8,13 @@ use schemars::{schema_for, JsonSchema};
 cfg_if! {
     if #[cfg(feature = "napi")] {
         mod napi;
-        pub use napi::antenna::Antenna;
-        pub use napi::antenna::AntennaSrc;
+        pub use self::napi::antenna::Antenna;
+        pub use self::napi::antenna::AntennaSrc;
     } else {
         pub use antenna::Antenna;
         pub use antenna::AntennaSrc;
+        pub use app::App;
+        pub use app::AppPermission;
     }
 }
 
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
index 2f13a563d..338998019 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs
@@ -46,7 +46,7 @@ pub enum AntennaSrc {
     Instances,
 }
 
-impl TryFrom<AntennaSrcEnum> for AntennaSrc {
+impl TryFrom<AntennaSrcEnum> for super::AntennaSrc {
     type Error = crate::error::Error;
 
     fn try_from(value: AntennaSrcEnum) -> Result<Self, Self::Error> {
@@ -55,12 +55,13 @@ impl TryFrom<AntennaSrcEnum> for AntennaSrc {
 }
 
 // ---- TODO: could be macro
-impl Schema<Self> for Antenna {}
-pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| Antenna::validator());
+impl Schema<Self> for super::Antenna {}
+pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| super::Antenna::validator());
 // ----
 
 #[cfg(test)]
 mod unit_test {
+    use pretty_assertions::assert_eq;
     use serde_json::json;
 
     use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::AntennaSrc};
@@ -128,20 +129,23 @@ mod unit_test {
         let result = VALIDATOR
             .validate(&instance)
             .expect_err("validation must fail");
-        let mut paths: Vec<String> = result.map(|e| e.schema_path.to_string()).collect();
+        let mut paths: Vec<String> = result
+            .map(|e| e.instance_path.to_string())
+            .filter(|e| !e.is_empty())
+            .collect();
         paths.sort();
         assert_eq!(
             paths,
             vec![
-                "/properties/caseSensitive/type",
-                "/properties/createdAt/format",
-                "/properties/excludeKeywords/type",
-                "/properties/id/type",
-                "/properties/keywords/type",
-                "/properties/src/enum",
-                "/properties/userListId/type",
-                "/properties/users/items/type",
-                "/required"
+                "/caseSensitive",
+                #[cfg(not(feature = "napi"))]
+                "/createdAt",
+                "/excludeKeywords",
+                "/id",
+                "/keywords",
+                "/src",
+                "/userListId",
+                "/users/0"
             ]
         );
     }
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/crates/model/src/schema/app.rs
index b45cad6d6..f24c1387b 100644
--- a/packages/backend/native-utils/crates/model/src/schema/app.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/app.rs
@@ -13,14 +13,14 @@ pub struct App {
     #[schemars(url)]
     pub callback_url: Option<String>,
     #[schema(inline)]
-    pub permission: Vec<Permission>,
+    pub permission: Vec<AppPermission>,
     pub secret: Option<String>,
     pub is_authorized: Option<bool>,
 }
 
 /// This represents `permissions` in `packages/calckey-js/src/consts.ts`.
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
-pub enum Permission {
+pub enum AppPermission {
     #[serde(rename = "read:account")]
     ReadAccount,
     #[serde(rename = "write:account")]
diff --git a/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
index cfba50d7f..ffb817c12 100644
--- a/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
+++ b/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
@@ -1,10 +1,9 @@
+use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
+use napi_derive::napi;
 use parse_display::FromStr;
 use schemars::JsonSchema;
 use utoipa::ToSchema;
 
-use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
-use napi_derive::napi;
-
 #[napi]
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
index 90732130a..2da1e59d4 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
@@ -4,6 +4,7 @@ mod int_test {
         repository::Repository,
         schema,
     };
+    use pretty_assertions::assert_eq;
     use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
     use crate::{cleanup, prepare};
diff --git a/packages/backend/native-utils/crates/util/Cargo.toml b/packages/backend/native-utils/crates/util/Cargo.toml
index ad5486b4b..6050342dd 100644
--- a/packages/backend/native-utils/crates/util/Cargo.toml
+++ b/packages/backend/native-utils/crates/util/Cargo.toml
@@ -10,3 +10,6 @@ cuid2 = "0.1.0"
 once_cell = "1.17.1"
 rand = "0.8.5"
 thiserror = "1.0.40"
+
+[dev-dependencies]
+pretty_assertions = "1.3.0"
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/crates/util/src/id.rs
index 2831ef79d..d3c5809ea 100644
--- a/packages/backend/native-utils/crates/util/src/id.rs
+++ b/packages/backend/native-utils/crates/util/src/id.rs
@@ -22,6 +22,7 @@ pub fn create_id() -> Result<String, ErrorUninitialized> {
 
 #[cfg(test)]
 mod unit_test {
+    use pretty_assertions::{assert_eq, assert_ne};
     use std::thread;
 
     use crate::id;
diff --git a/packages/backend/native-utils/crates/util/src/random.rs b/packages/backend/native-utils/crates/util/src/random.rs
index 1c4a20d50..5ee06d128 100644
--- a/packages/backend/native-utils/crates/util/src/random.rs
+++ b/packages/backend/native-utils/crates/util/src/random.rs
@@ -10,6 +10,7 @@ pub fn gen_string(length: u16) -> String {
 
 #[cfg(test)]
 mod unit_test {
+    use pretty_assertions::{assert_eq, assert_ne};
     use std::thread;
 
     use super::gen_string;

From 5f849e417ec0f3ba9755e1b1ebbfc562c4eefa4e Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 08:48:12 -0400
Subject: [PATCH 36/66] move files out from crate

---
 packages/backend/native-utils/Cargo.toml      | 33 ++++++++++++++---
 .../native-utils/crates/database/Cargo.toml   | 12 -------
 .../native-utils/crates/model/Cargo.toml      | 35 -------------------
 .../native-utils/crates/util/Cargo.toml       | 15 --------
 .../{crates => }/migration/Cargo.toml         |  0
 .../{crates => }/migration/README.md          |  0
 .../{crates => }/migration/src/lib.rs         |  0
 .../src/m20230531_180824_drop_reversi.rs      |  0
 .../{crates => }/migration/src/main.rs        |  0
 .../{crates => }/migration/src/vec_to_json.rs |  0
 .../database/src => src/database}/error.rs    |  0
 .../src/lib.rs => src/database/mod.rs}        |  6 ++--
 packages/backend/native-utils/src/lib.rs      |  5 +++
 .../{crates/model/src => src/model}/entity.rs |  0
 .../model}/entity/abuse_user_report.rs        |  0
 .../src => src/model}/entity/access_token.rs  |  0
 .../model/src => src/model}/entity/ad.rs      |  0
 .../src => src/model}/entity/announcement.rs  |  0
 .../model}/entity/announcement_read.rs        |  0
 .../model/src => src/model}/entity/antenna.rs |  0
 .../src => src/model}/entity/antenna_note.rs  |  0
 .../model/src => src/model}/entity/app.rs     |  0
 .../model}/entity/attestation_challenge.rs    |  0
 .../src => src/model}/entity/auth_session.rs  |  0
 .../src => src/model}/entity/blocking.rs      |  0
 .../model/src => src/model}/entity/channel.rs |  0
 .../model}/entity/channel_following.rs        |  0
 .../model}/entity/channel_note_pining.rs      |  0
 .../model/src => src/model}/entity/clip.rs    |  0
 .../src => src/model}/entity/clip_note.rs     |  0
 .../src => src/model}/entity/drive_file.rs    |  0
 .../src => src/model}/entity/drive_folder.rs  |  0
 .../model/src => src/model}/entity/emoji.rs   |  0
 .../model}/entity/follow_request.rs           |  0
 .../src => src/model}/entity/following.rs     |  0
 .../src => src/model}/entity/gallery_like.rs  |  0
 .../src => src/model}/entity/gallery_post.rs  |  0
 .../model/src => src/model}/entity/hashtag.rs |  0
 .../src => src/model}/entity/instance.rs      |  0
 .../model}/entity/messaging_message.rs        |  0
 .../model/src => src/model}/entity/meta.rs    |  0
 .../src => src/model}/entity/migrations.rs    |  0
 .../model}/entity/moderation_log.rs           |  0
 .../src => src/model}/entity/muted_note.rs    |  0
 .../model/src => src/model}/entity/muting.rs  |  0
 .../model}/entity/newtype/macros.rs           |  0
 .../src => src/model}/entity/newtype/mod.rs   |  0
 .../model/src => src/model}/entity/note.rs    |  0
 .../src => src/model}/entity/note_edit.rs     |  0
 .../src => src/model}/entity/note_favorite.rs |  0
 .../src => src/model}/entity/note_reaction.rs |  0
 .../model}/entity/note_thread_muting.rs       |  0
 .../src => src/model}/entity/note_unread.rs   |  0
 .../src => src/model}/entity/note_watching.rs |  0
 .../src => src/model}/entity/notification.rs  |  0
 .../model/src => src/model}/entity/page.rs    |  0
 .../src => src/model}/entity/page_like.rs     |  0
 .../model}/entity/password_reset_request.rs   |  0
 .../model/src => src/model}/entity/poll.rs    |  0
 .../src => src/model}/entity/poll_vote.rs     |  0
 .../model/src => src/model}/entity/prelude.rs |  0
 .../src => src/model}/entity/promo_note.rs    |  0
 .../src => src/model}/entity/promo_read.rs    |  0
 .../model}/entity/registration_ticket.rs      |  0
 .../src => src/model}/entity/registry_item.rs |  0
 .../model/src => src/model}/entity/relay.rs   |  0
 .../src => src/model}/entity/renote_muting.rs |  0
 .../model}/entity/sea_orm_active_enums.rs     |  0
 .../model/src => src/model}/entity/signin.rs  |  0
 .../model}/entity/sw_subscription.rs          |  0
 .../src => src/model}/entity/used_username.rs |  0
 .../model/src => src/model}/entity/user.rs    |  0
 .../src => src/model}/entity/user_group.rs    |  0
 .../model}/entity/user_group_invitation.rs    |  0
 .../model}/entity/user_group_invite.rs        |  0
 .../model}/entity/user_group_joining.rs       |  0
 .../model/src => src/model}/entity/user_ip.rs |  0
 .../src => src/model}/entity/user_keypair.rs  |  0
 .../src => src/model}/entity/user_list.rs     |  0
 .../model}/entity/user_list_joining.rs        |  0
 .../model}/entity/user_note_pining.rs         |  0
 .../src => src/model}/entity/user_pending.rs  |  0
 .../src => src/model}/entity/user_profile.rs  |  0
 .../model}/entity/user_publickey.rs           |  0
 .../model}/entity/user_security_key.rs        |  0
 .../model/src => src/model}/entity/webhook.rs |  0
 .../{crates/model/src => src/model}/error.rs  |  9 ++++-
 .../model/src/lib.rs => src/model/mod.rs}     |  0
 .../model/src => src/model}/repository.rs     |  7 ++--
 .../src => src/model}/repository/antenna.rs   |  7 ++--
 .../{crates/model/src => src/model}/schema.rs |  0
 .../model/src => src/model}/schema/antenna.rs |  9 ++---
 .../model/src => src/model}/schema/app.rs     |  0
 .../model/src => src/model}/schema/napi.rs    |  0
 .../src => src/model}/schema/napi/antenna.rs  | 13 ++++++-
 .../{crates/util/src => src/util}/id.rs       |  2 +-
 .../util/src/lib.rs => src/util/mod.rs}       |  0
 .../{crates/util/src => src/util}/random.rs   |  0
 .../{crates/model => }/tests/common.rs        | 17 +++++----
 .../backend/native-utils/tests/model/mod.rs   |  1 +
 .../mod.rs => tests/model/repository.rs}      |  0
 .../model}/repository/antenna.rs              |  2 ++
 102 files changed, 82 insertions(+), 91 deletions(-)
 delete mode 100644 packages/backend/native-utils/crates/database/Cargo.toml
 delete mode 100644 packages/backend/native-utils/crates/model/Cargo.toml
 delete mode 100644 packages/backend/native-utils/crates/util/Cargo.toml
 rename packages/backend/native-utils/{crates => }/migration/Cargo.toml (100%)
 rename packages/backend/native-utils/{crates => }/migration/README.md (100%)
 rename packages/backend/native-utils/{crates => }/migration/src/lib.rs (100%)
 rename packages/backend/native-utils/{crates => }/migration/src/m20230531_180824_drop_reversi.rs (100%)
 rename packages/backend/native-utils/{crates => }/migration/src/main.rs (100%)
 rename packages/backend/native-utils/{crates => }/migration/src/vec_to_json.rs (100%)
 rename packages/backend/native-utils/{crates/database/src => src/database}/error.rs (100%)
 rename packages/backend/native-utils/{crates/database/src/lib.rs => src/database/mod.rs} (87%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/abuse_user_report.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/access_token.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/ad.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/announcement.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/announcement_read.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/antenna.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/antenna_note.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/app.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/attestation_challenge.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/auth_session.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/blocking.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/channel.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/channel_following.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/channel_note_pining.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/clip.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/clip_note.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/drive_file.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/drive_folder.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/emoji.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/follow_request.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/following.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/gallery_like.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/gallery_post.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/hashtag.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/instance.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/messaging_message.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/meta.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/migrations.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/moderation_log.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/muted_note.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/muting.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/newtype/macros.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/newtype/mod.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_edit.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_favorite.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_reaction.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_thread_muting.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_unread.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/note_watching.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/notification.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/page.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/page_like.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/password_reset_request.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/poll.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/poll_vote.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/prelude.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/promo_note.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/promo_read.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/registration_ticket.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/registry_item.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/relay.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/renote_muting.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/sea_orm_active_enums.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/signin.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/sw_subscription.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/used_username.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_group.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_group_invitation.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_group_invite.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_group_joining.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_ip.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_keypair.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_list.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_list_joining.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_note_pining.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_pending.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_profile.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_publickey.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/user_security_key.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/entity/webhook.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/error.rs (62%)
 rename packages/backend/native-utils/{crates/model/src/lib.rs => src/model/mod.rs} (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/repository.rs (75%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/repository/antenna.rs (92%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/schema.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/schema/antenna.rs (93%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/schema/app.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/schema/napi.rs (100%)
 rename packages/backend/native-utils/{crates/model/src => src/model}/schema/napi/antenna.rs (78%)
 rename packages/backend/native-utils/{crates/util/src => src/util}/id.rs (97%)
 rename packages/backend/native-utils/{crates/util/src/lib.rs => src/util/mod.rs} (100%)
 rename packages/backend/native-utils/{crates/util/src => src/util}/random.rs (100%)
 rename packages/backend/native-utils/{crates/model => }/tests/common.rs (96%)
 create mode 100644 packages/backend/native-utils/tests/model/mod.rs
 rename packages/backend/native-utils/{crates/model/tests/repository/mod.rs => tests/model/repository.rs} (100%)
 rename packages/backend/native-utils/{crates/model/tests => tests/model}/repository/antenna.rs (97%)

diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index 6f3c0e23f..3c70a0209 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -4,15 +4,40 @@ name = "native-utils"
 version = "0.0.0"
 
 [workspace]
-members = ["crates/*"]
+members = ["migration/Cargo.toml"]
+
+[features]
+default = ["napi"]
+noarray = []
+napi = ["dep:napi", "dep:napi-derive"]
 
 [lib]
-crate-type = ["cdylib"]
+crate-type = ["cdylib", "lib"]
 
 [dependencies]
+async-trait = "0.1.68"
+cfg-if = "1.0.0"
+chrono = "0.4.24"
+cuid2 = "0.1.0"
+derive_more = "0.99.17"
+jsonschema = "0.17.0"
+once_cell = "1.17.1"
+parse-display = "0.8.0"
+rand = "0.8.5"
+schemars = { version = "0.8.12", features = ["chrono"] }
+sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "postgres-array", "sqlx-sqlite", "runtime-tokio-rustls"] }
+serde = { version = "1.0.163", features = ["derive"] }
+serde_json = "1.0.96"
+thiserror = "1.0.40"
+tokio = { version = "1.28.1", features = ["full"] }
+utoipa = "3.3.0"
+
 # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
-napi = { version = "2.12.0", default-features = false, features = ["napi4"] }
-napi-derive = "2.12.0"
+napi = { version = "2.12.0", default-features = false, features = ["napi4", "tokio_rt"], optional = true }
+napi-derive = { version = "2.12.0", optional = true }
+
+[dev-dependencies]
+pretty_assertions = "1.3.0"
 
 [build-dependencies]
 napi-build = "2.0.1"
diff --git a/packages/backend/native-utils/crates/database/Cargo.toml b/packages/backend/native-utils/crates/database/Cargo.toml
deleted file mode 100644
index 440a76cf5..000000000
--- a/packages/backend/native-utils/crates/database/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "database"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-once_cell = "1.17.1"
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
-thiserror = "1.0.40"
-tokio = { version = "1.28.1", features = ["macros"] }
diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml
deleted file mode 100644
index 4925fb702..000000000
--- a/packages/backend/native-utils/crates/model/Cargo.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[package]
-name = "model"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-[features]
-default = ["napi"]
-noarray = []
-napi = ["dep:napi", "dep:napi-derive"]
-
-[dependencies]
-async-trait = "0.1.68"
-cfg-if = "1.0.0"
-chrono = "0.4.24"
-database = { path = "../database" }
-derive_more = "0.99.17"
-jsonschema = "0.17.0"
-once_cell = "1.17.1"
-parse-display = "0.8.0"
-schemars = { version = "0.8.12", features = ["chrono"] }
-sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "postgres-array", "sqlx-sqlite", "runtime-tokio-rustls"] }
-serde = { version = "1.0.163", features = ["derive"] }
-serde_json = "1.0.96"
-thiserror = "1.0.40"
-tokio = { version = "1.28.1", features = ["sync"] }
-util = { path = "../util" }
-utoipa = "3.3.0"
-
-# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
-napi = { version = "2.12.0", default-features = false, features = ["napi4"], optional = true }
-napi-derive = { version = "2.12.0", optional = true }
-
-[dev-dependencies]
-pretty_assertions = "1.3.0"
diff --git a/packages/backend/native-utils/crates/util/Cargo.toml b/packages/backend/native-utils/crates/util/Cargo.toml
deleted file mode 100644
index 6050342dd..000000000
--- a/packages/backend/native-utils/crates/util/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-name = "util"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-cuid2 = "0.1.0"
-once_cell = "1.17.1"
-rand = "0.8.5"
-thiserror = "1.0.40"
-
-[dev-dependencies]
-pretty_assertions = "1.3.0"
diff --git a/packages/backend/native-utils/crates/migration/Cargo.toml b/packages/backend/native-utils/migration/Cargo.toml
similarity index 100%
rename from packages/backend/native-utils/crates/migration/Cargo.toml
rename to packages/backend/native-utils/migration/Cargo.toml
diff --git a/packages/backend/native-utils/crates/migration/README.md b/packages/backend/native-utils/migration/README.md
similarity index 100%
rename from packages/backend/native-utils/crates/migration/README.md
rename to packages/backend/native-utils/migration/README.md
diff --git a/packages/backend/native-utils/crates/migration/src/lib.rs b/packages/backend/native-utils/migration/src/lib.rs
similarity index 100%
rename from packages/backend/native-utils/crates/migration/src/lib.rs
rename to packages/backend/native-utils/migration/src/lib.rs
diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs b/packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs
similarity index 100%
rename from packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs
rename to packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs
diff --git a/packages/backend/native-utils/crates/migration/src/main.rs b/packages/backend/native-utils/migration/src/main.rs
similarity index 100%
rename from packages/backend/native-utils/crates/migration/src/main.rs
rename to packages/backend/native-utils/migration/src/main.rs
diff --git a/packages/backend/native-utils/crates/migration/src/vec_to_json.rs b/packages/backend/native-utils/migration/src/vec_to_json.rs
similarity index 100%
rename from packages/backend/native-utils/crates/migration/src/vec_to_json.rs
rename to packages/backend/native-utils/migration/src/vec_to_json.rs
diff --git a/packages/backend/native-utils/crates/database/src/error.rs b/packages/backend/native-utils/src/database/error.rs
similarity index 100%
rename from packages/backend/native-utils/crates/database/src/error.rs
rename to packages/backend/native-utils/src/database/error.rs
diff --git a/packages/backend/native-utils/crates/database/src/lib.rs b/packages/backend/native-utils/src/database/mod.rs
similarity index 87%
rename from packages/backend/native-utils/crates/database/src/lib.rs
rename to packages/backend/native-utils/src/database/mod.rs
index 0012d2292..c3cdea727 100644
--- a/packages/backend/native-utils/crates/database/src/lib.rs
+++ b/packages/backend/native-utils/src/database/mod.rs
@@ -1,9 +1,8 @@
 pub mod error;
 
+use error::Error;
 use sea_orm::{Database, DbConn};
 
-use crate::error::Error;
-
 static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
 
 pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
@@ -18,8 +17,7 @@ pub fn get_database() -> Result<&'static DbConn, Error> {
 
 #[cfg(test)]
 mod unit_test {
-    use super::get_database;
-    use crate::error::Error;
+    use super::{error::Error, get_database};
 
     #[test]
     fn error_uninitialized() {
diff --git a/packages/backend/native-utils/src/lib.rs b/packages/backend/native-utils/src/lib.rs
index e13190140..6a5e3f7f2 100644
--- a/packages/backend/native-utils/src/lib.rs
+++ b/packages/backend/native-utils/src/lib.rs
@@ -1 +1,6 @@
+pub mod database;
+pub mod model;
+pub mod util;
+
+#[cfg(feature = "napi")]
 pub mod mastodon_api;
diff --git a/packages/backend/native-utils/crates/model/src/entity.rs b/packages/backend/native-utils/src/model/entity.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity.rs
rename to packages/backend/native-utils/src/model/entity.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs b/packages/backend/native-utils/src/model/entity/abuse_user_report.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/abuse_user_report.rs
rename to packages/backend/native-utils/src/model/entity/abuse_user_report.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/access_token.rs b/packages/backend/native-utils/src/model/entity/access_token.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/access_token.rs
rename to packages/backend/native-utils/src/model/entity/access_token.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/ad.rs b/packages/backend/native-utils/src/model/entity/ad.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/ad.rs
rename to packages/backend/native-utils/src/model/entity/ad.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement.rs b/packages/backend/native-utils/src/model/entity/announcement.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/announcement.rs
rename to packages/backend/native-utils/src/model/entity/announcement.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/announcement_read.rs b/packages/backend/native-utils/src/model/entity/announcement_read.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/announcement_read.rs
rename to packages/backend/native-utils/src/model/entity/announcement_read.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/src/model/entity/antenna.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/antenna.rs
rename to packages/backend/native-utils/src/model/entity/antenna.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna_note.rs b/packages/backend/native-utils/src/model/entity/antenna_note.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/antenna_note.rs
rename to packages/backend/native-utils/src/model/entity/antenna_note.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/app.rs b/packages/backend/native-utils/src/model/entity/app.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/app.rs
rename to packages/backend/native-utils/src/model/entity/app.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs b/packages/backend/native-utils/src/model/entity/attestation_challenge.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/attestation_challenge.rs
rename to packages/backend/native-utils/src/model/entity/attestation_challenge.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/auth_session.rs b/packages/backend/native-utils/src/model/entity/auth_session.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/auth_session.rs
rename to packages/backend/native-utils/src/model/entity/auth_session.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/blocking.rs b/packages/backend/native-utils/src/model/entity/blocking.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/blocking.rs
rename to packages/backend/native-utils/src/model/entity/blocking.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel.rs b/packages/backend/native-utils/src/model/entity/channel.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/channel.rs
rename to packages/backend/native-utils/src/model/entity/channel.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_following.rs b/packages/backend/native-utils/src/model/entity/channel_following.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/channel_following.rs
rename to packages/backend/native-utils/src/model/entity/channel_following.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs b/packages/backend/native-utils/src/model/entity/channel_note_pining.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/channel_note_pining.rs
rename to packages/backend/native-utils/src/model/entity/channel_note_pining.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip.rs b/packages/backend/native-utils/src/model/entity/clip.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/clip.rs
rename to packages/backend/native-utils/src/model/entity/clip.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/clip_note.rs b/packages/backend/native-utils/src/model/entity/clip_note.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/clip_note.rs
rename to packages/backend/native-utils/src/model/entity/clip_note.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_file.rs b/packages/backend/native-utils/src/model/entity/drive_file.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/drive_file.rs
rename to packages/backend/native-utils/src/model/entity/drive_file.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/drive_folder.rs b/packages/backend/native-utils/src/model/entity/drive_folder.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/drive_folder.rs
rename to packages/backend/native-utils/src/model/entity/drive_folder.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/emoji.rs b/packages/backend/native-utils/src/model/entity/emoji.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/emoji.rs
rename to packages/backend/native-utils/src/model/entity/emoji.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/follow_request.rs b/packages/backend/native-utils/src/model/entity/follow_request.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/follow_request.rs
rename to packages/backend/native-utils/src/model/entity/follow_request.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/following.rs b/packages/backend/native-utils/src/model/entity/following.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/following.rs
rename to packages/backend/native-utils/src/model/entity/following.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_like.rs b/packages/backend/native-utils/src/model/entity/gallery_like.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/gallery_like.rs
rename to packages/backend/native-utils/src/model/entity/gallery_like.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/gallery_post.rs b/packages/backend/native-utils/src/model/entity/gallery_post.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/gallery_post.rs
rename to packages/backend/native-utils/src/model/entity/gallery_post.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/hashtag.rs b/packages/backend/native-utils/src/model/entity/hashtag.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/hashtag.rs
rename to packages/backend/native-utils/src/model/entity/hashtag.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/instance.rs b/packages/backend/native-utils/src/model/entity/instance.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/instance.rs
rename to packages/backend/native-utils/src/model/entity/instance.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/messaging_message.rs b/packages/backend/native-utils/src/model/entity/messaging_message.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/messaging_message.rs
rename to packages/backend/native-utils/src/model/entity/messaging_message.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/meta.rs b/packages/backend/native-utils/src/model/entity/meta.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/meta.rs
rename to packages/backend/native-utils/src/model/entity/meta.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/migrations.rs b/packages/backend/native-utils/src/model/entity/migrations.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/migrations.rs
rename to packages/backend/native-utils/src/model/entity/migrations.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/moderation_log.rs b/packages/backend/native-utils/src/model/entity/moderation_log.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/moderation_log.rs
rename to packages/backend/native-utils/src/model/entity/moderation_log.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/muted_note.rs b/packages/backend/native-utils/src/model/entity/muted_note.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/muted_note.rs
rename to packages/backend/native-utils/src/model/entity/muted_note.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/muting.rs b/packages/backend/native-utils/src/model/entity/muting.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/muting.rs
rename to packages/backend/native-utils/src/model/entity/muting.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs b/packages/backend/native-utils/src/model/entity/newtype/macros.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs
rename to packages/backend/native-utils/src/model/entity/newtype/macros.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/src/model/entity/newtype/mod.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs
rename to packages/backend/native-utils/src/model/entity/newtype/mod.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note.rs b/packages/backend/native-utils/src/model/entity/note.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note.rs
rename to packages/backend/native-utils/src/model/entity/note.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_edit.rs b/packages/backend/native-utils/src/model/entity/note_edit.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_edit.rs
rename to packages/backend/native-utils/src/model/entity/note_edit.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_favorite.rs b/packages/backend/native-utils/src/model/entity/note_favorite.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_favorite.rs
rename to packages/backend/native-utils/src/model/entity/note_favorite.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_reaction.rs b/packages/backend/native-utils/src/model/entity/note_reaction.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_reaction.rs
rename to packages/backend/native-utils/src/model/entity/note_reaction.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs b/packages/backend/native-utils/src/model/entity/note_thread_muting.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_thread_muting.rs
rename to packages/backend/native-utils/src/model/entity/note_thread_muting.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_unread.rs b/packages/backend/native-utils/src/model/entity/note_unread.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_unread.rs
rename to packages/backend/native-utils/src/model/entity/note_unread.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/note_watching.rs b/packages/backend/native-utils/src/model/entity/note_watching.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/note_watching.rs
rename to packages/backend/native-utils/src/model/entity/note_watching.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/notification.rs b/packages/backend/native-utils/src/model/entity/notification.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/notification.rs
rename to packages/backend/native-utils/src/model/entity/notification.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/page.rs b/packages/backend/native-utils/src/model/entity/page.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/page.rs
rename to packages/backend/native-utils/src/model/entity/page.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/page_like.rs b/packages/backend/native-utils/src/model/entity/page_like.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/page_like.rs
rename to packages/backend/native-utils/src/model/entity/page_like.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs b/packages/backend/native-utils/src/model/entity/password_reset_request.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/password_reset_request.rs
rename to packages/backend/native-utils/src/model/entity/password_reset_request.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll.rs b/packages/backend/native-utils/src/model/entity/poll.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/poll.rs
rename to packages/backend/native-utils/src/model/entity/poll.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/poll_vote.rs b/packages/backend/native-utils/src/model/entity/poll_vote.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/poll_vote.rs
rename to packages/backend/native-utils/src/model/entity/poll_vote.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/prelude.rs b/packages/backend/native-utils/src/model/entity/prelude.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/prelude.rs
rename to packages/backend/native-utils/src/model/entity/prelude.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_note.rs b/packages/backend/native-utils/src/model/entity/promo_note.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/promo_note.rs
rename to packages/backend/native-utils/src/model/entity/promo_note.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/promo_read.rs b/packages/backend/native-utils/src/model/entity/promo_read.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/promo_read.rs
rename to packages/backend/native-utils/src/model/entity/promo_read.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs b/packages/backend/native-utils/src/model/entity/registration_ticket.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/registration_ticket.rs
rename to packages/backend/native-utils/src/model/entity/registration_ticket.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/registry_item.rs b/packages/backend/native-utils/src/model/entity/registry_item.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/registry_item.rs
rename to packages/backend/native-utils/src/model/entity/registry_item.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/relay.rs b/packages/backend/native-utils/src/model/entity/relay.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/relay.rs
rename to packages/backend/native-utils/src/model/entity/relay.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/renote_muting.rs b/packages/backend/native-utils/src/model/entity/renote_muting.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/renote_muting.rs
rename to packages/backend/native-utils/src/model/entity/renote_muting.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs b/packages/backend/native-utils/src/model/entity/sea_orm_active_enums.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/sea_orm_active_enums.rs
rename to packages/backend/native-utils/src/model/entity/sea_orm_active_enums.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/signin.rs b/packages/backend/native-utils/src/model/entity/signin.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/signin.rs
rename to packages/backend/native-utils/src/model/entity/signin.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs b/packages/backend/native-utils/src/model/entity/sw_subscription.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/sw_subscription.rs
rename to packages/backend/native-utils/src/model/entity/sw_subscription.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/used_username.rs b/packages/backend/native-utils/src/model/entity/used_username.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/used_username.rs
rename to packages/backend/native-utils/src/model/entity/used_username.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user.rs b/packages/backend/native-utils/src/model/entity/user.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user.rs
rename to packages/backend/native-utils/src/model/entity/user.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group.rs b/packages/backend/native-utils/src/model/entity/user_group.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_group.rs
rename to packages/backend/native-utils/src/model/entity/user_group.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs b/packages/backend/native-utils/src/model/entity/user_group_invitation.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_group_invitation.rs
rename to packages/backend/native-utils/src/model/entity/user_group_invitation.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs b/packages/backend/native-utils/src/model/entity/user_group_invite.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_group_invite.rs
rename to packages/backend/native-utils/src/model/entity/user_group_invite.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs b/packages/backend/native-utils/src/model/entity/user_group_joining.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_group_joining.rs
rename to packages/backend/native-utils/src/model/entity/user_group_joining.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_ip.rs b/packages/backend/native-utils/src/model/entity/user_ip.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_ip.rs
rename to packages/backend/native-utils/src/model/entity/user_ip.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_keypair.rs b/packages/backend/native-utils/src/model/entity/user_keypair.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_keypair.rs
rename to packages/backend/native-utils/src/model/entity/user_keypair.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list.rs b/packages/backend/native-utils/src/model/entity/user_list.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_list.rs
rename to packages/backend/native-utils/src/model/entity/user_list.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs b/packages/backend/native-utils/src/model/entity/user_list_joining.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_list_joining.rs
rename to packages/backend/native-utils/src/model/entity/user_list_joining.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs b/packages/backend/native-utils/src/model/entity/user_note_pining.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_note_pining.rs
rename to packages/backend/native-utils/src/model/entity/user_note_pining.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_pending.rs b/packages/backend/native-utils/src/model/entity/user_pending.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_pending.rs
rename to packages/backend/native-utils/src/model/entity/user_pending.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_profile.rs b/packages/backend/native-utils/src/model/entity/user_profile.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_profile.rs
rename to packages/backend/native-utils/src/model/entity/user_profile.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_publickey.rs b/packages/backend/native-utils/src/model/entity/user_publickey.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_publickey.rs
rename to packages/backend/native-utils/src/model/entity/user_publickey.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/user_security_key.rs b/packages/backend/native-utils/src/model/entity/user_security_key.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/user_security_key.rs
rename to packages/backend/native-utils/src/model/entity/user_security_key.rs
diff --git a/packages/backend/native-utils/crates/model/src/entity/webhook.rs b/packages/backend/native-utils/src/model/entity/webhook.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/entity/webhook.rs
rename to packages/backend/native-utils/src/model/entity/webhook.rs
diff --git a/packages/backend/native-utils/crates/model/src/error.rs b/packages/backend/native-utils/src/model/error.rs
similarity index 62%
rename from packages/backend/native-utils/crates/model/src/error.rs
rename to packages/backend/native-utils/src/model/error.rs
index c90f3f5a3..2292246ae 100644
--- a/packages/backend/native-utils/crates/model/src/error.rs
+++ b/packages/backend/native-utils/src/model/error.rs
@@ -3,9 +3,16 @@ pub enum Error {
     #[error("Failed to parse string")]
     ParseError(#[from] parse_display::ParseError),
     #[error("Failed to get database connection")]
-    DbConnError(#[from] database::error::Error),
+    DbConnError(#[from] crate::database::error::Error),
     #[error("Database operation error: {0}")]
     DbOperationError(#[from] sea_orm::DbErr),
     #[error("Requested entity not found")]
     NotFound,
 }
+
+#[cfg(feature = "napi")]
+impl Into<napi::Error> for Error {
+    fn into(self) -> napi::Error {
+        napi::Error::from_reason(self.to_string())
+    }
+}
diff --git a/packages/backend/native-utils/crates/model/src/lib.rs b/packages/backend/native-utils/src/model/mod.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/lib.rs
rename to packages/backend/native-utils/src/model/mod.rs
diff --git a/packages/backend/native-utils/crates/model/src/repository.rs b/packages/backend/native-utils/src/model/repository.rs
similarity index 75%
rename from packages/backend/native-utils/crates/model/src/repository.rs
rename to packages/backend/native-utils/src/model/repository.rs
index 83573ab16..0f9f7de32 100644
--- a/packages/backend/native-utils/crates/model/src/repository.rs
+++ b/packages/backend/native-utils/src/model/repository.rs
@@ -3,7 +3,7 @@ pub mod antenna;
 use async_trait::async_trait;
 use schemars::JsonSchema;
 
-use crate::error::Error;
+use super::error::Error;
 
 #[async_trait]
 pub trait Repository<T: JsonSchema> {
@@ -14,7 +14,10 @@ pub trait Repository<T: JsonSchema> {
 mod macros {
     macro_rules! impl_pack_by_id {
         ($a:ty, $b:ident) => {
-            match <$a>::find_by_id($b).one(database::get_database()?).await? {
+            match <$a>::find_by_id($b)
+                .one(crate::database::get_database()?)
+                .await?
+            {
                 None => Err(Error::NotFound),
                 Some(m) => m.pack().await,
             }
diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/src/model/repository/antenna.rs
similarity index 92%
rename from packages/backend/native-utils/crates/model/src/repository/antenna.rs
rename to packages/backend/native-utils/src/model/repository/antenna.rs
index c8324edd3..7c614b954 100644
--- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs
+++ b/packages/backend/native-utils/src/model/repository/antenna.rs
@@ -2,9 +2,10 @@ use async_trait::async_trait;
 use cfg_if::cfg_if;
 use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
 
-use crate::entity::{antenna, antenna_note, user_group_joining};
-use crate::error::Error;
-use crate::schema::Antenna;
+use crate::database;
+use crate::model::entity::{antenna, antenna_note, user_group_joining};
+use crate::model::error::Error;
+use crate::model::schema::Antenna;
 
 use super::macros::impl_pack_by_id;
 use super::Repository;
diff --git a/packages/backend/native-utils/crates/model/src/schema.rs b/packages/backend/native-utils/src/model/schema.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/schema.rs
rename to packages/backend/native-utils/src/model/schema.rs
diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
similarity index 93%
rename from packages/backend/native-utils/crates/model/src/schema/antenna.rs
rename to packages/backend/native-utils/src/model/schema/antenna.rs
index 338998019..6376b3bc7 100644
--- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -5,7 +5,8 @@ use schemars::JsonSchema;
 use utoipa::ToSchema;
 
 use super::Schema;
-use crate::entity::sea_orm_active_enums::AntennaSrcEnum;
+use crate::model;
+use crate::model::entity::sea_orm_active_enums::AntennaSrcEnum;
 
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
@@ -47,10 +48,10 @@ pub enum AntennaSrc {
 }
 
 impl TryFrom<AntennaSrcEnum> for super::AntennaSrc {
-    type Error = crate::error::Error;
+    type Error = model::error::Error;
 
     fn try_from(value: AntennaSrcEnum) -> Result<Self, Self::Error> {
-        value.to_string().parse().map_err(crate::error::Error::from)
+        value.to_string().parse().map_err(model::error::Error::from)
     }
 }
 
@@ -64,7 +65,7 @@ mod unit_test {
     use pretty_assertions::assert_eq;
     use serde_json::json;
 
-    use crate::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::AntennaSrc};
+    use crate::model::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::AntennaSrc};
 
     use super::VALIDATOR;
 
diff --git a/packages/backend/native-utils/crates/model/src/schema/app.rs b/packages/backend/native-utils/src/model/schema/app.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/schema/app.rs
rename to packages/backend/native-utils/src/model/schema/app.rs
diff --git a/packages/backend/native-utils/crates/model/src/schema/napi.rs b/packages/backend/native-utils/src/model/schema/napi.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/src/schema/napi.rs
rename to packages/backend/native-utils/src/model/schema/napi.rs
diff --git a/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs b/packages/backend/native-utils/src/model/schema/napi/antenna.rs
similarity index 78%
rename from packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
rename to packages/backend/native-utils/src/model/schema/napi/antenna.rs
index ffb817c12..e5c156efa 100644
--- a/packages/backend/native-utils/crates/model/src/schema/napi/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/napi/antenna.rs
@@ -1,9 +1,12 @@
-use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
+use napi::bindgen_prelude::*;
 use napi_derive::napi;
 use parse_display::FromStr;
 use schemars::JsonSchema;
 use utoipa::ToSchema;
 
+use crate::model::entity::antenna::Model;
+use crate::model::repository::Repository;
+
 #[napi]
 #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
 #[serde(rename_all = "camelCase")]
@@ -44,3 +47,11 @@ pub enum AntennaSrc {
     Group,
     Instances,
 }
+
+#[napi]
+impl Antenna {
+    #[napi]
+    pub async fn pack_by_id(id: String) -> napi::Result<Antenna> {
+        Model::pack_by_id(id).await.map_err(Into::into)
+    }
+}
diff --git a/packages/backend/native-utils/crates/util/src/id.rs b/packages/backend/native-utils/src/util/id.rs
similarity index 97%
rename from packages/backend/native-utils/crates/util/src/id.rs
rename to packages/backend/native-utils/src/util/id.rs
index d3c5809ea..98dd63c4e 100644
--- a/packages/backend/native-utils/crates/util/src/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -25,7 +25,7 @@ mod unit_test {
     use pretty_assertions::{assert_eq, assert_ne};
     use std::thread;
 
-    use crate::id;
+    use crate::util::id;
 
     #[test]
     fn can_generate_unique_ids() {
diff --git a/packages/backend/native-utils/crates/util/src/lib.rs b/packages/backend/native-utils/src/util/mod.rs
similarity index 100%
rename from packages/backend/native-utils/crates/util/src/lib.rs
rename to packages/backend/native-utils/src/util/mod.rs
diff --git a/packages/backend/native-utils/crates/util/src/random.rs b/packages/backend/native-utils/src/util/random.rs
similarity index 100%
rename from packages/backend/native-utils/crates/util/src/random.rs
rename to packages/backend/native-utils/src/util/random.rs
diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/tests/common.rs
similarity index 96%
rename from packages/backend/native-utils/crates/model/tests/common.rs
rename to packages/backend/native-utils/tests/common.rs
index 554a8ca73..775b37212 100644
--- a/packages/backend/native-utils/crates/model/tests/common.rs
+++ b/packages/backend/native-utils/tests/common.rs
@@ -1,20 +1,19 @@
 #![cfg(not(feature = "napi"))]
 
-extern crate model;
-
-mod repository;
+mod model;
 
 use chrono::Utc;
-use model::entity;
-use model::entity::sea_orm_active_enums::AntennaSrcEnum;
+use native_utils::database;
+use native_utils::model::entity;
+use native_utils::model::entity::sea_orm_active_enums::AntennaSrcEnum;
+use native_utils::util::{
+    id::{create_id, init_id},
+    random::gen_string,
+};
 use sea_orm::{
     sea_query::TableCreateStatement, ActiveModelTrait, ConnectionTrait, DbBackend, DbConn, DbErr,
     EntityTrait, IntoActiveModel, TransactionTrait,
 };
-use util::{
-    id::{create_id, init_id},
-    random::gen_string,
-};
 
 /// Insert predefined entries in the database.
 async fn prepare() {
diff --git a/packages/backend/native-utils/tests/model/mod.rs b/packages/backend/native-utils/tests/model/mod.rs
new file mode 100644
index 000000000..a35bac056
--- /dev/null
+++ b/packages/backend/native-utils/tests/model/mod.rs
@@ -0,0 +1 @@
+mod repository;
diff --git a/packages/backend/native-utils/crates/model/tests/repository/mod.rs b/packages/backend/native-utils/tests/model/repository.rs
similarity index 100%
rename from packages/backend/native-utils/crates/model/tests/repository/mod.rs
rename to packages/backend/native-utils/tests/model/repository.rs
diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/tests/model/repository/antenna.rs
similarity index 97%
rename from packages/backend/native-utils/crates/model/tests/repository/antenna.rs
rename to packages/backend/native-utils/tests/model/repository/antenna.rs
index 2da1e59d4..a37007398 100644
--- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs
+++ b/packages/backend/native-utils/tests/model/repository/antenna.rs
@@ -1,4 +1,6 @@
 mod int_test {
+    use native_utils::{database, model};
+
     use model::{
         entity::{antenna, user},
         repository::Repository,

From bc209143e67b7991a98e0735337b1ea57b0aee84 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 09:29:52 -0400
Subject: [PATCH 37/66] adjust module structure

---
 .../backend/native-utils/src/model/schema.rs  | 25 ++++----
 .../native-utils/src/model/schema/antenna.rs  | 60 +++++++++++++++++++
 .../native-utils/src/model/schema/napi.rs     |  1 -
 .../src/model/schema/napi/antenna.rs          | 57 ------------------
 4 files changed, 72 insertions(+), 71 deletions(-)
 delete mode 100644 packages/backend/native-utils/src/model/schema/napi.rs
 delete mode 100644 packages/backend/native-utils/src/model/schema/napi/antenna.rs

diff --git a/packages/backend/native-utils/src/model/schema.rs b/packages/backend/native-utils/src/model/schema.rs
index 71f9348b3..ef4368dda 100644
--- a/packages/backend/native-utils/src/model/schema.rs
+++ b/packages/backend/native-utils/src/model/schema.rs
@@ -5,19 +5,6 @@ use cfg_if::cfg_if;
 use jsonschema::JSONSchema;
 use schemars::{schema_for, JsonSchema};
 
-cfg_if! {
-    if #[cfg(feature = "napi")] {
-        mod napi;
-        pub use self::napi::antenna::Antenna;
-        pub use self::napi::antenna::AntennaSrc;
-    } else {
-        pub use antenna::Antenna;
-        pub use antenna::AntennaSrc;
-        pub use app::App;
-        pub use app::AppPermission;
-    }
-}
-
 /// Structs of schema defitions implement this trait in order to
 /// provide the JSON Schema validator [`jsonschema::JSONSchema`].
 pub trait Schema<T: JsonSchema> {
@@ -33,3 +20,15 @@ pub trait Schema<T: JsonSchema> {
             .expect("Unable to compile schema")
     }
 }
+
+cfg_if! {
+    if #[cfg(feature = "napi")] {
+        pub use antenna::napi::AntennaSchema as Antenna;
+        pub use antenna::napi::AntennaSrc;
+    } else {
+        pub use antenna::Antenna;
+        pub use antenna::AntennaSrc;
+        pub use app::App;
+        pub use app::AppPermission;
+    }
+}
diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
index 6376b3bc7..8b553c082 100644
--- a/packages/backend/native-utils/src/model/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -60,6 +60,66 @@ impl Schema<Self> for super::Antenna {}
 pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| super::Antenna::validator());
 // ----
 
+#[cfg(feature = "napi")]
+pub mod napi {
+    use napi::bindgen_prelude::*;
+    use napi_derive::napi;
+    use parse_display::FromStr;
+    use schemars::JsonSchema;
+    use utoipa::ToSchema;
+
+    use crate::model::{entity::antenna, repository::Repository};
+
+    #[napi]
+    #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
+    #[serde(rename_all = "camelCase")]
+    pub struct AntennaSchema {
+        pub id: String,
+        pub created_at: String,
+        pub name: String,
+        pub keywords: Vec<Vec<String>>,
+        pub exclude_keywords: Vec<Vec<String>>,
+        #[schema(inline)]
+        pub src: AntennaSrc,
+        pub user_list_id: Option<String>,
+        pub user_group_id: Option<String>,
+        pub users: Vec<String>,
+        pub instances: Vec<String>,
+        #[serde(default)]
+        pub case_sensitive: bool,
+        #[serde(default)]
+        pub notify: bool,
+        #[serde(default)]
+        pub with_replies: bool,
+        #[serde(default)]
+        pub with_file: bool,
+        #[serde(default)]
+        pub has_unread_note: bool,
+    }
+
+    #[napi]
+    #[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
+    #[serde(rename_all = "camelCase")]
+    #[display(style = "camelCase")]
+    #[display("'{}'")]
+    pub enum AntennaSrc {
+        Home,
+        All,
+        Users,
+        List,
+        Group,
+        Instances,
+    }
+
+    #[napi]
+    impl AntennaSchema {
+        #[napi]
+        pub async fn pack_by_id(id: String) -> napi::Result<AntennaSchema> {
+            antenna::Model::pack_by_id(id).await.map_err(Into::into)
+        }
+    }
+}
+
 #[cfg(test)]
 mod unit_test {
     use pretty_assertions::assert_eq;
diff --git a/packages/backend/native-utils/src/model/schema/napi.rs b/packages/backend/native-utils/src/model/schema/napi.rs
deleted file mode 100644
index 16130e4cc..000000000
--- a/packages/backend/native-utils/src/model/schema/napi.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod antenna;
diff --git a/packages/backend/native-utils/src/model/schema/napi/antenna.rs b/packages/backend/native-utils/src/model/schema/napi/antenna.rs
deleted file mode 100644
index e5c156efa..000000000
--- a/packages/backend/native-utils/src/model/schema/napi/antenna.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use napi::bindgen_prelude::*;
-use napi_derive::napi;
-use parse_display::FromStr;
-use schemars::JsonSchema;
-use utoipa::ToSchema;
-
-use crate::model::entity::antenna::Model;
-use crate::model::repository::Repository;
-
-#[napi]
-#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct Antenna {
-    pub id: String,
-    pub created_at: String,
-    pub name: String,
-    pub keywords: Vec<Vec<String>>,
-    pub exclude_keywords: Vec<Vec<String>>,
-    #[schema(inline)]
-    pub src: AntennaSrc,
-    pub user_list_id: Option<String>,
-    pub user_group_id: Option<String>,
-    pub users: Vec<String>,
-    pub instances: Vec<String>,
-    #[serde(default)]
-    pub case_sensitive: bool,
-    #[serde(default)]
-    pub notify: bool,
-    #[serde(default)]
-    pub with_replies: bool,
-    #[serde(default)]
-    pub with_file: bool,
-    #[serde(default)]
-    pub has_unread_note: bool,
-}
-
-#[napi]
-#[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
-#[serde(rename_all = "camelCase")]
-#[display(style = "camelCase")]
-#[display("'{}'")]
-pub enum AntennaSrc {
-    Home,
-    All,
-    Users,
-    List,
-    Group,
-    Instances,
-}
-
-#[napi]
-impl Antenna {
-    #[napi]
-    pub async fn pack_by_id(id: String) -> napi::Result<Antenna> {
-        Model::pack_by_id(id).await.map_err(Into::into)
-    }
-}

From 3af4a86254ccf67b7a0c2060bf55013776500c77 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 09:55:57 -0400
Subject: [PATCH 38/66] use schema in native-utils

---
 packages/backend/native-utils/package.json    |  8 ++---
 packages/backend/package.json                 |  2 +-
 .../src/models/repositories/antenna.ts        | 34 +++----------------
 pnpm-workspace.yaml                           |  1 +
 4 files changed, 11 insertions(+), 34 deletions(-)

diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index aa194bad3..f1ea2c9b4 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -23,8 +23,8 @@
   },
   "license": "MIT",
   "devDependencies": {
-    "@napi-rs/cli": "^2.15.0",
-    "ava": "^5.1.1"
+    "@napi-rs/cli": "2.15.0",
+    "ava": "5.1.1"
   },
   "ava": {
     "timeout": "3m"
@@ -40,7 +40,7 @@
     "test": "ava",
     "universal": "napi universal",
     "version": "napi version",
-    "cargo:unit": "cargo test --workspace unit_test",
-    "cargo:integration": "cargo test --workspace int_test -- --test-threads=1"
+    "cargo:unit": "cargo test unit_test",
+    "cargo:integration": "cargo test --no-default-features int_test -- --test-threads=1"
   }
 }
diff --git a/packages/backend/package.json b/packages/backend/package.json
index c084d67bc..0b0315a06 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -9,7 +9,7 @@
 		"migrate": "typeorm migration:run -d ormconfig.js",
 		"revertmigration": "typeorm migration:revert -d ormconfig.js",
 		"check:connect": "node ./check_connect.js",
-		"build": "napi build --platform --release --cargo-cwd native-utils ./native-utils/built/ && pnpm swc src -d built -D",
+		"build": "pnpm swc src -d built -D",
 		"watch": "pnpm swc src -d built -D -w",
 		"lint": "pnpm rome check \"src/**/*.ts\"",
 		"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
diff --git a/packages/backend/src/models/repositories/antenna.ts b/packages/backend/src/models/repositories/antenna.ts
index c325e2589..d9405f4a9 100644
--- a/packages/backend/src/models/repositories/antenna.ts
+++ b/packages/backend/src/models/repositories/antenna.ts
@@ -1,36 +1,12 @@
 import { db } from "@/db/postgre.js";
 import { Antenna } from "@/models/entities/antenna.js";
-import type { Packed } from "@/misc/schema.js";
-import { AntennaNotes, UserGroupJoinings } from "../index.js";
+import { AntennaSchema } from "native-utils/built/index.js";
 
 export const AntennaRepository = db.getRepository(Antenna).extend({
-	async pack(src: Antenna["id"] | Antenna): Promise<Packed<"Antenna">> {
-		const antenna =
-			typeof src === "object" ? src : await this.findOneByOrFail({ id: src });
+	async pack(src: Antenna["id"] | Antenna): Promise<AntennaSchema> {
+		const id =
+			typeof src === "object" ? src.id : src;
 
-		const hasUnreadNote =
-			(await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) !=
-			null;
-		const userGroupJoining = antenna.userGroupJoiningId
-			? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId })
-			: null;
-
-		return {
-			id: antenna.id,
-			createdAt: antenna.createdAt.toISOString(),
-			name: antenna.name,
-			keywords: antenna.keywords,
-			excludeKeywords: antenna.excludeKeywords,
-			src: antenna.src,
-			userListId: antenna.userListId,
-			userGroupId: userGroupJoining ? userGroupJoining.userGroupId : null,
-			users: antenna.users,
-			instances: antenna.instances,
-			caseSensitive: antenna.caseSensitive,
-			notify: antenna.notify,
-			withReplies: antenna.withReplies,
-			withFile: antenna.withFile,
-			hasUnreadNote,
-		};
+		return await AntennaSchema.packById(id);
 	},
 });
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index a2ebb0465..2bf4474f0 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,5 +1,6 @@
 packages:
  - 'packages/backend'
+ - 'packages/backend/native-utils'
  - 'packages/client'
  - 'packages/sw'
  - 'packages/calckey-js'

From af853045784f59ddaef867e481e4a1f9036b02a3 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 11:55:14 -0400
Subject: [PATCH 39/66] add native calls

---
 packages/backend/native-utils/Cargo.toml      |   5 +-
 packages/backend/native-utils/package.json    |   4 +-
 .../native-utils/src/database/error.rs        |   4 +
 .../backend/native-utils/src/database/mod.rs  |  16 ++-
 packages/backend/native-utils/src/lib.rs      |   1 +
 packages/backend/native-utils/src/macros.rs   |  11 ++
 .../backend/native-utils/src/model/error.rs   |  13 +--
 .../native-utils/src/model/repository.rs      |   5 +
 .../backend/native-utils/src/model/schema.rs  |   5 +-
 .../native-utils/src/model/schema/antenna.rs  | 107 +++++++++---------
 packages/backend/native-utils/src/util/id.rs  |  47 +++++++-
 .../backend/native-utils/src/util/random.rs   |   7 ++
 12 files changed, 151 insertions(+), 74 deletions(-)
 create mode 100644 packages/backend/native-utils/src/macros.rs

diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index 3c70a0209..ba7a48b8d 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -9,7 +9,7 @@ members = ["migration/Cargo.toml"]
 [features]
 default = ["napi"]
 noarray = []
-napi = ["dep:napi", "dep:napi-derive"]
+napi = ["dep:napi", "dep:napi-derive", "dep:radix_fmt"]
 
 [lib]
 crate-type = ["cdylib", "lib"]
@@ -33,8 +33,9 @@ tokio = { version = "1.28.1", features = ["full"] }
 utoipa = "3.3.0"
 
 # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
-napi = { version = "2.12.0", default-features = false, features = ["napi4", "tokio_rt"], optional = true }
+napi = { version = "2.12.0", default-features = false, features = ["napi6", "tokio_rt"], optional = true }
 napi-derive = { version = "2.12.0", optional = true }
+radix_fmt = { version = "1.0.0", optional = true }
 
 [dev-dependencies]
 pretty_assertions = "1.3.0"
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index f1ea2c9b4..8423f569b 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -34,13 +34,13 @@
   },
   "scripts": {
     "artifacts": "napi artifacts",
-    "build": "napi build --platform --release ./built/",
+    "build": "napi build --features napi --platform --release ./built/",
     "build:debug": "napi build --platform",
     "prepublishOnly": "napi prepublish -t npm",
     "test": "ava",
     "universal": "napi universal",
     "version": "napi version",
     "cargo:unit": "cargo test unit_test",
-    "cargo:integration": "cargo test --no-default-features int_test -- --test-threads=1"
+    "cargo:integration": "cargo test --no-default-features -F noarray int_test -- --test-threads=1"
   }
 }
diff --git a/packages/backend/native-utils/src/database/error.rs b/packages/backend/native-utils/src/database/error.rs
index babdd6831..68e959e0a 100644
--- a/packages/backend/native-utils/src/database/error.rs
+++ b/packages/backend/native-utils/src/database/error.rs
@@ -1,5 +1,7 @@
 use sea_orm::error::DbErr;
 
+use crate::impl_into_napi_error;
+
 #[derive(thiserror::Error, Debug, PartialEq, Eq)]
 pub enum Error {
     #[error("The database connections have not been initialized yet")]
@@ -7,3 +9,5 @@ pub enum Error {
     #[error("ORM error: {0}")]
     OrmError(#[from] DbErr),
 }
+
+impl_into_napi_error!(Error);
diff --git a/packages/backend/native-utils/src/database/mod.rs b/packages/backend/native-utils/src/database/mod.rs
index c3cdea727..80189a813 100644
--- a/packages/backend/native-utils/src/database/mod.rs
+++ b/packages/backend/native-utils/src/database/mod.rs
@@ -1,12 +1,13 @@
 pub mod error;
 
+use cfg_if::cfg_if;
 use error::Error;
 use sea_orm::{Database, DbConn};
 
 static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
 
-pub async fn init_database(connection_uri: impl Into<String>) -> Result<(), Error> {
-    let conn = Database::connect(connection_uri.into()).await?;
+pub async fn init_database(conn_uri: impl Into<String>) -> Result<(), Error> {
+    let conn = Database::connect(conn_uri.into()).await?;
     DB_CONN.get_or_init(move || conn);
     Ok(())
 }
@@ -15,6 +16,17 @@ pub fn get_database() -> Result<&'static DbConn, Error> {
     DB_CONN.get().ok_or(Error::Uninitialized)
 }
 
+cfg_if! {
+    if #[cfg(feature = "napi")] {
+        use napi_derive::napi;
+
+        #[napi]
+        pub async fn native_init_database(conn_uri: String) -> napi::Result<()> {
+            init_database(conn_uri).await.map_err(Into::into)
+        }
+    }
+}
+
 #[cfg(test)]
 mod unit_test {
     use super::{error::Error, get_database};
diff --git a/packages/backend/native-utils/src/lib.rs b/packages/backend/native-utils/src/lib.rs
index 6a5e3f7f2..f18e69a48 100644
--- a/packages/backend/native-utils/src/lib.rs
+++ b/packages/backend/native-utils/src/lib.rs
@@ -1,4 +1,5 @@
 pub mod database;
+pub mod macros;
 pub mod model;
 pub mod util;
 
diff --git a/packages/backend/native-utils/src/macros.rs b/packages/backend/native-utils/src/macros.rs
new file mode 100644
index 000000000..49ab82632
--- /dev/null
+++ b/packages/backend/native-utils/src/macros.rs
@@ -0,0 +1,11 @@
+#[macro_export]
+macro_rules! impl_into_napi_error {
+    ($a:ty) => {
+        #[cfg(feature = "napi")]
+        impl Into<napi::Error> for $a {
+            fn into(self) -> napi::Error {
+                napi::Error::from_reason(self.to_string())
+            }
+        }
+    };
+}
diff --git a/packages/backend/native-utils/src/model/error.rs b/packages/backend/native-utils/src/model/error.rs
index 2292246ae..8e9213066 100644
--- a/packages/backend/native-utils/src/model/error.rs
+++ b/packages/backend/native-utils/src/model/error.rs
@@ -1,8 +1,10 @@
+use crate::impl_into_napi_error;
+
 #[derive(thiserror::Error, Debug, PartialEq, Eq)]
 pub enum Error {
-    #[error("Failed to parse string")]
+    #[error("Failed to parse string: {0}")]
     ParseError(#[from] parse_display::ParseError),
-    #[error("Failed to get database connection")]
+    #[error("Failed to get database connection: {0}")]
     DbConnError(#[from] crate::database::error::Error),
     #[error("Database operation error: {0}")]
     DbOperationError(#[from] sea_orm::DbErr),
@@ -10,9 +12,4 @@ pub enum Error {
     NotFound,
 }
 
-#[cfg(feature = "napi")]
-impl Into<napi::Error> for Error {
-    fn into(self) -> napi::Error {
-        napi::Error::from_reason(self.to_string())
-    }
-}
+impl_into_napi_error!(Error);
diff --git a/packages/backend/native-utils/src/model/repository.rs b/packages/backend/native-utils/src/model/repository.rs
index 0f9f7de32..5abf7907f 100644
--- a/packages/backend/native-utils/src/model/repository.rs
+++ b/packages/backend/native-utils/src/model/repository.rs
@@ -5,13 +5,18 @@ use schemars::JsonSchema;
 
 use super::error::Error;
 
+/// Repositories have a packer that converts a database model to its
+/// corresponding API schema.
 #[async_trait]
 pub trait Repository<T: JsonSchema> {
     async fn pack(self) -> Result<T, Error>;
+    /// Retrieves one model by its id and pack it.
     async fn pack_by_id(id: String) -> Result<T, Error>;
 }
 
 mod macros {
+    /// Provides the default implementation of
+    /// [crate::model::repository::Repository::pack_by_id].
     macro_rules! impl_pack_by_id {
         ($a:ty, $b:ident) => {
             match <$a>::find_by_id($b)
diff --git a/packages/backend/native-utils/src/model/schema.rs b/packages/backend/native-utils/src/model/schema.rs
index ef4368dda..4c0ca7941 100644
--- a/packages/backend/native-utils/src/model/schema.rs
+++ b/packages/backend/native-utils/src/model/schema.rs
@@ -23,8 +23,9 @@ pub trait Schema<T: JsonSchema> {
 
 cfg_if! {
     if #[cfg(feature = "napi")] {
-        pub use antenna::napi::AntennaSchema as Antenna;
-        pub use antenna::napi::AntennaSrc;
+        // Will be disabled once we completely migrate to rust
+        pub use antenna::NativeAntennaSchema as Antenna;
+        pub use antenna::NativeAntennaSrc as AntennaSrc;
     } else {
         pub use antenna::Antenna;
         pub use antenna::AntennaSrc;
diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
index 8b553c082..99521a98b 100644
--- a/packages/backend/native-utils/src/model/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -1,3 +1,4 @@
+use cfg_if::cfg_if;
 use jsonschema::JSONSchema;
 use once_cell::sync::Lazy;
 use parse_display::FromStr;
@@ -60,62 +61,62 @@ impl Schema<Self> for super::Antenna {}
 pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| super::Antenna::validator());
 // ----
 
-#[cfg(feature = "napi")]
-pub mod napi {
-    use napi::bindgen_prelude::*;
-    use napi_derive::napi;
-    use parse_display::FromStr;
-    use schemars::JsonSchema;
-    use utoipa::ToSchema;
+cfg_if! {
+    if #[cfg(feature = "napi")] {
+        use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
+        use napi_derive::napi;
 
-    use crate::model::{entity::antenna, repository::Repository};
+        use crate::model::entity::antenna;
+        use crate::model::repository::Repository;
 
-    #[napi]
-    #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
-    #[serde(rename_all = "camelCase")]
-    pub struct AntennaSchema {
-        pub id: String,
-        pub created_at: String,
-        pub name: String,
-        pub keywords: Vec<Vec<String>>,
-        pub exclude_keywords: Vec<Vec<String>>,
-        #[schema(inline)]
-        pub src: AntennaSrc,
-        pub user_list_id: Option<String>,
-        pub user_group_id: Option<String>,
-        pub users: Vec<String>,
-        pub instances: Vec<String>,
-        #[serde(default)]
-        pub case_sensitive: bool,
-        #[serde(default)]
-        pub notify: bool,
-        #[serde(default)]
-        pub with_replies: bool,
-        #[serde(default)]
-        pub with_file: bool,
-        #[serde(default)]
-        pub has_unread_note: bool,
-    }
-
-    #[napi]
-    #[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
-    #[serde(rename_all = "camelCase")]
-    #[display(style = "camelCase")]
-    #[display("'{}'")]
-    pub enum AntennaSrc {
-        Home,
-        All,
-        Users,
-        List,
-        Group,
-        Instances,
-    }
-
-    #[napi]
-    impl AntennaSchema {
+        /// For NAPI because [chrono] is not supported.
         #[napi]
-        pub async fn pack_by_id(id: String) -> napi::Result<AntennaSchema> {
-            antenna::Model::pack_by_id(id).await.map_err(Into::into)
+        #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
+        #[serde(rename_all = "camelCase")]
+        pub struct NativeAntennaSchema {
+            pub id: String,
+            pub created_at: String,
+            pub name: String,
+            pub keywords: Vec<Vec<String>>,
+            pub exclude_keywords: Vec<Vec<String>>,
+            #[schema(inline)]
+            pub src: NativeAntennaSrc,
+            pub user_list_id: Option<String>,
+            pub user_group_id: Option<String>,
+            pub users: Vec<String>,
+            pub instances: Vec<String>,
+            #[serde(default)]
+            pub case_sensitive: bool,
+            #[serde(default)]
+            pub notify: bool,
+            #[serde(default)]
+            pub with_replies: bool,
+            #[serde(default)]
+            pub with_file: bool,
+            #[serde(default)]
+            pub has_unread_note: bool,
+        }
+
+        #[napi]
+        #[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
+        #[serde(rename_all = "camelCase")]
+        #[display(style = "camelCase")]
+        #[display("'{}'")]
+        pub enum NativeAntennaSrc {
+            Home,
+            All,
+            Users,
+            List,
+            Group,
+            Instances,
+        }
+
+        #[napi]
+        impl NativeAntennaSchema {
+            #[napi]
+            pub async fn pack_by_id(id: String) -> napi::Result<NativeAntennaSchema> {
+                antenna::Model::pack_by_id(id).await.map_err(Into::into)
+            }
         }
     }
 }
diff --git a/packages/backend/native-utils/src/util/id.rs b/packages/backend/native-utils/src/util/id.rs
index 98dd63c4e..1d28b80c0 100644
--- a/packages/backend/native-utils/src/util/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -1,18 +1,31 @@
 //! ID generation utility based on [cuid2]
 
-use cuid2::CuidConstructor;
+use cfg_if::cfg_if;
 use once_cell::sync::OnceCell;
 
+use crate::impl_into_napi_error;
+
 #[derive(thiserror::Error, Debug, PartialEq, Eq)]
 #[error("ID generator has not been initialized yet")]
 pub struct ErrorUninitialized;
 
-static GENERATOR: OnceCell<CuidConstructor> = OnceCell::new();
+impl_into_napi_error!(ErrorUninitialized);
 
-pub fn init_id(length: u16) {
-    GENERATOR.get_or_init(move || CuidConstructor::new().with_length(length));
+static FINGERPRINT: OnceCell<String> = OnceCell::new();
+static GENERATOR: OnceCell<cuid2::CuidConstructor> = OnceCell::new();
+
+/// Initializes Cuid2 generator. Must be called before any [create_id].
+pub fn init_id(length: u16, fingerprint: impl Into<String>) {
+    FINGERPRINT.get_or_init(move || format!("{}{}", fingerprint.into(), cuid2::create_id()));
+    GENERATOR.get_or_init(move || {
+        cuid2::CuidConstructor::new()
+            .with_length(length)
+            .with_fingerprinter(|| FINGERPRINT.get().unwrap().clone())
+    });
 }
 
+/// Returns Cuid2 with the length specified by [init_id]. Must be called after
+/// [init_id], otherwise returns [ErrorUninitialized].
 pub fn create_id() -> Result<String, ErrorUninitialized> {
     match GENERATOR.get() {
         None => Err(ErrorUninitialized),
@@ -20,6 +33,30 @@ pub fn create_id() -> Result<String, ErrorUninitialized> {
     }
 }
 
+cfg_if! {
+    if #[cfg(feature = "napi")] {
+        use radix_fmt::radix_36;
+        use std::cmp;
+        use napi::bindgen_prelude::BigInt;
+        use napi_derive::napi;
+
+        const TIME_2000: u64 = 946_684_800_000;
+
+        /// Calls [init_id] inside. Must be called before [native_create_id].
+        #[napi]
+        pub fn native_init_id_generator(length: u16, fingerprint: String) {
+            init_id(length, fingerprint);
+        }
+
+        /// Generates
+        #[napi]
+        pub fn native_create_id(date_num: BigInt) -> String {
+            let time = cmp::max(date_num.get_u64().1 - TIME_2000, 0);
+            format!("{:0>8}{}", radix_36(time).to_string(), create_id().unwrap())
+        }
+    }
+}
+
 #[cfg(test)]
 mod unit_test {
     use pretty_assertions::{assert_eq, assert_ne};
@@ -30,7 +67,7 @@ mod unit_test {
     #[test]
     fn can_generate_unique_ids() {
         assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
-        id::init_id(12);
+        id::init_id(12, "");
         assert_eq!(id::create_id().unwrap().len(), 12);
         assert_ne!(id::create_id().unwrap(), id::create_id().unwrap());
         let id1 = thread::spawn(|| id::create_id().unwrap());
diff --git a/packages/backend/native-utils/src/util/random.rs b/packages/backend/native-utils/src/util/random.rs
index 5ee06d128..ffcbca980 100644
--- a/packages/backend/native-utils/src/util/random.rs
+++ b/packages/backend/native-utils/src/util/random.rs
@@ -1,5 +1,6 @@
 use rand::{distributions::Alphanumeric, thread_rng, Rng};
 
+/// Generate random string based on [thread_rng] and [Alphanumeric].
 pub fn gen_string(length: u16) -> String {
     thread_rng()
         .sample_iter(Alphanumeric)
@@ -8,6 +9,12 @@ pub fn gen_string(length: u16) -> String {
         .collect()
 }
 
+#[cfg(feature = "napi")]
+#[napi_derive::napi]
+pub fn native_random_str(length: u16) -> String {
+    gen_string(length)
+}
+
 #[cfg(test)]
 mod unit_test {
     use pretty_assertions::{assert_eq, assert_ne};

From d8f95d7d99224991607ab0090bfd96bf09e39bac Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 12:19:36 -0400
Subject: [PATCH 40/66] fix unit test

---
 packages/backend/native-utils/Cargo.toml      |  2 +-
 packages/backend/native-utils/src/util/id.rs  | 43 ++++++++++++++-----
 packages/backend/native-utils/tests/common.rs |  2 +-
 3 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index ba7a48b8d..071d0f331 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -7,7 +7,7 @@ version = "0.0.0"
 members = ["migration/Cargo.toml"]
 
 [features]
-default = ["napi"]
+default = []
 noarray = []
 napi = ["dep:napi", "dep:napi-derive", "dep:radix_fmt"]
 
diff --git a/packages/backend/native-utils/src/util/id.rs b/packages/backend/native-utils/src/util/id.rs
index 1d28b80c0..539b0415e 100644
--- a/packages/backend/native-utils/src/util/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -41,11 +41,13 @@ cfg_if! {
         use napi_derive::napi;
 
         const TIME_2000: u64 = 946_684_800_000;
+        const TIMESTAMP_LENGTH: u16 = 8;
 
         /// Calls [init_id] inside. Must be called before [native_create_id].
         #[napi]
         pub fn native_init_id_generator(length: u16, fingerprint: String) {
-            init_id(length, fingerprint);
+            // length to pass init_id shoule be greater than or equal to 8.
+            init_id(cmp::max(length - TIMESTAMP_LENGTH, 8), fingerprint);
         }
 
         /// Generates
@@ -59,19 +61,38 @@ cfg_if! {
 
 #[cfg(test)]
 mod unit_test {
+    use cfg_if::cfg_if;
     use pretty_assertions::{assert_eq, assert_ne};
     use std::thread;
-
     use crate::util::id;
 
-    #[test]
-    fn can_generate_unique_ids() {
-        assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
-        id::init_id(12, "");
-        assert_eq!(id::create_id().unwrap().len(), 12);
-        assert_ne!(id::create_id().unwrap(), id::create_id().unwrap());
-        let id1 = thread::spawn(|| id::create_id().unwrap());
-        let id2 = thread::spawn(|| id::create_id().unwrap());
-        assert_ne!(id1.join().unwrap(), id2.join().unwrap())
+    cfg_if! {
+        if #[cfg(feature = "napi")] {
+            use chrono::Utc;
+
+            #[test]
+            fn can_generate_aid_compat_ids() {
+                id::native_init_id_generator(16, "".to_string());
+                let id1 = id::native_create_id(Utc::now().timestamp_millis().into());
+                assert_eq!(id1.len(), 16);
+                let id1 = id::native_create_id(Utc::now().timestamp_millis().into());
+                let id2 = id::native_create_id(Utc::now().timestamp_millis().into());
+                assert_ne!(id1, id2);
+                let id1 = thread::spawn(|| id::native_create_id(Utc::now().timestamp_millis().into()));
+                let id2 = thread::spawn(|| id::native_create_id(Utc::now().timestamp_millis().into()));
+                assert_ne!(id1.join().unwrap(), id2.join().unwrap());
+            }
+        } else {
+            #[test]
+            fn can_generate_unique_ids() {
+                assert_eq!(id::create_id(), Err(id::ErrorUninitialized));
+                id::init_id(12, "");
+                assert_eq!(id::create_id().unwrap().len(), 12);
+                assert_ne!(id::create_id().unwrap(), id::create_id().unwrap());
+                let id1 = thread::spawn(|| id::create_id().unwrap());
+                let id2 = thread::spawn(|| id::create_id().unwrap());
+                assert_ne!(id1.join().unwrap(), id2.join().unwrap())
+            }
+        }
     }
 }
diff --git a/packages/backend/native-utils/tests/common.rs b/packages/backend/native-utils/tests/common.rs
index 775b37212..61dd20aac 100644
--- a/packages/backend/native-utils/tests/common.rs
+++ b/packages/backend/native-utils/tests/common.rs
@@ -139,7 +139,7 @@ async fn cleanup() {
 }
 
 async fn setup_model(db: &DbConn) {
-    init_id(12);
+    init_id(12, "");
 
     db.transaction::<_, (), DbErr>(|txn| {
         Box::pin(async move {

From 7a25a9ac2fcbdd51a8248352e152277692cc02bd Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 15:00:48 -0400
Subject: [PATCH 41/66] add test

---
 .../native-utils/__test__/index.spec.mjs      | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/packages/backend/native-utils/__test__/index.spec.mjs b/packages/backend/native-utils/__test__/index.spec.mjs
index 1788dbb06..6e6a91858 100644
--- a/packages/backend/native-utils/__test__/index.spec.mjs
+++ b/packages/backend/native-utils/__test__/index.spec.mjs
@@ -1,6 +1,12 @@
 import test from "ava";
 
-import { convertId, IdConvertType } from "../built/index.js";
+import {
+	convertId,
+	IdConvertType,
+	nativeInitIdGenerator,
+	nativeCreateId,
+	nativeRandomStr,
+} from "../built/index.js";
 
 test("convert to mastodon id", (t) => {
 	t.is(convertId("9gf61ehcxv", IdConvertType.MastodonId), "960365976481219");
@@ -13,3 +19,14 @@ test("convert to mastodon id", (t) => {
 		"3494513243013053824",
 	);
 });
+
+test("create cuid2 with timestamp prefix", (t) => {
+	nativeInitIdGenerator(16, "");
+	t.not(nativeCreateId(BigInt(Date.now())), nativeCreateId(BigInt(Date.now())));
+	t.is(nativeCreateId(BigInt(Date.now())).length, 16);
+});
+
+test("create random string", (t) => {
+	t.not(nativeRandomStr(16), nativeRandomStr(16));
+	t.is(nativeRandomStr(24).length, 24);
+});

From bd5fbb1e3a1ba45876738bfc97484e7f55708af9 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 15:01:03 -0400
Subject: [PATCH 42/66] use native generators

---
 packages/backend/src/misc/gen-id.ts        | 19 +++++-----------
 packages/backend/src/misc/secure-rndstr.ts | 25 +++-------------------
 2 files changed, 8 insertions(+), 36 deletions(-)

diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts
index fb92dd808..c9e52c829 100644
--- a/packages/backend/src/misc/gen-id.ts
+++ b/packages/backend/src/misc/gen-id.ts
@@ -1,14 +1,9 @@
-import { init, createId } from "@paralleldrive/cuid2";
 import config from "@/config/index.js";
+import { nativeCreateId, nativeInitIdGenerator } from "native-utils/built";
 
-const TIME2000 = 946684800000;
-const TIMESTAMP_LENGTH = 8;
-
-const length =
-	Math.min(Math.max(config.cuid?.length ?? 16, 16), 24) - TIMESTAMP_LENGTH;
-const fingerprint = `${config.cuid?.fingerprint ?? ""}${createId()}`;
-
-const genCuid2 = init({ length, fingerprint });
+const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24);
+const fingerprint = config.cuid?.fingerprint ?? "";
+nativeInitIdGenerator(length, fingerprint);
 
 /**
  * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`.
@@ -19,9 +14,5 @@ const genCuid2 = init({ length, fingerprint });
  * Ref: https://github.com/paralleldrive/cuid2#parameterized-length
  */
 export function genId(date?: Date): string {
-	const now = (date ?? new Date()).getTime();
-	const time = Math.max(now - TIME2000, 0);
-	const timestamp = time.toString(36).padStart(TIMESTAMP_LENGTH, "0");
-
-	return `${timestamp}${genCuid2()}`;
+	return nativeCreateId(BigInt((date ?? new Date()).getTime()));
 }
diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts
index 7f5754e1c..4f4c9884a 100644
--- a/packages/backend/src/misc/secure-rndstr.ts
+++ b/packages/backend/src/misc/secure-rndstr.ts
@@ -1,24 +1,5 @@
-import * as crypto from "node:crypto";
+import { nativeRandomStr } from "native-utils/built";
 
-const L_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";
-const LU_CHARS =
-	"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-export function secureRndstr(length = 32, useLU = true): string {
-	const chars = useLU ? LU_CHARS : L_CHARS;
-	const chars_len = chars.length;
-
-	let str = "";
-
-	for (let i = 0; i < length; i++) {
-		let rand = Math.floor(
-			(crypto.randomBytes(1).readUInt8(0) / 0xff) * chars_len,
-		);
-		if (rand === chars_len) {
-			rand = chars_len - 1;
-		}
-		str += chars.charAt(rand);
-	}
-
-	return str;
+export function secureRndstr(length = 32, _ = true): string {
+	return nativeRandomStr(length);
 }

From 77fd2ab0ad3365dad9b6175922954cdc81f49cba Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 15:01:29 -0400
Subject: [PATCH 43/66] initialize native database on boot

---
 packages/backend/src/db/postgre.ts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts
index dd202b3de..9ffaf596c 100644
--- a/packages/backend/src/db/postgre.ts
+++ b/packages/backend/src/db/postgre.ts
@@ -78,6 +78,7 @@ import { entities as charts } from "@/services/chart/entities.js";
 import { envOption } from "../env.js";
 import { dbLogger } from "./logger.js";
 import { redisClient } from "./redis.js";
+import { nativeInitDatabase } from "native-utils/built/index.js";
 
 const sqlLogger = dbLogger.createSubLogger("sql", "gray", false);
 
@@ -220,6 +221,9 @@ export const db = new DataSource({
 });
 
 export async function initDb(force = false) {
+	await nativeInitDatabase(
+		`postgres://${config.db.user}:${config.db.pass}@${config.db.host}:${config.db.port}/${config.db.db}`,
+	);
 	if (force) {
 		if (db.isInitialized) {
 			await db.destroy();

From 34d2efa59835972cb7c49dd5fb8be3bbdf293170 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 15:04:25 -0400
Subject: [PATCH 44/66] remove node cuid2

---
 packages/backend/package.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/packages/backend/package.json b/packages/backend/package.json
index 0b0315a06..020257dd8 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -32,7 +32,6 @@
 		"@koa/cors": "3.4.3",
 		"@koa/multer": "3.0.0",
 		"@koa/router": "9.0.1",
-		"@paralleldrive/cuid2": "2.2.0",
 		"@peertube/http-signature": "1.7.0",
 		"@redocly/openapi-core": "1.0.0-beta.120",
 		"@sinonjs/fake-timers": "9.1.2",

From b0a7970ac7c3069f5131a3cc2d6ad13278278ae5 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 15:50:40 -0400
Subject: [PATCH 45/66] fix native import

---
 .../native-utils/src/model/schema/antenna.rs  | 26 ++++++++-----------
 packages/backend/src/misc/gen-id.ts           |  2 +-
 packages/backend/src/misc/secure-rndstr.ts    |  2 +-
 .../src/models/repositories/antenna.ts        | 12 +++++----
 4 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
index 99521a98b..198230e9a 100644
--- a/packages/backend/native-utils/src/model/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -70,7 +70,7 @@ cfg_if! {
         use crate::model::repository::Repository;
 
         /// For NAPI because [chrono] is not supported.
-        #[napi]
+        #[napi(object)]
         #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
         #[serde(rename_all = "camelCase")]
         pub struct NativeAntennaSchema {
@@ -97,26 +97,22 @@ cfg_if! {
             pub has_unread_note: bool,
         }
 
-        #[napi]
+        #[napi(string_enum)]
         #[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
-        #[serde(rename_all = "camelCase")]
-        #[display(style = "camelCase")]
         #[display("'{}'")]
+        #[allow(non_camel_case_types)]
         pub enum NativeAntennaSrc {
-            Home,
-            All,
-            Users,
-            List,
-            Group,
-            Instances,
+            home,
+            all,
+            users,
+            list,
+            group,
+            instances,
         }
 
         #[napi]
-        impl NativeAntennaSchema {
-            #[napi]
-            pub async fn pack_by_id(id: String) -> napi::Result<NativeAntennaSchema> {
-                antenna::Model::pack_by_id(id).await.map_err(Into::into)
-            }
+        pub async fn native_pack_antenna_by_id(id: String) -> napi::Result<NativeAntennaSchema> {
+            antenna::Model::pack_by_id(id).await.map_err(Into::into)
         }
     }
 }
diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts
index c9e52c829..a016111ca 100644
--- a/packages/backend/src/misc/gen-id.ts
+++ b/packages/backend/src/misc/gen-id.ts
@@ -1,5 +1,5 @@
 import config from "@/config/index.js";
-import { nativeCreateId, nativeInitIdGenerator } from "native-utils/built";
+import { nativeCreateId, nativeInitIdGenerator } from "native-utils/built/index.js";
 
 const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24);
 const fingerprint = config.cuid?.fingerprint ?? "";
diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts
index 4f4c9884a..3d69a4d4a 100644
--- a/packages/backend/src/misc/secure-rndstr.ts
+++ b/packages/backend/src/misc/secure-rndstr.ts
@@ -1,4 +1,4 @@
-import { nativeRandomStr } from "native-utils/built";
+import { nativeRandomStr } from "native-utils/built/index.js";
 
 export function secureRndstr(length = 32, _ = true): string {
 	return nativeRandomStr(length);
diff --git a/packages/backend/src/models/repositories/antenna.ts b/packages/backend/src/models/repositories/antenna.ts
index d9405f4a9..d66aab4ee 100644
--- a/packages/backend/src/models/repositories/antenna.ts
+++ b/packages/backend/src/models/repositories/antenna.ts
@@ -1,12 +1,14 @@
 import { db } from "@/db/postgre.js";
 import { Antenna } from "@/models/entities/antenna.js";
-import { AntennaSchema } from "native-utils/built/index.js";
+import {
+	NativeAntennaSchema,
+	nativePackAntennaById,
+} from "native-utils/built/index.js";
 
 export const AntennaRepository = db.getRepository(Antenna).extend({
-	async pack(src: Antenna["id"] | Antenna): Promise<AntennaSchema> {
-		const id =
-			typeof src === "object" ? src.id : src;
+	async pack(src: Antenna["id"] | Antenna): Promise<NativeAntennaSchema> {
+		const id = typeof src === "object" ? src.id : src;
 
-		return await AntennaSchema.packById(id);
+		return await nativePackAntennaById(id);
 	},
 });

From 6679f992e72218e40dc37032a4fdc5773ba3568d Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 16:05:29 -0400
Subject: [PATCH 46/66] pnpm install

---
 pnpm-lock.yaml | 499 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 480 insertions(+), 19 deletions(-)

diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c06f87dd..0d65da71e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -108,9 +108,6 @@ importers:
       '@koa/router':
         specifier: 9.0.1
         version: 9.0.1
-      '@paralleldrive/cuid2':
-        specifier: 2.2.0
-        version: 2.2.0
       '@peertube/http-signature':
         specifier: 1.7.0
         version: 1.7.0
@@ -612,6 +609,15 @@ importers:
         specifier: 8.11.0
         version: 8.11.0
 
+  packages/backend/native-utils:
+    devDependencies:
+      '@napi-rs/cli':
+        specifier: 2.15.0
+        version: 2.15.0
+      ava:
+        specifier: 5.1.1
+        version: 5.1.1
+
   packages/calckey-js:
     dependencies:
       autobind-decorator:
@@ -2288,11 +2294,6 @@ packages:
     resolution: {integrity: sha512-RDDr7ZF0cgbd37+NBGeQOjP7Tm/iNM+y3FmrT5bVQBXLePOTuKVC/dBsdN5UZv3Sl2XAwEvBfaGR90E0d8AA6g==}
     engines: {node: '>= 10'}
     hasBin: true
-    dev: false
-
-  /@noble/hashes@1.3.0:
-    resolution: {integrity: sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==}
-    dev: false
 
   /@nodelib/fs.scandir@2.1.5:
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
@@ -2347,12 +2348,6 @@ packages:
       through: 2.3.4
     dev: false
 
-  /@paralleldrive/cuid2@2.2.0:
-    resolution: {integrity: sha512-CVQDpPIUHrUGGLdrMGz1NmqZvqmsB2j2rCIQEu1EvxWjlFh4fhvEGmgR409cY20/67/WlJsggenq0no3p3kYsw==}
-    dependencies:
-      '@noble/hashes': 1.3.0
-    dev: false
-
   /@peertube/http-signature@1.7.0:
     resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==}
     engines: {node: '>=0.10'}
@@ -4170,6 +4165,14 @@ packages:
       clean-stack: 2.2.0
       indent-string: 4.0.0
 
+  /aggregate-error@4.0.1:
+    resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==}
+    engines: {node: '>=12'}
+    dependencies:
+      clean-stack: 4.2.0
+      indent-string: 5.0.0
+    dev: true
+
   /ajv-keywords@3.5.2(ajv@6.12.6):
     resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
     peerDependencies:
@@ -4239,6 +4242,11 @@ packages:
     resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
     engines: {node: '>=8'}
 
+  /ansi-regex@6.0.1:
+    resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+    engines: {node: '>=12'}
+    dev: true
+
   /ansi-styles@2.2.1:
     resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
     engines: {node: '>=0.10.0'}
@@ -4261,6 +4269,11 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+    dev: true
+
   /ansi-wrap@0.1.0:
     resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==}
     engines: {node: '>=0.10.0'}
@@ -4420,6 +4433,11 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /array-find-index@1.0.2:
+    resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
   /array-initial@1.1.0:
     resolution: {integrity: sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==}
     engines: {node: '>=0.10.0'}
@@ -4459,11 +4477,21 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /arrgv@1.0.2:
+    resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==}
+    engines: {node: '>=8.0.0'}
+    dev: true
+
   /arrify@1.0.1:
     resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /arrify@3.0.0:
+    resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==}
+    engines: {node: '>=12'}
+    dev: true
+
   /asap@2.0.6:
     resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
 
@@ -4569,6 +4597,65 @@ packages:
       oauth: 0.9.15
     dev: false
 
+  /ava@5.1.1:
+    resolution: {integrity: sha512-od1CWgWVIKZSdEc1dhQWhbsd6KBs0EYjek7eqZNGPvy+NyC9Q1bXixcadlgOXwDG9aM0zLMQZwRXfe9gMb1LQQ==}
+    engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'}
+    hasBin: true
+    peerDependencies:
+      '@ava/typescript': '*'
+    peerDependenciesMeta:
+      '@ava/typescript':
+        optional: true
+    dependencies:
+      acorn: 8.8.1
+      acorn-walk: 8.2.0
+      ansi-styles: 6.2.1
+      arrgv: 1.0.2
+      arrify: 3.0.0
+      callsites: 4.0.0
+      cbor: 8.1.0
+      chalk: 5.2.0
+      chokidar: 3.5.3
+      chunkd: 2.0.1
+      ci-info: 3.7.1
+      ci-parallel-vars: 1.0.1
+      clean-yaml-object: 0.1.0
+      cli-truncate: 3.1.0
+      code-excerpt: 4.0.0
+      common-path-prefix: 3.0.0
+      concordance: 5.0.4
+      currently-unhandled: 0.4.1
+      debug: 4.3.4(supports-color@8.1.1)
+      del: 7.0.0
+      emittery: 1.0.1
+      figures: 5.0.0
+      globby: 13.1.4
+      ignore-by-default: 2.1.0
+      indent-string: 5.0.0
+      is-error: 2.2.2
+      is-plain-object: 5.0.0
+      is-promise: 4.0.0
+      matcher: 5.0.0
+      mem: 9.0.2
+      ms: 2.1.3
+      p-event: 5.0.1
+      p-map: 5.5.0
+      picomatch: 2.3.1
+      pkg-conf: 4.0.0
+      plur: 5.1.0
+      pretty-ms: 8.0.0
+      resolve-cwd: 3.0.0
+      slash: 3.0.0
+      stack-utils: 2.0.6
+      strip-ansi: 7.1.0
+      supertap: 3.0.1
+      temp-dir: 3.0.0
+      write-file-atomic: 5.0.1
+      yargs: 17.6.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /available-typed-arrays@1.0.5:
     resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
     engines: {node: '>= 0.4'}
@@ -4833,6 +4920,10 @@ packages:
   /bluebird@3.7.2:
     resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
 
+  /blueimp-md5@2.19.0:
+    resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==}
+    dev: true
+
   /blurhash@1.1.5:
     resolution: {integrity: sha512-a+LO3A2DfxTaTztsmkbLYmUzUeApi0LZuKalwbNmqAHR6HhJGMt1qSV/R3wc+w4DL28holjqO3Bg74aUGavGjg==}
 
@@ -5109,6 +5200,11 @@ packages:
     resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
     engines: {node: '>=6'}
 
+  /callsites@4.0.0:
+    resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==}
+    engines: {node: '>=12.20'}
+    dev: true
+
   /camelcase-keys@6.2.2:
     resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
     engines: {node: '>=8'}
@@ -5205,7 +5301,6 @@ packages:
   /chalk@5.2.0:
     resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
     engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-    dev: false
 
   /char-regex@1.0.2:
     resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
@@ -5315,11 +5410,19 @@ packages:
     engines: {node: '>=6.0'}
     dev: true
 
+  /chunkd@2.0.1:
+    resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==}
+    dev: true
+
   /ci-info@3.7.1:
     resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==}
     engines: {node: '>=8'}
     dev: true
 
+  /ci-parallel-vars@1.0.1:
+    resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==}
+    dev: true
+
   /city-timezones@1.2.1:
     resolution: {integrity: sha512-hruuB611QFoUFMsan7xd9B2VPMrA8XC716O/999WW34kmaJUT1hxKF2W8TSXAWkhSqgvbu70DjcDv7/wpM6vow==}
     dependencies:
@@ -5351,6 +5454,18 @@ packages:
     resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
     engines: {node: '>=6'}
 
+  /clean-stack@4.2.0:
+    resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==}
+    engines: {node: '>=12'}
+    dependencies:
+      escape-string-regexp: 5.0.0
+    dev: true
+
+  /clean-yaml-object@0.1.0:
+    resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
   /cli-cursor@3.1.0:
     resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
     engines: {node: '>=8'}
@@ -5388,6 +5503,14 @@ packages:
       string-width: 4.2.3
     dev: true
 
+  /cli-truncate@3.1.0:
+    resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      slice-ansi: 5.0.0
+      string-width: 5.1.2
+    dev: true
+
   /cliui@3.2.0:
     resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==}
     dependencies:
@@ -5418,7 +5541,6 @@ packages:
       string-width: 4.2.3
       strip-ansi: 6.0.1
       wrap-ansi: 7.0.0
-    dev: false
 
   /clone-buffer@1.0.0:
     resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==}
@@ -5499,6 +5621,13 @@ packages:
       q: 1.5.1
     dev: true
 
+  /code-excerpt@4.0.0:
+    resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      convert-to-spaces: 2.0.1
+    dev: true
+
   /code-point-at@1.1.0:
     resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==}
     engines: {node: '>=0.10.0'}
@@ -5630,6 +5759,10 @@ packages:
     engines: {node: ^12.20.0 || >=14}
     dev: true
 
+  /common-path-prefix@3.0.0:
+    resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==}
+    dev: true
+
   /common-tags@1.8.2:
     resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
     engines: {node: '>=4.0.0'}
@@ -5665,6 +5798,20 @@ packages:
       readable-stream: 2.3.7
       typedarray: 0.0.6
 
+  /concordance@5.0.4:
+    resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==}
+    engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'}
+    dependencies:
+      date-time: 3.1.0
+      esutils: 2.0.3
+      fast-diff: 1.3.0
+      js-string-escape: 1.0.1
+      lodash: 4.17.21
+      md5-hex: 3.0.1
+      semver: 7.3.8
+      well-known-symbols: 2.0.0
+    dev: true
+
   /condense-newlines@0.2.1:
     resolution: {integrity: sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==}
     engines: {node: '>=0.10.0'}
@@ -5873,6 +6020,11 @@ packages:
     resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
     dev: true
 
+  /convert-to-spaces@2.0.1:
+    resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
   /cookies@0.8.0:
     resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==}
     engines: {node: '>= 0.8'}
@@ -6075,6 +6227,13 @@ packages:
     resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
     dev: true
 
+  /currently-unhandled@0.4.1:
+    resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      array-find-index: 1.0.2
+    dev: true
+
   /custom-event-polyfill@1.0.7:
     resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
     dev: true
@@ -6177,6 +6336,13 @@ packages:
     resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
     engines: {node: '>=0.11'}
 
+  /date-time@3.1.0:
+    resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
+    engines: {node: '>=6'}
+    dependencies:
+      time-zone: 1.0.0
+    dev: true
+
   /dayjs@1.11.7:
     resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
 
@@ -6341,6 +6507,20 @@ packages:
     resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
     dev: true
 
+  /del@7.0.0:
+    resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==}
+    engines: {node: '>=14.16'}
+    dependencies:
+      globby: 13.1.4
+      graceful-fs: 4.2.11
+      is-glob: 4.0.3
+      is-path-cwd: 3.0.0
+      is-path-inside: 4.0.0
+      p-map: 5.5.0
+      rimraf: 3.0.2
+      slash: 4.0.0
+    dev: true
+
   /delayed-stream@1.0.0:
     resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
     engines: {node: '>=0.4.0'}
@@ -6520,6 +6700,10 @@ packages:
       object.defaults: 1.1.0
     dev: true
 
+  /eastasianwidth@0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+    dev: true
+
   /ecc-jsbn@0.1.2:
     resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
     dependencies:
@@ -6561,9 +6745,18 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /emittery@1.0.1:
+    resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==}
+    engines: {node: '>=14.16'}
+    dev: true
+
   /emoji-regex@8.0.0:
     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
 
+  /emoji-regex@9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+    dev: true
+
   /emojis-list@3.0.0:
     resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
     engines: {node: '>= 4'}
@@ -7198,6 +7391,10 @@ packages:
   /fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
 
+  /fast-diff@1.3.0:
+    resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+    dev: true
+
   /fast-glob@3.2.12:
     resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
     engines: {node: '>=8.6.0'}
@@ -7269,6 +7466,14 @@ packages:
       escape-string-regexp: 1.0.5
     dev: true
 
+  /figures@5.0.0:
+    resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==}
+    engines: {node: '>=14'}
+    dependencies:
+      escape-string-regexp: 5.0.0
+      is-unicode-supported: 1.3.0
+    dev: true
+
   /file-entry-cache@6.0.1:
     resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
     engines: {node: ^10.12.0 || >=12.0.0}
@@ -7345,6 +7550,14 @@ packages:
       locate-path: 6.0.0
       path-exists: 4.0.0
 
+  /find-up@6.3.0:
+    resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      locate-path: 7.2.0
+      path-exists: 5.0.0
+    dev: true
+
   /find-versions@5.1.0:
     resolution: {integrity: sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==}
     engines: {node: '>=12'}
@@ -7571,7 +7784,7 @@ packages:
     engines: {node: '>=10'}
     dependencies:
       at-least-node: 1.0.0
-      graceful-fs: 4.2.10
+      graceful-fs: 4.2.11
       jsonfile: 6.1.0
       universalify: 2.0.0
     dev: true
@@ -7882,6 +8095,17 @@ packages:
       slash: 3.0.0
     dev: true
 
+  /globby@13.1.4:
+    resolution: {integrity: sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      dir-glob: 3.0.1
+      fast-glob: 3.2.12
+      ignore: 5.2.4
+      merge2: 1.4.1
+      slash: 4.0.0
+    dev: true
+
   /glogg@1.0.2:
     resolution: {integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==}
     engines: {node: '>= 0.10'}
@@ -8393,6 +8617,11 @@ packages:
   /ieee754@1.2.1:
     resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
 
+  /ignore-by-default@2.1.0:
+    resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==}
+    engines: {node: '>=10 <11 || >=12 <13 || >=14'}
+    dev: true
+
   /ignore@4.0.6:
     resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
     engines: {node: '>= 4'}
@@ -8435,6 +8664,11 @@ packages:
     resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
     engines: {node: '>=8'}
 
+  /indent-string@5.0.0:
+    resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
+    engines: {node: '>=12'}
+    dev: true
+
   /indexes-of@1.0.1:
     resolution: {integrity: sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==}
     dev: true
@@ -8659,6 +8893,10 @@ packages:
     resolution: {integrity: sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==}
     dev: false
 
+  /is-error@2.2.2:
+    resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==}
+    dev: true
+
   /is-expression@4.0.0:
     resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==}
     dependencies:
@@ -8691,6 +8929,11 @@ packages:
     resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
     engines: {node: '>=8'}
 
+  /is-fullwidth-code-point@4.0.0:
+    resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+    engines: {node: '>=12'}
+    dev: true
+
   /is-generator-fn@2.1.0:
     resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
     engines: {node: '>=6'}
@@ -8756,10 +8999,20 @@ packages:
     resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
     engines: {node: '>=0.12.0'}
 
+  /is-path-cwd@3.0.0:
+    resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
   /is-path-inside@3.0.3:
     resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
     engines: {node: '>=8'}
 
+  /is-path-inside@4.0.0:
+    resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
+    engines: {node: '>=12'}
+    dev: true
+
   /is-plain-obj@1.1.0:
     resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
     engines: {node: '>=0.10.0'}
@@ -8787,6 +9040,10 @@ packages:
   /is-promise@2.2.2:
     resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
 
+  /is-promise@4.0.0:
+    resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+    dev: true
+
   /is-regex@1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
     engines: {node: '>= 0.4'}
@@ -8856,6 +9113,11 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /is-unicode-supported@1.3.0:
+    resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
+    engines: {node: '>=12'}
+    dev: true
+
   /is-url@1.2.4:
     resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
     dev: false
@@ -9501,6 +9763,11 @@ packages:
   /js-sdsl@4.2.0:
     resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==}
 
+  /js-string-escape@1.0.1:
+    resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==}
+    engines: {node: '>= 0.8'}
+    dev: true
+
   /js-stringify@1.0.2:
     resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
 
@@ -10133,6 +10400,11 @@ packages:
       strip-bom: 2.0.0
     dev: true
 
+  /load-json-file@7.0.1:
+    resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
   /loader-runner@4.3.0:
     resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
     engines: {node: '>=6.11.5'}
@@ -10163,6 +10435,13 @@ packages:
     dependencies:
       p-locate: 5.0.0
 
+  /locate-path@7.2.0:
+    resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      p-locate: 6.0.0
+    dev: true
+
   /lodash.assignin@4.2.0:
     resolution: {integrity: sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==}
     dev: false
@@ -10365,6 +10644,13 @@ packages:
       tmpl: 1.0.5
     dev: true
 
+  /map-age-cleaner@0.1.3:
+    resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==}
+    engines: {node: '>=6'}
+    dependencies:
+      p-defer: 1.0.0
+    dev: true
+
   /map-cache@0.2.2:
     resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
     engines: {node: '>=0.10.0'}
@@ -10403,6 +10689,13 @@ packages:
       - supports-color
     dev: true
 
+  /matcher@5.0.0:
+    resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      escape-string-regexp: 5.0.0
+    dev: true
+
   /math-expression-evaluator@1.4.0:
     resolution: {integrity: sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==}
     dev: true
@@ -10411,6 +10704,13 @@ packages:
     resolution: {integrity: sha512-/ZVem4WygUnbmo/iE4oHZpZS97btfBtYy5Iwn1396vUZU7YhgVEN8J4UWwfZwY1ZqoTYlPgjvSw9WXauuXL0mg==}
     dev: true
 
+  /md5-hex@3.0.1:
+    resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==}
+    engines: {node: '>=8'}
+    dependencies:
+      blueimp-md5: 2.19.0
+    dev: true
+
   /media-typer@0.3.0:
     resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
     engines: {node: '>= 0.6'}
@@ -10424,6 +10724,14 @@ packages:
       - encoding
     dev: false
 
+  /mem@9.0.2:
+    resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==}
+    engines: {node: '>=12.20'}
+    dependencies:
+      map-age-cleaner: 0.1.3
+      mimic-fn: 4.0.0
+    dev: true
+
   /meow@9.0.0:
     resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==}
     engines: {node: '>=10'}
@@ -11322,6 +11630,18 @@ packages:
     engines: {node: '>=12.20'}
     dev: false
 
+  /p-defer@1.0.0:
+    resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /p-event@5.0.1:
+    resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      p-timeout: 5.1.0
+    dev: true
+
   /p-finally@1.0.0:
     resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
     engines: {node: '>=4'}
@@ -11339,6 +11659,13 @@ packages:
     dependencies:
       yocto-queue: 0.1.0
 
+  /p-limit@4.0.0:
+    resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      yocto-queue: 1.0.0
+    dev: true
+
   /p-locate@4.1.0:
     resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
     engines: {node: '>=8'}
@@ -11351,12 +11678,26 @@ packages:
     dependencies:
       p-limit: 3.1.0
 
+  /p-locate@6.0.0:
+    resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      p-limit: 4.0.0
+    dev: true
+
   /p-map@4.0.0:
     resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
     engines: {node: '>=10'}
     dependencies:
       aggregate-error: 3.1.0
 
+  /p-map@5.5.0:
+    resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==}
+    engines: {node: '>=12'}
+    dependencies:
+      aggregate-error: 4.0.1
+    dev: true
+
   /p-queue@6.6.2:
     resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
     engines: {node: '>=8'}
@@ -11372,6 +11713,11 @@ packages:
       p-finally: 1.0.0
     dev: true
 
+  /p-timeout@5.1.0:
+    resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
+    engines: {node: '>=12'}
+    dev: true
+
   /p-try@2.2.0:
     resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
     engines: {node: '>=6'}
@@ -11424,6 +11770,11 @@ packages:
       xtend: 4.0.2
     dev: false
 
+  /parse-ms@3.0.0:
+    resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==}
+    engines: {node: '>=12'}
+    dev: true
+
   /parse-node-version@1.0.1:
     resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
     engines: {node: '>= 0.10'}
@@ -11485,6 +11836,11 @@ packages:
     resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
     engines: {node: '>=8'}
 
+  /path-exists@5.0.0:
+    resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
   /path-is-absolute@1.0.1:
     resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
     engines: {node: '>=0.10.0'}
@@ -11647,6 +12003,14 @@ packages:
     engines: {node: '>= 6'}
     dev: true
 
+  /pkg-conf@4.0.0:
+    resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      find-up: 6.3.0
+      load-json-file: 7.0.1
+    dev: true
+
   /pkg-dir@4.2.0:
     resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
     engines: {node: '>=8'}
@@ -11677,6 +12041,13 @@ packages:
       irregular-plurals: 3.5.0
     dev: true
 
+  /plur@5.1.0:
+    resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      irregular-plurals: 3.5.0
+    dev: true
+
   /pluralize@8.0.0:
     resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
     engines: {node: '>=4'}
@@ -12015,6 +12386,13 @@ packages:
     engines: {node: '>= 0.8'}
     dev: true
 
+  /pretty-ms@8.0.0:
+    resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==}
+    engines: {node: '>=14.16'}
+    dependencies:
+      parse-ms: 3.0.0
+    dev: true
+
   /pretty@2.0.0:
     resolution: {integrity: sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==}
     engines: {node: '>=0.10.0'}
@@ -12985,6 +13363,13 @@ packages:
     dependencies:
       lru-cache: 6.0.0
 
+  /serialize-error@7.0.1:
+    resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
+    engines: {node: '>=10'}
+    dependencies:
+      type-fest: 0.13.1
+    dev: true
+
   /serialize-javascript@6.0.0:
     resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
     dependencies:
@@ -13086,6 +13471,11 @@ packages:
   /signal-exit@3.0.7:
     resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
 
+  /signal-exit@4.0.2:
+    resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==}
+    engines: {node: '>=14'}
+    dev: true
+
   /simple-concat@1.0.1:
     resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
     dev: false
@@ -13113,6 +13503,11 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /slash@4.0.0:
+    resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
+    engines: {node: '>=12'}
+    dev: true
+
   /slice-ansi@3.0.0:
     resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
     engines: {node: '>=8'}
@@ -13131,6 +13526,14 @@ packages:
       is-fullwidth-code-point: 3.0.0
     dev: true
 
+  /slice-ansi@5.0.0:
+    resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-styles: 6.2.1
+      is-fullwidth-code-point: 4.0.0
+    dev: true
+
   /smart-buffer@4.2.0:
     resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
     engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
@@ -13454,6 +13857,15 @@ packages:
       is-fullwidth-code-point: 3.0.0
       strip-ansi: 6.0.1
 
+  /string-width@5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+    dependencies:
+      eastasianwidth: 0.2.0
+      emoji-regex: 9.2.2
+      strip-ansi: 7.1.0
+    dev: true
+
   /string_decoder@0.10.31:
     resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
     dev: false
@@ -13486,6 +13898,13 @@ packages:
     dependencies:
       ansi-regex: 5.0.1
 
+  /strip-ansi@7.1.0:
+    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-regex: 6.0.1
+    dev: true
+
   /strip-bom@2.0.0:
     resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==}
     engines: {node: '>=0.10.0'}
@@ -13568,6 +13987,16 @@ packages:
       - supports-color
     dev: false
 
+  /supertap@3.0.1:
+    resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      indent-string: 5.0.0
+      js-yaml: 3.14.1
+      serialize-error: 7.0.1
+      strip-ansi: 7.1.0
+    dev: true
+
   /supports-color@2.0.0:
     resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
     engines: {node: '>=0.8.0'}
@@ -13725,6 +14154,11 @@ packages:
       yallist: 4.0.0
     dev: false
 
+  /temp-dir@3.0.0:
+    resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==}
+    engines: {node: '>=14.16'}
+    dev: true
+
   /terminal-link@2.1.1:
     resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==}
     engines: {node: '>=8'}
@@ -13877,6 +14311,11 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /time-zone@1.0.0:
+    resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==}
+    engines: {node: '>=4'}
+    dev: true
+
   /timsort@0.3.0:
     resolution: {integrity: sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==}
     dev: true
@@ -14201,6 +14640,11 @@ packages:
     resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
     engines: {node: '>=4'}
 
+  /type-fest@0.13.1:
+    resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
+    engines: {node: '>=10'}
+    dev: true
+
   /type-fest@0.18.1:
     resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
     engines: {node: '>=10'}
@@ -14609,7 +15053,7 @@ packages:
     dependencies:
       fs-mkdirp-stream: 1.0.0
       glob-stream: 6.1.0
-      graceful-fs: 4.2.10
+      graceful-fs: 4.2.11
       is-valid-glob: 1.0.0
       lazystream: 1.0.1
       lead: 1.0.0
@@ -14945,6 +15389,11 @@ packages:
       - supports-color
     dev: false
 
+  /well-known-symbols@2.0.0:
+    resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==}
+    engines: {node: '>=6'}
+    dev: true
+
   /whatwg-encoding@1.0.5:
     resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}
     dependencies:
@@ -15091,6 +15540,14 @@ packages:
       typedarray-to-buffer: 3.1.5
     dev: true
 
+  /write-file-atomic@5.0.1:
+    resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+    dependencies:
+      imurmurhash: 0.1.4
+      signal-exit: 4.0.2
+    dev: true
+
   /ws@7.5.9:
     resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==}
     engines: {node: '>=8.3.0'}
@@ -15289,7 +15746,6 @@ packages:
       string-width: 4.2.3
       y18n: 5.0.8
       yargs-parser: 21.1.1
-    dev: false
 
   /yargs@7.1.2:
     resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==}
@@ -15329,6 +15785,11 @@ packages:
     resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
     engines: {node: '>=10'}
 
+  /yocto-queue@1.0.0:
+    resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
+    engines: {node: '>=12.20'}
+    dev: true
+
   /z-schema@5.0.5:
     resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
     engines: {node: '>=8.0.0'}

From 3bfb1a0cf023cf55b6c4965f29fff96c1239802a Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 16:10:01 -0400
Subject: [PATCH 47/66] add format script

---
 package.json                                 | 2 +-
 packages/backend/native-utils/package.json   | 1 +
 packages/backend/native-utils/src/util/id.rs | 2 +-
 packages/backend/src/misc/gen-id.ts          | 5 ++++-
 4 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/package.json b/package.json
index 5c57c79cf..41fc1e666 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
 		"e2e": "start-server-and-test start:test http://localhost:61812 cy:run",
 		"mocha": "pnpm --filter backend run mocha",
 		"test": "pnpm run mocha",
-		"format": "pnpm rome format packages/**/* --write && pnpm --filter client run format",
+		"format": "pnpm rome format packages/**/* --write && pnpm -r run format",
 		"clean": "pnpm node ./scripts/clean.js",
 		"clean-all": "pnpm node ./scripts/clean-all.js",
 		"cleanall": "pnpm run clean-all"
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 8423f569b..1503bca19 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -40,6 +40,7 @@
     "test": "ava",
     "universal": "napi universal",
     "version": "napi version",
+		"format": "cargo fmt",
     "cargo:unit": "cargo test unit_test",
     "cargo:integration": "cargo test --no-default-features -F noarray int_test -- --test-threads=1"
   }
diff --git a/packages/backend/native-utils/src/util/id.rs b/packages/backend/native-utils/src/util/id.rs
index 539b0415e..b8bf54747 100644
--- a/packages/backend/native-utils/src/util/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -61,10 +61,10 @@ cfg_if! {
 
 #[cfg(test)]
 mod unit_test {
+    use crate::util::id;
     use cfg_if::cfg_if;
     use pretty_assertions::{assert_eq, assert_ne};
     use std::thread;
-    use crate::util::id;
 
     cfg_if! {
         if #[cfg(feature = "napi")] {
diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts
index a016111ca..ea0d414e7 100644
--- a/packages/backend/src/misc/gen-id.ts
+++ b/packages/backend/src/misc/gen-id.ts
@@ -1,5 +1,8 @@
 import config from "@/config/index.js";
-import { nativeCreateId, nativeInitIdGenerator } from "native-utils/built/index.js";
+import {
+	nativeCreateId,
+	nativeInitIdGenerator,
+} from "native-utils/built/index.js";
 
 const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24);
 const fingerprint = config.cuid?.fingerprint ?? "";

From 8b021f828ff2c5bc9e202d46b8d3db6d4e66cd8d Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 16:34:45 -0400
Subject: [PATCH 48/66] fix unit tests

---
 .../backend/native-utils/src/model/schema/antenna.rs     | 9 ++++++++-
 packages/backend/native-utils/src/util/id.rs             | 2 +-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
index 198230e9a..00f1216ac 100644
--- a/packages/backend/native-utils/src/model/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -119,6 +119,7 @@ cfg_if! {
 
 #[cfg(test)]
 mod unit_test {
+    use cfg_if::cfg_if;
     use pretty_assertions::assert_eq;
     use serde_json::json;
 
@@ -129,7 +130,13 @@ mod unit_test {
     #[test]
     fn src_from_active_enum() {
         let src = AntennaSrc::try_from(AntennaSrcEnum::All).unwrap();
-        assert_eq!(src, AntennaSrc::All);
+        cfg_if! {
+            if #[cfg(feature = "napi")] {
+                assert_eq!(src, AntennaSrc::all);
+            } else {
+                assert_eq!(src, AntennaSrc::All);
+            }
+        }
     }
 
     #[test]
diff --git a/packages/backend/native-utils/src/util/id.rs b/packages/backend/native-utils/src/util/id.rs
index b8bf54747..b17b112d7 100644
--- a/packages/backend/native-utils/src/util/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -91,7 +91,7 @@ mod unit_test {
                 assert_ne!(id::create_id().unwrap(), id::create_id().unwrap());
                 let id1 = thread::spawn(|| id::create_id().unwrap());
                 let id2 = thread::spawn(|| id::create_id().unwrap());
-                assert_ne!(id1.join().unwrap(), id2.join().unwrap())
+                assert_ne!(id1.join().unwrap(), id2.join().unwrap());
             }
         }
     }

From 1279f396a6359943fe7857d96304090f60f07e2b Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 23:01:53 -0400
Subject: [PATCH 49/66] add unit test

---
 packages/backend/native-utils/package.json    |  4 +-
 .../native-utils/src/model/schema/antenna.rs  | 10 ++--
 .../native-utils/src/model/schema/app.rs      | 48 +++++++++++++++++--
 packages/backend/native-utils/src/util/id.rs  |  4 +-
 4 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 1503bca19..029372548 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -41,7 +41,7 @@
     "universal": "napi universal",
     "version": "napi version",
 		"format": "cargo fmt",
-    "cargo:unit": "cargo test unit_test",
-    "cargo:integration": "cargo test --no-default-features -F noarray int_test -- --test-threads=1"
+    "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
+    "cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"
   }
 }
diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs
index 00f1216ac..4ec1e0794 100644
--- a/packages/backend/native-utils/src/model/schema/antenna.rs
+++ b/packages/backend/native-utils/src/model/schema/antenna.rs
@@ -142,7 +142,7 @@ mod unit_test {
     #[test]
     fn antenna_valid() {
         let instance = json!({
-            "id": "9f4x0bkx1u",
+            "id": "9fil64s6g7cskdrb",
             "createdAt": "2023-05-24T06:56:14.323Z",
             "name": "Valid Antenna",
             "keywords": [["first", "keyword"], ["second"]],
@@ -150,7 +150,7 @@ mod unit_test {
             "src": "users",
             // "userListId" and "userGroupId" can be null or be omitted
             "userListId": null,
-            "users": ["9f4yjw6m13", "9f4yk2cp6d"],
+            "users": ["9fil64s6g7cskdrb", "9fil66brl1udxau2"],
             "instances": [],
             // "caseSensitive", "notify", "withReplies", "withFile", and
             // "hasUnreadNote" are false if ommited
@@ -175,14 +175,14 @@ mod unit_test {
             "keywords": "invalid keyword",
             // "excludeKeywords" is required
             "excludeKeywords": null,
-            // "src" should be one of "home", "all", "users", "list", "group", and
+            // "src" must be one of "home", "all", "users", "list", "group", and
             // "instances"
             "src": "invalid_src",
             // "userListId" is string
             "userListId": ["9f4ziiqfxw"],
             // "users" must be an array of strings
-            "users": [1, "9f4ykyuza6"],
-            "instances": ["9f4ykyuybo"],
+            "users": [1, "9fil64s6g7cskdrb"],
+            "instances": ["9fil65jzhtjpi3xn"],
             // "caseSensitive" is boolean
             "caseSensitive": 0,
             "notify": true,
diff --git a/packages/backend/native-utils/src/model/schema/app.rs b/packages/backend/native-utils/src/model/schema/app.rs
index f24c1387b..682b82ec0 100644
--- a/packages/backend/native-utils/src/model/schema/app.rs
+++ b/packages/backend/native-utils/src/model/schema/app.rs
@@ -95,13 +95,53 @@ pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| App::validator());
 
 #[cfg(test)]
 mod unit_test {
+    use pretty_assertions::assert_eq;
+    use serde_json::json;
+
+    use crate::util::id::{create_id, init_id};
+    use crate::util::random::gen_string;
+
+    use super::VALIDATOR;
+
     #[test]
-    fn valid() {
-        todo!();
+    fn app_valid() {
+        init_id(12, "");
+        let instance = json!({
+            "id": create_id().unwrap(),
+            "name": "Test App",
+            "secret": gen_string(24),
+            "callbackUrl": "urn:ietf:wg:oauth:2.0:oob",
+            "permission": ["read:account", "write:account", "read:notes"],
+        });
+
+        assert!(VALIDATOR.is_valid(&instance));
     }
 
     #[test]
-    fn invalid() {
-        todo!();
+    fn app_invalid() {
+        init_id(12, "");
+        let instance = json!({
+            "id": create_id().unwrap(),
+            // "name" is required
+            "name": null,
+            // "permission" must be one of the app permissions
+            "permission": ["write:invalid_perm", "write:notes"],
+            // "secret" is a nullable string
+            "secret": 123,
+            // "is_authorized" is a nullable boolean
+            "isAuthorized": "true-ish",
+        });
+        let result = VALIDATOR
+            .validate(&instance)
+            .expect_err("validation must fail");
+        let mut paths: Vec<String> = result
+            .map(|e| e.instance_path.to_string())
+            .filter(|e| !e.is_empty())
+            .collect();
+        paths.sort();
+        assert_eq!(
+            paths,
+            vec!["/isAuthorized", "/name", "/permission/0", "/secret"]
+        );
     }
 }
diff --git a/packages/backend/native-utils/src/util/id.rs b/packages/backend/native-utils/src/util/id.rs
index b17b112d7..d922518f9 100644
--- a/packages/backend/native-utils/src/util/id.rs
+++ b/packages/backend/native-utils/src/util/id.rs
@@ -72,9 +72,9 @@ mod unit_test {
 
             #[test]
             fn can_generate_aid_compat_ids() {
-                id::native_init_id_generator(16, "".to_string());
+                id::native_init_id_generator(20, "".to_string());
                 let id1 = id::native_create_id(Utc::now().timestamp_millis().into());
-                assert_eq!(id1.len(), 16);
+                assert_eq!(id1.len(), 20);
                 let id1 = id::native_create_id(Utc::now().timestamp_millis().into());
                 let id2 = id::native_create_id(Utc::now().timestamp_millis().into());
                 assert_ne!(id1, id2);

From 31ac7fb34f47bf6ca7eb3938728a65609dcd032b Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 23:29:48 -0400
Subject: [PATCH 50/66] add integration test of antenna

---
 packages/backend/native-utils/tests/common.rs | 14 ++++-
 .../tests/model/repository/antenna.rs         | 53 +++++++++++++++++--
 2 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/packages/backend/native-utils/tests/common.rs b/packages/backend/native-utils/tests/common.rs
index 61dd20aac..186e862bd 100644
--- a/packages/backend/native-utils/tests/common.rs
+++ b/packages/backend/native-utils/tests/common.rs
@@ -164,7 +164,7 @@ async fn setup_model(db: &DbConn) {
                 id: create_id().unwrap(),
                 created_at: Utc::now().into(),
                 user_id: user_id.to_owned(),
-                name: "Test Antenna".to_string(),
+                name: "Alice Antenna".to_string(),
                 src: AntennaSrcEnum::All,
                 keywords: vec![
                     vec!["foo".to_string(), "bar".to_string()],
@@ -185,6 +185,18 @@ async fn setup_model(db: &DbConn) {
                 .reset_all()
                 .insert(txn)
                 .await?;
+            let note_model = entity::note::Model {
+                id: create_id().unwrap(),
+                created_at: Utc::now().into(),
+                text: Some("Testing 123".to_string()),
+                user_id: user_id.to_owned(),
+                ..Default::default()
+            };
+            note_model
+                .into_active_model()
+                .reset_all()
+                .insert(txn)
+                .await?;
 
             Ok(())
         })
diff --git a/packages/backend/native-utils/tests/model/repository/antenna.rs b/packages/backend/native-utils/tests/model/repository/antenna.rs
index a37007398..3bda2ca18 100644
--- a/packages/backend/native-utils/tests/model/repository/antenna.rs
+++ b/packages/backend/native-utils/tests/model/repository/antenna.rs
@@ -1,13 +1,13 @@
 mod int_test {
-    use native_utils::{database, model};
+    use native_utils::{database, model, util};
 
     use model::{
-        entity::{antenna, user},
+        entity::{antenna, antenna_note, note, user},
         repository::Repository,
         schema,
     };
     use pretty_assertions::assert_eq;
-    use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
+    use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter};
 
     use crate::{cleanup, prepare};
 
@@ -39,7 +39,7 @@ mod int_test {
         let result = schema::Antenna {
             id: alice_antenna.id,
             created_at: alice_antenna.created_at.into(),
-            name: "Test Antenna".to_string(),
+            name: "Alice Antenna".to_string(),
             keywords: vec![
                 vec!["foo".to_string(), "bar".to_string()],
                 vec!["foobar".to_string()],
@@ -70,6 +70,49 @@ mod int_test {
 
     #[tokio::test]
     async fn unread_note() {
-        todo!();
+        prepare().await;
+        let db = database::get_database().unwrap();
+
+        let (alice, alice_antenna) = user::Entity::find()
+            .filter(user::Column::Username.eq("alice"))
+            .find_also_related(antenna::Entity)
+            .one(db)
+            .await
+            .unwrap()
+            .expect("alice not found");
+        let alice_antenna = alice_antenna.expect("alice's antenna not found");
+        let packed = alice_antenna
+            .to_owned()
+            .pack()
+            .await
+            .expect("Unable to pack");
+        assert_eq!(packed.has_unread_note, false);
+
+        let note_model = note::Entity::find()
+            .filter(note::Column::UserId.eq(alice.id))
+            .one(db)
+            .await
+            .unwrap()
+            .expect("note not found");
+        let antenna_note = antenna_note::Model {
+            id: util::id::create_id().unwrap(),
+            antenna_id: alice_antenna.id.to_owned(),
+            note_id: note_model.id.to_owned(),
+            read: false,
+        };
+        antenna_note
+            .into_active_model()
+            .reset_all()
+            .insert(db)
+            .await
+            .unwrap();
+        let packed = alice_antenna
+            .to_owned()
+            .pack()
+            .await
+            .expect("Unable to pack");
+        assert_eq!(packed.has_unread_note, true);
+
+        cleanup().await;
     }
 }

From dc8ab49a783f5d29a52ee311b1eef8f8d9d3c131 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Fri, 2 Jun 2023 23:37:36 -0400
Subject: [PATCH 51/66] fix migration

---
 packages/backend/native-utils/Cargo.toml                      | 2 +-
 packages/backend/native-utils/migration/Cargo.toml            | 4 ++--
 .../migration/src/m20230531_180824_drop_reversi.rs            | 2 ++
 packages/backend/native-utils/migration/src/vec_to_json.rs    | 4 ++--
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index 071d0f331..9b030e37d 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -4,7 +4,7 @@ name = "native-utils"
 version = "0.0.0"
 
 [workspace]
-members = ["migration/Cargo.toml"]
+members = ["migration"]
 
 [features]
 default = []
diff --git a/packages/backend/native-utils/migration/Cargo.toml b/packages/backend/native-utils/migration/Cargo.toml
index dbfd41be6..0b4b2b2e7 100644
--- a/packages/backend/native-utils/migration/Cargo.toml
+++ b/packages/backend/native-utils/migration/Cargo.toml
@@ -10,12 +10,12 @@ path = "src/lib.rs"
 
 [features]
 default = []
-convert = ["model/noarray"]
+convert = ["dep:native-utils"]
 
 [dependencies]
 async-std = { version = "1", features = ["attributes", "tokio1"] }
 serde_json = "1.0.96"
-model = { path = "../model" }
+native-utils = { path = "../", optional = true }
 indicatif = { version = "0.17.4", features = ["tokio"] }
 tokio = { version = "1.28.2", features = ["full"] }
 futures = "0.3.28"
diff --git a/packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs b/packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs
index c2726dd76..32b8dae22 100644
--- a/packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs
+++ b/packages/backend/native-utils/migration/src/m20230531_180824_drop_reversi.rs
@@ -18,6 +18,7 @@ impl MigrationTrait for Migration {
             DbBackend::Postgres,
             Table::drop()
                 .table(ReversiGame::Table)
+                .if_exists()
                 .to_string(PostgresQueryBuilder),
         ))
         .await?;
@@ -25,6 +26,7 @@ impl MigrationTrait for Migration {
             DbBackend::Postgres,
             Table::drop()
                 .table(ReversiMatching::Table)
+                .if_exists()
                 .to_string(PostgresQueryBuilder),
         ))
         .await?;
diff --git a/packages/backend/native-utils/migration/src/vec_to_json.rs b/packages/backend/native-utils/migration/src/vec_to_json.rs
index c762dcf1c..c4a6d9b07 100644
--- a/packages/backend/native-utils/migration/src/vec_to_json.rs
+++ b/packages/backend/native-utils/migration/src/vec_to_json.rs
@@ -1,7 +1,7 @@
-#![allow(dead_code)]
+#![cfg(feature = "convert")]
 
 use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
-use model::entity::newtype::{I32Vec, StringVec};
+use native_utils::model::entity::newtype::{I32Vec, StringVec};
 use sea_orm_migration::{
     prelude::*,
     sea_orm::{Database, DbBackend, DbConn, Statement, TryGetable},

From 9e4b3c6a1fdeda247ce2792bcdcd8a433aae0ac4 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 3 Jun 2023 00:27:00 -0400
Subject: [PATCH 52/66] call seaorm migrations after typeorm

---
 .../backend/native-utils/migration/Cargo.toml |  2 ++
 .../native-utils/migration/src/main.rs        | 34 +++++++++++++++++++
 .../native-utils/migration/src/vec_to_json.rs |  2 --
 packages/backend/package.json                 |  8 +++--
 4 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/packages/backend/native-utils/migration/Cargo.toml b/packages/backend/native-utils/migration/Cargo.toml
index 0b4b2b2e7..3813eccd8 100644
--- a/packages/backend/native-utils/migration/Cargo.toml
+++ b/packages/backend/native-utils/migration/Cargo.toml
@@ -19,6 +19,8 @@ native-utils = { path = "../", optional = true }
 indicatif = { version = "0.17.4", features = ["tokio"] }
 tokio = { version = "1.28.2", features = ["full"] }
 futures = "0.3.28"
+serde_yaml = "0.9.21"
+serde = { version = "1.0.163", features = ["derive"] }
 
 [dependencies.sea-orm-migration]
 version = "0.11.0"
diff --git a/packages/backend/native-utils/migration/src/main.rs b/packages/backend/native-utils/migration/src/main.rs
index 31a72026e..a845a41ff 100644
--- a/packages/backend/native-utils/migration/src/main.rs
+++ b/packages/backend/native-utils/migration/src/main.rs
@@ -1,11 +1,45 @@
+use serde::Deserialize;
+use std::env;
+use std::fs;
+
 use sea_orm_migration::prelude::*;
 
+#[cfg(feature = "convert")]
 mod vec_to_json;
 
 #[async_std::main]
 async fn main() {
+    let cwd = env::current_dir().unwrap();
+    let yml = fs::File::open(cwd.join("../../.config/default.yml"))
+        .expect("Unable to read '.config/default.yml'");
+    let config: Config = serde_yaml::from_reader(yml).expect("Unable to parse");
+
+    env::set_var(
+        "DATABASE_URL",
+        format!(
+            "postgres://{}:{}@{}:{}/{}",
+            config.db.user, config.db.pass, config.db.host, config.db.port, config.db.db
+        ),
+    );
+
     cli::run_cli(migration::Migrator).await;
 
     #[cfg(feature = "convert")]
     vec_to_json::convert().await;
 }
+
+#[derive(Debug, PartialEq, Deserialize)]
+#[serde(rename = "camelCase")]
+pub struct Config {
+    pub db: DbConfig,
+}
+
+#[derive(Debug, PartialEq, Deserialize)]
+#[serde(rename = "camelCase")]
+pub struct DbConfig {
+    pub host: String,
+    pub port: u32,
+    pub db: String,
+    pub user: String,
+    pub pass: String,
+}
diff --git a/packages/backend/native-utils/migration/src/vec_to_json.rs b/packages/backend/native-utils/migration/src/vec_to_json.rs
index c4a6d9b07..104357a49 100644
--- a/packages/backend/native-utils/migration/src/vec_to_json.rs
+++ b/packages/backend/native-utils/migration/src/vec_to_json.rs
@@ -1,5 +1,3 @@
-#![cfg(feature = "convert")]
-
 use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
 use native_utils::model::entity::newtype::{I32Vec, StringVec};
 use sea_orm_migration::{
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 020257dd8..ca916576b 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -6,8 +6,12 @@
 	"scripts": {
 		"start": "pnpm node ./built/index.js",
 		"start:test": "NODE_ENV=test pnpm node ./built/index.js",
-		"migrate": "typeorm migration:run -d ormconfig.js",
-		"revertmigration": "typeorm migration:revert -d ormconfig.js",
+		"migrate": "pnpm run migrate:typeorm && pnpm run migrate:cargo",
+		"migrate:typeorm": "typeorm migration:run -d ormconfig.js",
+		"migrate:cargo": "cargo run --manifest-path native-utils/migration/Cargo.toml -- up",
+		"revertmigration": "pnpm run revertmigration:cargo && pnpm run revertmigration:typeorm",
+		"revertmigration:typeorm": "typeorm migration:revert -d ormconfig.js",
+		"revertmigration:cargo": "cargo run --manifest-path native-utils/migration/Cargo.toml -- down",
 		"check:connect": "node ./check_connect.js",
 		"build": "pnpm swc src -d built -D",
 		"watch": "pnpm swc src -d built -D -w",

From 2f0629b42bdd0c9632313eb8f04beab758c7e436 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 3 Jun 2023 00:36:51 -0400
Subject: [PATCH 53/66] cargo formats all modules

---
 packages/backend/native-utils/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 029372548..691914171 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -40,7 +40,7 @@
     "test": "ava",
     "universal": "napi universal",
     "version": "napi version",
-		"format": "cargo fmt",
+		"format": "cargo fmt --all",
     "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
     "cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"
   }

From e3e007333465d44be7cfa737e69e063e45a20ed1 Mon Sep 17 00:00:00 2001
From: Namekuji <nmkj@wahh.foo>
Date: Sat, 3 Jun 2023 00:40:51 -0400
Subject: [PATCH 54/66] add cargo test script

---
 packages/backend/native-utils/package.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 691914171..64f9e0e50 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -37,10 +37,11 @@
     "build": "napi build --features napi --platform --release ./built/",
     "build:debug": "napi build --platform",
     "prepublishOnly": "napi prepublish -t npm",
-    "test": "ava",
+    "test": "pnpm run cargo:test && pnpm run build && ava",
     "universal": "napi universal",
     "version": "napi version",
 		"format": "cargo fmt --all",
+		"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
     "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
     "cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"
   }

From d33cee63bd4f7acb9510e7858644eec35502bf65 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 21:45:11 -0700
Subject: [PATCH 55/66] refactor: :recycle: ssr views

Correct og:type for users, format docs, deprecate _info_card_
---
 packages/backend/src/server/web/index.ts      | 18 -------
 .../backend/src/server/web/views/channel.pug  |  2 +-
 .../backend/src/server/web/views/clip.pug     |  2 +-
 .../src/server/web/views/gallery-post.pug     |  2 +-
 .../src/server/web/views/info-card.pug        | 50 -------------------
 .../backend/src/server/web/views/note.pug     |  4 +-
 .../backend/src/server/web/views/page.pug     |  2 +-
 .../backend/src/server/web/views/user.pug     | 11 ++--
 8 files changed, 12 insertions(+), 79 deletions(-)
 delete mode 100644 packages/backend/src/server/web/views/info-card.pug

diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts
index f1e0ed692..0d4034f55 100644
--- a/packages/backend/src/server/web/index.ts
+++ b/packages/backend/src/server/web/index.ts
@@ -590,24 +590,6 @@ router.get("/channels/:channel", async (ctx, next) => {
 });
 //#endregion
 
-router.get("/_info_card_", async (ctx) => {
-	const meta = await fetchMeta(true);
-	if (meta.privateMode) {
-		ctx.status = 403;
-		return;
-	}
-
-	ctx.remove("X-Frame-Options");
-
-	await ctx.render("info-card", {
-		version: config.version,
-		host: config.host,
-		meta: meta,
-		originalUsersCount: await Users.countBy({ host: IsNull() }),
-		originalNotesCount: await Notes.countBy({ userHost: IsNull() }),
-	});
-});
-
 router.get("/bios", async (ctx) => {
 	await ctx.render("bios", {
 		version: config.version,
diff --git a/packages/backend/src/server/web/views/channel.pug b/packages/backend/src/server/web/views/channel.pug
index c4594b766..2427144fb 100644
--- a/packages/backend/src/server/web/views/channel.pug
+++ b/packages/backend/src/server/web/views/channel.pug
@@ -13,7 +13,7 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='article')
+		meta(property='og:type' content='article')
 		meta(property='og:title'       content= title)
 		meta(property='og:description' content= channel.description)
 		meta(property='og:url'         content= url)
diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug
index 4c29d64d1..79d629380 100644
--- a/packages/backend/src/server/web/views/clip.pug
+++ b/packages/backend/src/server/web/views/clip.pug
@@ -14,7 +14,7 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='article')
+		meta(property='og:type' content='article')
 		meta(property='og:title'       content= title)
 		meta(property='og:description' content= clip.description)
 		meta(property='og:url'         content= url)
diff --git a/packages/backend/src/server/web/views/gallery-post.pug b/packages/backend/src/server/web/views/gallery-post.pug
index 86bbb4769..561a19b25 100644
--- a/packages/backend/src/server/web/views/gallery-post.pug
+++ b/packages/backend/src/server/web/views/gallery-post.pug
@@ -14,7 +14,7 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='article')
+		meta(property='og:type' content='article')
 		meta(property='og:title'       content= title)
 		meta(property='og:description' content= post.description)
 		meta(property='og:url'         content= url)
diff --git a/packages/backend/src/server/web/views/info-card.pug b/packages/backend/src/server/web/views/info-card.pug
deleted file mode 100644
index be52d0c39..000000000
--- a/packages/backend/src/server/web/views/info-card.pug
+++ /dev/null
@@ -1,50 +0,0 @@
-doctype html
-
-html
-
-	head
-		meta(charset='utf-8')
-		meta(name='application-name' content='Calckey')
-		title= meta.name || host
-		style.
-			html, body {
-				margin: 0;
-				padding: 0;
-				min-height: 100vh;
-				background: #fff;
-			}
-
-			#a {
-				display: block;
-			}
-
-			#banner {
-				background-size: cover;
-				background-position: center center;
-			}
-
-			#title {
-				display: inline-block;
-				margin: 24px;
-				padding: 0.5em 0.8em;
-				color: #fff;
-				background: rgba(0, 0, 0, 0.5);
-				font-weight: bold;
-				font-size: 1.3em;
-			}
-
-			#content {
-				overflow: auto;
-				color: #353c3e;
-			}
-
-			#description {
-				margin: 24px;
-			}
-
-	body
-		a#a(href=`https://${host}` target="_blank")
-			header#banner(style=`background-image: url(${meta.bannerUrl})`)
-				div#title= meta.name || host
-		div#content
-			div#description= meta.description
diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug
index ff2a77165..dae0a82d5 100644
--- a/packages/backend/src/server/web/views/note.pug
+++ b/packages/backend/src/server/web/views/note.pug
@@ -18,7 +18,7 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='article')
+		meta(property='og:type' content='article')
 		meta(property='og:title'       content= title)
 		meta(property='og:description' content= summary)
 		meta(property='og:url'         content= url)
@@ -27,7 +27,7 @@ block og
 			meta(property='og:image:width'     content=note.files[0].properties.width)
 			meta(property='og:image:height'    content=note.files[0].properties.height)
 			meta(property='og:image:type'      content=note.files[0].type)
-			meta(property='twitter:card'       content="summary_large_image")
+			meta(property='twitter:card' content="summary_large_image")
 		if isVideo
 			meta(property='og:video:type'      content=note.files[0].type)
 			meta(property='og:video'           content=note.files[0].url)
diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug
index eacaaab98..bfc7ebf79 100644
--- a/packages/backend/src/server/web/views/page.pug
+++ b/packages/backend/src/server/web/views/page.pug
@@ -14,7 +14,7 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='article')
+		meta(property='og:type' content='article')
 		meta(property='og:title'       content= title)
 		meta(property='og:description' content= page.summary)
 		meta(property='og:url'         content= url)
diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug
index 1cc429156..f5820f55f 100644
--- a/packages/backend/src/server/web/views/user.pug
+++ b/packages/backend/src/server/web/views/user.pug
@@ -13,11 +13,12 @@ block desc
 
 block og
 	unless privateMode
-		meta(property='og:type'        content='blog')
-		meta(property='og:title'       content= title)
-		meta(property='og:description' content= profile.description)
-		meta(property='og:url'         content= url)
-		meta(property='og:image'       content= avatarUrl)
+		meta(property='og:type' content='profile')
+		meta(property='og:title'         content= title)
+		meta(property='og:description'   content= profile.description)
+		meta(property='og:url'           content= url)
+		meta(property='og:image'         content= avatarUrl)
+		meta(property='profile:username' content= user.username)
 
 block meta
 	unless privateMode

From 117f95799ba7683fd565b976df233bdd14465f94 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 22:11:34 -0700
Subject: [PATCH 56/66] refactor: :recycle: sync note summaries

---
 locales/ar-SA.yml                               | 1 -
 locales/bn-BD.yml                               | 1 -
 locales/ca-ES.yml                               | 1 -
 locales/cs-CZ.yml                               | 1 -
 locales/da-DK.yml                               | 1 -
 locales/de-DE.yml                               | 1 -
 locales/el-GR.yml                               | 1 -
 locales/en-US.yml                               | 1 -
 locales/es-ES.yml                               | 1 -
 locales/fi.yml                                  | 1 -
 locales/fr-FR.yml                               | 1 -
 locales/id-ID.yml                               | 1 -
 locales/it-IT.yml                               | 1 -
 locales/ja-JP.yml                               | 1 -
 locales/ja-KS.yml                               | 1 -
 locales/ko-KR.yml                               | 1 -
 locales/nl-NL.yml                               | 1 -
 locales/pl-PL.yml                               | 1 -
 locales/pt-PT.yml                               | 1 -
 locales/ro-RO.yml                               | 1 -
 locales/ru-RU.yml                               | 1 -
 locales/sk-SK.yml                               | 1 -
 locales/sv-SE.yml                               | 1 -
 locales/th-TH.yml                               | 1 -
 locales/uk-UA.yml                               | 1 -
 locales/vi-VN.yml                               | 1 -
 locales/zh-CN.yml                               | 1 -
 locales/zh-TW.yml                               | 1 -
 packages/backend/src/misc/get-note-summary.ts   | 5 +++--
 packages/client/src/scripts/get-note-summary.ts | 5 +++--
 30 files changed, 6 insertions(+), 32 deletions(-)

diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 148cd32a0..3ce83ebcc 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -176,7 +176,6 @@ operations: "الإجراءات"
 software: "البرمجية"
 version: "الإصدار"
 metadata: "البيانات الوصفية"
-withNFiles: "{n} ملف (ملفات)"
 monitor: "شاشة التحكم"
 jobQueue: "قائمة الانتظار"
 cpuAndMemory: "وحدة المعالجة المركزية والذاكرة"
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index cde425d7f..f08e4bfc2 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -177,7 +177,6 @@ operations: "ক্রিয়াকলাপ"
 software: "সফটওয়্যার"
 version: "সংস্করণ"
 metadata: "মেটাডাটা"
-withNFiles: "{n} টি ফাইল"
 monitor: "মনিটর"
 jobQueue: "জব কিউ"
 cpuAndMemory: "সিপিউ এবং মেমরি"
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index f438b4f9a..857caac1f 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -791,7 +791,6 @@ selectUser: Selecciona un usuari
 latestStatus: Últim estat
 storageUsage: Ús del emmagatzematge
 metadata: Metadades
-withNFiles: '{n} fitxer(s)'
 monitor: Seguiment
 software: Programari
 version: Versió
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index 1d12e69ab..8b502762f 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -189,7 +189,6 @@ operations: "Operace"
 software: "Software"
 version: "Verze"
 metadata: "Metadata"
-withNFiles: "{n} soubor(ů)"
 monitor: "Monitorovat"
 jobQueue: "Fronta úloh"
 cpuAndMemory: "CPU a paměť"
diff --git a/locales/da-DK.yml b/locales/da-DK.yml
index c6d339a2e..878273c65 100644
--- a/locales/da-DK.yml
+++ b/locales/da-DK.yml
@@ -117,7 +117,6 @@ operations: Operationer
 software: Software
 metadata: Metadata
 version: Version
-withNFiles: '{n} fil(er)'
 monitor: Vagt
 jobQueue: Jobkø
 statistics: Statistik
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 2a039af4c..45edbe045 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -200,7 +200,6 @@ operations: "Tätigkeiten"
 software: "Software"
 version: "Version"
 metadata: "Metadaten"
-withNFiles: "{n} Datei(en)"
 monitor: "Überwachung"
 jobQueue: "Auftragswarteschlange"
 cpuAndMemory: "CPU und Speicher"
diff --git a/locales/el-GR.yml b/locales/el-GR.yml
index 57270f7aa..d444882b4 100644
--- a/locales/el-GR.yml
+++ b/locales/el-GR.yml
@@ -435,7 +435,6 @@ nothing: Δεν υπάρχει τίποτα να δείτε εδώ
 newNoteRecived: Υπάρχουν νέες δημοσιεύσεις
 passwordMatched: Ταιριάζει
 unmarkAsSensitive: Αναίρεση επισήμανσης ως Ευαίσθητο Περιεχόμενο (NSFW)
-withNFiles: '{n} αρχείο(-α)'
 blockedUsers: Μπλοκαρισμένα μέλη
 noteDeleteConfirm: Θέλετε σίγουρα να διαγράψετε αυτή τη δημοσίευση;
 preview: Προεπισκόπηση
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 5b6abcc35..127b2d0fe 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -211,7 +211,6 @@ operations: "Operations"
 software: "Software"
 version: "Version"
 metadata: "Metadata"
-withNFiles: "{n} file(s)"
 monitor: "Monitor"
 jobQueue: "Job Queue"
 cpuAndMemory: "CPU and Memory"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 49f51bff6..2dc40f359 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -195,7 +195,6 @@ operations: "Operaciones"
 software: "Software"
 version: "Versión"
 metadata: "Metadatos"
-withNFiles: "{n} archivos"
 monitor: "Monitor"
 jobQueue: "Cola de trabajos"
 cpuAndMemory: "CPU y Memoria"
diff --git a/locales/fi.yml b/locales/fi.yml
index ec7438096..aa9699cca 100644
--- a/locales/fi.yml
+++ b/locales/fi.yml
@@ -182,7 +182,6 @@ followsYou: Seuraa sinua
 pageLoadErrorDescription: Tämä yleensä johtuu verkkovirheistä tai selaimen välimuistista.
   Kokeile tyhjentämällä välimuisti ja yritä sitten hetken kuluttua uudelleen.
 enterListName: Anna listalle nimi
-withNFiles: '{n} tiedosto(t)'
 instanceInfo: Instanssin tiedot
 clearQueue: Tyhjennä jono
 suspendConfirm: Oletko varma, että haluat keskeyttää tämän tilin?
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index e7416f577..dad095688 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -201,7 +201,6 @@ operations: "Opérations"
 software: "Logiciel"
 version: "Version"
 metadata: "Métadonnées"
-withNFiles: "{n} fichier(s)"
 monitor: "Contrôle"
 jobQueue: "File d’attente"
 cpuAndMemory: "Processeur et mémoire"
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index 4caca4439..f9859c2c7 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -197,7 +197,6 @@ operations: "Tindakan"
 software: "Perangkat lunak"
 version: "Versi"
 metadata: "Metadata"
-withNFiles: "{n} berkas"
 monitor: "Pantau"
 jobQueue: "Antrian kerja"
 cpuAndMemory: "CPU dan Memori"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 6dc4b68b5..ed3632ec6 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -175,7 +175,6 @@ operations: "Operazioni"
 software: "Software"
 version: "Versione"
 metadata: "Metadato"
-withNFiles: "{n} file in allegato"
 monitor: "Monitorare"
 jobQueue: "Coda di lavoro"
 cpuAndMemory: "CPU e Memoria"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 94454f3f9..1bbc38c49 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -188,7 +188,6 @@ operations: "操作"
 software: "ソフトウェア"
 version: "バージョン"
 metadata: "メタデータ"
-withNFiles: "{n}つのファイル"
 monitor: "モニター"
 jobQueue: "ジョブキュー"
 cpuAndMemory: "CPUとメモリ"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index d5c48276f..8a9b91486 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -177,7 +177,6 @@ operations: "操作"
 software: "ソフトウェア"
 version: "バージョン"
 metadata: "メタデータ"
-withNFiles: "{n}個のファイル"
 monitor: "モニター"
 jobQueue: "ジョブキュー"
 cpuAndMemory: "CPUとメモリ"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 15e776faf..7143cf2f9 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -177,7 +177,6 @@ operations: "작업"
 software: "소프트웨어"
 version: "버전"
 metadata: "메타데이터"
-withNFiles: "{n}개의 파일"
 monitor: "모니터"
 jobQueue: "작업 대기열"
 cpuAndMemory: "CPU와 메모리"
diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml
index 49b737e91..115c003e3 100644
--- a/locales/nl-NL.yml
+++ b/locales/nl-NL.yml
@@ -179,7 +179,6 @@ operations: "Verwerkingen"
 software: "Software"
 version: "Versie"
 metadata: "Metadata"
-withNFiles: "{n} bestand(en)"
 monitor: "Monitor"
 jobQueue: "Job Queue"
 cpuAndMemory: "CPU en geheugen"
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 659e204af..a1b0f0c15 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -187,7 +187,6 @@ operations: "Działania"
 software: "Oprogramowanie"
 version: "Wersja"
 metadata: "Metadane"
-withNFiles: "{n} plik(i/ów)"
 monitor: "Monitor"
 jobQueue: "Kolejka zadań"
 cpuAndMemory: "CPU i pamięć"
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index 2803df928..3e15beebb 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -177,7 +177,6 @@ operations: "operar"
 software: "Programas"
 version: "versão"
 metadata: "Metadados"
-withNFiles: "{n} Um arquivo"
 monitor: "monitor"
 jobQueue: "Fila de trabalhos"
 cpuAndMemory: "CPU e memória"
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index 92a35ffa8..ba51950e3 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -177,7 +177,6 @@ operations: "Operațiuni"
 software: "Software"
 version: "Versiune"
 metadata: "Metadata"
-withNFiles: "{n} fișier(e)"
 monitor: "Monitor"
 jobQueue: "coada de job-uri"
 cpuAndMemory: "CPU și memorie"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index ad47d7d37..01b21b0fc 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -192,7 +192,6 @@ operations: "Операции"
 software: "Программы"
 version: "Версия"
 metadata: "Метаданные"
-withNFiles: "Файлы, {n} шт"
 monitor: "Монитор"
 jobQueue: "Очередь заданий"
 cpuAndMemory: "Процессор и память"
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index a36caf1fd..462f34ed2 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -177,7 +177,6 @@ operations: "Operácie"
 software: "Softvér"
 version: "Verzia"
 metadata: "Metadáta"
-withNFiles: "{n} súbor(ov)"
 monitor: "Monitor"
 jobQueue: "Fronta úloh"
 cpuAndMemory: "CPU a pamäť"
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 993af2a23..6523ce068 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -176,7 +176,6 @@ operations: "Operationer"
 software: "Mjukvara"
 version: "Version"
 metadata: "Metadata"
-withNFiles: "{n} fil(er)"
 monitor: "Övervakning"
 jobQueue: "Jobbkö"
 cpuAndMemory: "CPU och minne"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index b6d81d8f5..9666737ee 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -177,7 +177,6 @@ operations: "ดำเนินการ"
 software: "ซอฟต์แวร์"
 version: "เวอร์ชั่น"
 metadata: "ข้อมูลเมตา"
-withNFiles: "{n} ไฟล์(s)"
 monitor: "มอนิเตอร์"
 jobQueue: "คิวงาน"
 cpuAndMemory: "ซีพียู และ หน่วยความจำ"
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 0368a0897..549dce666 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -177,7 +177,6 @@ operations: "Операції"
 software: "Програмне забезпечення"
 version: "Версія"
 metadata: "Метадані"
-withNFiles: "файли: {n}"
 monitor: "Монітор"
 jobQueue: "Черга завдань"
 cpuAndMemory: "ЦП та пам'ять"
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index 7662af409..4b254fe94 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -177,7 +177,6 @@ operations: "Vận hành"
 software: "Phần mềm"
 version: "Phiên bản"
 metadata: "Metadata"
-withNFiles: "{n} tập tin"
 monitor: "Giám sát"
 jobQueue: "Công việc chờ xử lý"
 cpuAndMemory: "CPU và Dung lượng"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 8ca19e596..5359cb6ef 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -181,7 +181,6 @@ operations: "操作"
 software: "软件"
 version: "版本"
 metadata: "元数据"
-withNFiles: "{n}个文件"
 monitor: "服务器状态"
 jobQueue: "作业队列"
 cpuAndMemory: "CPU和内存"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index fd5117f48..61b5afbe6 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -180,7 +180,6 @@ operations: "操作"
 software: "軟體"
 version: "版本"
 metadata: "元資料"
-withNFiles: "{n}個檔案"
 monitor: "監視器"
 jobQueue: "佇列"
 cpuAndMemory: "CPU及記憶體用量"
diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts
index 446e3fc14..285dcffd3 100644
--- a/packages/backend/src/misc/get-note-summary.ts
+++ b/packages/backend/src/misc/get-note-summary.ts
@@ -20,12 +20,13 @@ export const getNoteSummary = (note: Packed<"Note">): string => {
 
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
-		summary += ` (📎${note.files!.length})`;
+		const len = note.files?.length;
+		summary += ` 📎 (${len !== 1 ? len : ''})`;
 	}
 
 	// 投票が添付されているとき
 	if (note.poll) {
-		summary += " (📊)";
+		summary += " 📊";
 	}
 
 	/*
diff --git a/packages/client/src/scripts/get-note-summary.ts b/packages/client/src/scripts/get-note-summary.ts
index 43bd1d3b9..4333bd6f0 100644
--- a/packages/client/src/scripts/get-note-summary.ts
+++ b/packages/client/src/scripts/get-note-summary.ts
@@ -23,12 +23,13 @@ export const getNoteSummary = (note: misskey.entities.Note): string => {
 
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
-		summary += ` (${i18n.t("withNFiles", { n: note.files.length })})`;
+		const len = note.files?.length;
+		summary += ` 📎 (${len !== 1 ? len : ''})`;
 	}
 
 	// 投票が添付されているとき
 	if (note.poll) {
-		summary += ` (${i18n.ts.poll})`;
+		summary += " 📊";
 	}
 
 	/*

From 30b33d2c20b92e01c76a95a0be5aeae817a8efcc Mon Sep 17 00:00:00 2001
From: Kainoa Kanter <kainoa@t1c.dev>
Date: Sat, 3 Jun 2023 06:02:47 +0000
Subject: [PATCH 57/66] dev39

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 41fc1e666..703fef632 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "calckey",
-	"version": "14.0.0-dev35",
+	"version": "14.0.0-dev39",
 	"codename": "aqua",
 	"repository": {
 		"type": "git",

From 792f28a367b6864d65bcc0d22039df58cb2ef244 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:20:34 -0700
Subject: [PATCH 58/66] fix: remove unessicary extra line in note menu

---
 packages/client/src/scripts/get-note-menu.ts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/packages/client/src/scripts/get-note-menu.ts b/packages/client/src/scripts/get-note-menu.ts
index 6eeecf4a6..aaec3099d 100644
--- a/packages/client/src/scripts/get-note-menu.ts
+++ b/packages/client/src/scripts/get-note-menu.ts
@@ -399,8 +399,6 @@ export function getNoteMenu(props: {
 				  ]
 				: []),
 
-			null,
-
 			isAppearAuthor || isModerator
 				? {
 						icon: "ph-trash ph-bold ph-lg",

From decdb6490ce76699b8cae471cd771993ba19f866 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:21:06 -0700
Subject: [PATCH 59/66] chore: formatting

---
 packages/backend/src/misc/get-note-summary.ts   | 2 +-
 packages/client/src/scripts/get-note-summary.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts
index 285dcffd3..63521c1c6 100644
--- a/packages/backend/src/misc/get-note-summary.ts
+++ b/packages/backend/src/misc/get-note-summary.ts
@@ -21,7 +21,7 @@ export const getNoteSummary = (note: Packed<"Note">): string => {
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
 		const len = note.files?.length;
-		summary += ` 📎 (${len !== 1 ? len : ''})`;
+		summary += ` 📎 (${len !== 1 ? len : ""})`;
 	}
 
 	// 投票が添付されているとき
diff --git a/packages/client/src/scripts/get-note-summary.ts b/packages/client/src/scripts/get-note-summary.ts
index 4333bd6f0..4a1530162 100644
--- a/packages/client/src/scripts/get-note-summary.ts
+++ b/packages/client/src/scripts/get-note-summary.ts
@@ -24,7 +24,7 @@ export const getNoteSummary = (note: misskey.entities.Note): string => {
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
 		const len = note.files?.length;
-		summary += ` 📎 (${len !== 1 ? len : ''})`;
+		summary += ` 📎 (${len !== 1 ? len : ""})`;
 	}
 
 	// 投票が添付されているとき

From ed5a4395dfbb666cf8e79eb1c5d0336e4d4aefb9 Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Sat, 3 Jun 2023 15:24:16 +0900
Subject: [PATCH 60/66] fix tutorial

---
 .../client/src/components/MkTutorialDialog.vue     | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/client/src/components/MkTutorialDialog.vue b/packages/client/src/components/MkTutorialDialog.vue
index 6927e961c..b4d8eee0a 100644
--- a/packages/client/src/components/MkTutorialDialog.vue
+++ b/packages/client/src/components/MkTutorialDialog.vue
@@ -140,26 +140,26 @@
 										</template>
 									</I18n>
 								</li>
-								<li v-if="timelines.includes('recommended')">
+								<li v-if="timelines.includes('social')">
 									<I18n
 										:src="i18n.ts._tutorial.step5_5"
 										tag="div"
 									>
 										<template #icon>
 											<i
-												class="ph-thumbs-up ph-bold ph-lg"
+												class="ph-handshake ph-bold ph-lg"
 											/>
 										</template>
 									</I18n>
 								</li>
-								<li v-if="timelines.includes('social')">
+								<li v-if="timelines.includes('recommended')">
 									<I18n
 										:src="i18n.ts._tutorial.step5_6"
 										tag="div"
 									>
 										<template #icon>
 											<i
-												class="ph-handshake ph-bold ph-lg"
+												class="ph-thumbs-up ph-bold ph-lg"
 											/>
 										</template>
 									</I18n>
@@ -235,12 +235,12 @@ let timelines = ["home"];
 if (isLocalTimelineAvailable) {
 	timelines.push("local");
 }
-if (isRecommendedTimelineAvailable) {
-	timelines.push("recommended");
-}
 if (isLocalTimelineAvailable) {
 	timelines.push("social");
 }
+if (isRecommendedTimelineAvailable) {
+	timelines.push("recommended");
+}
 if (isGlobalTimelineAvailable) {
 	timelines.push("global");
 }

From c0dd5aa9646a18cfef857adfe79a34714f1dd533 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:28:21 -0700
Subject: [PATCH 61/66] =?UTF-8?q?perf:=20=E3=82=A4=E3=83=B3=E3=82=B9?=
 =?UTF-8?q?=E3=82=BF=E3=83=B3=E3=82=B9=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB?=
 =?UTF-8?q?=E3=83=88=E3=83=86=E3=83=BC=E3=83=9E=E3=82=92=E4=BA=88=E3=82=81?=
 =?UTF-8?q?json5=20->=20json=E3=81=AB=E5=A4=89=E6=8F=9B=E3=81=97=E3=81=A6?=
 =?UTF-8?q?=E3=81=8A=E3=81=8F=E3=81=93=E3=81=A8=E3=81=A7json5=E3=82=92?=
 =?UTF-8?q?=E5=88=9D=E6=9C=9F=E3=83=90=E3=83=B3=E3=83=89=E3=83=AB=E3=81=AB?=
 =?UTF-8?q?=E5=90=AB=E3=82=81=E3=81=9A=E3=81=AB=E6=B8=88=E3=82=80=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Syuilo <syuilotan@yahoo.co.jp>
---
 packages/backend/src/server/api/endpoints/meta.ts | 10 ++++++++--
 packages/client/src/init.ts                       |  5 ++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 139afc88b..23cfe4018 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -1,3 +1,4 @@
+import * as JSON5 from "json5";
 import { IsNull, MoreThan } from "typeorm";
 import config from "@/config/index.js";
 import { fetchMeta } from "@/misc/fetch-meta.js";
@@ -462,8 +463,13 @@ export default define(meta, paramDef, async (ps, me) => {
 		maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
 		maxCaptionTextLength: MAX_CAPTION_TEXT_LENGTH,
 		emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis),
-		defaultLightTheme: instance.defaultLightTheme,
-		defaultDarkTheme: instance.defaultDarkTheme,
+		// クライアントの手間を減らすためあらかじめJSONに変換しておく
+		defaultLightTheme: instance.defaultLightTheme
+			? JSON.stringify(JSON5.parse(instance.defaultLightTheme))
+			: null,
+		defaultDarkTheme: instance.defaultDarkTheme
+			? JSON.stringify(JSON5.parse(instance.defaultDarkTheme))
+			: null,
 		ads:
 			instance.privateMode && !me
 				? []
diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts
index 7a004688d..5d9ae12f3 100644
--- a/packages/client/src/init.ts
+++ b/packages/client/src/init.ts
@@ -27,7 +27,6 @@ import {
 	defineAsyncComponent,
 } from "vue";
 import { compareVersions } from "compare-versions";
-import JSON5 from "json5";
 
 import widgets from "@/widgets";
 import directives from "@/directives";
@@ -312,12 +311,12 @@ import { getAccountFromId } from "@/scripts/get-account-from-id";
 			if (instance.defaultLightTheme != null)
 				ColdDeviceStorage.set(
 					"lightTheme",
-					JSON5.parse(instance.defaultLightTheme),
+					JSON.parse(instance.defaultLightTheme),
 				);
 			if (instance.defaultDarkTheme != null)
 				ColdDeviceStorage.set(
 					"darkTheme",
-					JSON5.parse(instance.defaultDarkTheme),
+					JSON.parse(instance.defaultDarkTheme),
 				);
 			defaultStore.set("themeInitial", false);
 		}

From 0b9ef6bc52323f8944c853bb142b30713e85019b Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:30:51 -0700
Subject: [PATCH 62/66] refactor: remove mk remnants

---
 packages/backend/migration/1000000000000-Init.js        | 2 +-
 packages/backend/src/models/entities/meta.ts            | 4 ++--
 packages/backend/src/server/api/endpoints/admin/meta.ts | 4 ++--
 packages/backend/src/server/api/endpoints/meta.ts       | 4 ++--
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/backend/migration/1000000000000-Init.js b/packages/backend/migration/1000000000000-Init.js
index c07500e35..d32a6e0d2 100644
--- a/packages/backend/migration/1000000000000-Init.js
+++ b/packages/backend/migration/1000000000000-Init.js
@@ -220,7 +220,7 @@ export class Init1000000000000 {
 			`CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON "notification" ("notifieeId") `,
 		);
 		await queryRunner.query(
-			`CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/assets/ai.png', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT 'https://xn--931a.moe/aiart/yubitun.png', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT true, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`,
+			`CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/static-assets/badges/info.png', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT '/static-assets/badges/error.png', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT true, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`,
 		);
 		await queryRunner.query(
 			`CREATE TABLE "following" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_c76c6e044bdf76ecf8bfb82a645" PRIMARY KEY ("id"))`,
diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts
index 433ad0db5..b22c6510f 100644
--- a/packages/backend/src/models/entities/meta.ts
+++ b/packages/backend/src/models/entities/meta.ts
@@ -162,7 +162,7 @@ export class Meta {
 	@Column("varchar", {
 		length: 512,
 		nullable: true,
-		default: "/assets/ai.png",
+		default: "/static-assets/badges/info.png",
 	})
 	public mascotImageUrl: string | null;
 
@@ -187,7 +187,7 @@ export class Meta {
 	@Column("varchar", {
 		length: 512,
 		nullable: true,
-		default: "https://xn--931a.moe/aiart/yubitun.png",
+		default: "/static-assets/badges/error.png",
 	})
 	public errorImageUrl: string | null;
 
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index 24c895cbb..ad7031063 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -64,7 +64,7 @@ export const meta = {
 				type: "string",
 				optional: false,
 				nullable: false,
-				default: "/assets/ai.png",
+				default: "/static-assets/badges/info.png",
 			},
 			bannerUrl: {
 				type: "string",
@@ -75,7 +75,7 @@ export const meta = {
 				type: "string",
 				optional: false,
 				nullable: false,
-				default: "https://xn--931a.moe/aiart/yubitun.png",
+				default: "/static-assets/badges/error.png",
 			},
 			iconUrl: {
 				type: "string",
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 23cfe4018..c603cb9ac 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -155,7 +155,7 @@ export const meta = {
 				type: "string",
 				optional: false,
 				nullable: false,
-				default: "/assets/ai.png",
+				default: "/static-assets/badges/info.png",
 			},
 			bannerUrl: {
 				type: "string",
@@ -166,7 +166,7 @@ export const meta = {
 				type: "string",
 				optional: false,
 				nullable: false,
-				default: "https://xn--931a.moe/aiart/yubitun.png",
+				default: "/static-assets/badges/error.png",
 			},
 			iconUrl: {
 				type: "string",

From 141fbc7b67c838956ced2babc25063c9bf65bbd5 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:38:05 -0700
Subject: [PATCH 63/66] regress: no metrics in dashboard for now

---
 packages/client/src/pages/admin/overview.vue | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue
index 67da86746..d88022595 100644
--- a/packages/client/src/pages/admin/overview.vue
+++ b/packages/client/src/pages/admin/overview.vue
@@ -51,10 +51,10 @@
 				<XQueue domain="inbox" />
 			</MkFolder>
 
-			<MkFolder class="item">
+			<!-- <MkFolder class="item">
 				<template #header>Server metrics</template>
 				<XMetrics domain="inbox" />
-			</MkFolder>
+			</MkFolder> -->
 		</div>
 	</MkSpacer>
 </template>
@@ -76,7 +76,7 @@ import XActiveUsers from "./overview.active-users.vue";
 import XStats from "./overview.stats.vue";
 import XModerators from "./overview.moderators.vue";
 import XHeatmap from "./overview.heatmap.vue";
-import XMetrics from "./overview.metrics.vue";
+// import XMetrics from "./overview.metrics.vue";
 import MkTagCloud from "@/components/MkTagCloud.vue";
 import { version, url } from "@/config";
 import * as os from "@/os";

From 04d4d21f74063e0ef5221f2136689fde4c3d6ebc Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 2 Jun 2023 23:55:31 -0700
Subject: [PATCH 64/66] fix: summary if 1 attachment

---
 packages/backend/src/misc/get-note-summary.ts   | 2 +-
 packages/client/src/scripts/get-note-summary.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts
index 63521c1c6..0a662e434 100644
--- a/packages/backend/src/misc/get-note-summary.ts
+++ b/packages/backend/src/misc/get-note-summary.ts
@@ -21,7 +21,7 @@ export const getNoteSummary = (note: Packed<"Note">): string => {
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
 		const len = note.files?.length;
-		summary += ` 📎 (${len !== 1 ? len : ""})`;
+		summary += ` 📎${len !== 1 ? ` (${len})` : ""}`;
 	}
 
 	// 投票が添付されているとき
diff --git a/packages/client/src/scripts/get-note-summary.ts b/packages/client/src/scripts/get-note-summary.ts
index 4a1530162..bbbe4afb8 100644
--- a/packages/client/src/scripts/get-note-summary.ts
+++ b/packages/client/src/scripts/get-note-summary.ts
@@ -24,7 +24,7 @@ export const getNoteSummary = (note: misskey.entities.Note): string => {
 	// ファイルが添付されているとき
 	if ((note.files || []).length !== 0) {
 		const len = note.files?.length;
-		summary += ` 📎 (${len !== 1 ? len : ""})`;
+		summary += ` 📎${len !== 1 ? ` (${len})` : ""}`;
 	}
 
 	// 投票が添付されているとき

From d0ff53ad70114c2e839f2d2a2bc3aaeac91724f1 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Sat, 3 Jun 2023 00:41:30 -0700
Subject: [PATCH 65/66] chore: :arrow_up: up various deps

---
 package.json                               |  4 +-
 packages/backend/native-utils/Cargo.toml   |  2 +-
 packages/backend/native-utils/package.json |  2 +-
 packages/backend/package.json              |  2 +-
 packages/client/.vscode/settings.json      | 11 ++-
 packages/client/package.json               | 10 +--
 pnpm-lock.yaml                             | 84 ++++++++++++----------
 7 files changed, 67 insertions(+), 48 deletions(-)

diff --git a/package.json b/package.json
index 703fef632..6b6531fc6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "calckey",
-	"version": "14.0.0-dev39",
+	"version": "14.0.0-dev40",
 	"codename": "aqua",
 	"repository": {
 		"type": "git",
@@ -38,7 +38,7 @@
 	"dependencies": {
 		"@bull-board/api": "5.2.0",
 		"@bull-board/ui": "5.2.0",
-		"@napi-rs/cli": "^2.15.0",
+		"@napi-rs/cli": "^2.16.1",
 		"@tensorflow/tfjs": "^3.21.0",
 		"focus-trap": "^7.2.0",
 		"focus-trap-vue": "^4.0.1",
diff --git a/packages/backend/native-utils/Cargo.toml b/packages/backend/native-utils/Cargo.toml
index 9b030e37d..f93180fe4 100644
--- a/packages/backend/native-utils/Cargo.toml
+++ b/packages/backend/native-utils/Cargo.toml
@@ -33,7 +33,7 @@ tokio = { version = "1.28.1", features = ["full"] }
 utoipa = "3.3.0"
 
 # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
-napi = { version = "2.12.0", default-features = false, features = ["napi6", "tokio_rt"], optional = true }
+napi = { version = "2.13.1", default-features = false, features = ["napi6", "tokio_rt"], optional = true }
 napi-derive = { version = "2.12.0", optional = true }
 radix_fmt = { version = "1.0.0", optional = true }
 
diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json
index 64f9e0e50..2e6a721f4 100644
--- a/packages/backend/native-utils/package.json
+++ b/packages/backend/native-utils/package.json
@@ -23,7 +23,7 @@
   },
   "license": "MIT",
   "devDependencies": {
-    "@napi-rs/cli": "2.15.0",
+    "@napi-rs/cli": "2.16.1",
     "ava": "5.1.1"
   },
   "ava": {
diff --git a/packages/backend/package.json b/packages/backend/package.json
index ca916576b..47e9c415c 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -63,7 +63,7 @@
 		"cli-highlight": "2.1.11",
 		"color-convert": "2.0.1",
 		"content-disposition": "0.5.4",
-		"date-fns": "2.29.3",
+		"date-fns": "2.30.0",
 		"deep-email-validator": "0.1.21",
 		"escape-regexp": "0.0.1",
 		"feed": "4.2.2",
diff --git a/packages/client/.vscode/settings.json b/packages/client/.vscode/settings.json
index 1950a66b9..d654bb166 100644
--- a/packages/client/.vscode/settings.json
+++ b/packages/client/.vscode/settings.json
@@ -1,6 +1,15 @@
 {
-	"typescript.tsdk": "node_modules\\typescript\\lib",
+	"typescript.tsdk": "node_modules/typescript/lib",
 	"path-intellisense.mappings": {
 		"@": "${workspaceRoot}/packages/client/src/"
 	},
+	"files.exclude": {
+		"**/.git": true,
+		"**/.svn": true,
+		"**/.hg": true,
+		"**/CVS": true,
+		"**/.DS_Store": true,
+		"**/Thumbs.db": true,
+		"**/_client_dist_": true
+	}
 }
diff --git a/packages/client/package.json b/packages/client/package.json
index ccddda6b9..83ea429c4 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -33,17 +33,17 @@
 		"broadcast-channel": "4.19.1",
 		"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
 		"calckey-js": "workspace:*",
-		"chart.js": "4.1.1",
-		"chartjs-adapter-date-fns": "2.0.1",
+		"chart.js": "4.3.0",
+		"chartjs-adapter-date-fns": "3.0.0",
 		"chartjs-chart-matrix": "^2.0.1",
-		"chartjs-plugin-gradient": "0.5.1",
-		"chartjs-plugin-zoom": "1.2.1",
+		"chartjs-plugin-gradient": "0.6.1",
+		"chartjs-plugin-zoom": "2.0.1",
 		"city-timezones": "^1.2.1",
 		"compare-versions": "5.0.3",
 		"cropperjs": "2.0.0-beta.2",
 		"cross-env": "7.0.3",
 		"cypress": "10.11.0",
-		"date-fns": "2.29.3",
+		"date-fns": "2.30.0",
 		"escape-regexp": "0.0.1",
 		"eventemitter3": "4.0.7",
 		"gsap": "^3.11.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0d65da71e..f001fec77 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -18,8 +18,8 @@ importers:
         specifier: 5.2.0
         version: 5.2.0
       '@napi-rs/cli':
-        specifier: ^2.15.0
-        version: 2.15.0
+        specifier: ^2.16.1
+        version: 2.16.1
       '@tensorflow/tfjs':
         specifier: ^3.21.0
         version: 3.21.0(seedrandom@3.0.5)
@@ -190,8 +190,8 @@ importers:
         specifier: 0.5.4
         version: 0.5.4
       date-fns:
-        specifier: 2.29.3
-        version: 2.29.3
+        specifier: 2.30.0
+        version: 2.30.0
       deep-email-validator:
         specifier: 0.1.21
         version: 0.1.21
@@ -612,8 +612,8 @@ importers:
   packages/backend/native-utils:
     devDependencies:
       '@napi-rs/cli':
-        specifier: 2.15.0
-        version: 2.15.0
+        specifier: 2.16.1
+        version: 2.16.1
       ava:
         specifier: 5.1.1
         version: 5.1.1
@@ -754,20 +754,20 @@ importers:
         specifier: workspace:*
         version: link:../calckey-js
       chart.js:
-        specifier: 4.1.1
-        version: 4.1.1
+        specifier: 4.3.0
+        version: 4.3.0
       chartjs-adapter-date-fns:
-        specifier: 2.0.1
-        version: 2.0.1(chart.js@4.1.1)
+        specifier: 3.0.0
+        version: 3.0.0(chart.js@4.3.0)(date-fns@2.30.0)
       chartjs-chart-matrix:
         specifier: ^2.0.1
-        version: 2.0.1(chart.js@4.1.1)
+        version: 2.0.1(chart.js@4.3.0)
       chartjs-plugin-gradient:
-        specifier: 0.5.1
-        version: 0.5.1(chart.js@4.1.1)
+        specifier: 0.6.1
+        version: 0.6.1(chart.js@4.3.0)
       chartjs-plugin-zoom:
-        specifier: 1.2.1
-        version: 1.2.1(chart.js@4.1.1)
+        specifier: 2.0.1
+        version: 2.0.1(chart.js@4.3.0)
       city-timezones:
         specifier: ^1.2.1
         version: 1.2.1
@@ -784,8 +784,8 @@ importers:
         specifier: 10.11.0
         version: 10.11.0
       date-fns:
-        specifier: 2.29.3
-        version: 2.29.3
+        specifier: 2.30.0
+        version: 2.30.0
       escape-regexp:
         specifier: 0.0.1
         version: 0.0.1
@@ -1262,6 +1262,12 @@ packages:
       regenerator-runtime: 0.13.11
     dev: true
 
+  /@babel/runtime@7.22.3:
+    resolution: {integrity: sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      regenerator-runtime: 0.13.11
+
   /@babel/template@7.20.7:
     resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
     engines: {node: '>=6.9.0'}
@@ -2290,8 +2296,8 @@ packages:
     dev: false
     optional: true
 
-  /@napi-rs/cli@2.15.0:
-    resolution: {integrity: sha512-RDDr7ZF0cgbd37+NBGeQOjP7Tm/iNM+y3FmrT5bVQBXLePOTuKVC/dBsdN5UZv3Sl2XAwEvBfaGR90E0d8AA6g==}
+  /@napi-rs/cli@2.16.1:
+    resolution: {integrity: sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==}
     engines: {node: '>= 10'}
     hasBin: true
 
@@ -5315,43 +5321,45 @@ packages:
     resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
     dev: true
 
-  /chart.js@4.1.1:
-    resolution: {integrity: sha512-P0pCosNXp+LR8zO/QTkZKT6Hb7p0DPFtypEeVOf+6x06hX13NIb75R0DXUA4Ksx/+48chDQKtCCmRCviQRTqsA==}
-    engines: {pnpm: ^7.0.0}
+  /chart.js@4.3.0:
+    resolution: {integrity: sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==}
+    engines: {pnpm: '>=7'}
     dependencies:
       '@kurkle/color': 0.3.2
     dev: true
 
-  /chartjs-adapter-date-fns@2.0.1(chart.js@4.1.1):
-    resolution: {integrity: sha512-v3WV9rdnQ05ce3A0ZCjzUekJCAbfm6+3HqSoeY2BIkdMYZoYr/4T+ril1tZyDl869lz6xdNVMXejUFT9YKpw4A==}
+  /chartjs-adapter-date-fns@3.0.0(chart.js@4.3.0)(date-fns@2.30.0):
+    resolution: {integrity: sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==}
     peerDependencies:
       chart.js: '>=2.8.0'
+      date-fns: '>=2.0.0'
     dependencies:
-      chart.js: 4.1.1
+      chart.js: 4.3.0
+      date-fns: 2.30.0
     dev: true
 
-  /chartjs-chart-matrix@2.0.1(chart.js@4.1.1):
+  /chartjs-chart-matrix@2.0.1(chart.js@4.3.0):
     resolution: {integrity: sha512-BGfeY+/PHnITyDlc7WfnKJ1RyOfgOzIqWp/gxzzl7pUjyoGzHDcw51qd2xJF9gdT9Def7ZwOnOMm8GJUXDxI0w==}
     peerDependencies:
       chart.js: '>=3.0.0'
     dependencies:
-      chart.js: 4.1.1
+      chart.js: 4.3.0
     dev: true
 
-  /chartjs-plugin-gradient@0.5.1(chart.js@4.1.1):
-    resolution: {integrity: sha512-vhwlYGZWan4MGZZ4Wj64Y4aIql1uCPCU1JcggLWn3cgYEv4G7pXp1YgM4XH5ugmyn6BVCgQqAhiJ2h6hppzHmQ==}
+  /chartjs-plugin-gradient@0.6.1(chart.js@4.3.0):
+    resolution: {integrity: sha512-TGHNIh8KqQMLdb+UfY80cBHYRyOC47eeokmgkeajRdKGbFt462lJiyiq4ZJ25fiM7BGsmzoBLhmVyEw4B3gQxw==}
     peerDependencies:
       chart.js: '>=2.6.0'
     dependencies:
-      chart.js: 4.1.1
+      chart.js: 4.3.0
     dev: true
 
-  /chartjs-plugin-zoom@1.2.1(chart.js@4.1.1):
-    resolution: {integrity: sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==}
+  /chartjs-plugin-zoom@2.0.1(chart.js@4.3.0):
+    resolution: {integrity: sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==}
     peerDependencies:
-      chart.js: ^3.2.0
+      chart.js: '>=3.2.0'
     dependencies:
-      chart.js: 4.1.1
+      chart.js: 4.3.0
       hammerjs: 2.0.8
     dev: true
 
@@ -6332,9 +6340,11 @@ packages:
       whatwg-url: 11.0.0
     dev: false
 
-  /date-fns@2.29.3:
-    resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
+  /date-fns@2.30.0:
+    resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
     engines: {node: '>=0.11'}
+    dependencies:
+      '@babel/runtime': 7.22.3
 
   /date-time@3.1.0:
     resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
@@ -14754,7 +14764,7 @@ packages:
       buffer: 6.0.3
       chalk: 4.1.2
       cli-highlight: 2.1.11
-      date-fns: 2.29.3
+      date-fns: 2.30.0
       debug: 4.3.4(supports-color@8.1.1)
       dotenv: 16.0.3
       glob: 7.2.3

From a80b6eeb82644a852f4168c12ee331da4c1ec79b Mon Sep 17 00:00:00 2001
From: Kainoa Kanter <kainoa@t1c.dev>
Date: Sat, 3 Jun 2023 09:12:32 +0000
Subject: [PATCH 66/66] fix outdated docker deps

---
 Dockerfile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Dockerfile b/Dockerfile
index c378444f7..0aa13aefe 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,6 +3,7 @@ FROM node:19-alpine as build
 WORKDIR /calckey
 
 # Install compilation dependencies
+RUN apk update
 RUN apk add --no-cache --no-progress git alpine-sdk python3 rust cargo vips
 
 # Copy only the dependency-related files first, to cache efficiently