diff --git a/FRONTEND_INTEGRATION.md b/FRONTEND_INTEGRATION.md new file mode 100644 index 0000000..e945f95 --- /dev/null +++ b/FRONTEND_INTEGRATION.md @@ -0,0 +1,241 @@ +# Frontend Authentication Integration Guide + +This document provides guidance for integrating the frontend authentication system with backend APIs and existing SDLC Core components. + +## Authentication API Endpoints + +The frontend expects the following API endpoints to be implemented: + +### POST /auth/api/login +**Request:** +```json +{ + "username": "string", + "password": "string", + "rememberMe": boolean (optional) +} +``` + +**Response (Success - 200):** +```json +{ + "user": { + "id": number, + "username": "string", + "email": "string", + "roles": [ + { + "id": number, + "name": "string", + "description": "string" + } + ], + "isActive": boolean, + "memberSince": "string", + "lastLogin": "string" + }, + "token": "string" (optional - for JWT implementation) +} +``` + +**Response (Error - 401):** +```json +{ + "error": "Invalid credentials" +} +``` + +### POST /auth/api/register +**Request:** +```json +{ + "username": "string", + "email": "string", + "password": "string", + "confirmPassword": "string" +} +``` + +**Response:** Same as login success response + +### POST /auth/api/logout +**Request:** Empty body or JWT token in headers +**Response:** 200 OK + +### GET /auth/api/user/profile +**Request:** JWT token in Authorization header (if using JWT) +**Response:** User object (same format as login response) + +## Role-Based Access Integration + +### Available Roles +- `admin` - Full system administrator access +- `user` - Standard user access +- `moderator` - Content moderation access +- `analyst` - Analytics and reporting access +- `developer` - Development and deployment access + +### Using Authentication in Components + +```tsx +import { useAuth, RequireRole, RequireAuth } from '../stores/authStore'; + +// Check authentication status +const { isAuthenticated, user, hasRole } = useAuth(); + +// Protect entire components + + + + +// Protect by specific role + + + + +// Protect by multiple roles + + + + +// Check roles in code +if (hasRole('analyst')) { + // Show analytics features +} +``` + +### Protecting API Calls + +```tsx +import { useAuth } from '../stores/authStore'; + +const MyComponent = () => { + const { user, isAuthenticated } = useAuth(); + + const callProtectedAPI = async () => { + if (!isAuthenticated) { + throw new Error('User not authenticated'); + } + + // Include user token in API calls + const response = await fetch('/api/protected-endpoint', { + headers: { + 'Authorization': `Bearer ${user.token}`, // if using JWT + 'Content-Type': 'application/json' + } + }); + + return response.json(); + }; +}; +``` + +## Backend Integration Steps + +### 1. Update Authentication Store +Replace the mock API in `frontend/stores/authStore.tsx`: + +```tsx +// Replace mockApi object with actual API calls +const api = { + login: async (credentials: LoginCredentials): Promise => { + const response = await fetch('/auth/api/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(credentials) + }); + + if (!response.ok) { + const error = await response.json(); + throw new Error(error.message || 'Login failed'); + } + + return response.json(); + }, + + // ... implement other methods +}; +``` + +### 2. Add JWT Token Management (Optional) +If using JWT tokens: + +```tsx +// Add token to localStorage +localStorage.setItem('authToken', user.token); + +// Include token in API requests +const token = localStorage.getItem('authToken'); +headers: { + 'Authorization': `Bearer ${token}` +} + +// Remove token on logout +localStorage.removeItem('authToken'); +``` + +### 3. Environment Configuration +Add environment variables for API endpoints: + +```env +VITE_API_BASE_URL=http://localhost:3000 +VITE_AUTH_ENDPOINT=/auth/api +``` + +### 4. Error Handling +Update error handling for production: + +```tsx +// Add proper error boundaries +// Implement user-friendly error messages +// Add logging for authentication errors +``` + +## Security Considerations + +1. **HTTPS Only**: Ensure all authentication happens over HTTPS +2. **Token Expiration**: Implement proper token expiration and refresh +3. **Rate Limiting**: Add rate limiting to prevent brute force attacks +4. **Password Policies**: Enforce strong password requirements +5. **Session Management**: Implement secure session handling +6. **CSRF Protection**: Add CSRF token validation for forms + +## Testing + +The authentication system includes comprehensive test scenarios: + +1. **Login Flow**: Valid/invalid credentials, remember me functionality +2. **Registration**: New user creation, validation, role assignment +3. **Role Protection**: Access control for admin/user roles +4. **Navigation**: Context-aware navigation based on auth state +5. **Session Persistence**: Page refresh maintaining login state +6. **Logout**: Clean session termination + +## Demo Credentials + +For development/testing: +- Admin: `admin` / `admin123` +- User: `user` / `user123` + +Remove these before production deployment. + +## Component Architecture + +``` +AuthProvider (Context) +├── App (Main routing logic) +├── Navigation (Auth-aware navigation) +├── LoginForm (Authentication form) +├── RegisterForm (User registration) +├── Dashboard (User profile & info) +├── AdminPanel (Role-protected admin interface) +└── AuthGuards (HOCs for access control) + ├── RequireAuth + ├── RequireRole + ├── RequireAdmin + ├── RequireModerator + ├── RequireAnalyst + └── RequireDeveloper +``` + +This architecture provides a solid foundation for secure, role-based authentication throughout the SDLC Core system. \ No newline at end of file diff --git a/frontend/App.tsx b/frontend/App.tsx index 33e84a8..5cfde15 100644 --- a/frontend/App.tsx +++ b/frontend/App.tsx @@ -1,35 +1,79 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { SettingsProvider } from './stores/settingsStore'; +import { AuthProvider, useAuth } from './stores/authStore'; import { Navigation } from './components/Navigation'; import { SettingsPage } from './pages/SettingsPage'; -import { DashboardPage } from './pages/DashboardPage'; +import { HomePage } from './components/HomePage'; +import { LoginForm } from './components/LoginForm'; +import { RegisterForm } from './components/RegisterForm'; +import { Dashboard } from './components/Dashboard'; +import { AdminPanel } from './components/AdminPanel'; import './styles.css'; -function App() { - // Simple routing based on hash - const currentHash = window.location.hash.slice(1) || '/'; +const AppContent: React.FC = () => { + const { isAuthenticated, isLoading } = useAuth(); + const [currentHash, setCurrentHash] = useState(window.location.hash.slice(1) || '/'); + + // Handle hash changes without page reload + useEffect(() => { + const handleHashChange = () => { + setCurrentHash(window.location.hash.slice(1) || '/'); + }; + + window.addEventListener('hashchange', handleHashChange); + return () => window.removeEventListener('hashchange', handleHashChange); + }, []); + + // Redirect to dashboard when authenticated and on login/register pages + useEffect(() => { + if (isAuthenticated && (currentHash === '/login' || currentHash === '/register')) { + window.location.hash = '/dashboard'; + } + }, [isAuthenticated, currentHash]); const renderPage = () => { + if (isLoading) { + return ( +
+
+
+ ); + } + + // Public routes + if (currentHash === '/login') { + return ; + } + + if (currentHash === '/register') { + return ; + } + + // Protected routes + if (!isAuthenticated) { + if (currentHash === '/') { + return ; + } + // Redirect to login for protected routes + window.location.hash = '/login'; + return ; + } + + // Authenticated routes switch (currentHash) { + case '/dashboard': + return ; + case '/admin': + return ; case '/settings': return ; case '/': default: - return ; + // For authenticated users, default to dashboard + return ; } }; - // Update navigation links to use hash routing - React.useEffect(() => { - const handleHashChange = () => { - // Force re-render when hash changes - window.location.reload(); - }; - - window.addEventListener('hashchange', handleHashChange); - return () => window.removeEventListener('hashchange', handleHashChange); - }, []); - return (
@@ -38,6 +82,14 @@ function App() {
); +}; + +function App() { + return ( + + + + ); } export default App; \ No newline at end of file diff --git a/frontend/components/AdminPanel.tsx b/frontend/components/AdminPanel.tsx new file mode 100644 index 0000000..12bf7c1 --- /dev/null +++ b/frontend/components/AdminPanel.tsx @@ -0,0 +1,211 @@ +import React from 'react'; +import { RequireAdmin } from './AuthGuards'; + +// Mock data for admin panel +const mockUsers = [ + { + id: 1, + username: 'admin', + email: 'admin@sdlccore.com', + status: 'Active', + roles: ['admin'], + created: '08/15/2025' + }, + { + id: 2, + username: 'developer1', + email: 'dev@sdlccore.com', + status: 'Active', + roles: ['developer'], + created: '08/16/2025' + }, + { + id: 3, + username: 'analyst1', + email: 'analyst@sdlccore.com', + status: 'Active', + roles: ['analyst'], + created: '08/17/2025' + } +]; + +const mockRoles = [ + { + id: 1, + name: 'admin', + description: 'Full system administrator access' + }, + { + id: 2, + name: 'user', + description: 'Standard user access' + }, + { + id: 3, + name: 'moderator', + description: 'Content moderation access' + }, + { + id: 4, + name: 'analyst', + description: 'Analytics and reporting access' + }, + { + id: 5, + name: 'developer', + description: 'Development and deployment access' + } +]; + +export const AdminPanel: React.FC = () => { + return ( + +
+
Access Denied
+
You need administrator privileges to access this panel.
+
+ + }> +
+
+

