diff --git a/.caddy-label b/.caddy-label new file mode 100644 index 0000000..e7576e3 --- /dev/null +++ b/.caddy-label @@ -0,0 +1,14 @@ +# Primary (www) domain with reverse proxy +caddy_0=https://www.techdiary.dev +caddy_0.handle_path=/* +caddy_0.handle_path.0_reverse_proxy={{upstreams 3000}} +caddy_0.encode=zstd gzip +caddy_0.try_files={path} /index.html /index.php +caddy_0.header=-Server + +# Redirect non-www to www +caddy_1=https://techdiary.dev +caddy_1.redir=https://www.techdiary.dev{uri} + +# Set Docker network for Caddy to access the app +caddy_ingress_network=coolify \ No newline at end of file diff --git a/.gitignore b/.gitignore index f31f6d9..1a632ba 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /.pnp .pnp.js yarn.lock +pnpm-lock.yaml .yarn/cache bun.lockb .yarn/install-state.gz @@ -37,3 +38,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +.vscode/mcp.json \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..725be5a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Next.js: debug server-side", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev", + "skipFiles": ["/**"], + "serverReadyAction": { + "pattern": "started server on .+, url: (https?://.+)", + "uriFormat": "%s", + "action": "openExternally" + } + }, + { + "name": "Next.js: debug client-side", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}" + }, + { + "name": "Next.js: debug full stack", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev", + "serverReadyAction": { + "pattern": "started server on .+, url: (https?://.+)", + "uriFormat": "%s", + "action": "debugWithChrome" + } + } + ] +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index b586b2c..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/migrations/0025_reflective_masque.sql b/migrations/0025_reflective_masque.sql new file mode 100644 index 0000000..2244eb4 --- /dev/null +++ b/migrations/0025_reflective_masque.sql @@ -0,0 +1,23 @@ +CREATE TABLE "series_items" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "series_id" uuid NOT NULL, + "type" varchar NOT NULL, + "title" varchar, + "article_id" uuid, + "index" integer DEFAULT 0 NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +CREATE TABLE "series" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "title" varchar NOT NULL, + "cover_image" jsonb, + "owner_id" uuid NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "series_items" ADD CONSTRAINT "series_items_series_id_series_id_fk" FOREIGN KEY ("series_id") REFERENCES "public"."series"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "series_items" ADD CONSTRAINT "series_items_article_id_articles_id_fk" FOREIGN KEY ("article_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "series" ADD CONSTRAINT "series_owner_id_users_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/migrations/0026_pink_selene.sql b/migrations/0026_pink_selene.sql new file mode 100644 index 0000000..2129890 --- /dev/null +++ b/migrations/0026_pink_selene.sql @@ -0,0 +1 @@ +ALTER TABLE "series" ADD COLUMN "handle" varchar NOT NULL; \ No newline at end of file diff --git a/migrations/0027_small_yellow_claw.sql b/migrations/0027_small_yellow_claw.sql new file mode 100644 index 0000000..ac8da34 --- /dev/null +++ b/migrations/0027_small_yellow_claw.sql @@ -0,0 +1 @@ +ALTER TABLE "series" ALTER COLUMN "handle" DROP NOT NULL; \ No newline at end of file diff --git a/migrations/0028_redundant_landau.sql b/migrations/0028_redundant_landau.sql new file mode 100644 index 0000000..a910e91 --- /dev/null +++ b/migrations/0028_redundant_landau.sql @@ -0,0 +1,2 @@ +ALTER TABLE "user_socials" ALTER COLUMN "id" SET DATA TYPE uuid;--> statement-breakpoint +ALTER TABLE "user_socials" ALTER COLUMN "id" SET DEFAULT gen_random_uuid(); \ No newline at end of file diff --git a/migrations/0029_blushing_roland_deschain.sql b/migrations/0029_blushing_roland_deschain.sql new file mode 100644 index 0000000..bed12b1 --- /dev/null +++ b/migrations/0029_blushing_roland_deschain.sql @@ -0,0 +1,2 @@ +ALTER TABLE "user_follows" ALTER COLUMN "id" SET DATA TYPE uuid;--> statement-breakpoint +ALTER TABLE "user_follows" ALTER COLUMN "id" SET DEFAULT gen_random_uuid(); \ No newline at end of file diff --git a/migrations/meta/0025_snapshot.json b/migrations/meta/0025_snapshot.json new file mode 100644 index 0000000..80757cd --- /dev/null +++ b/migrations/meta/0025_snapshot.json @@ -0,0 +1,810 @@ +{ + "id": "a2fe20d0-ec12-43aa-8971-fbd5df25d3c7", + "prevId": "9cfc84e0-3085-4499-906f-81b5dd9f1a35", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.article_tag": { + "name": "article_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "article_tag_article_id_articles_id_fk": { + "name": "article_tag_article_id_articles_id_fk", + "tableFrom": "article_tag", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "article_tag_tag_id_tags_id_fk": { + "name": "article_tag_tag_id_tags_id_fk", + "tableFrom": "article_tag", + "tableTo": "tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "commentable_type": { + "name": "commentable_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "commentable_id": { + "name": "commentable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_parent_id_comments_id_fk": { + "name": "comments_parent_id_comments_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series_items": { + "name": "series_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_items_series_id_series_id_fk": { + "name": "series_items_series_id_series_id_fk", + "tableFrom": "series_items", + "tableTo": "series", + "columnsFrom": [ + "series_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "series_items_article_id_articles_id_fk": { + "name": "series_items_article_id_articles_id_fk", + "tableFrom": "series_items", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series": { + "name": "series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_owner_id_users_id_fk": { + "name": "series_owner_id_users_id_fk", + "tableFrom": "series", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "varchar(6)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_follows": { + "name": "user_follows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "followee_id": { + "name": "followee_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_follows_follower_id_users_id_fk": { + "name": "user_follows_follower_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_follows_followee_id_users_id_fk": { + "name": "user_follows_followee_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "followee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_action_at": { + "name": "last_action_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_socials": { + "name": "user_socials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "service": { + "name": "service", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "service_uid": { + "name": "service_uid", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_socials_user_id_users_id_fk": { + "name": "user_socials_user_id_users_id_fk", + "tableFrom": "user_socials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "profile_photo": { + "name": "profile_photo", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "education": { + "name": "education", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "designation": { + "name": "designation", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "profile_readme": { + "name": "profile_readme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "skills": { + "name": "skills", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0026_snapshot.json b/migrations/meta/0026_snapshot.json new file mode 100644 index 0000000..04ca354 --- /dev/null +++ b/migrations/meta/0026_snapshot.json @@ -0,0 +1,816 @@ +{ + "id": "f9898263-c4dd-48dc-b33d-cdd0eb7631cb", + "prevId": "a2fe20d0-ec12-43aa-8971-fbd5df25d3c7", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.article_tag": { + "name": "article_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "article_tag_article_id_articles_id_fk": { + "name": "article_tag_article_id_articles_id_fk", + "tableFrom": "article_tag", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "article_tag_tag_id_tags_id_fk": { + "name": "article_tag_tag_id_tags_id_fk", + "tableFrom": "article_tag", + "tableTo": "tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "commentable_type": { + "name": "commentable_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "commentable_id": { + "name": "commentable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_parent_id_comments_id_fk": { + "name": "comments_parent_id_comments_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series_items": { + "name": "series_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_items_series_id_series_id_fk": { + "name": "series_items_series_id_series_id_fk", + "tableFrom": "series_items", + "tableTo": "series", + "columnsFrom": [ + "series_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "series_items_article_id_articles_id_fk": { + "name": "series_items_article_id_articles_id_fk", + "tableFrom": "series_items", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series": { + "name": "series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_owner_id_users_id_fk": { + "name": "series_owner_id_users_id_fk", + "tableFrom": "series", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "varchar(6)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_follows": { + "name": "user_follows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "followee_id": { + "name": "followee_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_follows_follower_id_users_id_fk": { + "name": "user_follows_follower_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_follows_followee_id_users_id_fk": { + "name": "user_follows_followee_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "followee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_action_at": { + "name": "last_action_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_socials": { + "name": "user_socials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "service": { + "name": "service", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "service_uid": { + "name": "service_uid", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_socials_user_id_users_id_fk": { + "name": "user_socials_user_id_users_id_fk", + "tableFrom": "user_socials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "profile_photo": { + "name": "profile_photo", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "education": { + "name": "education", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "designation": { + "name": "designation", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "profile_readme": { + "name": "profile_readme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "skills": { + "name": "skills", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0027_snapshot.json b/migrations/meta/0027_snapshot.json new file mode 100644 index 0000000..08612ff --- /dev/null +++ b/migrations/meta/0027_snapshot.json @@ -0,0 +1,816 @@ +{ + "id": "ceec444b-e45d-4ede-986b-d72a60a77b1b", + "prevId": "f9898263-c4dd-48dc-b33d-cdd0eb7631cb", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.article_tag": { + "name": "article_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "article_tag_article_id_articles_id_fk": { + "name": "article_tag_article_id_articles_id_fk", + "tableFrom": "article_tag", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "article_tag_tag_id_tags_id_fk": { + "name": "article_tag_tag_id_tags_id_fk", + "tableFrom": "article_tag", + "tableTo": "tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "commentable_type": { + "name": "commentable_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "commentable_id": { + "name": "commentable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_parent_id_comments_id_fk": { + "name": "comments_parent_id_comments_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series_items": { + "name": "series_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_items_series_id_series_id_fk": { + "name": "series_items_series_id_series_id_fk", + "tableFrom": "series_items", + "tableTo": "series", + "columnsFrom": [ + "series_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "series_items_article_id_articles_id_fk": { + "name": "series_items_article_id_articles_id_fk", + "tableFrom": "series_items", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series": { + "name": "series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_owner_id_users_id_fk": { + "name": "series_owner_id_users_id_fk", + "tableFrom": "series", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "varchar(6)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_follows": { + "name": "user_follows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "followee_id": { + "name": "followee_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_follows_follower_id_users_id_fk": { + "name": "user_follows_follower_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_follows_followee_id_users_id_fk": { + "name": "user_follows_followee_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "followee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_action_at": { + "name": "last_action_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_socials": { + "name": "user_socials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "service": { + "name": "service", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "service_uid": { + "name": "service_uid", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_socials_user_id_users_id_fk": { + "name": "user_socials_user_id_users_id_fk", + "tableFrom": "user_socials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "profile_photo": { + "name": "profile_photo", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "education": { + "name": "education", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "designation": { + "name": "designation", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "profile_readme": { + "name": "profile_readme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "skills": { + "name": "skills", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0028_snapshot.json b/migrations/meta/0028_snapshot.json new file mode 100644 index 0000000..0075ffa --- /dev/null +++ b/migrations/meta/0028_snapshot.json @@ -0,0 +1,817 @@ +{ + "id": "d8d27f76-1a27-4e41-9282-f56786e5aa9f", + "prevId": "ceec444b-e45d-4ede-986b-d72a60a77b1b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.article_tag": { + "name": "article_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "article_tag_article_id_articles_id_fk": { + "name": "article_tag_article_id_articles_id_fk", + "tableFrom": "article_tag", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "article_tag_tag_id_tags_id_fk": { + "name": "article_tag_tag_id_tags_id_fk", + "tableFrom": "article_tag", + "tableTo": "tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "commentable_type": { + "name": "commentable_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "commentable_id": { + "name": "commentable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_parent_id_comments_id_fk": { + "name": "comments_parent_id_comments_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series_items": { + "name": "series_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_items_series_id_series_id_fk": { + "name": "series_items_series_id_series_id_fk", + "tableFrom": "series_items", + "tableTo": "series", + "columnsFrom": [ + "series_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "series_items_article_id_articles_id_fk": { + "name": "series_items_article_id_articles_id_fk", + "tableFrom": "series_items", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series": { + "name": "series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_owner_id_users_id_fk": { + "name": "series_owner_id_users_id_fk", + "tableFrom": "series", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "varchar(6)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_follows": { + "name": "user_follows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "followee_id": { + "name": "followee_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_follows_follower_id_users_id_fk": { + "name": "user_follows_follower_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_follows_followee_id_users_id_fk": { + "name": "user_follows_followee_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "followee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_action_at": { + "name": "last_action_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_socials": { + "name": "user_socials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "service": { + "name": "service", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "service_uid": { + "name": "service_uid", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_socials_user_id_users_id_fk": { + "name": "user_socials_user_id_users_id_fk", + "tableFrom": "user_socials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "profile_photo": { + "name": "profile_photo", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "education": { + "name": "education", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "designation": { + "name": "designation", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "profile_readme": { + "name": "profile_readme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "skills": { + "name": "skills", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0029_snapshot.json b/migrations/meta/0029_snapshot.json new file mode 100644 index 0000000..bf2c3b1 --- /dev/null +++ b/migrations/meta/0029_snapshot.json @@ -0,0 +1,818 @@ +{ + "id": "6077cd2c-0b02-495c-84fc-61c88d6272b2", + "prevId": "d8d27f76-1a27-4e41-9282-f56786e5aa9f", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.article_tag": { + "name": "article_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "article_tag_article_id_articles_id_fk": { + "name": "article_tag_article_id_articles_id_fk", + "tableFrom": "article_tag", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "article_tag_tag_id_tags_id_fk": { + "name": "article_tag_tag_id_tags_id_fk", + "tableFrom": "article_tag", + "tableTo": "tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "commentable_type": { + "name": "commentable_type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "commentable_id": { + "name": "commentable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_parent_id_comments_id_fk": { + "name": "comments_parent_id_comments_id_fk", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series_items": { + "name": "series_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "article_id": { + "name": "article_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_items_series_id_series_id_fk": { + "name": "series_items_series_id_series_id_fk", + "tableFrom": "series_items", + "tableTo": "series", + "columnsFrom": [ + "series_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "series_items_article_id_articles_id_fk": { + "name": "series_items_article_id_articles_id_fk", + "tableFrom": "series_items", + "tableTo": "articles", + "columnsFrom": [ + "article_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.series": { + "name": "series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "cover_image": { + "name": "cover_image", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "series_owner_id_users_id_fk": { + "name": "series_owner_id_users_id_fk", + "tableFrom": "series", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "varchar(6)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_follows": { + "name": "user_follows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "followee_id": { + "name": "followee_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_follows_follower_id_users_id_fk": { + "name": "user_follows_follower_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_follows_followee_id_users_id_fk": { + "name": "user_follows_followee_id_users_id_fk", + "tableFrom": "user_follows", + "tableTo": "users", + "columnsFrom": [ + "followee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_action_at": { + "name": "last_action_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_socials": { + "name": "user_socials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "service": { + "name": "service", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "service_uid": { + "name": "service_uid", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_socials_user_id_users_id_fk": { + "name": "user_socials_user_id_users_id_fk", + "tableFrom": "user_socials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "profile_photo": { + "name": "profile_photo", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "education": { + "name": "education", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "designation": { + "name": "designation", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "profile_readme": { + "name": "profile_readme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "skills": { + "name": "skills", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index a8a779a..add4234 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -176,6 +176,41 @@ "when": 1743331413433, "tag": "0024_complex_prodigy", "breakpoints": true + }, + { + "idx": 25, + "version": "7", + "when": 1743862111643, + "tag": "0025_reflective_masque", + "breakpoints": true + }, + { + "idx": 26, + "version": "7", + "when": 1743863252956, + "tag": "0026_pink_selene", + "breakpoints": true + }, + { + "idx": 27, + "version": "7", + "when": 1743863306485, + "tag": "0027_small_yellow_claw", + "breakpoints": true + }, + { + "idx": 28, + "version": "7", + "when": 1743919426607, + "tag": "0028_redundant_landau", + "breakpoints": true + }, + { + "idx": 29, + "version": "7", + "when": 1743919570807, + "tag": "0029_blushing_roland_deschain", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index be3ef26..c8d9eda 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "dependencies": { "@cloudinary/react": "^1.14.1", "@cloudinary/url-gen": "^1.21.0", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@hookform/error-message": "^2.0.1", "@hookform/resolvers": "^5.0.0", "@markdoc/markdoc": "^0.5.1", @@ -36,6 +39,8 @@ "class-variance-authority": "^0.7.1", "cloudinary": "^2.6.0", "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", "dotenv": "^16.4.7", "drizzle-orm": "^0.41.0", "jotai": "^2.12.2", @@ -51,6 +56,7 @@ "react-mde": "^12.0.8", "recharts": "^2.15.1", "sass": "^1.86.0", + "schema-dts": "^1.1.5", "tailwind-merge": "^3.0.2", "tw-animate-css": "^1.2.4", "zod": "^3.24.2" diff --git a/src/app/(home)/_components/ArticleFeed.tsx b/src/app/(home)/_components/ArticleFeed.tsx index c165058..983d91b 100644 --- a/src/app/(home)/_components/ArticleFeed.tsx +++ b/src/app/(home)/_components/ArticleFeed.tsx @@ -1,71 +1,139 @@ "use client"; import * as articleActions from "@/backend/services/article.actions"; +import * as seriesActions from "@/backend/services/series.action"; import ArticleCard from "@/components/ArticleCard"; +import SeriesCard from "@/components/SeriesCard"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import VisibilitySensor from "@/components/VisibilitySensor"; import { readingTime } from "@/lib/utils"; import getFileUrl from "@/utils/getFileUrl"; import { useInfiniteQuery } from "@tanstack/react-query"; -import VisibilitySensor from "@/components/VisibilitySensor"; +import { Loader } from "lucide-react"; +import { useState } from "react"; const ArticleFeed = () => { - const feedInfiniteQuery = useInfiniteQuery({ - queryKey: ["article-feed-2"], + const [feedType, setFeedType] = useState<"articles" | "series">("articles"); + + const articleFeedQuery = useInfiniteQuery({ + queryKey: ["article-feed", feedType], queryFn: ({ pageParam }) => articleActions.articleFeed({ limit: 5, page: pageParam }), initialPageParam: 1, getNextPageParam: (lastPage) => { + if (!lastPage?.meta.hasNextPage) return undefined; const _page = lastPage?.meta?.currentPage ?? 1; return _page + 1; }, + enabled: feedType === "articles", }); + const seriesFeedQuery = useInfiniteQuery({ + queryKey: ["series-feed", feedType], + queryFn: ({ pageParam }) => + seriesActions.seriesFeed({ limit: 5, page: pageParam }), + initialPageParam: 1, + getNextPageParam: (lastPage) => { + if (!lastPage?.meta.hasNextPage) return undefined; + const _page = lastPage?.meta?.currentPage ?? 1; + return _page + 1; + }, + enabled: feedType === "series", + }); + + const activeFeedQuery = + feedType === "articles" ? articleFeedQuery : seriesFeedQuery; + const isLoading = + feedType === "articles" + ? articleFeedQuery.isFetching + : seriesFeedQuery.isFetching; + return ( -
- {Boolean(feedInfiniteQuery.isFetching) && ( - <> -
-
-
-
-
-
- - )} + <> +
+ setFeedType(value as "articles" | "series")} + className="w-full" + > + + Articles + Series + + +
- {feedInfiniteQuery.data?.pages - .flatMap((page) => page?.nodes) - .map((article) => ( - + {isLoading && ( + <> +
+
+
+
+ + )} + + {feedType === "articles" && + articleFeedQuery.data?.pages + .flatMap((page) => page?.nodes) + .map((article) => ( + + ))} + + {feedType === "series" && + seriesFeedQuery.data?.pages + .flatMap((page) => page?.nodes) + .map((series) => ( + + ))} + +
+ {activeFeedQuery.isFetchingNextPage && ( +
+ +
+ )} + { + console.log(`fetching next page for ${feedType}`); + await activeFeedQuery.fetchNextPage(); }} - publishedAt={article?.created_at.toDateString() ?? ""} - readingTime={readingTime(article?.body ?? "")} - likes={0} - comments={0} /> - ))} - -
- { - console.log("fetching next page"); - await feedInfiniteQuery.fetchNextPage(); - // alert("Fetching next page"); - }} - /> +
-
+ ); }; diff --git a/src/app/dashboard/bookmarks/page.tsx b/src/app/(home)/_components/bookmarks/page.tsx similarity index 100% rename from src/app/dashboard/bookmarks/page.tsx rename to src/app/(home)/_components/bookmarks/page.tsx diff --git a/src/app/[username]/(profile-page)/page.tsx b/src/app/[username]/(profile-page)/page.tsx index 09039d2..23c4cca 100644 --- a/src/app/[username]/(profile-page)/page.tsx +++ b/src/app/[username]/(profile-page)/page.tsx @@ -1,6 +1,6 @@ import { getUserByUsername } from "@/backend/services/user.action"; import _t from "@/i18n/_t"; -import { markdownToHtml } from "@/utils/markdoc-parser"; +import { markdocParser } from "@/utils/markdoc-parser"; import Image from "next/image"; import React from "react"; @@ -14,17 +14,13 @@ const UserProfilePage: React.FC = async ({ params }) => { : _params.username.toLowerCase(); const profile = await getUserByUsername(username, ["profile_readme"]); - // return
{JSON.stringify(profile, null, 2)}
; return (
{profile?.profile_readme ? ( -
+
+ {markdocParser(profile?.profile_readme ?? "")} +
) : (
; +} + +export const size = { + width: 1200, + height: 630, +}; +export const contentType = "image/png"; + +const getFileLocation = async (path: string) => { + const logoData = await readFile(join(process.cwd(), path)); + return Uint8Array.from(logoData).buffer; +}; + +export default async function Image(options: ArticlePageProps) { + const { articleHandle } = await options.params; + const [article] = await persistenceRepository.article.findRows({ + where: eq("handle", articleHandle), + columns: ["title", "excerpt", "cover_image", "body"], + limit: 1, + joins: [ + joinTable({ + as: "user", + joinTo: "users", + localField: "author_id", + foreignField: "id", + columns: ["username", "profile_photo"], + }), + ], + }); + + return new ImageResponse( + ( +
+
+

+ {article.title} +

+
+ +
+ {/* User profile */} +
+ logo +

+ @{article.user?.username ?? "Unknown user"} +

+
+ + {/* Logo */} +
+ logo +

Techdiary

+
+
+
+ ), + { + ...size, + fonts: [ + { + name: "KohinoorBangla", + data: await getFileLocation( + "/public/fonts/KohinoorBangla-Regular.woff" + ), + style: "normal", + weight: 400, + }, + ], + } + ); +} diff --git a/src/app/[username]/[articleHandle]/page.tsx b/src/app/[username]/[articleHandle]/page.tsx index 6769b3b..e4df358 100644 --- a/src/app/[username]/[articleHandle]/page.tsx +++ b/src/app/[username]/[articleHandle]/page.tsx @@ -1,18 +1,18 @@ import HomeLeftSidebar from "@/app/(home)/_components/HomeLeftSidebar"; import * as articleActions from "@/backend/services/article.actions"; import AppImage from "@/components/AppImage"; +import type { Article, WithContext } from "schema-dts"; import HomepageLayout from "@/components/layout/HomepageLayout"; import { readingTime, removeMarkdownSyntax } from "@/lib/utils"; -import { markdownToHtml } from "@/utils/markdoc-parser"; -import { Metadata, NextPage } from "next"; +import { markdocParser } from "@/utils/markdoc-parser"; +import { Metadata, NextPage, ResolvingMetadata } from "next"; +import Image from "next/image"; import Link from "next/link"; import { notFound } from "next/navigation"; import ArticleSidebar from "./_components/ArticleSidebar"; -import Image from "next/image"; - -export const metadata: Metadata = { - title: "Article detail", -}; +import getFileUrl from "@/utils/getFileUrl"; +import { persistenceRepository } from "@/backend/persistence-repositories"; +import { eq } from "@/backend/persistence/persistence-where-operator"; interface ArticlePageProps { params: Promise<{ @@ -21,82 +21,139 @@ interface ArticlePageProps { }>; } +export async function generateMetadata( + options: ArticlePageProps +): Promise { + // read route params + const { articleHandle } = await options.params; + const [article] = await persistenceRepository.article.findRows({ + where: eq("handle", articleHandle), + columns: ["title", "excerpt", "cover_image", "body"], + limit: 1, + }); + + if (!article.cover_image) { + return { + title: article.title, + description: removeMarkdownSyntax(article.body ?? "", 20), + }; + } + + return { + title: article.title, + description: removeMarkdownSyntax( + article.excerpt ?? article.body ?? "", + 20 + ), + openGraph: { + images: [ + { + url: getFileUrl(article.cover_image), + alt: article.title, + }, + ], + }, + }; +} + const Page: NextPage = async ({ params }) => { const _params = await params; const article = await articleActions.articleDetailByHandle( _params.articleHandle ); + const jsonLd: WithContext
= { + "@context": "https://schema.org", + "@type": "Article", + name: article?.title, + image: getFileUrl(article?.cover_image), + description: article?.excerpt ?? removeMarkdownSyntax(article?.body ?? ""), + author: { + "@type": "Person", + name: article?.user?.name, + image: article?.user?.profile_photo, + url: `https://www.techdiary.dev/@${article?.user?.username}`, + }, + articleBody: removeMarkdownSyntax(article?.body ?? "", 300), + }; + if (!article) { throw notFound(); } - const parsedHTML = markdownToHtml(article?.body ?? ""); + const parsedHTML = markdocParser(article?.body ?? ""); return ( - } - RightSidebar={} - > - {/* {!article &&
Article not found
} */} -
- {article?.cover_image && ( -
- -
- )} + <> +