From 0bbaa6e3d8f066a9c5ad1f8ec9d0de679607cdb3 Mon Sep 17 00:00:00 2001 From: emil Date: Fri, 15 May 2026 21:48:09 +0300 Subject: [PATCH] =?UTF-8?q?feat(dm-dashboard):=20Wave=202=20=E2=80=94=20Dr?= =?UTF-8?q?izzle=20migration,=20DmSidebar=20fix,=20CORS=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .sisyphus/boulder.json | 16 +- .../notepads/dm-dashboard-ai/learnings.md | 87 +++ drizzle/0001_curved_black_panther.down.sql | 15 + drizzle/0001_curved_black_panther.sql | 58 ++ drizzle/meta/0001_snapshot.json | 535 ++++++++++++++++++ drizzle/meta/_journal.json | 7 + src/components/dm/DmSidebar.astro | 20 +- src/env.d.ts | 1 + src/i18n/dm-translations.ts | 2 + src/lib/cors.ts | 59 ++ src/middleware/index.ts | 5 +- src/pages/api/dm/health.ts | 14 + src/pages/dm/index.astro | 2 +- test-results/.last-run.json | 4 - .../14822f9a45c88c055549b161d4dad443.png | Bin 0 -> 82845 bytes .../bcb32270aa43080d121faed0203abb46.png | Bin 0 -> 62336 bytes .../672c116720edabb1a8b3c001ec123a46.png | Bin 0 -> 83610 bytes .../0766df62cc91f661be548b8ed1e68c2b.png | Bin 0 -> 74972 bytes .../631aa30ee194299d66130babfdabe2e0.png | Bin 0 -> 79658 bytes .../673c192a98b4fa0cd88cd954b7e0ac87.png | Bin 0 -> 66857 bytes .../5170e3a60759410b49fc8eec78dd0f7d.png | Bin 0 -> 50440 bytes .../f899af6b6a21190e051e7cedb1cfbe87.png | Bin 0 -> 72850 bytes .../0d3d6742ba1593f2ada062667fc16a84.png | Bin 0 -> 48657 bytes .../8b4e2b984c2e0fe9df7a090deb13e9c6.png | Bin 0 -> 79303 bytes .../044720f20b21363d19e0d884396eefbd.png | Bin 0 -> 59600 bytes .../2856348d96250f72457a4caf2c9edd47.png | Bin 0 -> 84772 bytes .../error-context.md | 32 ++ .../error-context.md | 91 +++ .../error-context.md | 39 ++ .../error-context.md | 23 + .../error-context.md | 23 + .../error-context.md | 23 + .../error-context.md | 60 ++ .../error-context.md | 29 + tests/cors.test.ts | 117 ++++ tests/dm/sidebar.spec.ts | 50 ++ 36 files changed, 1294 insertions(+), 18 deletions(-) create mode 100644 drizzle/0001_curved_black_panther.down.sql create mode 100644 drizzle/0001_curved_black_panther.sql create mode 100644 drizzle/meta/0001_snapshot.json create mode 100644 src/lib/cors.ts create mode 100644 src/pages/api/dm/health.ts delete mode 100644 test-results/.last-run.json create mode 100644 test-results/.playwright-artifacts-0/14822f9a45c88c055549b161d4dad443.png create mode 100644 test-results/.playwright-artifacts-1/bcb32270aa43080d121faed0203abb46.png create mode 100644 test-results/.playwright-artifacts-2/672c116720edabb1a8b3c001ec123a46.png create mode 100644 test-results/.playwright-artifacts-3/0766df62cc91f661be548b8ed1e68c2b.png create mode 100644 test-results/.playwright-artifacts-4/631aa30ee194299d66130babfdabe2e0.png create mode 100644 test-results/.playwright-artifacts-4/673c192a98b4fa0cd88cd954b7e0ac87.png create mode 100644 test-results/.playwright-artifacts-5/5170e3a60759410b49fc8eec78dd0f7d.png create mode 100644 test-results/.playwright-artifacts-5/f899af6b6a21190e051e7cedb1cfbe87.png create mode 100644 test-results/.playwright-artifacts-6/0d3d6742ba1593f2ada062667fc16a84.png create mode 100644 test-results/.playwright-artifacts-6/8b4e2b984c2e0fe9df7a090deb13e9c6.png create mode 100644 test-results/.playwright-artifacts-7/044720f20b21363d19e0d884396eefbd.png create mode 100644 test-results/.playwright-artifacts-7/2856348d96250f72457a4caf2c9edd47.png create mode 100644 test-results/dm-initiative-Initiative-T-0efed-rt-by-initiative-descending-chromium/error-context.md create mode 100644 test-results/dm-initiative-Initiative-T-9c1f7-urn-cycles-active-combatant-chromium/error-context.md create mode 100644 test-results/dm-notes-Notes-Panel-auto-save-indicator-appears-chromium/error-context.md create mode 100644 test-results/dm-notes-Notes-Panel-character-counter-updates-chromium/error-context.md create mode 100644 test-results/dm-notes-Notes-Panel-clear-button-empties-notes-chromium/error-context.md create mode 100644 test-results/dm-notes-Notes-Panel-mobile-viewport-renders-correctly-chromium/error-context.md create mode 100644 test-results/dm-notes-Notes-Panel-typing-in-textarea-works-chromium/error-context.md create mode 100644 test-results/dm-reference-Open5e-Reference-tab-switching-works-chromium/error-context.md create mode 100644 tests/cors.test.ts create mode 100644 tests/dm/sidebar.spec.ts diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json index 3ffa0d8..8a1663e 100644 --- a/.sisyphus/boulder.json +++ b/.sisyphus/boulder.json @@ -394,7 +394,7 @@ "plan_name": "dm-dashboard-ai", "status": "active", "started_at": "2026-05-15T17:58:09.859Z", - "updated_at": "2026-05-15T18:24:29.818Z", + "updated_at": "2026-05-15T18:36:00.096Z", "session_ids": [ "ses_1d3921469ffeQox08ZjNWWJq7u" ], @@ -407,12 +407,12 @@ "task_key": "final-wave:f1", "task_label": "F1", "task_title": "**Plan Compliance Audit** — `oracle`", - "session_id": "ses_1d333a383ffeOqEVZptN3EbGAY", + "session_id": "ses_1d31971f9ffedffglMh0qVc3Mi", "agent": "Sisyphus-Junior", "category": "quick", - "updated_at": "2026-05-15T18:24:29.818Z", "started_at": "2026-05-15T18:24:29.818Z", - "status": "running" + "status": "running", + "updated_at": "2026-05-15T18:36:00.097Z" } } } @@ -420,7 +420,7 @@ "active_plan": "/home/emil/Desktop/Coding/AI/Randify.pro/.sisyphus/plans/dm-dashboard-ai.md", "started_at": "2026-05-15T17:58:09.859Z", "status": "active", - "updated_at": "2026-05-15T18:24:29.818Z", + "updated_at": "2026-05-15T18:36:00.096Z", "session_ids": [ "ses_1d3921469ffeQox08ZjNWWJq7u" ], @@ -433,12 +433,12 @@ "task_key": "final-wave:f1", "task_label": "F1", "task_title": "**Plan Compliance Audit** — `oracle`", - "session_id": "ses_1d333a383ffeOqEVZptN3EbGAY", + "session_id": "ses_1d31971f9ffedffglMh0qVc3Mi", "agent": "Sisyphus-Junior", "category": "quick", - "updated_at": "2026-05-15T18:24:29.818Z", "started_at": "2026-05-15T18:24:29.818Z", - "status": "running" + "status": "running", + "updated_at": "2026-05-15T18:36:00.097Z" } }, "agent": "atlas" diff --git a/.sisyphus/notepads/dm-dashboard-ai/learnings.md b/.sisyphus/notepads/dm-dashboard-ai/learnings.md index dab4cfa..a540da2 100644 --- a/.sisyphus/notepads/dm-dashboard-ai/learnings.md +++ b/.sisyphus/notepads/dm-dashboard-ai/learnings.md @@ -43,3 +43,90 @@ - `npx tsc --noEmit`: 0 errors - `npx vitest run src/lib/auth/`: 18/18 tests passed + +--- + +# CORS Configuration for DM API Routes — Learnings + +## Date: 2026-05-15 + +### Patterns Applied + +1. **Reusable CORS utility (`src/lib/cors.ts`)** + - Created `getCorsHeaders()`, `createCorsResponse()`, `handleCorsPreflight()`, and `jsonResponse()` helpers. + - Allowed origins are validated by hostname using `URL` parsing: `randify.pro`, `dm.randify.pro`, `localhost:4321`. + - Disallowed origins receive an empty `Access-Control-Allow-Origin` header (no wildcard). + - `Vary: Origin` header is included to prevent CDN caching issues with CORS. + +2. **DM API route pattern (`src/pages/api/dm/health.ts`)** + - New DM API routes should import helpers from `@/lib/cors`. + - Every route must export an `OPTIONS` handler that calls `handleCorsPreflight(origin)`. + - Every response should be created via `jsonResponse()` or `createCorsResponse()` to ensure CORS headers are present. + - `export const prerender = false` is required for API routes. + +3. **Allowed origins** + - `https://randify.pro` + - `https://dm.randify.pro` + - `http://localhost:4321` + - Any protocol is accepted as long as the hostname matches. + +4. **happy-dom `Request` limitation** + - `new Request(url, { headers: { origin: '...' } })` strips the `origin` header in happy-dom (vitest environment). + - Tests that call Astro API routes must construct a mock request object with a custom `headers.get()` method instead of relying on the global `Request` class for origin propagation. + - Example pattern in `tests/cors.test.ts` (`mockRequest` helper). + +### Verification + +- `npx vitest run tests/cors.test.ts`: 12/12 passed +- `npx vitest run` (full suite): 218/218 passed + +--- + +# Drizzle Migration Generation — Learnings + +## Date: 2026-05-15 + +### Context + +Task: Generate and apply Drizzle migration for updated DB schema (Task 2 completed). + +### What Was Done + +1. **Generated migration via `drizzle-kit generate`** + - Command: `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/randify npx drizzle-kit generate` + - Generated file: `drizzle/0001_curved_black_panther.sql` + - Journal updated: `drizzle/meta/_journal.json` + +2. **Reviewed generated SQL for correctness** + - New tables created: `npcs`, `generation_counters`, `translations`, `notes`, `initiative_sessions` + - Existing table altered: `users` — added `tier` (varchar(20), default 'free') and `boosty_verified_at` (timestamp) + - All FK constraints use `ON DELETE cascade` as specified in schema + - Indexes match schema definitions: + - `generation_counters_user_window_model_idx` (unique) + - `translations_slug_type_language_idx` + - CHECK constraint added: `users_tier_check` enforcing `('free', 'pro')` + - `translations.slug` correctly marked as `UNIQUE` + +3. **Verified migration applies cleanly** + - Command: `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/randify npm run db:migrate` + - Result: Migrations completed successfully (exit 0) + - Verified tables in DB: 7 tables present (`users`, `sessions`, `npcs`, `generation_counters`, `translations`, `notes`, `initiative_sessions`) + +4. **Created down migration for reversibility** + - File: `drizzle/0001_curved_black_panther.down.sql` + - Operations: drop new tables, remove added columns/constraints from `users` + - Tested down migration against local DB: executed cleanly + - Re-applied up migration after test to restore expected state + +### Key Findings + +- **`.env` DATABASE_URL mismatch**: `.env` points to `dmuser:dmpass@localhost:5432/dmdashboard`, but the docker-compose PostgreSQL uses `postgres:postgres@localhost:5432/randify`. For DB commands to work locally, `DATABASE_URL` must be overridden inline or `.env` must be updated. +- **Drizzle-kit does not auto-generate `.down.sql` files**. Reversibility must be handled manually. The down migration should drop tables in reverse dependency order and remove columns after dropping their constraints. +- **Testing down migrations**: After testing a down migration, reset `drizzle.__drizzle_migrations` and re-run the official `db:migrate` script rather than applying raw SQL, to keep Drizzle's internal tracking consistent. + +### Verification + +- `npm run db:migrate` with correct `DATABASE_URL`: exit 0 +- `\dt` in `randify` DB: 7 tables confirmed +- Down migration tested manually: all statements executed without error + diff --git a/drizzle/0001_curved_black_panther.down.sql b/drizzle/0001_curved_black_panther.down.sql new file mode 100644 index 0000000..9ab02ee --- /dev/null +++ b/drizzle/0001_curved_black_panther.down.sql @@ -0,0 +1,15 @@ +ALTER TABLE "users" DROP CONSTRAINT "users_tier_check"; +--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "tier"; +--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "boosty_verified_at"; +--> statement-breakpoint +DROP TABLE "translations"; +--> statement-breakpoint +DROP TABLE "npcs"; +--> statement-breakpoint +DROP TABLE "notes"; +--> statement-breakpoint +DROP TABLE "initiative_sessions"; +--> statement-breakpoint +DROP TABLE "generation_counters"; \ No newline at end of file diff --git a/drizzle/0001_curved_black_panther.sql b/drizzle/0001_curved_black_panther.sql new file mode 100644 index 0000000..4cdb3c9 --- /dev/null +++ b/drizzle/0001_curved_black_panther.sql @@ -0,0 +1,58 @@ +CREATE TABLE "generation_counters" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "hour_window" timestamp NOT NULL, + "count" integer NOT NULL, + "model" varchar(50) NOT NULL +); +--> statement-breakpoint +CREATE TABLE "initiative_sessions" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "name" varchar(255) NOT NULL, + "participants" jsonb, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "notes" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "title" varchar(255) NOT NULL, + "content" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "npcs" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "name" varchar(255) NOT NULL, + "race" varchar(100), + "role" varchar(100), + "level" integer, + "tone" varchar(100), + "content" jsonb, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "translations" ( + "id" serial PRIMARY KEY NOT NULL, + "slug" varchar(255) NOT NULL, + "type" varchar(100) NOT NULL, + "language" varchar(10) DEFAULT 'ru' NOT NULL, + "content" jsonb, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "translations_slug_unique" UNIQUE("slug") +); +--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "tier" varchar(20) DEFAULT 'free';--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "boosty_verified_at" timestamp;--> statement-breakpoint +ALTER TABLE "generation_counters" ADD CONSTRAINT "generation_counters_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "initiative_sessions" ADD CONSTRAINT "initiative_sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "notes" ADD CONSTRAINT "notes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "npcs" ADD CONSTRAINT "npcs_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE UNIQUE INDEX "generation_counters_user_window_model_idx" ON "generation_counters" USING btree ("user_id","hour_window","model");--> statement-breakpoint +CREATE INDEX "translations_slug_type_language_idx" ON "translations" USING btree ("slug","type","language");--> statement-breakpoint +ALTER TABLE "users" ADD CONSTRAINT "users_tier_check" CHECK ("users"."tier" IN ('free', 'pro')); \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..fffb228 --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,535 @@ +{ + "id": "5a462f3f-9903-44f9-bc9c-58038e24e590", + "prevId": "993d57f2-7253-4ab4-b631-ab26ff2b9356", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.generation_counters": { + "name": "generation_counters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "hour_window": { + "name": "hour_window", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "generation_counters_user_window_model_idx": { + "name": "generation_counters_user_window_model_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "hour_window", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "generation_counters_user_id_users_id_fk": { + "name": "generation_counters_user_id_users_id_fk", + "tableFrom": "generation_counters", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.initiative_sessions": { + "name": "initiative_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "participants": { + "name": "participants", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "initiative_sessions_user_id_users_id_fk": { + "name": "initiative_sessions_user_id_users_id_fk", + "tableFrom": "initiative_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notes": { + "name": "notes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "notes_user_id_users_id_fk": { + "name": "notes_user_id_users_id_fk", + "tableFrom": "notes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.npcs": { + "name": "npcs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "race": { + "name": "race", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "tone": { + "name": "tone", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "npcs_user_id_users_id_fk": { + "name": "npcs_user_id_users_id_fk", + "tableFrom": "npcs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.translations": { + "name": "translations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "language": { + "name": "language", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "default": "'ru'" + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "translations_slug_type_language_idx": { + "name": "translations_slug_type_language_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "language", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "translations_slug_unique": { + "name": "translations_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "vk_id": { + "name": "vk_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "yandex_id": { + "name": "yandex_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "avatar": { + "name": "avatar", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + }, + "tier": { + "name": "tier", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'free'" + }, + "boosty_verified_at": { + "name": "boosty_verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "users_tier_check": { + "name": "users_tier_check", + "value": "\"users\".\"tier\" IN ('free', 'pro')" + } + }, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index ce3e4e2..adb438e 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1778781758609, "tag": "0000_short_warpath", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1778869902855, + "tag": "0001_curved_black_panther", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/components/dm/DmSidebar.astro b/src/components/dm/DmSidebar.astro index 2b271fd..0762c68 100644 --- a/src/components/dm/DmSidebar.astro +++ b/src/components/dm/DmSidebar.astro @@ -5,6 +5,7 @@ export interface Props { user?: { name?: string; avatar?: string; + tier?: 'free' | 'pro'; } | null; } @@ -14,7 +15,7 @@ const { user } = Astro.props;