@s-hirano-ist/s-database 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/package.json +3 -4
  2. package/prisma/migrations/0_init/migration.sql +107 -0
  3. package/prisma/migrations/1_better_auth/migration.sql +69 -0
  4. package/prisma/migrations/migration_lock.toml +1 -1
  5. package/prisma/remap-userids-better-auth.sql +98 -0
  6. package/prisma/schema.prisma +112 -31
  7. package/src/generated/edge.js +56 -8
  8. package/src/generated/index-browser.js +51 -3
  9. package/src/generated/index.d.ts +6191 -35
  10. package/src/generated/index.js +56 -8
  11. package/src/generated/package.json +1 -1
  12. package/src/generated/query_compiler_fast_bg.wasm +0 -0
  13. package/src/generated/query_compiler_fast_bg.wasm-base64.js +1 -1
  14. package/src/generated/schema.prisma +112 -31
  15. package/src/index.ts +63 -7
  16. package/prisma/migrations/20241005070905_initial_with_user/migration.sql +0 -105
  17. package/prisma/migrations/20241005122052_category_unique_name/migration.sql +0 -11
  18. package/prisma/migrations/20241006114119_add_role/migration.sql +0 -5
  19. package/prisma/migrations/20241011230910_add_scope_and_username/migration.sql +0 -24
  20. package/prisma/migrations/20241012012914_migrate_user_verified_to_role/migration.sql +0 -11
  21. package/prisma/migrations/20241012014828_delete_user_email/migration.sql +0 -11
  22. package/prisma/migrations/20241013122009_delete_unique_on_profile_name/migration.sql +0 -2
  23. package/prisma/migrations/20241113115839_add_image_table/migration.sql +0 -13
  24. package/prisma/migrations/20241116050545_login_lock/migration.sql +0 -3
  25. package/prisma/migrations/20250104003943_delete_user_scope_column/migration.sql +0 -11
  26. package/prisma/migrations/20250104031930_delete_unauthorized_role_enum/migration.sql +0 -16
  27. package/prisma/migrations/20250104033736_change_user_role_enum_name/migration.sql +0 -19
  28. package/prisma/migrations/20250104064405_add_static_books_and_contents/migration.sql +0 -27
  29. package/prisma/migrations/20250113084254_drop_user_table/migration.sql +0 -37
  30. package/prisma/migrations/20250118084244_add_image_metadata/migration.sql +0 -14
  31. package/prisma/migrations/20250129231002_add_static_image_table/migration.sql +0 -14
  32. package/prisma/migrations/20250504020635_add_static_news_table/migration.sql +0 -27
  33. package/prisma/migrations/20250510025039_fix_no_unique_for_categories/migration.sql +0 -2
  34. package/prisma/migrations/20250614000736_add_google_api_data/migration.sql +0 -31
  35. package/prisma/migrations/20250719061839_add_og_for_static_news/migration.sql +0 -4
  36. package/prisma/migrations/20250730114244_delete_uint8arrayimage_from_static_books/migration.sql +0 -8
  37. package/prisma/migrations/20250811111733_delete_static_news/migration.sql +0 -20
  38. package/prisma/migrations/20250811115459_delete_updated_recently/migration.sql +0 -34
  39. package/prisma/migrations/20250811131348_merge_viewer_to_dumper/migration.sql +0 -54
  40. package/prisma/migrations/20250812234654_add_unique_costraints_on_unique_key/migration.sql +0 -19
  41. package/prisma/migrations/20250813033448_add_unique_constraints_on_images/migration.sql +0 -8
  42. package/prisma/migrations/20250813085846_delete_single_unique_constraints/migration.sql +0 -5
  43. package/prisma/migrations/20250813140904_change_id_from_int_to_uuid/migration.sql +0 -27
  44. package/prisma/migrations/20250813141347_move_image_id_to_paths/migration.sql +0 -15
  45. package/prisma/migrations/20250815002544_change_default_values/migration.sql +0 -39
  46. package/prisma/migrations/20250815040824_rename_images_paths_to_path/migration.sql +0 -17
  47. package/prisma/migrations/20250818232331_change_news_contents_to_article_note/migration.sql +0 -57
  48. package/prisma/migrations/20250819024722_delete_default_now_for_created_at/migration.sql +0 -14
  49. package/prisma/migrations/20251214044139_add_last_updated_to_status_schema/migration.sql +0 -2
  50. package/prisma/migrations/20260104035357_add_image_paths_for_book_dumper/migration.sql +0 -2
  51. package/prisma/migrations/20260118120015_add_schema_restrictions_on_cols/migration.sql +0 -93
  52. package/prisma/migrations/20260125055037_remove_image_tags_description/migration.sql +0 -10
  53. package/prisma/migrations/20260214022211_add_more_url_length_to_og_image/migration.sql +0 -2
  54. package/prisma/migrations/20260418090234_rating_to_required/migration.sql +0 -8
  55. package/prisma/migrations/20260419000000_merge_google_title_into_title/migration.sql +0 -15
  56. package/src/resolve-db-env.ts +0 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@s-hirano-ist/s-database",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "Prisma database schema and client for s-private project",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -10,7 +10,6 @@
