first commit

Made-with: Cursor
This commit is contained in:
Michilis
2026-04-01 02:46:53 +00:00
commit 76210db03d
126 changed files with 20208 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL PRIMARY KEY,
"pubkey" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'USER',
"displayName" TEXT,
"username" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Meetup" (
"id" TEXT NOT NULL PRIMARY KEY,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"date" TEXT NOT NULL,
"time" TEXT NOT NULL,
"location" TEXT NOT NULL,
"link" TEXT,
"imageId" TEXT,
"status" TEXT NOT NULL DEFAULT 'UPCOMING',
"featured" BOOLEAN NOT NULL DEFAULT false,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Media" (
"id" TEXT NOT NULL PRIMARY KEY,
"slug" TEXT NOT NULL,
"type" TEXT NOT NULL,
"mimeType" TEXT NOT NULL,
"size" INTEGER NOT NULL,
"originalFilename" TEXT NOT NULL,
"uploadedBy" TEXT NOT NULL,
"title" TEXT,
"description" TEXT,
"altText" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "Post" (
"id" TEXT NOT NULL PRIMARY KEY,
"nostrEventId" TEXT NOT NULL,
"title" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"content" TEXT NOT NULL,
"excerpt" TEXT,
"authorPubkey" TEXT NOT NULL,
"authorName" TEXT,
"featured" BOOLEAN NOT NULL DEFAULT false,
"visible" BOOLEAN NOT NULL DEFAULT true,
"publishedAt" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Category" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "PostCategory" (
"postId" TEXT NOT NULL,
"categoryId" TEXT NOT NULL,
PRIMARY KEY ("postId", "categoryId"),
CONSTRAINT "PostCategory_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "PostCategory_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "HiddenContent" (
"id" TEXT NOT NULL PRIMARY KEY,
"nostrEventId" TEXT NOT NULL,
"reason" TEXT,
"hiddenBy" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "BlockedPubkey" (
"id" TEXT NOT NULL PRIMARY KEY,
"pubkey" TEXT NOT NULL,
"reason" TEXT,
"blockedBy" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "Relay" (
"id" TEXT NOT NULL PRIMARY KEY,
"url" TEXT NOT NULL,
"priority" INTEGER NOT NULL DEFAULT 0,
"active" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "Setting" (
"id" TEXT NOT NULL PRIMARY KEY,
"key" TEXT NOT NULL,
"value" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "NostrEventCache" (
"id" TEXT NOT NULL PRIMARY KEY,
"eventId" TEXT NOT NULL,
"kind" INTEGER NOT NULL,
"pubkey" TEXT NOT NULL,
"content" TEXT NOT NULL,
"tags" TEXT NOT NULL,
"createdAt" INTEGER NOT NULL,
"cachedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "Submission" (
"id" TEXT NOT NULL PRIMARY KEY,
"eventId" TEXT,
"naddr" TEXT,
"title" TEXT NOT NULL,
"authorPubkey" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"reviewedBy" TEXT,
"reviewNote" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Faq" (
"id" TEXT NOT NULL PRIMARY KEY,
"question" TEXT NOT NULL,
"answer" TEXT NOT NULL,
"order" INTEGER NOT NULL DEFAULT 0,
"showOnHomepage" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "User_pubkey_key" ON "User"("pubkey");
-- CreateIndex
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Post_nostrEventId_key" ON "Post"("nostrEventId");
-- CreateIndex
CREATE UNIQUE INDEX "Post_slug_key" ON "Post"("slug");
-- CreateIndex
CREATE UNIQUE INDEX "Category_slug_key" ON "Category"("slug");
-- CreateIndex
CREATE UNIQUE INDEX "Relay_url_key" ON "Relay"("url");
-- CreateIndex
CREATE UNIQUE INDEX "Setting_key_key" ON "Setting"("key");
-- CreateIndex
CREATE UNIQUE INDEX "NostrEventCache_eventId_key" ON "NostrEventCache"("eventId");

View File

@@ -0,0 +1,23 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Meetup" (
"id" TEXT NOT NULL PRIMARY KEY,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"date" TEXT NOT NULL,
"time" TEXT NOT NULL,
"location" TEXT NOT NULL,
"link" TEXT,
"imageId" TEXT,
"status" TEXT NOT NULL DEFAULT 'UPCOMING',
"featured" BOOLEAN NOT NULL DEFAULT false,
"visibility" TEXT NOT NULL DEFAULT 'PUBLIC',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Meetup" ("createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt") SELECT "createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt" FROM "Meetup";
DROP TABLE "Meetup";
ALTER TABLE "new_Meetup" RENAME TO "Meetup";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,23 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Meetup" (
"id" TEXT NOT NULL PRIMARY KEY,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"date" TEXT NOT NULL,
"time" TEXT NOT NULL,
"location" TEXT NOT NULL,
"link" TEXT,
"imageId" TEXT,
"status" TEXT NOT NULL DEFAULT 'DRAFT',
"featured" BOOLEAN NOT NULL DEFAULT false,
"visibility" TEXT NOT NULL DEFAULT 'PUBLIC',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Meetup" ("createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt", "visibility") SELECT "createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt", "visibility" FROM "Meetup";
DROP TABLE "Meetup";
ALTER TABLE "new_Meetup" RENAME TO "Meetup";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"

View File

@@ -0,0 +1,149 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
pubkey String @unique
role String @default("USER") // USER, MODERATOR, ADMIN
displayName String?
username String? @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Meetup {
id String @id @default(uuid())
title String
description String
date String
time String
location String
link String?
imageId String?
status String @default("DRAFT") // DRAFT, PUBLISHED, CANCELLED (Upcoming/Past derived from date)
featured Boolean @default(false)
visibility String @default("PUBLIC") // PUBLIC, HIDDEN
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Media {
id String @id // ULID, not auto-generated
slug String
type String // "image" | "video"
mimeType String
size Int
originalFilename String
uploadedBy String
title String?
description String?
altText String?
createdAt DateTime @default(now())
}
model Post {
id String @id @default(uuid())
nostrEventId String @unique
title String
slug String @unique
content String
excerpt String?
authorPubkey String
authorName String?
featured Boolean @default(false)
visible Boolean @default(true)
publishedAt DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
categories PostCategory[]
}
model Category {
id String @id @default(uuid())
name String
slug String @unique
sortOrder Int @default(0)
createdAt DateTime @default(now())
posts PostCategory[]
}
model PostCategory {
postId String
categoryId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
@@id([postId, categoryId])
}
model HiddenContent {
id String @id @default(uuid())
nostrEventId String
reason String?
hiddenBy String
createdAt DateTime @default(now())
}
model BlockedPubkey {
id String @id @default(uuid())
pubkey String
reason String?
blockedBy String
createdAt DateTime @default(now())
}
model Relay {
id String @id @default(uuid())
url String @unique
priority Int @default(0)
active Boolean @default(true)
createdAt DateTime @default(now())
}
model Setting {
id String @id @default(uuid())
key String @unique
value String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model NostrEventCache {
id String @id @default(uuid())
eventId String @unique
kind Int
pubkey String
content String
tags String // JSON string
createdAt Int // event timestamp
cachedAt DateTime @default(now())
}
model Submission {
id String @id @default(uuid())
eventId String?
naddr String?
title String
authorPubkey String
status String @default("PENDING") // PENDING, APPROVED, REJECTED
reviewedBy String?
reviewNote String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Faq {
id String @id @default(uuid())
question String
answer String
order Int @default(0)
showOnHomepage Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

85
backend/prisma/seed.ts Normal file
View File

@@ -0,0 +1,85 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
const relays = [
{ url: 'wss://relay.damus.io', priority: 1 },
{ url: 'wss://nos.lol', priority: 2 },
{ url: 'wss://relay.nostr.band', priority: 3 },
];
for (const relay of relays) {
await prisma.relay.upsert({
where: { url: relay.url },
update: {},
create: relay,
});
}
const settings = [
{ key: 'site_title', value: 'Belgian Bitcoin Embassy' },
{ key: 'site_tagline', value: 'Your gateway to Bitcoin in Belgium' },
{ key: 'telegram_link', value: 'https://t.me/belgianbitcoinembassy' },
{ key: 'nostr_link', value: '' },
{ key: 'x_link', value: '' },
{ key: 'youtube_link', value: '' },
{ key: 'discord_link', value: '' },
{ key: 'linkedin_link', value: '' },
];
for (const setting of settings) {
await prisma.setting.upsert({
where: { key: setting.key },
update: {},
create: setting,
});
}
const categories = [
{ name: 'Bitcoin', slug: 'bitcoin', sortOrder: 1 },
{ name: 'Lightning', slug: 'lightning', sortOrder: 2 },
{ name: 'Privacy', slug: 'privacy', sortOrder: 3 },
{ name: 'Education', slug: 'education', sortOrder: 4 },
{ name: 'Community', slug: 'community', sortOrder: 5 },
];
for (const category of categories) {
await prisma.category.upsert({
where: { slug: category.slug },
update: {},
create: category,
});
}
const existingMeetup = await prisma.meetup.findFirst({
where: { title: 'Monthly Bitcoin Meetup' },
});
if (!existingMeetup) {
await prisma.meetup.create({
data: {
title: 'Monthly Bitcoin Meetup',
description:
'Join us for our monthly Bitcoin meetup! We discuss the latest developments, share knowledge, and connect with fellow Bitcoiners in Belgium.',
date: '2025-02-15',
time: '19:00',
location: 'Brussels, Belgium',
link: 'https://meetup.com/example',
status: 'UPCOMING',
featured: true,
},
});
}
console.log('Seed completed successfully.');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});