This commit is contained in:
2025-10-03 15:43:22 +05:00
commit 531e2d2e7e
54 changed files with 2943 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema/index";
const db = drizzle(process.env.DATABASE_URL!, { schema });
export default db;
+33
View File
@@ -0,0 +1,33 @@
import {
pgTable,
uuid,
varchar,
timestamp,
integer,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { serverSessions } from "./serverSessions";
export const apps = pgTable("apps", {
id: uuid("id").primaryKey().defaultRandom(),
name: varchar("name").notNull(), // Имя приложения (например, "minecraft")
title: varchar("title").notNull(), // Название приложения (например, "Майнкрафт")
gpuLimitMb: integer("gpu_limit_mb"), // Лимит GPU в мегабайтах (только для stream серверов)
psVersion: integer("ps_version"), // Версия Pixel Streaming (например, "1")
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// Zod schemas for validation
export const insertAppSchema = createInsertSchema(apps);
export const selectAppSchema = createSelectSchema(apps);
// Relations
export const appsRelations = relations(apps, ({ many }) => ({
serverSessions: many(serverSessions),
}));
// Type exports
export type App = typeof apps.$inferSelect;
export type NewApp = typeof apps.$inferInsert;
+49
View File
@@ -0,0 +1,49 @@
import {
pgTable,
uuid,
varchar,
timestamp,
text,
inet,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { users } from "./users";
// Храним пользовательские сессии. accessToken хранится как bcrypt-хэш
export const authSessions = pgTable("auth_sessions", {
id: uuid("id").primaryKey().defaultRandom(),
userId: uuid("user_id")
.notNull()
.references(() => users.id),
// bcrypt-хэш токена доступа. Длина 60-72 символа, но оставим запас
accessTokenHash: varchar("access_token_hash", { length: 72 }).notNull(),
// Доп. метаданные устройства/браузера
userAgent: text("user_agent"),
ipAddress: inet("ip_address"),
// Срок действия и отзыв
expiresAt: timestamp("expires_at", { withTimezone: true }),
revokedAt: timestamp("revoked_at", { withTimezone: true }),
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.defaultNow()
.notNull(),
});
// Relations
export const authSessionsRelations = relations(authSessions, ({ one }) => ({
user: one(users, {
fields: [authSessions.userId],
references: [users.id],
}),
}));
// Zod schemas for validation
export const insertAuthSessionSchema = createInsertSchema(authSessions);
export const selectAuthSessionSchema = createSelectSchema(authSessions);
// Type exports
export type AuthSession = typeof authSessions.$inferSelect;
export type NewAuthSession = typeof authSessions.$inferInsert;
+9
View File
@@ -0,0 +1,9 @@
import { pgEnum } from "drizzle-orm/pg-core";
// Enum для ролей пользователей
export const roleNameEnum = pgEnum("role_name", [
"admin",
"director",
"manager",
]);
+9
View File
@@ -0,0 +1,9 @@
// Export all schemas
export * from "./enums";
export * from "./streamServers";
export * from "./localServers";
export * from "./apps";
export * from "./users";
export * from "./serverSessions";
export * from "./authSessions";
export * from "./protectedRoutes";
+27
View File
@@ -0,0 +1,27 @@
import { pgTable, uuid, varchar } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { serverSessions } from "./serverSessions";
export const localServers = pgTable("local_servers", {
id: uuid("id").primaryKey().defaultRandom(),
localIp: varchar("local_ip", { length: 45 }).notNull(), // IPv6 can be up to 45 chars
hostname: varchar("hostname", { length: 255 }).notNull(),
location: varchar("location", { length: 10 }).notNull(), // ru1, uae1
type: varchar("type", { length: 10 }).notNull(), // demo, prod
});
// Zod schemas for validation
export const insertLocalServerSchema = createInsertSchema(localServers);
export const selectLocalServerSchema = createSelectSchema(localServers);
// Relations
export const localServersRelations = relations(localServers, ({ many }) => ({
serverSessions: many(serverSessions, {
relationName: "session_local_server",
}),
}));
// Type exports
export type LocalServer = typeof localServers.$inferSelect;
export type NewLocalServer = typeof localServers.$inferInsert;
+31
View File
@@ -0,0 +1,31 @@
import { pgTable, varchar, text, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { roleNameEnum } from "./enums";
export const protectedRoutes = pgTable("protected_routes", {
path: varchar("path", { length: 255 }).primaryKey(), // /auth/register-user
methods: varchar("methods", { length: 50 })
.array()
.notNull()
.default([]), // Массив: ["GET", "POST", "PUT", "DELETE", "PATCH"]
roles: roleNameEnum("roles")
.array()
.notNull()
.default([]), // Массив: ["admin", "director", "manager"]
description: text("description"), // Описание маршрута
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.defaultNow()
.notNull(),
});
// Zod schemas for validation
export const insertProtectedRouteSchema = createInsertSchema(protectedRoutes);
export const selectProtectedRouteSchema = createSelectSchema(protectedRoutes);
// Type exports
export type ProtectedRoute = typeof protectedRoutes.$inferSelect;
export type NewProtectedRoute = typeof protectedRoutes.$inferInsert;
+60
View File
@@ -0,0 +1,60 @@
import { pgTable, uuid, integer, timestamp, pgEnum } from "drizzle-orm/pg-core";
import { streamServers } from "./streamServers";
import { localServers } from "./localServers";
import { apps } from "./apps";
import { users } from "./users";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
// Enums
export const sessionModeEnum = pgEnum("session_mode", ["stream", "local"]);
export const serverSessions = pgTable("server_sessions", {
id: uuid("id").primaryKey().defaultRandom(),
serverId: uuid("server_id").notNull(),
appId: uuid("app_id")
.notNull()
.references(() => apps.id),
userId: uuid("user_id")
.notNull()
.references(() => users.id),
startAt: timestamp("start_at").defaultNow().notNull(),
endAt: timestamp("end_at"), // Default 30 minutes from start_at
appPid: integer("app_pid"),
cirrusPid: integer("cirrus_pid"),
mode: sessionModeEnum("mode").notNull(), // stream, local
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// Relations
export const serverSessionsRelations = relations(serverSessions, ({ one }) => ({
app: one(apps, {
fields: [serverSessions.appId],
references: [apps.id],
}),
user: one(users, {
fields: [serverSessions.userId],
references: [users.id],
}),
// Полиморфная реляция для serverId
// В зависимости от mode, serverId может ссылаться на stream_servers или local_servers
streamServer: one(streamServers, {
fields: [serverSessions.serverId],
references: [streamServers.id],
relationName: "session_stream_server",
}),
localServer: one(localServers, {
fields: [serverSessions.serverId],
references: [localServers.id],
relationName: "session_local_server",
}),
}));
// Zod schemas for validation
export const insertServerSessionSchema = createInsertSchema(serverSessions);
export const selectServerSessionSchema = createSelectSchema(serverSessions);
// Type exports
export type ServerSession = typeof serverSessions.$inferSelect;
export type NewServerSession = typeof serverSessions.$inferInsert;
+31
View File
@@ -0,0 +1,31 @@
import { pgTable, uuid, varchar, pgEnum } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { serverSessions } from "./serverSessions";
// Enums
export const serverLocationEnum = pgEnum("server_location", ["ru1", "uae1"]);
export const serverTypeEnum = pgEnum("server_type", ["demo", "prod"]);
export const streamServers = pgTable("stream_servers", {
id: uuid("id").primaryKey().defaultRandom(),
localIp: varchar("local_ip", { length: 45 }).notNull(), // IPv6 can be up to 45 chars
hostname: varchar("hostname", { length: 255 }).notNull(),
location: serverLocationEnum("location").notNull(),
type: serverTypeEnum("type").notNull(),
});
// Zod schemas for validation
export const insertStreamServerSchema = createInsertSchema(streamServers);
export const selectStreamServerSchema = createSelectSchema(streamServers);
// Relations
export const streamServersRelations = relations(streamServers, ({ many }) => ({
serverSessions: many(serverSessions, {
relationName: "session_stream_server",
}),
}));
// Type exports
export type StreamServer = typeof streamServers.$inferSelect;
export type NewStreamServer = typeof streamServers.$inferInsert;
+34
View File
@@ -0,0 +1,34 @@
import { pgTable, uuid, varchar, timestamp } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { roleNameEnum } from "./enums";
import { serverSessions } from "./serverSessions";
import { authSessions } from "./authSessions";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: varchar("email", { length: 255 }).notNull().unique(),
password: varchar("password", { length: 255 }).notNull(), // scrypt hash
fullName: varchar("full_name", { length: 255 }).notNull(), // ФИО
role: roleNameEnum("role").notNull().default("manager"),
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.defaultNow()
.notNull(),
});
// Zod schemas for validation
export const insertUserSchema = createInsertSchema(users);
export const selectUserSchema = createSelectSchema(users);
// Relations
export const usersRelations = relations(users, ({ many }) => ({
serverSessions: many(serverSessions),
authSessions: many(authSessions),
}));
// Type exports
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;