diff --git a/inventory-server/auth/schema.sql b/inventory-server/auth/schema.sql
index 836b17b..13f1508 100644
--- a/inventory-server/auth/schema.sql
+++ b/inventory-server/auth/schema.sql
@@ -2,10 +2,14 @@ CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
+ email VARCHAR UNIQUE,
+ is_admin BOOLEAN DEFAULT FALSE,
+ is_active BOOLEAN DEFAULT TRUE,
+ last_login TIMESTAMP WITH TIME ZONE,
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-
-- Function to update the updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
@@ -18,14 +22,6 @@ $$ language 'plpgsql';
-- Sequence and defined type for users table if not exists
CREATE SEQUENCE IF NOT EXISTS users_id_seq;
--- Update users table with new fields
-ALTER TABLE "public"."users"
- ADD COLUMN IF NOT EXISTS "email" varchar UNIQUE,
- ADD COLUMN IF NOT EXISTS "is_admin" boolean DEFAULT FALSE,
- ADD COLUMN IF NOT EXISTS "is_active" boolean DEFAULT TRUE,
- ADD COLUMN IF NOT EXISTS "last_login" timestamp with time zone,
- ADD COLUMN IF NOT EXISTS "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP;
-
-- Create permissions table
CREATE TABLE IF NOT EXISTS "public"."permissions" (
"id" SERIAL PRIMARY KEY,
@@ -58,8 +54,7 @@ CREATE TRIGGER update_permissions_updated_at
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
--- Insert default permissions by page
--- Core page access permissions
+-- Insert default permissions by page - only the ones used in application
INSERT INTO permissions (name, code, description, category) VALUES
('Dashboard Access', 'access:dashboard', 'Can access the Dashboard page', 'Pages'),
('Products Access', 'access:products', 'Can access the Products page', 'Pages'),
@@ -73,52 +68,14 @@ INSERT INTO permissions (name, code, description, category) VALUES
('AI Validation Debug Access', 'access:ai_validation_debug', 'Can access the AI Validation Debug page', 'Pages')
ON CONFLICT (code) DO NOTHING;
--- Granular permissions for Products
-INSERT INTO permissions (name, code, description, category) VALUES
- ('View Products', 'view:products', 'Can view product listings', 'Products'),
- ('Create Products', 'create:products', 'Can create new products', 'Products'),
- ('Edit Products', 'edit:products', 'Can edit product details', 'Products'),
- ('Delete Products', 'delete:products', 'Can delete products', 'Products')
-ON CONFLICT (code) DO NOTHING;
-
--- Granular permissions for Categories
-INSERT INTO permissions (name, code, description, category) VALUES
- ('View Categories', 'view:categories', 'Can view categories', 'Categories'),
- ('Create Categories', 'create:categories', 'Can create new categories', 'Categories'),
- ('Edit Categories', 'edit:categories', 'Can edit categories', 'Categories'),
- ('Delete Categories', 'delete:categories', 'Can delete categories', 'Categories')
-ON CONFLICT (code) DO NOTHING;
-
--- Granular permissions for Vendors
-INSERT INTO permissions (name, code, description, category) VALUES
- ('View Vendors', 'view:vendors', 'Can view vendors', 'Vendors'),
- ('Create Vendors', 'create:vendors', 'Can create new vendors', 'Vendors'),
- ('Edit Vendors', 'edit:vendors', 'Can edit vendors', 'Vendors'),
- ('Delete Vendors', 'delete:vendors', 'Can delete vendors', 'Vendors')
-ON CONFLICT (code) DO NOTHING;
-
--- Granular permissions for Purchase Orders
-INSERT INTO permissions (name, code, description, category) VALUES
- ('View Purchase Orders', 'view:purchase_orders', 'Can view purchase orders', 'Purchase Orders'),
- ('Create Purchase Orders', 'create:purchase_orders', 'Can create new purchase orders', 'Purchase Orders'),
- ('Edit Purchase Orders', 'edit:purchase_orders', 'Can edit purchase orders', 'Purchase Orders'),
- ('Delete Purchase Orders', 'delete:purchase_orders', 'Can delete purchase orders', 'Purchase Orders')
-ON CONFLICT (code) DO NOTHING;
-
--- User management permissions
-INSERT INTO permissions (name, code, description, category) VALUES
- ('View Users', 'view:users', 'Can view user accounts', 'Users'),
- ('Create Users', 'create:users', 'Can create user accounts', 'Users'),
- ('Edit Users', 'edit:users', 'Can modify user accounts', 'Users'),
- ('Delete Users', 'delete:users', 'Can delete user accounts', 'Users'),
- ('Manage Permissions', 'manage:permissions', 'Can assign permissions to users', 'Users')
-ON CONFLICT (code) DO NOTHING;
-
--- System permissions
+-- Settings section permissions
INSERT INTO permissions (name, code, description, category) VALUES
- ('Run Calculations', 'run:calculations', 'Can trigger system calculations', 'System'),
- ('Import Data', 'import:data', 'Can import data into the system', 'System'),
- ('System Settings', 'edit:system_settings', 'Can modify system settings', 'System')
+ ('Data Management', 'settings:data_management', 'Access to the Data Management settings section', 'Settings'),
+ ('Stock Management', 'settings:stock_management', 'Access to the Stock Management settings section', 'Settings'),
+ ('Performance Metrics', 'settings:performance_metrics', 'Access to the Performance Metrics settings section', 'Settings'),
+ ('Calculation Settings', 'settings:calculation_settings', 'Access to the Calculation Settings section', 'Settings'),
+ ('Template Management', 'settings:templates', 'Access to the Template Management settings section', 'Settings'),
+ ('User Management', 'settings:user_management', 'Access to the User Management settings section', 'Settings')
ON CONFLICT (code) DO NOTHING;
-- Set any existing users as admin
diff --git a/inventory/src/App.tsx b/inventory/src/App.tsx
index 4609f6a..a6868f4 100644
--- a/inventory/src/App.tsx
+++ b/inventory/src/App.tsx
@@ -18,6 +18,7 @@ import { Import } from '@/pages/Import';
import { AiValidationDebug } from "@/pages/AiValidationDebug"
import { AuthProvider } from './contexts/AuthContext';
import { Protected } from './components/auth/Protected';
+import { FirstAccessiblePage } from './components/auth/FirstAccessiblePage';
const queryClient = new QueryClient();
@@ -78,6 +79,11 @@ function App() {
}>
+ }>
+
+
+ } />
diff --git a/inventory/src/components/auth/FirstAccessiblePage.tsx b/inventory/src/components/auth/FirstAccessiblePage.tsx
new file mode 100644
index 0000000..15fcf8d
--- /dev/null
+++ b/inventory/src/components/auth/FirstAccessiblePage.tsx
@@ -0,0 +1,44 @@
+import { useContext } from "react";
+import { Navigate } from "react-router-dom";
+import { AuthContext } from "@/contexts/AuthContext";
+
+// Define available pages in order of priority
+const PAGES = [
+ { path: "/products", permission: "access:products" },
+ { path: "/categories", permission: "access:categories" },
+ { path: "/vendors", permission: "access:vendors" },
+ { path: "/purchase-orders", permission: "access:purchase_orders" },
+ { path: "/analytics", permission: "access:analytics" },
+ { path: "/forecasting", permission: "access:forecasting" },
+ { path: "/import", permission: "access:import" },
+ { path: "/settings", permission: "access:settings" },
+ { path: "/ai-validation/debug", permission: "access:ai_validation_debug" }
+];
+
+export function FirstAccessiblePage() {
+ const { user } = useContext(AuthContext);
+
+ // If user isn't loaded yet, don't render anything
+ if (!user) {
+ return null;
+ }
+
+ // Admin users have access to all pages, so this component
+ // shouldn't be rendering for them (handled by App.tsx)
+ if (user.is_admin) {
+ return null;
+ }
+
+ // Find the first page the user has access to
+ const firstAccessiblePage = PAGES.find(page => {
+ return user.permissions?.includes(page.permission);
+ });
+
+ // If we found a page, redirect to it
+ if (firstAccessiblePage) {
+ return ;
+ }
+
+ // If user has no access to any page, redirect to login
+ return ;
+}
diff --git a/inventory/src/pages/Settings.tsx b/inventory/src/pages/Settings.tsx
index 48cabac..35b3f46 100644
--- a/inventory/src/pages/Settings.tsx
+++ b/inventory/src/pages/Settings.tsx
@@ -8,33 +8,90 @@ import { UserManagement } from "@/components/settings/UserManagement";
import { motion } from 'framer-motion';
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Protected } from "@/components/auth/Protected";
+import { useContext, useMemo } from "react";
+import { AuthContext } from "@/contexts/AuthContext";
+
+// Define available settings tabs with their permission requirements
+const SETTINGS_TABS = [
+ { id: "data-management", permission: "settings:data_management", label: "Data Management" },
+ { id: "stock-management", permission: "settings:stock_management", label: "Stock Management" },
+ { id: "performance-metrics", permission: "settings:performance_metrics", label: "Performance Metrics" },
+ { id: "calculation-settings", permission: "settings:calculation_settings", label: "Calculation Settings" },
+ { id: "templates", permission: "settings:templates", label: "Template Management" },
+ { id: "user-management", permission: "settings:user_management", label: "User Management" }
+];
export function Settings() {
+ const { user } = useContext(AuthContext);
+
+ // Determine the first tab the user has access to
+ const defaultTab = useMemo(() => {
+ // Admin users have access to all tabs
+ if (user?.is_admin) {
+ return SETTINGS_TABS[0].id;
+ }
+
+ // Find the first tab the user has permission to access
+ const firstAccessibleTab = SETTINGS_TABS.find(tab =>
+ user?.permissions?.includes(tab.permission)
+ );
+
+ // Return the ID of the first accessible tab, or first tab as fallback
+ return firstAccessibleTab?.id || SETTINGS_TABS[0].id;
+ }, [user]);
+
+ // Check if user has access to any tab
+ const hasAccessToAnyTab = useMemo(() => {
+ if (user?.is_admin) return true;
+ return SETTINGS_TABS.some(tab => user?.permissions?.includes(tab.permission));
+ }, [user]);
+
+ // If user doesn't have access to any tabs, show a helpful message
+ if (!hasAccessToAnyTab) {
+ return (
+
+
+
Settings
+
+
+
+ You don't have permission to access any settings. Please contact an administrator for assistance.
+
+
+
+ );
+ }
+
return (
Settings
-
+
- Data Management
- Stock Management
-
- Performance Metrics
-
-
+
+ Data Management
+
+
+ Stock Management
+
+
+
+ Performance Metrics
+
+
+
Calculation Settings
-
- Template Management
-
-
+
+
+ Template Management
+
+
+
User Management
@@ -42,20 +99,53 @@ export function Settings() {
-
+
+
+ You don't have permission to access Data Management.
+
+
+ }
+ >
+
+
-
+
+
+ You don't have permission to access Stock Management.
+
+
+ }
+ >
+
+
-
+
+
+ You don't have permission to access Performance Metrics.
+
+
+ }
+ >
+
+
@@ -69,12 +159,23 @@ export function Settings() {
-
+
+
+ You don't have permission to access Template Management.
+
+
+ }
+ >
+
+