Refactor Protected and Public Routes for Consistent Loading UI; Enhance HomePage with User Company and Branch Details; Update LoginPage Layout; Introduce User Relations in Auth Services

This commit is contained in:
2025-10-03 17:52:56 +05:00
parent 531e2d2e7e
commit 0b024af454
31 changed files with 1770 additions and 115 deletions
+24
View File
@@ -0,0 +1,24 @@
import { pgTable, uuid, varchar, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { companies } from "./companies";
export const branches = pgTable("branches", {
id: uuid("id").primaryKey().defaultRandom(),
companyId: uuid("company_id")
.notNull()
.references(() => companies.id, { onDelete: "cascade" }),
name: varchar("name", { length: 255 }).notNull(),
address: varchar("address", { length: 500 }),
city: varchar("city", { length: 100 }),
country: varchar("country", { length: 100 }),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// Zod schemas for validation
export const insertBranchSchema = createInsertSchema(branches);
export const selectBranchSchema = createSelectSchema(branches);
// Type exports
export type Branch = typeof branches.$inferSelect;
export type NewBranch = typeof branches.$inferInsert;
+18
View File
@@ -0,0 +1,18 @@
import { pgTable, uuid, varchar, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
export const companies = pgTable("companies", {
id: uuid("id").primaryKey().defaultRandom(),
name: varchar("name", { length: 255 }).notNull(),
description: varchar("description", { length: 1000 }),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// Zod schemas for validation
export const insertCompanySchema = createInsertSchema(companies);
export const selectCompanySchema = createSelectSchema(companies);
// Type exports
export type Company = typeof companies.$inferSelect;
export type NewCompany = typeof companies.$inferInsert;
-1
View File
@@ -6,4 +6,3 @@ export const roleNameEnum = pgEnum("role_name", [
"director",
"manager",
]);
+22 -2
View File
@@ -1,9 +1,29 @@
// Export all schemas
export * from "./enums";
export * from "./streamServers";
export * from "./localServers";
export * from "./servers";
export * from "./apps";
export * from "./companies";
export * from "./branches";
export * from "./users";
export * from "./userBranches";
export * from "./serverSessions";
export * from "./authSessions";
export * from "./protectedRoutes";
// Relations (defined here to avoid circular dependencies)
import { relations } from "drizzle-orm";
import { companies } from "./companies";
import { branches } from "./branches";
import { userBranches } from "./userBranches";
export const companiesRelations = relations(companies, ({ many }) => ({
branches: many(branches),
}));
export const branchesRelations = relations(branches, ({ one, many }) => ({
company: one(companies, {
fields: [branches.companyId],
references: [companies.id],
}),
userBranches: many(userBranches),
}));
-27
View File
@@ -1,27 +0,0 @@
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;
+2 -9
View File
@@ -4,14 +4,8 @@ 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"]
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()
@@ -28,4 +22,3 @@ export const selectProtectedRouteSchema = createSelectSchema(protectedRoutes);
// Type exports
export type ProtectedRoute = typeof protectedRoutes.$inferSelect;
export type NewProtectedRoute = typeof protectedRoutes.$inferInsert;
+13 -13
View File
@@ -1,6 +1,5 @@
import { pgTable, uuid, integer, timestamp, pgEnum } from "drizzle-orm/pg-core";
import { streamServers } from "./streamServers";
import { localServers } from "./localServers";
import { servers } from "./servers";
import { apps } from "./apps";
import { users } from "./users";
import { relations } from "drizzle-orm";
@@ -8,10 +7,18 @@ import { createInsertSchema, createSelectSchema } from "drizzle-zod";
// Enums
export const sessionModeEnum = pgEnum("session_mode", ["stream", "local"]);
export const sessionStatusEnum = pgEnum("session_status", [
"starting",
"started",
"ending",
"ended",
]);
export const serverSessions = pgTable("server_sessions", {
id: uuid("id").primaryKey().defaultRandom(),
serverId: uuid("server_id").notNull(),
serverId: uuid("server_id")
.notNull()
.references(() => servers.id),
appId: uuid("app_id")
.notNull()
.references(() => apps.id),
@@ -23,6 +30,7 @@ export const serverSessions = pgTable("server_sessions", {
appPid: integer("app_pid"),
cirrusPid: integer("cirrus_pid"),
mode: sessionModeEnum("mode").notNull(), // stream, local
status: sessionStatusEnum("status").notNull(), // starting, started, ending, ended
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
@@ -37,17 +45,9 @@ export const serverSessionsRelations = relations(serverSessions, ({ one }) => ({
fields: [serverSessions.userId],
references: [users.id],
}),
// Полиморфная реляция для serverId
// В зависимости от mode, serverId может ссылаться на stream_servers или local_servers
streamServer: one(streamServers, {
server: one(servers, {
fields: [serverSessions.serverId],
references: [streamServers.id],
relationName: "session_stream_server",
}),
localServer: one(localServers, {
fields: [serverSessions.serverId],
references: [localServers.id],
relationName: "session_local_server",
references: [servers.id],
}),
}));
+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", ["stream", "local"]);
export const serverTierEnum = pgEnum("server_tier", ["demo", "prod"]);
export const servers = pgTable("servers", {
id: uuid("id").primaryKey().defaultRandom(),
localIp: varchar("local_ip", { length: 45 }).notNull(), // IPv6 can be up to 45 chars
hostname: varchar("hostname").notNull(),
type: serverTypeEnum("type").notNull(), // stream, local
location: serverLocationEnum("location"), // ru1, uae1 (только для stream)
tier: serverTierEnum("tier"), // demo, prod (только для stream)
});
// Zod schemas for validation
export const insertServerSchema = createInsertSchema(servers);
export const selectServerSchema = createSelectSchema(servers);
// Relations
export const serversRelations = relations(servers, ({ many }) => ({
serverSessions: many(serverSessions),
}));
// Type exports
export type Server = typeof servers.$inferSelect;
export type NewServer = typeof servers.$inferInsert;
-31
View File
@@ -1,31 +0,0 @@
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;
+42
View File
@@ -0,0 +1,42 @@
import { pgTable, uuid, timestamp, primaryKey } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { users } from "./users";
import { branches } from "./branches";
// Junction table для связи many-to-many между пользователями и филиалами
export const userBranches = pgTable(
"user_branches",
{
userId: uuid("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
branchId: uuid("branch_id")
.notNull()
.references(() => branches.id, { onDelete: "cascade" }),
createdAt: timestamp("created_at").defaultNow().notNull(),
},
(table) => ({
pk: primaryKey({ columns: [table.userId, table.branchId] }),
})
);
// Relations
export const userBranchesRelations = relations(userBranches, ({ one }) => ({
user: one(users, {
fields: [userBranches.userId],
references: [users.id],
}),
branch: one(branches, {
fields: [userBranches.branchId],
references: [branches.id],
}),
}));
// Zod schemas for validation
export const insertUserBranchSchema = createInsertSchema(userBranches);
export const selectUserBranchSchema = createSelectSchema(userBranches);
// Type exports
export type UserBranch = typeof userBranches.$inferSelect;
export type NewUserBranch = typeof userBranches.$inferInsert;
+9 -1
View File
@@ -4,6 +4,8 @@ import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { roleNameEnum } from "./enums";
import { serverSessions } from "./serverSessions";
import { authSessions } from "./authSessions";
import { userBranches } from "./userBranches";
import { branches } from "./branches";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
@@ -11,6 +13,7 @@ export const users = pgTable("users", {
password: varchar("password", { length: 255 }).notNull(), // scrypt hash
fullName: varchar("full_name", { length: 255 }).notNull(), // ФИО
role: roleNameEnum("role").notNull().default("manager"),
currentBranchId: uuid("current_branch_id").references(() => branches.id), // Текущий выбранный филиал
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
@@ -24,9 +27,14 @@ export const insertUserSchema = createInsertSchema(users);
export const selectUserSchema = createSelectSchema(users);
// Relations
export const usersRelations = relations(users, ({ many }) => ({
export const usersRelations = relations(users, ({ one, many }) => ({
serverSessions: many(serverSessions),
authSessions: many(authSessions),
userBranches: many(userBranches),
currentBranch: one(branches, {
fields: [users.currentBranchId],
references: [branches.id],
}),
}));
// Type exports