10
10
  "types": "./src/index.ts",
11
11
  "default": "./src/index.ts"
12
12
  },
13
- "./resolve-db-env": "./src/resolve-db-env.ts",
14
13
  "./generated": "./src/generated/index.js",
15
14
  "./generated/*": "./src/generated/*"
16
15
  },
@@ -36,12 +35,12 @@
36
35
  "prisma": "7.8.0"
37
36
  },
38
37
  "devDependencies": {
39
- "prisma-erd-generator": "2.4.2",
38
+ "prisma-erd-generator": "2.4.3",
40
39
  "typescript": "6.0.3"
41
40
  },
42
41
  "scripts": {
43
42
  "prisma:generate": "mkdir -p erd && prisma generate",
44
- "prisma:migrate": "prisma migrate dev",
43
+ "prisma:migrate:diff": "prisma migrate diff --from-migrations prisma/migrations --to-schema prisma/schema.prisma --script",
45
44
  "prisma:deploy": "prisma migrate deploy",
46
45
  "prisma:studio": "prisma studio",
47
46
  "docs:build": "bash scripts/generate-db-docs.sh",
@@ -0,0 +1,107 @@
1
+ -- CreateSchema
2
+ CREATE SCHEMA IF NOT EXISTS "public";
3
+
4
+ -- CreateEnum
5
+ CREATE TYPE "Status" AS ENUM ('UNEXPORTED', 'LAST_UPDATED', 'EXPORTED');
6
+
7
+ -- CreateTable
8
+ CREATE TABLE "categories" (
9
+ "id" STRING(36) NOT NULL,
10
+ "name" STRING(16) NOT NULL,
11
+ "created_at" TIMESTAMP(3) NOT NULL,
12
+ "updated_at" TIMESTAMP(3) NOT NULL,
13
+ "user_id" STRING(128) NOT NULL,
14
+
15
+ CONSTRAINT "categories_pkey" PRIMARY KEY ("id")
16
+ ) WITH (schema_locked = false);
17
+
18
+ -- CreateTable
19
+ CREATE TABLE "articles" (
20
+ "id" STRING(36) NOT NULL,
21
+ "title" STRING(128) NOT NULL,
22
+ "url" STRING(2048) NOT NULL,
23
+ "quote" STRING(512),
24
+ "og_image_url" STRING(4096),
25
+ "og_title" STRING(512),
26
+ "og_description" STRING(1024),
27
+ "category_id" STRING(36) NOT NULL,
28
+ "status" "Status" NOT NULL,
29
+ "user_id" STRING(128) NOT NULL,
30
+ "created_at" TIMESTAMP(3) NOT NULL,
31
+ "updated_at" TIMESTAMP(3) NOT NULL,
32
+ "exported_at" TIMESTAMP(3),
33
+
34
+ CONSTRAINT "articles_pkey" PRIMARY KEY ("id")
35
+ ) WITH (schema_locked = false);
36
+
37
+ -- CreateTable
38
+ CREATE TABLE "notes" (
39
+ "id" STRING(36) NOT NULL,
40
+ "title" STRING(64) NOT NULL,
41
+ "markdown" STRING NOT NULL,
42
+ "status" "Status" NOT NULL,
43
+ "user_id" STRING(128) NOT NULL,
44
+ "created_at" TIMESTAMP(3) NOT NULL,
45
+ "updated_at" TIMESTAMP(3) NOT NULL,
46
+ "exported_at" TIMESTAMP(3),
47
+
48
+ CONSTRAINT "notes_pkey" PRIMARY KEY ("id")
49
+ ) WITH (schema_locked = false);
50
+
51
+ -- CreateTable
52
+ CREATE TABLE "images" (
53
+ "id" STRING(36) NOT NULL,
54
+ "path" STRING(512) NOT NULL,
55
+ "content_type" STRING(32) NOT NULL,
56
+ "file_size" INT4,
57
+ "width" INT4,
58
+ "height" INT4,
59
+ "status" "Status" NOT NULL,
60
+ "user_id" STRING(128) NOT NULL,
61
+ "created_at" TIMESTAMP(3) NOT NULL,
62
+ "updated_at" TIMESTAMP(3) NOT NULL,
63
+ "exported_at" TIMESTAMP(3),
64
+
65
+ CONSTRAINT "images_pkey" PRIMARY KEY ("id")
66
+ ) WITH (schema_locked = false);
67
+
68
+ -- CreateTable
69
+ CREATE TABLE "books" (
70
+ "id" STRING(36) NOT NULL,
71
+ "isbn" STRING(17) NOT NULL,
72
+ "title" STRING(512) NOT NULL,
73
+ "google_subtitle" STRING(512),
74
+ "google_authors" STRING[],
75
+ "google_description" STRING,
76
+ "google_img_src" STRING(2048),
77
+ "google_href" STRING(2048),
78
+ "image_path" STRING(512),
79
+ "markdown" STRING,
80
+ "rating" INT4 NOT NULL,
81
+ "tags" STRING[],
82
+ "status" "Status" NOT NULL,
83
+ "user_id" STRING(128) NOT NULL,
84
+ "created_at" TIMESTAMP(3) NOT NULL,
85
+ "updated_at" TIMESTAMP(3) NOT NULL,
86
+ "exported_at" TIMESTAMP(3),
87
+
88
+ CONSTRAINT "books_pkey" PRIMARY KEY ("id")
89
+ ) WITH (schema_locked = false);
90
+
91
+ -- CreateIndex
92
+ CREATE UNIQUE INDEX "categories_name_user_id_key" ON "categories"("name", "user_id");
93
+
94
+ -- CreateIndex
95
+ CREATE UNIQUE INDEX "articles_url_user_id_key" ON "articles"("url", "user_id");
96
+
97
+ -- CreateIndex
98
+ CREATE UNIQUE INDEX "notes_title_user_id_key" ON "notes"("title", "user_id");
99
+
100
+ -- CreateIndex
101
+ CREATE UNIQUE INDEX "images_path_user_id_key" ON "images"("path", "user_id");
102
+
103
+ -- CreateIndex
104
+ CREATE UNIQUE INDEX "books_isbn_user_id_key" ON "books"("isbn", "user_id");
105
+
106
+ -- AddForeignKey
107
+ ALTER TABLE "articles" ADD CONSTRAINT "articles_category_id_fkey" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,69 @@
1
+ -- CreateTable
2
+ CREATE TABLE "user" (
3
+ "id" STRING(64) NOT NULL,
4
+ "name" STRING NOT NULL,
5
+ "email" STRING NOT NULL,
6
+ "email_verified" BOOL NOT NULL DEFAULT false,
7
+ "image" STRING,
8
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ "updated_at" TIMESTAMP(3) NOT NULL,
10
+
11
+ CONSTRAINT "user_pkey" PRIMARY KEY ("id")
12
+ ) WITH (schema_locked = false);
13
+
14
+ -- CreateTable
15
+ CREATE TABLE "session" (
16
+ "id" STRING(64) NOT NULL,
17
+ "expires_at" TIMESTAMP(3) NOT NULL,
18
+ "token" STRING NOT NULL,
19
+ "ip_address" STRING,
20
+ "user_agent" STRING,
21
+ "user_id" STRING(64) NOT NULL,
22
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
+ "updated_at" TIMESTAMP(3) NOT NULL,
24
+
25
+ CONSTRAINT "session_pkey" PRIMARY KEY ("id")
26
+ ) WITH (schema_locked = false);
27
+
28
+ -- CreateTable
29
+ CREATE TABLE "account" (
30
+ "id" STRING(64) NOT NULL,
31
+ "account_id" STRING(128) NOT NULL,
32
+ "provider_id" STRING(64) NOT NULL,
33
+ "user_id" STRING(64) NOT NULL,
34
+ "access_token" STRING,
35
+ "refresh_token" STRING,
36
+ "id_token" STRING,
37
+ "access_token_expires_at" TIMESTAMP(3),
38
+ "refresh_token_expires_at" TIMESTAMP(3),
39
+ "scope" STRING,
40
+ "password" STRING,
41
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
42
+ "updated_at" TIMESTAMP(3) NOT NULL,
43
+
44
+ CONSTRAINT "account_pkey" PRIMARY KEY ("id")
45
+ ) WITH (schema_locked = false);
46
+
47
+ -- CreateTable
48
+ CREATE TABLE "verification" (
49
+ "id" STRING(64) NOT NULL,
50
+ "identifier" STRING NOT NULL,
51
+ "value" STRING NOT NULL,
52
+ "expires_at" TIMESTAMP(3) NOT NULL,
53
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
54
+ "updated_at" TIMESTAMP(3) NOT NULL,
55
+
56
+ CONSTRAINT "verification_pkey" PRIMARY KEY ("id")
57
+ ) WITH (schema_locked = false);
58
+
59
+ -- CreateIndex
60
+ CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
61
+
62
+ -- CreateIndex
63
+ CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
64
+
65
+ -- AddForeignKey
66
+ ALTER TABLE "session" ADD CONSTRAINT "session_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
67
+
68
+ -- AddForeignKey
69
+ ALTER TABLE "account" ADD CONSTRAINT "account_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -1,3 +1,3 @@
1
1
  # Please do not edit this file manually
2
2
  # It should be added in your version-control system (e.g., Git)
3
- provider = "postgresql"
3
+ provider = "cockroachdb"
@@ -0,0 +1,98 @@
1
+ -- One-time userId remap after migrating from NextAuth (Auth0 sub) to Better Auth.
2
+ --
3
+ -- Context
4
+ -- -------
5
+ -- Before: every content row's `user_id` held the Auth0 `sub` (e.g. "auth0|abc").
6
+ -- After: Better Auth generates its own `user.id` and stores the Auth0 sub in
7
+ -- `account.account_id` (provider_id = 'auth0'). `getSelfId()` now returns
8
+ -- the Better Auth `user.id`, so existing content rows must be remapped
9
+ -- from the old sub to the new user.id to stay visible / tenant-scoped.
10
+ --
11
+ -- Prerequisites (run IN ORDER, before this script)
12
+ -- ------------------------------------------------
13
+ -- 1. `pnpm prisma:deploy` (creates user/session/account/verification tables).
14
+ -- 2. PROD ONLY: grant DML on the 4 new tables to the runtime user
15
+ -- `s-prod-runtime`, or the first sign-in fails with
16
+ -- `42501 user s-prod-runtime does not have INSERT privilege on relation verification`.
17
+ -- Run the GRANT (+ ALTER DEFAULT PRIVILEGES) from
18
+ -- docs/cockroachdb-role-minimization-runbook.md Step 2 in the Cloud Console.
19
+ -- (dev uses the all-privilege `s-dev` user, so this step is prod-only.)
20
+ -- 3. Log in ONCE through Better Auth (Auth0) so the user + account rows exist.
21
+ --
22
+ -- How to run — CockroachDB Cloud Console (no psql needed)
23
+ -- ------------------------------------------------------
24
+ -- Cloud Console -> your cluster -> "SQL Shell" tab. Make sure the correct
25
+ -- database is selected (top of the shell, or run `USE <database>;` first —
26
+ -- the same database as DATABASE_URL). Paste the STEP 2 block below and run.
27
+ -- Then paste STEP 3 to verify (every row count must be 0).
28
+ --
29
+ -- How to run — psql (alternative)
30
+ -- -------------------------------
31
+ -- psql "$DATABASE_URL" -f packages/database/prisma/remap-userids-better-auth.sql
32
+ --
33
+ -- Notes
34
+ -- -----
35
+ -- * Pure SQL (no psql meta-commands), so it pastes into the Cloud Console as-is.
36
+ -- * The five UPDATEs are independent and idempotent (no BEGIN/COMMIT needed):
37
+ -- once a row's user_id is the new id it no longer matches any account_id, so
38
+ -- re-running is safe and is a no-op.
39
+ -- * Run as raw SQL only. Do NOT route through the Prisma client: the tenant
40
+ -- extension (app/src/prisma.ts) rewrites updateMany to force the active
41
+ -- tenant's user_id, which would defeat the remap. Raw SQL bypasses it.
42
+ -- * The join through `account` (account_id = old sub -> user_id = new id) means
43
+ -- you never have to hardcode any id.
44
+
45
+ -- ===========================================================================
46
+ -- STEP 1 (optional pre-check): inspect the Auth0 account mapping.
47
+ -- Expect exactly one row for a single-user app: old_sub -> new_user_id.
48
+ -- ===========================================================================
49
+ SELECT provider_id, account_id AS old_sub, user_id AS new_user_id
50
+ FROM account
51
+ WHERE provider_id = 'auth0';
52
+
53
+ -- ===========================================================================
54
+ -- STEP 2: remap content rows from the old Auth0 sub to the new Better Auth id.
55
+ -- ===========================================================================
56
+ UPDATE articles a
57
+ SET user_id = acc.user_id
58
+ FROM account acc
59
+ WHERE acc.provider_id = 'auth0' AND a.user_id = acc.account_id;
60
+
61
+ UPDATE notes n
62
+ SET user_id = acc.user_id
63
+ FROM account acc
64
+ WHERE acc.provider_id = 'auth0' AND n.user_id = acc.account_id;
65
+
66
+ UPDATE images i
67
+ SET user_id = acc.user_id
68
+ FROM account acc
69
+ WHERE acc.provider_id = 'auth0' AND i.user_id = acc.account_id;
70
+
71
+ UPDATE books b
72
+ SET user_id = acc.user_id
73
+ FROM account acc
74
+ WHERE acc.provider_id = 'auth0' AND b.user_id = acc.account_id;
75
+
76
+ UPDATE categories c
77
+ SET user_id = acc.user_id
78
+ FROM account acc
79
+ WHERE acc.provider_id = 'auth0' AND c.user_id = acc.account_id;
80
+
81
+ -- ===========================================================================
82
+ -- STEP 3 (verification): every count MUST be 0 after STEP 2 (no row left on the
83
+ -- old sub). If any count is > 0, re-run STEP 2.
84
+ -- ===========================================================================
85
+ SELECT 'articles' AS tbl, count(*) AS rows_still_on_old_sub
86
+ FROM articles a JOIN account acc ON acc.provider_id = 'auth0' AND a.user_id = acc.account_id
87
+ UNION ALL
88
+ SELECT 'notes', count(*)
89
+ FROM notes n JOIN account acc ON acc.provider_id = 'auth0' AND n.user_id = acc.account_id
90
+ UNION ALL
91
+ SELECT 'images', count(*)
92
+ FROM images i JOIN account acc ON acc.provider_id = 'auth0' AND i.user_id = acc.account_id
93
+ UNION ALL
94
+ SELECT 'books', count(*)
95
+ FROM books b JOIN account acc ON acc.provider_id = 'auth0' AND b.user_id = acc.account_id
96
+ UNION ALL
97
+ SELECT 'categories', count(*)
98
+ FROM categories c JOIN account acc ON acc.provider_id = 'auth0' AND c.user_id = acc.account_id;
@@ -10,7 +10,7 @@ generator erd {
10
10
  }
11
11
 
12
12
  datasource db {
13
- provider = "postgresql"
13
+ provider = "cockroachdb"
14
14
  }
15
15
 
16
16
  enum Status {
@@ -20,38 +20,38 @@ enum Status {
20
20
  }
21
21
 
22
22
  model Category {
23
- id String @id @db.VarChar(36)
23
+ id String @id @db.String(36)
24
24
 
25
- name String @db.VarChar(16)
25
+ name String @db.String(16)
26
26
 
27
27
  Articles Article[]
28
28
 
29
29
  createdAt DateTime @map("created_at")
30
30
  updatedAt DateTime @updatedAt @map("updated_at")
31
31
 
32
- userId String @map("user_id") @db.VarChar(128)
32
+ userId String @map("user_id") @db.String(128)
33
33
 
34
34
  @@unique([name, userId])
35
35
  @@map("categories")
36
36
  }
37
37
 
38
38
  model Article {
39
- id String @id @db.VarChar(36)
39
+ id String @id @db.String(36)
40
40
 
41
- title String @db.VarChar(128)
42
- url String @db.VarChar(2048)
43
- quote String? @db.VarChar(512)
41
+ title String @db.String(128)
42
+ url String @db.String(2048)
43
+ quote String? @db.String(512)
44
44
 
45
- ogImageUrl String? @map("og_image_url") @db.VarChar(4096)
46
- ogTitle String? @map("og_title") @db.VarChar(512)
47
- ogDescription String? @map("og_description") @db.VarChar(1024)
45
+ ogImageUrl String? @map("og_image_url") @db.String(4096)
46
+ ogTitle String? @map("og_title") @db.String(512)
47
+ ogDescription String? @map("og_description") @db.String(1024)
48
48
 
49
49
  Category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade, onUpdate: Cascade)
50
- categoryId String @map("category_id") @db.VarChar(36)
50
+ categoryId String @map("category_id") @db.String(36)
51
51
 
52
52
  status Status
53
53
 
54
- userId String @map("user_id") @db.VarChar(128)
54
+ userId String @map("user_id") @db.String(128)
55
55
 
56
56
  createdAt DateTime @map("created_at")
57
57
  updatedAt DateTime @updatedAt @map("updated_at")
@@ -62,14 +62,14 @@ model Article {
62
62
  }
63
63
 
64
64
  model Note {
65
- id String @id @db.VarChar(36)
65
+ id String @id @db.String(36)
66
66
 
67
- title String @db.VarChar(64)
68
- markdown String @db.Text
67
+ title String @db.String(64)
68
+ markdown String @db.String
69
69
 
70
70
  status Status
71
71
 
72
- userId String @map("user_id") @db.VarChar(128)
72
+ userId String @map("user_id") @db.String(128)
73
73
 
74
74
  createdAt DateTime @map("created_at")
75
75
  updatedAt DateTime @updatedAt @map("updated_at")
@@ -80,17 +80,17 @@ model Note {
80
80
  }
81
81
 
82
82
  model Image {
83
- id String @id @db.VarChar(36)
83
+ id String @id @db.String(36)
84
84
 
85
- path String @db.VarChar(512)
86
- contentType String @map("content_type") @db.VarChar(32) // e.g.: image/jpeg, image/png
85
+ path String @db.String(512)
86
+ contentType String @map("content_type") @db.String(32) // e.g.: image/jpeg, image/png
87
87
  fileSize Int? @map("file_size") // byte
88
88
  width Int? // pixel
89
89
  height Int? // pixel
90
90
 
91
91
  status Status
92
92
 
93
- userId String @map("user_id") @db.VarChar(128)
93
+ userId String @map("user_id") @db.String(128)
94
94
 
95
95
  createdAt DateTime @map("created_at")
96
96
  updatedAt DateTime @updatedAt @map("updated_at")
@@ -101,26 +101,26 @@ model Image {
101
101
  }
102
102
 
103
103
  model Book {
104
- id String @id @db.VarChar(36)
105
- isbn String @db.VarChar(17)
106
- title String @db.VarChar(512)
104
+ id String @id @db.String(36)
105
+ isbn String @db.String(17)
106
+ title String @db.String(512)
107
107
 
108
- googleSubTitle String? @map("google_subtitle") @db.VarChar(512)
108
+ googleSubTitle String? @map("google_subtitle") @db.String(512)
109
109
  googleAuthors String[] @map("google_authors")
110
- googleDescription String? @map("google_description") @db.Text
111
- googleImgSrc String? @map("google_img_src") @db.VarChar(2048)
112
- googleHref String? @map("google_href") @db.VarChar(2048)
110
+ googleDescription String? @map("google_description") @db.String
111
+ googleImgSrc String? @map("google_img_src") @db.String(2048)
112
+ googleHref String? @map("google_href") @db.String(2048)
113
113
 
114
- imagePath String? @map("image_path") @db.VarChar(512)
114
+ imagePath String? @map("image_path") @db.String(512)
115
115
 
116
- markdown String? @db.Text
116
+ markdown String? @db.String
117
117
 
118
118
  rating Int // 1-5
119
119
  tags String[]
120
120
 
121
121
  status Status
122
122
 
123
- userId String @map("user_id") @db.VarChar(128)
123
+ userId String @map("user_id") @db.String(128)
124
124
 
125
125
  createdAt DateTime @map("created_at")
126
126
  updatedAt DateTime @updatedAt @map("updated_at")
@@ -129,3 +129,84 @@ model Book {
129
129
  @@unique([isbn, userId])
130
130
  @@map("books")
131
131
  }
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Better Auth tables (user / session / account / verification).
135
+ //
136
+ // Managed entirely by Better Auth via @better-auth/prisma-adapter. These are
137
+ // intentionally NOT registered in the Prisma tenant extension whitelist
138
+ // (app/src/prisma.ts), so tenant filtering never touches them. createdAt has a
139
+ // DB default and emailVerified defaults to false as a safety net for the
140
+ // library-managed write paths (unlike the domain models, which set timestamps
141
+ // explicitly in domain logic).
142
+ // ---------------------------------------------------------------------------
143
+
144
+ model User {
145
+ id String @id @db.String(64)
146
+
147
+ name String @db.String
148
+ email String @unique @db.String
149
+ emailVerified Boolean @default(false) @map("email_verified")
150
+ image String? @db.String
151
+
152
+ Sessions Session[]
153
+ Accounts Account[]
154
+
155
+ createdAt DateTime @default(now()) @map("created_at")
156
+ updatedAt DateTime @updatedAt @map("updated_at")
157
+
158
+ @@map("user")
159
+ }
160
+
161
+ model Session {
162
+ id String @id @db.String(64)
163
+
164
+ expiresAt DateTime @map("expires_at")
165
+ token String @unique @db.String
166
+ ipAddress String? @map("ip_address") @db.String
167
+ userAgent String? @map("user_agent") @db.String
168
+
169
+ User User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
170
+ userId String @map("user_id") @db.String(64)
171
+
172
+ createdAt DateTime @default(now()) @map("created_at")
173
+ updatedAt DateTime @updatedAt @map("updated_at")
174
+
175
+ @@map("session")
176
+ }
177
+
178
+ model Account {
179
+ id String @id @db.String(64)
180
+
181
+ accountId String @map("account_id") @db.String(128)
182
+ providerId String @map("provider_id") @db.String(64)
183
+
184
+ User User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
185
+ userId String @map("user_id") @db.String(64)
186
+
187
+ accessToken String? @map("access_token") @db.String
188
+ refreshToken String? @map("refresh_token") @db.String
189
+ idToken String? @map("id_token") @db.String
190
+ accessTokenExpiresAt DateTime? @map("access_token_expires_at")
191
+ refreshTokenExpiresAt DateTime? @map("refresh_token_expires_at")
192
+ scope String? @db.String
193
+ password String? @db.String
194
+
195
+ createdAt DateTime @default(now()) @map("created_at")
196
+ updatedAt DateTime @updatedAt @map("updated_at")
197
+
198
+ @@map("account")
199
+ }
200
+
201
+ model Verification {
202
+ id String @id @db.String(64)
203
+
204
+ identifier String @db.String
205
+ value String @db.String
206
+ expiresAt DateTime @map("expires_at")
207
+
208
+ createdAt DateTime @default(now()) @map("created_at")
209
+ updatedAt DateTime @updatedAt @map("updated_at")
210
+
211
+ @@map("verification")
212
+ }