Implement a new hardcoded permissions system for enhanced user access control

This commit replaces the previous dynamic, database-driven permissions system with a hardcoded, role-based access control (RBAC) structure. New files in `client/src/lib/permissions.ts` and `server/permissions.ts` define permissions per module and role, simplifying management and improving performance. Database tables related to roles, permissions, and user roles have been removed, and associated storage interface methods and routes have been deprecated or updated to reflect the new architecture. The `replit.md` file has also been updated to document these significant changes.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: a8a78c07-e900-425c-a577-5b4c5894379d
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/a8a78c07-e900-425c-a577-5b4c5894379d/7SnSmh4
This commit is contained in:
michaelschal committed 2025-08-11 19:11:11 +00:00
1 parent 70da3e9f5b
commit df479800e3
9 files changed
+441 -873

No files matched your search

+149
View File
@@ -0,0 +1,149 @@
// Système de permissions hardcodé par module
// Remplace l'ancien système flexible basé sur la base de données
export type Permission = 'view' | 'create' | 'edit' | 'delete' | 'validate';
export type Role = 'admin' | 'directeur' | 'manager' | 'employee';
export type Module =
| 'dashboard'
| 'calendar'
| 'orders'
| 'deliveries'
| 'reconciliation'
| 'publicity'
| 'customer-orders'
| 'dlc'
| 'tasks';
// Définition des permissions par module et par rôle
const PERMISSIONS: Record<Module, Record<Role, Permission[]>> = {
// Tableau de bord - tous les rôles peuvent le voir
dashboard: {
admin: ['view'],
directeur: ['view'],
manager: ['view'],
employee: ['view']
},
// Calendrier - Admin/Directeur tout, Manager tout sauf delete, Employé view
calendar: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
employee: ['view']
},
// Commandes - Admin/Directeur tout, Manager tout sauf delete, Employé view
orders: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
employee: ['view']
},
// Livraisons - Admin/Directeur tout, Manager tout sauf delete, Employé view
deliveries: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
employee: ['view']
},
// Rapprochement - Admin tout, Directeur tout sauf delete, Manager/Employé rien
reconciliation: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit'],
manager: [],
employee: []
},
// Publicité - Admin tout, autres view seulement
publicity: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view'],
manager: ['view'],
employee: ['view']
},
// Commandes client - Admin/Directeur tout, Manager tout sauf delete, Employé view + create
'customer-orders': {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
employee: ['view', 'create']
},
// DLC - Admin/Directeur tout, Manager tout sauf delete, Employé create + view
dlc: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
employee: ['view', 'create']
},
// Tâches - Admin/Directeur tout, Manager view + validate, Employé view
tasks: {
admin: ['view', 'create', 'edit', 'delete', 'validate'],
directeur: ['view', 'create', 'edit', 'delete', 'validate'],
manager: ['view', 'validate'],
employee: ['view']
}
};
// Hook pour vérifier les permissions
export function usePermissions(userRole?: string) {
const role = userRole?.toLowerCase() as Role;
// Vérifie si l'utilisateur peut accéder à un module
const canAccessModule = (module: Module): boolean => {
if (!role || !PERMISSIONS[module]) return false;
const permissions = PERMISSIONS[module][role] || [];
return permissions.length > 0;
};
// Vérifie si l'utilisateur peut effectuer une action sur un module
const canPerformAction = (module: Module, action: Permission): boolean => {
if (!role || !PERMISSIONS[module]) return false;
const permissions = PERMISSIONS[module][role] || [];
return permissions.includes(action);
};
// Retourne toutes les permissions pour un module
const getModulePermissions = (module: Module): Permission[] => {
if (!role || !PERMISSIONS[module]) return [];
return PERMISSIONS[module][role] || [];
};
// Vérifie si l'utilisateur peut voir le module (a au moins une permission)
const canView = (module: Module): boolean => canPerformAction(module, 'view');
const canCreate = (module: Module): boolean => canPerformAction(module, 'create');
const canEdit = (module: Module): boolean => canPerformAction(module, 'edit');
const canDelete = (module: Module): boolean => canPerformAction(module, 'delete');
const canValidate = (module: Module): boolean => canPerformAction(module, 'validate');
return {
canAccessModule,
canPerformAction,
getModulePermissions,
canView,
canCreate,
canEdit,
canDelete,
canValidate
};
}
// Fonction utilitaire pour les middlewares serveur
export function hasPermission(userRole: string, module: Module, action: Permission): boolean {
const role = userRole?.toLowerCase() as Role;
if (!role || !PERMISSIONS[module]) return false;
const permissions = PERMISSIONS[module][role] || [];
return permissions.includes(action);
}
// Fonction utilitaire pour vérifier l'accès à un module
export function hasModuleAccess(userRole: string, module: Module): boolean {
const role = userRole?.toLowerCase() as Role;
if (!role || !PERMISSIONS[module]) return false;
const permissions = PERMISSIONS[module][role] || [];
return permissions.length > 0;
}
+1 -119
View File
@@ -136,40 +136,7 @@ export const publicityParticipations = pgTable("publicity_participations", {
pk: primaryKey({ columns: [table.publicityId, table.groupId] })
}));
// Roles - Dynamic role management
export const roles = pgTable("roles", {
id: serial("id").primaryKey(),
name: varchar("name").notNull().unique(),
displayName: varchar("display_name").notNull(),
description: text("description"),
color: varchar("color").default("#6b7280"), // Couleur d'affichage
isSystem: boolean("is_system").default(false), // Rôles système non supprimables
isActive: boolean("is_active").default(true),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),
});
// Permissions - Available permissions in the system
export const permissions = pgTable("permissions", {
id: serial("id").primaryKey(),
name: varchar("name").notNull().unique(),
displayName: varchar("display_name").notNull(),
description: text("description"),
category: varchar("category").notNull(), // dashboard, orders, deliveries, users, etc.
action: varchar("action").notNull(), // read, create, update, delete, validate
resource: varchar("resource").notNull(), // orders, deliveries, users, etc.
isSystem: boolean("is_system").default(true), // Permissions système
createdAt: timestamp("created_at").defaultNow(),
});
// Role Permissions - Many to many relationship
export const rolePermissions = pgTable("role_permissions", {
roleId: integer("role_id").notNull(),
permissionId: integer("permission_id").notNull(),
createdAt: timestamp("created_at").defaultNow(),
}, (table) => ({
pk: primaryKey({ columns: [table.roleId, table.permissionId] })
}));
// NocoDB configuration globale (une seule instance NocoDB partagée)
export const nocodbConfig = pgTable("nocodb_config", {
@@ -221,15 +188,7 @@ export const customerOrders = pgTable("customer_orders", {
updatedAt: timestamp("updated_at").defaultNow(),
});
// User Roles - Many to many relationship (supports multiple roles per user)
export const userRoles = pgTable("user_roles", {
userId: varchar("user_id").notNull(),
roleId: integer("role_id").notNull(),
assignedBy: varchar("assigned_by").notNull(), // Who assigned this role
assignedAt: timestamp("assigned_at").defaultNow(),
}, (table) => ({
pk: primaryKey({ columns: [table.userId, table.roleId] })
}));
// DLC Products (Date Limite de Consommation)
export const dlcProducts = pgTable("dlc_products", {
@@ -273,7 +232,6 @@ export const tasks = pgTable("tasks", {
// Relations
export const usersRelations = relations(users, ({ many }) => ({
userGroups: many(userGroups),
userRoles: many(userRoles),
createdOrders: many(orders),
createdDeliveries: many(deliveries),
createdPublicities: many(publicities),
@@ -368,36 +326,7 @@ export const publicityParticipationsRelations = relations(publicityParticipation
}),
}));
export const rolesRelations = relations(roles, ({ many }) => ({
userRoles: many(userRoles),
rolePermissions: many(rolePermissions),
}));
export const userRolesRelations = relations(userRoles, ({ one }) => ({
user: one(users, {
fields: [userRoles.userId],
references: [users.id],
}),
role: one(roles, {
fields: [userRoles.roleId],
references: [roles.id],
}),
}));
export const permissionsRelations = relations(permissions, ({ many }) => ({
rolePermissions: many(rolePermissions),
}));
export const rolePermissionsRelations = relations(rolePermissions, ({ one }) => ({
role: one(roles, {
fields: [rolePermissions.roleId],
references: [roles.id],
}),
permission: one(permissions, {
fields: [rolePermissions.permissionId],
references: [permissions.id],
}),
}));
export const customerOrdersRelations = relations(customerOrders, ({ one }) => ({
group: one(groups, {
@@ -502,24 +431,7 @@ export const insertPublicityParticipationSchema = createInsertSchema(publicityPa
createdAt: true,
});
export const insertRoleSchema = createInsertSchema(roles).omit({
id: true,
createdAt: true,
updatedAt: true,
});
export const insertPermissionSchema = createInsertSchema(permissions).omit({
id: true,
createdAt: true,
});
export const insertRolePermissionSchema = createInsertSchema(rolePermissions).omit({
createdAt: true,
});
export const insertUserRoleSchema = createInsertSchema(userRoles).omit({
assignedAt: true,
});
export const insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
id: true,
@@ -606,31 +518,6 @@ export type PublicityWithRelations = Publicity & {
participations: (PublicityParticipation & { group: Group })[];
};
export type Role = typeof roles.$inferSelect;
export type InsertRole = z.infer<typeof insertRoleSchema>;
export type Permission = typeof permissions.$inferSelect;
export type InsertPermission = z.infer<typeof insertPermissionSchema>;
export type RolePermission = typeof rolePermissions.$inferSelect;
export type InsertRolePermission = z.infer<typeof insertRolePermissionSchema>;
export type UserRole = typeof userRoles.$inferSelect;
export type InsertUserRole = z.infer<typeof insertUserRoleSchema>;
export type RoleWithPermissions = Role & {
rolePermissions: (RolePermission & { permission: Permission })[];
};
export type UserWithRoles = User & {
userRoles: (UserRole & { role: Role })[];
};
export type PermissionWithActions = Permission & {
action: string;
resource: string;
};
export type NocodbConfig = typeof nocodbConfig.$inferSelect;
export type InsertNocodbConfig = z.infer<typeof insertNocodbConfigSchema>;
@@ -643,11 +530,6 @@ export type CustomerOrderWithRelations = CustomerOrder & {
supplier: Supplier;
};
export type UserWithRole = User & {
dynamicRole?: Role | null;
userGroups: (UserGroup & { group: Group })[];
};
export type DlcProduct = typeof dlcProducts.$inferSelect;
export type InsertDlcProduct = z.infer<typeof insertDlcProductSchema>;