Add executive meeting management system with role-based access

Implement a new API endpoint and UI for managing executive meetings, including role-based access control and database schema changes for meeting data and attendees.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 079afca5-8c32-40ea-b7d1-8bf26358ff75
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/BRoHDEI
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
riyadhafraa
2026-04-27 12:05:40 +00:00
parent 0a5e89a6d4
commit 66bc96f97f
11 changed files with 1057 additions and 1 deletions
+191
View File
@@ -0,0 +1,191 @@
import {
pgTable,
serial,
integer,
varchar,
text,
timestamp,
date,
time,
jsonb,
index,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { usersTable } from "./users";
export const executiveMeetingsTable = pgTable(
"executive_meetings",
{
id: serial("id").primaryKey(),
dailyNumber: integer("daily_number").notNull(),
titleAr: varchar("title_ar", { length: 300 }).notNull(),
titleEn: varchar("title_en", { length: 300 }).notNull().default(""),
meetingDate: date("meeting_date").notNull(),
startTime: time("start_time", { withTimezone: false }),
endTime: time("end_time", { withTimezone: false }),
location: varchar("location", { length: 300 }),
meetingUrl: text("meeting_url"),
platform: varchar("platform", { length: 32 }).notNull().default("none"),
status: varchar("status", { length: 32 }).notNull().default("scheduled"),
isHighlighted: integer("is_highlighted").notNull().default(0),
notes: text("notes"),
attachments: jsonb("attachments").default([]),
createdBy: integer("created_by").references(() => usersTable.id, {
onDelete: "set null",
}),
updatedBy: integer("updated_by").references(() => usersTable.id, {
onDelete: "set null",
}),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow()
.$onUpdate(() => new Date()),
},
(t) => ({
dateIdx: index("executive_meetings_date_idx").on(t.meetingDate),
dateNumberUnique: uniqueIndex("executive_meetings_date_number_unique").on(
t.meetingDate,
t.dailyNumber,
),
}),
);
export const executiveMeetingAttendeesTable = pgTable(
"executive_meeting_attendees",
{
id: serial("id").primaryKey(),
meetingId: integer("meeting_id")
.notNull()
.references(() => executiveMeetingsTable.id, { onDelete: "cascade" }),
name: varchar("name", { length: 200 }).notNull(),
title: varchar("title", { length: 200 }),
attendanceType: varchar("attendance_type", { length: 32 })
.notNull()
.default("internal"),
sortOrder: integer("sort_order").notNull().default(0),
},
(t) => ({
meetingIdx: index("executive_meeting_attendees_meeting_idx").on(t.meetingId),
}),
);
export const executiveMeetingRequestsTable = pgTable(
"executive_meeting_requests",
{
id: serial("id").primaryKey(),
meetingId: integer("meeting_id")
.notNull()
.references(() => executiveMeetingsTable.id, { onDelete: "cascade" }),
requestedBy: integer("requested_by").references(() => usersTable.id, {
onDelete: "set null",
}),
requestType: varchar("request_type", { length: 64 }).notNull(),
requestDetails: jsonb("request_details"),
status: varchar("status", { length: 32 }).notNull().default("new"),
reviewedBy: integer("reviewed_by").references(() => usersTable.id, {
onDelete: "set null",
}),
reviewDecision: varchar("review_decision", { length: 32 }),
reviewNotes: text("review_notes"),
assignedTo: integer("assigned_to").references(() => usersTable.id, {
onDelete: "set null",
}),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow()
.$onUpdate(() => new Date()),
},
);
export const executiveMeetingTasksTable = pgTable("executive_meeting_tasks", {
id: serial("id").primaryKey(),
requestId: integer("request_id").references(() => executiveMeetingRequestsTable.id, {
onDelete: "cascade",
}),
meetingId: integer("meeting_id").references(() => executiveMeetingsTable.id, {
onDelete: "cascade",
}),
assignedTo: integer("assigned_to").references(() => usersTable.id, {
onDelete: "set null",
}),
taskType: varchar("task_type", { length: 64 }).notNull(),
status: varchar("status", { length: 32 }).notNull().default("pending"),
dueAt: timestamp("due_at", { withTimezone: true }),
completedAt: timestamp("completed_at", { withTimezone: true }),
notes: text("notes"),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow()
.$onUpdate(() => new Date()),
});
export const executiveMeetingNotificationsTable = pgTable(
"executive_meeting_notifications",
{
id: serial("id").primaryKey(),
meetingId: integer("meeting_id").references(() => executiveMeetingsTable.id, {
onDelete: "cascade",
}),
userId: integer("user_id").references(() => usersTable.id, { onDelete: "cascade" }),
notificationType: varchar("notification_type", { length: 64 }).notNull(),
scheduledAt: timestamp("scheduled_at", { withTimezone: true }),
sentAt: timestamp("sent_at", { withTimezone: true }),
status: varchar("status", { length: 32 }).notNull().default("pending"),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
},
);
export const executiveMeetingAuditLogsTable = pgTable(
"executive_meeting_audit_logs",
{
id: serial("id").primaryKey(),
action: varchar("action", { length: 100 }).notNull(),
entityType: varchar("entity_type", { length: 50 }).notNull(),
entityId: integer("entity_id"),
oldValue: jsonb("old_value"),
newValue: jsonb("new_value"),
performedBy: integer("performed_by").references(() => usersTable.id, {
onDelete: "set null",
}),
performedAt: timestamp("performed_at", { withTimezone: true }).notNull().defaultNow(),
},
);
export const executiveMeetingPdfArchivesTable = pgTable(
"executive_meeting_pdf_archives",
{
id: serial("id").primaryKey(),
archiveDate: date("archive_date").notNull(),
filePath: text("file_path").notNull(),
version: integer("version").notNull().default(1),
generatedBy: integer("generated_by").references(() => usersTable.id, {
onDelete: "set null",
}),
generatedAt: timestamp("generated_at", { withTimezone: true }).notNull().defaultNow(),
},
);
export const executiveMeetingFontSettingsTable = pgTable(
"executive_meeting_font_settings",
{
id: serial("id").primaryKey(),
scope: varchar("scope", { length: 16 }).notNull().default("global"),
userId: integer("user_id").references(() => usersTable.id, { onDelete: "cascade" }),
fontFamily: varchar("font_family", { length: 100 }).notNull().default("system"),
fontSize: integer("font_size").notNull().default(14),
fontWeight: varchar("font_weight", { length: 16 }).notNull().default("regular"),
alignment: varchar("alignment", { length: 16 }).notNull().default("start"),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow()
.$onUpdate(() => new Date()),
},
);
export type ExecutiveMeeting = typeof executiveMeetingsTable.$inferSelect;
export type ExecutiveMeetingAttendee = typeof executiveMeetingAttendeesTable.$inferSelect;
export type ExecutiveMeetingRequest = typeof executiveMeetingRequestsTable.$inferSelect;
export type ExecutiveMeetingTask = typeof executiveMeetingTasksTable.$inferSelect;
+1
View File
@@ -12,3 +12,4 @@ export * from "./password-reset-tokens";
export * from "./notes";
export * from "./groups";
export * from "./audit-logs";
export * from "./executive-meetings";