Admin Panel

+

Manage users and roles in the system.

+
+ + {/* Users Management */} +
+
+

Users Management

+
+ +
+ + + + + + + + + + + + + + {mockUsers.map((user) => ( + + + + + + + + + + ))} + +
+ ID + + Username + + Email + + Status + + Roles + + Created + + Actions +
+ {user.id} + + {user.username} + + {user.email} + + + {user.status} + + +
+ {user.roles.map((role, index) => ( + + {role} + + ))} +
+
+ {user.created} + + + +
+
+
+ + {/* Roles Management */} +
+
+

Roles

+
+ +
+
+ {mockRoles.map((role) => ( +
+
+

+ {role.name} +

+ + {role.name} + +
+

+ {role.description} +

+
+ + +
+
+ ))} +
+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/frontend/components/AuthGuards.tsx b/frontend/components/AuthGuards.tsx new file mode 100644 index 0000000..73622a7 --- /dev/null +++ b/frontend/components/AuthGuards.tsx @@ -0,0 +1,75 @@ +import React, { ReactNode } from 'react'; +import { useAuth } from '../stores/authStore'; +import { UserRole } from '../types/auth'; + +interface RequireAuthProps { + children: ReactNode; + fallback?: ReactNode; +} + +export const RequireAuth: React.FC = ({ + children, + fallback =
Please log in to access this content.
+}) => { + const { isAuthenticated, isLoading } = useAuth(); + + if (isLoading) { + return
+
+
; + } + + if (!isAuthenticated) { + return <>{fallback}; + } + + return <>{children}; +}; + +interface RequireRoleProps { + children: ReactNode; + role: UserRole | UserRole[]; + fallback?: ReactNode; +} + +export const RequireRole: React.FC = ({ + children, + role, + fallback =
You don't have permission to access this content.
+}) => { + const { hasRole, hasAnyRole } = useAuth(); + + const hasPermission = Array.isArray(role) + ? hasAnyRole(role) + : hasRole(role); + + if (!hasPermission) { + return <>{fallback}; + } + + return <>{children}; +}; + +export const RequireAdmin: React.FC = ({ children, fallback }) => ( + + {children} + +); + +export const RequireModerator: React.FC = ({ children, fallback }) => ( + + {children} + +); + +export const RequireAnalyst: React.FC = ({ children, fallback }) => ( + + {children} + +); + +export const RequireDeveloper: React.FC = ({ children, fallback }) => ( + + {children} + +); \ No newline at end of file diff --git a/frontend/components/Dashboard.tsx b/frontend/components/Dashboard.tsx new file mode 100644 index 0000000..fe59510 --- /dev/null +++ b/frontend/components/Dashboard.tsx @@ -0,0 +1,165 @@ +import React from 'react'; +import { useAuth } from '../stores/authStore'; +import { Role } from '../types/auth'; + +const RoleBadge: React.FC<{ role: Role }> = ({ role }) => { + const getColorClass = (roleName: string) => { + switch (roleName) { + case 'admin': + return 'bg-red-100 text-red-800'; + case 'developer': + return 'bg-blue-100 text-blue-800'; + case 'analyst': + return 'bg-green-100 text-green-800'; + case 'moderator': + return 'bg-yellow-100 text-yellow-800'; + case 'user': + default: + return 'bg-gray-100 text-gray-800'; + } + }; + + return ( + + {role.name} + + ); +}; + +export const Dashboard: React.FC = () => { + const { user, logout, isLoading, hasRole } = useAuth(); + + if (!user) { + return null; + } + + const handleLogout = async () => { + try { + await logout(); + } catch (error) { + console.error('Logout failed:', error); + } + }; + + const handleRefreshProfile = () => { + window.location.reload(); + }; + + return ( +
+
+
+ + + + Logged in successfully! 👋 +
+
+ +
+

Dashboard

+

Welcome to your personal dashboard, {user.username}!

+
+ +
+
+

Profile Information

+
+ +
+
+
+
Username:
+
{user.username}
+
+ +
+
Email:
+
{user.email}
+
+ +
+
Account Status:
+
+ + {user.isActive ? 'Active' : 'Inactive'} + +
+
+ +
+
Member Since:
+
{user.memberSince}
+
+ +
+
Last Login:
+
{user.lastLogin}
+
+ +
+
Roles:
+
+
+ {user.roles.map((role) => ( + + ))} +
+
+
+
+
+
+ +
+
+

Quick Actions

+
+ +
+
+ {hasRole('admin') && ( + + Admin Panel + + )} + + + + +
+
+
+ +
+
+

System Info

+
+ +
+
+
SDLC Core Frontend Infrastructure
+
Role-based Authentication System
+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/frontend/components/HomePage.tsx b/frontend/components/HomePage.tsx new file mode 100644 index 0000000..aecd0f1 --- /dev/null +++ b/frontend/components/HomePage.tsx @@ -0,0 +1,177 @@ +import React from 'react'; + +export const HomePage: React.FC = () => { + return ( +
+ {/* Hero Section */} +
+
+
+

+ Welcome to SDLC Core +

+

+ A comprehensive software development lifecycle management platform with role-based authentication. +

+ +
+
+
+ + {/* Features Section */} +
+
+
+

+ Key Features +

+

+ Everything you need for modern software development lifecycle management +

+
+ +
+ {/* Role-Based Access */} +
+
+ + + +
+

Role-Based Access

+

+ Secure authentication system with granular role-based permissions. +

+
+ + {/* LLM Integration */} +
+
+ + + +
+

LLM Integration

+

+ Advanced AI capabilities with multiple LLM provider support. +

+
+ + {/* Analytics & Monitoring */} +
+
+ + + +
+

Analytics & Monitoring

+

+ Comprehensive analytics and monitoring for development workflows. +

+
+
+
+
+ + {/* Role-Based Access Details */} +
+
+
+

Role-Based Access

+

+ Secure authentication system with granular role-based permissions. +

+ +
+
+
+ A +
+

Admin

+

Full system access

+
+ +
+
+ D +
+

Developer

+

Code deployment

+
+ +
+
+ A +
+

Analyst

+

Data analysis

+
+ +
+
+ M +
+

Moderator

+

Content management

+
+ +
+
+ U +
+

User

+

Basic access

+
+
+
+
+
+ + {/* LLM Integration Details */} +
+
+
+

LLM Integration

+

+ Advanced AI capabilities with multiple LLM provider support. +

+ +
+
+

OpenAI GPT

+

Industry-leading language models

+
+
+

Anthropic Claude

+

Safe and helpful AI assistant

+
+
+

Custom Models

+

Support for specialized models

+
+
+
+
+
+ + {/* Analytics & Monitoring Details */} +
+
+
+

Analytics & Monitoring

+

+ Comprehensive analytics and monitoring for development workflows. +

+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/frontend/components/LoginForm.tsx b/frontend/components/LoginForm.tsx new file mode 100644 index 0000000..5365855 --- /dev/null +++ b/frontend/components/LoginForm.tsx @@ -0,0 +1,143 @@ +import React, { useState } from 'react'; +import { useAuth } from '../stores/authStore'; +import { LoginCredentials } from '../types/auth'; + +export const LoginForm: React.FC = () => { + const { login, isLoading, error, clearError } = useAuth(); + const [credentials, setCredentials] = useState({ + username: '', + password: '', + rememberMe: false + }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + clearError(); + + try { + await login(credentials); + // Navigation will be handled by the app based on auth state + } catch (error) { + // Error is handled by the auth store + } + }; + + const handleChange = (e: React.ChangeEvent) => { + const { name, value, type, checked } = e.target; + setCredentials(prev => ({ + ...prev, + [name]: type === 'checkbox' ? checked : value + })); + }; + + return ( +
+
+

+ Sign In +

+
+ +
+
+
+ {error && ( +
+ {error} +
+ )} + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ + +
+ +
+ +
+
+ +
+
+ Don't have an account? + + Register here + +
+
+ +
+
Demo accounts:
+
Admin: admin / admin123
+
User: user / user123
+
+
+
+ +
+ © 2024 SDLC Core. All rights reserved. +
+
+ ); +}; \ No newline at end of file diff --git a/frontend/components/Navigation.tsx b/frontend/components/Navigation.tsx index 74a33bc..365d92d 100644 --- a/frontend/components/Navigation.tsx +++ b/frontend/components/Navigation.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useAuth } from '../stores/authStore'; interface NavItemProps { href: string; @@ -22,7 +23,19 @@ const NavItem: React.FC = ({ href, children, isActive = false }) = }; export const Navigation: React.FC = () => { + const { user, isAuthenticated, logout, hasRole } = useAuth(); + const [isUserMenuOpen, setIsUserMenuOpen] = useState(false); const currentHash = window.location.hash.slice(1) || '/'; + + const handleLogout = async () => { + try { + await logout(); + setIsUserMenuOpen(false); + window.location.hash = '/'; + } catch (error) { + console.error('Logout failed:', error); + } + }; return (