feat: zentrale selfhost-dienste bereitstellen
This commit is contained in:
36
push-server/packages/db/drizzle/0001_central_services.sql
Normal file
36
push-server/packages/db/drizzle/0001_central_services.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
CREATE TYPE "public"."central_service" AS ENUM('ai', 'banking');--> statement-breakpoint
|
||||
CREATE TYPE "public"."usage_status" AS ENUM('succeeded', 'failed');--> statement-breakpoint
|
||||
CREATE TABLE "service_entitlements" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"instance_id" uuid NOT NULL,
|
||||
"service" "central_service" NOT NULL,
|
||||
"enabled" boolean DEFAULT false NOT NULL,
|
||||
"monthly_limit" bigint,
|
||||
"unit_price_micros" bigint DEFAULT 0 NOT NULL,
|
||||
"metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "service_usage_events" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"request_id" text NOT NULL,
|
||||
"instance_id" uuid NOT NULL,
|
||||
"service" "central_service" NOT NULL,
|
||||
"operation" text NOT NULL,
|
||||
"units" bigint DEFAULT 1 NOT NULL,
|
||||
"cost_micros" bigint DEFAULT 0 NOT NULL,
|
||||
"status" "usage_status" NOT NULL,
|
||||
"provider" text,
|
||||
"provider_request_id" text,
|
||||
"error_code" text,
|
||||
"metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "service_usage_events_request_id_unique" UNIQUE("request_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "service_entitlements" ADD CONSTRAINT "service_entitlements_instance_id_push_instances_id_fk" FOREIGN KEY ("instance_id") REFERENCES "public"."push_instances"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "service_usage_events" ADD CONSTRAINT "service_usage_events_instance_id_push_instances_id_fk" FOREIGN KEY ("instance_id") REFERENCES "public"."push_instances"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "service_entitlements_instance_service_idx" ON "service_entitlements" USING btree ("instance_id","service");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "service_usage_events_request_id_idx" ON "service_usage_events" USING btree ("request_id");--> statement-breakpoint
|
||||
CREATE INDEX "service_usage_events_instance_service_created_idx" ON "service_usage_events" USING btree ("instance_id","service","created_at");
|
||||
1159
push-server/packages/db/drizzle/meta/0001_snapshot.json
Normal file
1159
push-server/packages/db/drizzle/meta/0001_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,13 @@
|
||||
"when": 1779461560095,
|
||||
"tag": "0000_big_devos",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1785681122775,
|
||||
"tag": "0001_central_services",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,8 +3,10 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "tsx src/migrate.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -8,7 +8,9 @@ import pg from "pg";
|
||||
const { Pool } = pg;
|
||||
|
||||
const databaseUrl = process.env.DATABASE_URL || "postgres://fedeo_push:fedeo_push@localhost:5442/fedeo_push";
|
||||
const migrationsFolder = resolve(dirname(fileURLToPath(import.meta.url)), "../drizzle");
|
||||
const migrationsFolder = process.env.DRIZZLE_MIGRATIONS_FOLDER
|
||||
? resolve(process.env.DRIZZLE_MIGRATIONS_FOLDER)
|
||||
: resolve(dirname(fileURLToPath(import.meta.url)), "../drizzle");
|
||||
|
||||
const pool = new Pool({ connectionString: databaseUrl });
|
||||
const db = drizzle(pool);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
boolean,
|
||||
bigint,
|
||||
index,
|
||||
integer,
|
||||
jsonb,
|
||||
@@ -19,6 +20,8 @@ export const deviceStatus = pgEnum("device_status", ["active", "disabled", "inva
|
||||
export const deliveryStatus = pgEnum("delivery_status", ["accepted", "processing", "completed", "failed", "partial"]);
|
||||
export const attemptStatus = pgEnum("attempt_status", ["pending", "sent", "failed", "skipped"]);
|
||||
export const attemptProvider = pgEnum("attempt_provider", ["web_push", "apns", "fcm"]);
|
||||
export const centralService = pgEnum("central_service", ["ai", "banking"]);
|
||||
export const usageStatus = pgEnum("usage_status", ["succeeded", "failed"]);
|
||||
|
||||
export const pushInstances = pgTable(
|
||||
"push_instances",
|
||||
@@ -144,6 +147,51 @@ export const auditLogs = pgTable(
|
||||
}),
|
||||
);
|
||||
|
||||
export const serviceEntitlements = pgTable(
|
||||
"service_entitlements",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
instanceId: uuid("instance_id")
|
||||
.notNull()
|
||||
.references(() => pushInstances.id, { onDelete: "cascade" }),
|
||||
service: centralService("service").notNull(),
|
||||
enabled: boolean("enabled").notNull().default(false),
|
||||
monthlyLimit: bigint("monthly_limit", { mode: "number" }),
|
||||
unitPriceMicros: bigint("unit_price_micros", { mode: "number" }).notNull().default(0),
|
||||
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default(sql`'{}'::jsonb`),
|
||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
},
|
||||
(table) => ({
|
||||
instanceServiceIdx: uniqueIndex("service_entitlements_instance_service_idx").on(table.instanceId, table.service),
|
||||
}),
|
||||
);
|
||||
|
||||
export const serviceUsageEvents = pgTable(
|
||||
"service_usage_events",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
requestId: text("request_id").notNull().unique(),
|
||||
instanceId: uuid("instance_id")
|
||||
.notNull()
|
||||
.references(() => pushInstances.id, { onDelete: "cascade" }),
|
||||
service: centralService("service").notNull(),
|
||||
operation: text("operation").notNull(),
|
||||
units: bigint("units", { mode: "number" }).notNull().default(1),
|
||||
costMicros: bigint("cost_micros", { mode: "number" }).notNull().default(0),
|
||||
status: usageStatus("status").notNull(),
|
||||
provider: text("provider"),
|
||||
providerRequestId: text("provider_request_id"),
|
||||
errorCode: text("error_code"),
|
||||
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default(sql`'{}'::jsonb`),
|
||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
},
|
||||
(table) => ({
|
||||
requestIdIdx: uniqueIndex("service_usage_events_request_id_idx").on(table.requestId),
|
||||
instanceServiceCreatedIdx: index("service_usage_events_instance_service_created_idx").on(table.instanceId, table.service, table.createdAt),
|
||||
}),
|
||||
);
|
||||
|
||||
export type PushInstance = typeof pushInstances.$inferSelect;
|
||||
export type NewPushInstance = typeof pushInstances.$inferInsert;
|
||||
export type PushDevice = typeof pushDevices.$inferSelect;
|
||||
@@ -152,3 +200,5 @@ export type DeliveryJob = typeof deliveryJobs.$inferSelect;
|
||||
export type NewDeliveryJob = typeof deliveryJobs.$inferInsert;
|
||||
export type DeliveryAttempt = typeof deliveryAttempts.$inferSelect;
|
||||
export type NewDeliveryAttempt = typeof deliveryAttempts.$inferInsert;
|
||||
export type ServiceEntitlement = typeof serviceEntitlements.$inferSelect;
|
||||
export type ServiceUsageEvent = typeof serviceUsageEvents.$inferSelect;
|
||||
|
||||
Reference in New Issue
Block a user