refactor: Modularize IAM service routes into dedicated modules and add home page description
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from '@/hooks/use-translation';
|
||||
|
||||
/**
|
||||
@@ -16,39 +16,84 @@ export default function Home() {
|
||||
// VI: Lấy trạng thái xác thực từ store
|
||||
const { user, isAuthenticated, isLoading, fetchUser } = useAuthStore();
|
||||
|
||||
// EN: State to track if component is mounted on client
|
||||
// VI: State để theo dõi xem component đã mount trên client chưa
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
// EN: Set mounted state to true on client side
|
||||
// VI: Đặt trạng thái mounted thành true ở phía client
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
// EN: Fetch user data on component mount if not authenticated
|
||||
// VI: Fetch dữ liệu user khi component mount nếu chưa xác thực
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated && !isLoading) {
|
||||
if (isMounted && !isAuthenticated) {
|
||||
fetchUser();
|
||||
}
|
||||
}, [isAuthenticated, isLoading, fetchUser]);
|
||||
// EN: Only run once when mounted or fetchUser changes (which is stable)
|
||||
// VI: Chỉ chạy một lần khi mounted hoặc fetchUser thay đổi (ổn định)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isMounted]);
|
||||
|
||||
// EN: Prevent hydration mismatch by not rendering auth-dependent content until mounted
|
||||
// VI: Ngăn chặn hydration mismatch bằng cách không render nội dung phụ thuộc auth cho đến khi mounted
|
||||
if (!isMounted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// EN: Show loading state while checking authentication
|
||||
// VI: Hiển thị trạng thái loading trong khi kiểm tra xác thực
|
||||
if (isLoading) {
|
||||
return <div className="p-8">{t('common.loading')}</div>;
|
||||
return <div className="min-h-screen flex items-center justify-center p-8 bg-bg-primary text-text-primary">{t('common.loading')}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
// EN: Main content area with responsive padding
|
||||
// VI: Khu vực nội dung chính với padding responsive
|
||||
<main className="min-h-screen p-8">
|
||||
<h1 className="text-4xl font-bold mb-4">{t('home.title')}</h1>
|
||||
// EN: Main content area with centered layout for minimal aesthetic
|
||||
// VI: Khu vực nội dung chính với layout căn giữa cho thẩm mỹ tối giản
|
||||
<main className="min-h-screen flex flex-col items-center justify-center p-8 text-center bg-bg-primary text-text-primary">
|
||||
<div className="max-w-container-md w-full space-y-8 animate-fadeIn">
|
||||
{/* EN: Hero Title / VI: Tiêu đề Hero */}
|
||||
<h1 className="text-6xl font-bold tracking-tight mb-2 font-display">
|
||||
{t('home.title')}
|
||||
</h1>
|
||||
|
||||
{/* EN: Conditional rendering based on authentication status / VI: Render có điều kiện dựa trên trạng thái xác thực */}
|
||||
{isAuthenticated && user ? (
|
||||
// EN: Authenticated user welcome message / VI: Thông báo chào mừng người dùng đã xác thực
|
||||
<div>
|
||||
<p>{t('home.welcome', { email: user.email })}</p>
|
||||
<p>{t('home.role', { role: user.role })}</p>
|
||||
{/* EN: Subtitle/Description / VI: Phụ đề/Mô tả */}
|
||||
<p className="text-xl text-text-secondary max-w-lg mx-auto leading-relaxed">
|
||||
{t('home.description')}
|
||||
</p>
|
||||
|
||||
{/* EN: Conditional rendering based on authentication status / VI: Render có điều kiện dựa trên trạng thái xác thực */}
|
||||
<div className="pt-8">
|
||||
{isAuthenticated && user ? (
|
||||
// EN: Authenticated user welcome message / VI: Thông báo chào mừng người dùng đã xác thực
|
||||
<div className="space-y-4 p-6 rounded-2xl bg-bg-secondary border border-border-primary inline-block min-w-[300px]">
|
||||
<div className="w-16 h-16 bg-bg-tertiary rounded-full mx-auto flex items-center justify-center mb-4 text-2xl">
|
||||
{user.email?.[0].toUpperCase()}
|
||||
</div>
|
||||
<p className="text-lg font-medium">{t('home.welcome', { email: user.email })}</p>
|
||||
<div className="inline-flex items-center px-3 py-1 rounded-full bg-bg-tertiary text-text-secondary text-sm">
|
||||
<span className="w-2 h-2 rounded-full bg-accent-success mr-2"></span>
|
||||
{t('home.role', { role: user.role })}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
// EN: Login prompt for unauthenticated users / VI: Nhắc đăng nhập cho người dùng chưa xác thực
|
||||
<div className="space-y-6">
|
||||
<p className="text-text-secondary">{t('home.pleaseLogin')}</p>
|
||||
<div className="flex gap-4 justify-center">
|
||||
<a
|
||||
href="/auth/login"
|
||||
className="px-8 py-3 rounded-full bg-text-primary text-bg-primary font-medium hover:bg-text-secondary transition-colors"
|
||||
>
|
||||
Login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
// EN: Login prompt for unauthenticated users / VI: Nhắc đăng nhập cho người dùng chưa xác thực
|
||||
<div>
|
||||
<p>{t('home.pleaseLogin')}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -341,6 +341,7 @@
|
||||
},
|
||||
"home": {
|
||||
"title": "GoodGo Platform",
|
||||
"description": "Experience the next generation of minimal intelligence.",
|
||||
"welcome": "Welcome, {email}!",
|
||||
"role": "Role: {role}",
|
||||
"pleaseLogin": "Please log in to continue."
|
||||
@@ -396,4 +397,4 @@
|
||||
"enable": "Enable"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,6 +341,7 @@
|
||||
},
|
||||
"home": {
|
||||
"title": "Nền tảng GoodGo",
|
||||
"description": "Trải nghiệm thế hệ tiếp theo của trí tuệ tối giản.",
|
||||
"welcome": "Chào mừng, {email}!",
|
||||
"role": "Vai trò: {role}",
|
||||
"pleaseLogin": "Vui lòng đăng nhập để tiếp tục."
|
||||
@@ -396,4 +397,4 @@
|
||||
"enable": "Bật"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,163 +14,235 @@
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Color Palette - Dark Mode (Primary Theme)
|
||||
VI: Bảng màu - Dark Mode (Theme chính)
|
||||
============================================ */
|
||||
|
||||
/* Background Colors / Màu nền */
|
||||
--bg-primary: #0A0A0A; /* Almost black - Main background */
|
||||
--bg-secondary: #121212; /* Dark grey - Card/Panel background */
|
||||
--bg-tertiary: #1A1A1A; /* Dark grey - Hover states */
|
||||
--bg-elevated: #242424; /* Elevated surfaces (modals, dropdowns) */
|
||||
/* Background Colors / Màu nền */
|
||||
--bg-primary: #000000;
|
||||
/* Pure black - Main background */
|
||||
--bg-secondary: #0A0A0A;
|
||||
/* Almost black - Card/Panel background */
|
||||
--bg-tertiary: #141414;
|
||||
/* Very dark grey - Hover states */
|
||||
--bg-elevated: #1A1A1A;
|
||||
/* Elevated surfaces (modals, dropdowns) */
|
||||
|
||||
/* Text Colors (WCAG Compliant) / Màu chữ (tuân thủ WCAG) */
|
||||
--text-primary: #FAFAFA; /* Off-white - Primary text (4.5:1 contrast) */
|
||||
--text-secondary: #E0E0E0; /* Light grey - Secondary text */
|
||||
--text-tertiary: #A0A0A0; /* Grey - Tertiary/disabled text */
|
||||
--text-inverse: #1A1A1A; /* Dark - Text on light backgrounds */
|
||||
/* Text Colors (WCAG Compliant) / Màu chữ (tuân thủ WCAG) */
|
||||
--text-primary: #FFFFFF;
|
||||
/* Pure white - Primary text */
|
||||
--text-secondary: #888888;
|
||||
/* Mid grey - Secondary text */
|
||||
--text-tertiary: #444444;
|
||||
/* Dark grey - Tertiary/disabled text */
|
||||
--text-inverse: #000000;
|
||||
/* Black - Text on light/white backgrounds */
|
||||
|
||||
/* Brand/Accent Colors / Màu thương hiệu/Accent */
|
||||
--accent-primary: #3B82F6; /* Primary blue - CTAs, links */
|
||||
--accent-secondary: #8B5CF6; /* Purple - Highlights */
|
||||
--accent-success: #10B981; /* Green - Success states */
|
||||
--accent-warning: #F59E0B; /* Amber - Warnings */
|
||||
--accent-error: #EF4444; /* Red - Errors */
|
||||
--accent-info: #06B6D4; /* Cyan - Info */
|
||||
/* Brand/Accent Colors / Màu thương hiệu/Accent */
|
||||
--accent-primary: #FFFFFF;
|
||||
/* White - Primary actions (High contrast) */
|
||||
--accent-secondary: #333333;
|
||||
/* Dark grey - Secondary actions */
|
||||
--accent-success: #10B981;
|
||||
/* Green - Success states */
|
||||
--accent-warning: #F59E0B;
|
||||
/* Amber - Warnings */
|
||||
--accent-error: #EF4444;
|
||||
/* Red - Errors */
|
||||
--accent-info: #06B6D4;
|
||||
/* Cyan - Info */
|
||||
|
||||
/* Chat Specific Colors / Màu riêng cho Chat */
|
||||
--chat-user-bubble: #2563EB; /* Deep blue - User message */
|
||||
--chat-ai-bubble: #374151; /* Dark grey - AI message */
|
||||
--chat-user-text: #FFFFFF; /* White text on blue */
|
||||
--chat-ai-text: #F3F4F6; /* Light text on grey */
|
||||
--chat-timestamp: #9CA3AF; /* Timestamp grey */
|
||||
--chat-divider: #1F2937; /* Divider between messages */
|
||||
/* Chat Specific Colors / Màu riêng cho Chat */
|
||||
--chat-user-bubble: #1A1A1A;
|
||||
/* Dark grey - User message */
|
||||
--chat-ai-bubble: transparent;
|
||||
/* Transparent - AI message (Minimal) */
|
||||
--chat-user-text: #FFFFFF;
|
||||
/* White text */
|
||||
--chat-ai-text: #E5E5E5;
|
||||
/* Off-white text */
|
||||
--chat-timestamp: #555555;
|
||||
/* Dark grey timestamp */
|
||||
--chat-divider: #222222;
|
||||
/* Divider between messages */
|
||||
|
||||
/* Border Colors / Màu viền */
|
||||
--border-primary: #2A2A2A; /* Default borders */
|
||||
--border-secondary: #3A3A3A; /* Hover borders */
|
||||
--border-focus: #3B82F6; /* Focus state - Blue */
|
||||
/* Border Colors / Màu viền */
|
||||
--border-primary: #222222;
|
||||
/* Subtle borders */
|
||||
--border-secondary: #333333;
|
||||
/* Hover borders */
|
||||
--border-focus: #FFFFFF;
|
||||
/* Focus state - White */
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Light Mode Colors (Secondary Theme)
|
||||
VI: Màu sắc cho Light Mode (Theme phụ)
|
||||
============================================ */
|
||||
--bg-primary-light: #FFFFFF;
|
||||
--bg-secondary-light: #F9FAFB;
|
||||
--bg-tertiary-light: #F3F4F6;
|
||||
--text-primary-light: #111827;
|
||||
--text-secondary-light: #4B5563;
|
||||
--border-primary-light: #E5E7EB;
|
||||
--bg-primary-light: #F9F9F9;
|
||||
--bg-secondary-light: #FFFFFF;
|
||||
--bg-tertiary-light: #F0F0F0;
|
||||
--text-primary-light: #000000;
|
||||
--text-secondary-light: #666666;
|
||||
--border-primary-light: #E5E5E5;
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Typography
|
||||
VI: Kiểu chữ
|
||||
============================================ */
|
||||
|
||||
/* Font Stack / Bộ font */
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--font-mono: "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
/* Font Stack / Bộ font */
|
||||
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--font-mono: "JetBrains Mono", "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
|
||||
/* Type Scale / Kích thước chữ */
|
||||
--text-6xl: 3.75rem; /* 60px - Hero titles */
|
||||
--text-5xl: 3rem; /* 48px - Page titles */
|
||||
--text-4xl: 2.25rem; /* 36px - Section headers */
|
||||
--text-3xl: 1.875rem; /* 30px - Card headers */
|
||||
--text-2xl: 1.5rem; /* 24px - Large body */
|
||||
--text-xl: 1.25rem; /* 20px - Emphasized text */
|
||||
--text-lg: 1.125rem; /* 18px - Large body */
|
||||
--text-base: 1rem; /* 16px - Default body */
|
||||
--text-sm: 0.875rem; /* 14px - Small text */
|
||||
--text-xs: 0.75rem; /* 12px - Captions */
|
||||
/* Type Scale / Kích thước chữ */
|
||||
--text-6xl: 3.75rem;
|
||||
/* 60px - Hero titles */
|
||||
--text-5xl: 3rem;
|
||||
/* 48px - Page titles */
|
||||
--text-4xl: 2.25rem;
|
||||
/* 36px - Section headers */
|
||||
--text-3xl: 1.875rem;
|
||||
/* 30px - Card headers */
|
||||
--text-2xl: 1.5rem;
|
||||
/* 24px - Large body */
|
||||
--text-xl: 1.25rem;
|
||||
/* 20px - Emphasized text */
|
||||
--text-lg: 1.125rem;
|
||||
/* 18px - Large body */
|
||||
--text-base: 1rem;
|
||||
/* 16px - Default body */
|
||||
--text-sm: 0.875rem;
|
||||
/* 14px - Small text */
|
||||
--text-xs: 0.75rem;
|
||||
/* 12px - Captions */
|
||||
|
||||
/* Line Heights / Chiều cao dòng */
|
||||
--leading-none: 1;
|
||||
--leading-tight: 1.1;
|
||||
--leading-snug: 1.2;
|
||||
--leading-normal: 1.3;
|
||||
--leading-relaxed: 1.4;
|
||||
--leading-loose: 1.5;
|
||||
/* Line Heights / Chiều cao dòng */
|
||||
--leading-none: 1;
|
||||
--leading-tight: 1.1;
|
||||
--leading-snug: 1.2;
|
||||
--leading-normal: 1.5;
|
||||
--leading-relaxed: 1.625;
|
||||
--leading-loose: 2;
|
||||
|
||||
/* Font Weights / Độ đậm chữ */
|
||||
--font-light: 300; /* Light text */
|
||||
--font-normal: 400; /* Body text */
|
||||
--font-medium: 500; /* Emphasized */
|
||||
--font-semibold: 600; /* Headings */
|
||||
--font-bold: 700; /* Strong emphasis */
|
||||
/* Font Weights / Độ đậm chữ */
|
||||
--font-light: 300;
|
||||
/* Light text */
|
||||
--font-normal: 400;
|
||||
/* Body text */
|
||||
--font-medium: 500;
|
||||
/* Emphasized */
|
||||
--font-semibold: 600;
|
||||
/* Headings */
|
||||
--font-bold: 700;
|
||||
/* Strong emphasis */
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Spacing & Layout
|
||||
VI: Khoảng cách & Bố cục
|
||||
============================================ */
|
||||
|
||||
/* Base Unit: 4px (0.25rem) / Đơn vị cơ sở: 4px (0.25rem) */
|
||||
--space-0: 0;
|
||||
--space-1: 0.25rem; /* 4px */
|
||||
--space-2: 0.5rem; /* 8px */
|
||||
--space-3: 0.75rem; /* 12px */
|
||||
--space-4: 1rem; /* 16px */
|
||||
--space-5: 1.25rem; /* 20px */
|
||||
--space-6: 1.5rem; /* 24px */
|
||||
--space-8: 2rem; /* 32px */
|
||||
--space-10: 2.5rem; /* 40px */
|
||||
--space-12: 3rem; /* 48px */
|
||||
--space-16: 4rem; /* 64px */
|
||||
--space-20: 5rem; /* 80px */
|
||||
/* Base Unit: 4px (0.25rem) / Đơn vị cơ sở: 4px (0.25rem) */
|
||||
--space-0: 0;
|
||||
--space-1: 0.25rem;
|
||||
/* 4px */
|
||||
--space-2: 0.5rem;
|
||||
/* 8px */
|
||||
--space-3: 0.75rem;
|
||||
/* 12px */
|
||||
--space-4: 1rem;
|
||||
/* 16px */
|
||||
--space-5: 1.25rem;
|
||||
/* 20px */
|
||||
--space-6: 1.5rem;
|
||||
/* 24px */
|
||||
--space-8: 2rem;
|
||||
/* 32px */
|
||||
--space-10: 2.5rem;
|
||||
/* 40px */
|
||||
--space-12: 3rem;
|
||||
/* 48px */
|
||||
--space-16: 4rem;
|
||||
/* 64px */
|
||||
--space-20: 5rem;
|
||||
/* 80px */
|
||||
|
||||
/* Container Widths / Chiều rộng container */
|
||||
--container-sm: 640px; /* Small devices */
|
||||
--container-md: 768px; /* Medium devices */
|
||||
--container-lg: 1024px; /* Large devices */
|
||||
--container-xl: 1280px; /* Extra large */
|
||||
--container-2xl: 1536px; /* 2X large */
|
||||
--chat-max-width: 768px; /* Max width for chat messages */
|
||||
--sidebar-width: 280px; /* Conversation history sidebar */
|
||||
/* Container Widths / Chiều rộng container */
|
||||
--container-sm: 640px;
|
||||
/* Small devices */
|
||||
--container-md: 768px;
|
||||
/* Medium devices */
|
||||
--container-lg: 1024px;
|
||||
/* Large devices */
|
||||
--container-xl: 1280px;
|
||||
/* Extra large */
|
||||
--container-2xl: 1536px;
|
||||
/* 2X large */
|
||||
--chat-max-width: 800px;
|
||||
/* Max width for chat messages */
|
||||
--sidebar-width: 280px;
|
||||
/* Conversation history sidebar */
|
||||
|
||||
/* Border Radius / Bo góc */
|
||||
--radius-sm: 0.25rem; /* 4px - Small elements */
|
||||
--radius-md: 0.5rem; /* 8px - Buttons, inputs */
|
||||
--radius-lg: 0.75rem; /* 12px - Cards */
|
||||
--radius-xl: 1rem; /* 16px - Large cards */
|
||||
--radius-2xl: 1.5rem; /* 24px - Modals */
|
||||
--radius-full: 9999px; /* Full round - Avatars, pills */
|
||||
/* Border Radius / Bo góc */
|
||||
--radius-sm: 2px;
|
||||
/* Small elements - sharp */
|
||||
--radius-md: 4px;
|
||||
/* Buttons, inputs - sharp */
|
||||
--radius-lg: 8px;
|
||||
/* Cards - minimal roundness */
|
||||
--radius-xl: 12px;
|
||||
/* Large cards */
|
||||
--radius-2xl: 16px;
|
||||
/* Modals */
|
||||
--radius-full: 9999px;
|
||||
/* Full round - Avatars, pills */
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Shadows (Dark Mode Optimized)
|
||||
VI: Đổ bóng (Tối ưu cho Dark Mode)
|
||||
============================================ */
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.5);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.6);
|
||||
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.7);
|
||||
--shadow-glow: 0 0 20px rgba(59, 130, 246, 0.3); /* Blue glow for focus */
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.8);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.9);
|
||||
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.95);
|
||||
--shadow-glow: 0 0 20px rgba(255, 255, 255, 0.1);
|
||||
/* White glow for focus */
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Grid System & Breakpoints
|
||||
VI: Hệ thống lưới & Điểm ngắt
|
||||
============================================ */
|
||||
--screen-sm: 640px; /* Mobile landscape */
|
||||
--screen-md: 768px; /* Tablet */
|
||||
--screen-lg: 1024px; /* Desktop */
|
||||
--screen-xl: 1280px; /* Large desktop */
|
||||
--screen-2xl: 1536px; /* Extra large desktop */
|
||||
--screen-sm: 640px;
|
||||
/* Mobile landscape */
|
||||
--screen-md: 768px;
|
||||
/* Tablet */
|
||||
--screen-lg: 1024px;
|
||||
/* Desktop */
|
||||
--screen-xl: 1280px;
|
||||
/* Large desktop */
|
||||
--screen-2xl: 1536px;
|
||||
/* Extra large desktop */
|
||||
|
||||
/* ============================================
|
||||
/* ============================================
|
||||
EN: Animation & Transitions
|
||||
VI: Animation & Chuyển tiếp
|
||||
============================================ */
|
||||
|
||||
/* Timing Functions / Hàm thời gian */
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
/* Timing Functions / Hàm thời gian */
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
|
||||
/* Duration / Thời lượng */
|
||||
--duration-fast: 150ms; /* Hover effects */
|
||||
--duration-normal: 250ms; /* Default transitions */
|
||||
--duration-slow: 350ms; /* Complex animations */
|
||||
--duration-slower: 500ms; /* Page transitions */
|
||||
/* Duration / Thời lượng */
|
||||
--duration-fast: 150ms;
|
||||
/* Hover effects */
|
||||
--duration-normal: 250ms;
|
||||
/* Default transitions */
|
||||
--duration-slow: 350ms;
|
||||
/* Complex animations */
|
||||
--duration-slower: 500ms;
|
||||
/* Page transitions */
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -178,14 +250,14 @@
|
||||
VI: Ghi đè theme cho Light Mode
|
||||
============================================ */
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--bg-primary: var(--bg-primary-light);
|
||||
--bg-secondary: var(--bg-secondary-light);
|
||||
--bg-tertiary: var(--bg-tertiary-light);
|
||||
--text-primary: var(--text-primary-light);
|
||||
--text-secondary: var(--text-secondary-light);
|
||||
--border-primary: var(--border-primary-light);
|
||||
}
|
||||
:root {
|
||||
--bg-primary: var(--bg-primary-light);
|
||||
--bg-secondary: var(--bg-secondary-light);
|
||||
--bg-tertiary: var(--bg-tertiary-light);
|
||||
--text-primary: var(--text-primary-light);
|
||||
--text-secondary: var(--text-secondary-light);
|
||||
--border-primary: var(--border-primary-light);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -194,15 +266,15 @@
|
||||
============================================ */
|
||||
[data-theme="dark"],
|
||||
.dark {
|
||||
--bg-primary: #0A0A0A;
|
||||
--bg-secondary: #121212;
|
||||
--bg-tertiary: #1A1A1A;
|
||||
--bg-elevated: #242424;
|
||||
--text-primary: #FAFAFA;
|
||||
--text-secondary: #E0E0E0;
|
||||
--text-tertiary: #A0A0A0;
|
||||
--border-primary: #2A2A2A;
|
||||
--border-secondary: #3A3A3A;
|
||||
--bg-primary: #000000;
|
||||
--bg-secondary: #0A0A0A;
|
||||
--bg-tertiary: #141414;
|
||||
--bg-elevated: #1A1A1A;
|
||||
--text-primary: #FFFFFF;
|
||||
--text-secondary: #888888;
|
||||
--text-tertiary: #444444;
|
||||
--border-primary: #222222;
|
||||
--border-secondary: #333333;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -211,10 +283,10 @@
|
||||
============================================ */
|
||||
[data-theme="light"],
|
||||
.light {
|
||||
--bg-primary: var(--bg-primary-light);
|
||||
--bg-secondary: var(--bg-secondary-light);
|
||||
--bg-tertiary: var(--bg-tertiary-light);
|
||||
--text-primary: var(--text-primary-light);
|
||||
--text-secondary: var(--text-secondary-light);
|
||||
--border-primary: var(--border-primary-light);
|
||||
}
|
||||
--bg-primary: var(--bg-primary-light);
|
||||
--bg-secondary: var(--bg-secondary-light);
|
||||
--bg-tertiary: var(--bg-tertiary-light);
|
||||
--text-primary: var(--text-primary-light);
|
||||
--text-secondary: var(--text-secondary-light);
|
||||
--border-primary: var(--border-primary-light);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Application } from 'express';
|
||||
import swaggerJSDoc from 'swagger-jsdoc';
|
||||
import swaggerUi from 'swagger-ui-express';
|
||||
import { appConfig } from '../config/app.config';
|
||||
|
||||
/**
|
||||
* EN: Swagger/OpenAPI configuration for API documentation
|
||||
@@ -29,7 +30,7 @@ const options = {
|
||||
description: 'Development server',
|
||||
variables: {
|
||||
port: {
|
||||
default: '5000',
|
||||
default: String(appConfig.port),
|
||||
description: 'Port number for the development server',
|
||||
},
|
||||
},
|
||||
@@ -104,6 +105,155 @@ const options = {
|
||||
},
|
||||
required: ['success', 'error', 'timestamp'],
|
||||
},
|
||||
RegisterRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email', example: 'user@example.com' },
|
||||
password: { type: 'string', minLength: 8, example: 'StrongP@ssw0rd!' },
|
||||
username: { type: 'string', minLength: 3, example: 'johndoe' },
|
||||
},
|
||||
required: ['email', 'password'],
|
||||
},
|
||||
RegisterResponse: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user: { $ref: '#/components/schemas/User' },
|
||||
token: { type: 'string' },
|
||||
},
|
||||
},
|
||||
LoginRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email', example: 'user@example.com' },
|
||||
password: { type: 'string', example: 'StrongP@ssw0rd!' },
|
||||
},
|
||||
required: ['email', 'password'],
|
||||
},
|
||||
LoginResponse: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
accessToken: { type: 'string' },
|
||||
refreshToken: { type: 'string' },
|
||||
user: { $ref: '#/components/schemas/User' },
|
||||
},
|
||||
},
|
||||
User: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', example: 'cuid12345' },
|
||||
email: { type: 'string', format: 'email' },
|
||||
username: { type: 'string' },
|
||||
firstName: { type: 'string' },
|
||||
lastName: { type: 'string' },
|
||||
isActive: { type: 'boolean' },
|
||||
isEmailVerified: { type: 'boolean' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
updatedAt: { type: 'string', format: 'date-time' },
|
||||
},
|
||||
},
|
||||
CreateUserRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' },
|
||||
username: { type: 'string' },
|
||||
firstName: { type: 'string' },
|
||||
lastName: { type: 'string' },
|
||||
phone: { type: 'string' },
|
||||
},
|
||||
required: ['email'],
|
||||
},
|
||||
Organization: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
domain: { type: 'string' },
|
||||
isActive: { type: 'boolean' },
|
||||
parentId: { type: 'string' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
updatedAt: { type: 'string', format: 'date-time' },
|
||||
},
|
||||
},
|
||||
CreateOrganizationRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
domain: { type: 'string' },
|
||||
parentId: { type: 'string' },
|
||||
settings: { type: 'object' },
|
||||
},
|
||||
required: ['name'],
|
||||
},
|
||||
UpdateOrganizationRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
domain: { type: 'string' },
|
||||
parentId: { type: 'string' },
|
||||
settings: { type: 'object' },
|
||||
isActive: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
organizationId: { type: 'string' },
|
||||
isActive: { type: 'boolean' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
updatedAt: { type: 'string', format: 'date-time' },
|
||||
},
|
||||
},
|
||||
CreateGroupRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
organizationId: { type: 'string' },
|
||||
},
|
||||
required: ['name'],
|
||||
},
|
||||
UpdateGroupRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
isActive: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
UserProfile: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
userId: { type: 'string' },
|
||||
avatarUrl: { type: 'string' },
|
||||
bio: { type: 'string' },
|
||||
phoneNumber: { type: 'string' },
|
||||
address: { type: 'string' },
|
||||
preferences: { type: 'object' },
|
||||
},
|
||||
},
|
||||
UpdateProfileRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: { type: 'string' },
|
||||
lastName: { type: 'string' },
|
||||
phone: { type: 'string' },
|
||||
avatarUrl: { type: 'string' },
|
||||
preferences: { type: 'object' },
|
||||
},
|
||||
},
|
||||
UpdateUserRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
username: { type: 'string' },
|
||||
email: { type: 'string', format: 'email' },
|
||||
isActive: { type: 'boolean' },
|
||||
organizationId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
Feature: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -304,7 +454,17 @@ const options = {
|
||||
},
|
||||
],
|
||||
},
|
||||
apis: ['./src/routes/*.ts', './src/modules/*/feature.module.ts'], // Paths to files containing OpenAPI definitions
|
||||
apis: [
|
||||
'./src/routes/*.ts',
|
||||
'./src/modules/auth/*.routes.ts',
|
||||
'./src/modules/session/*.routes.ts',
|
||||
'./src/modules/oidc/*.routes.ts',
|
||||
'./src/modules/rbac/*.routes.ts',
|
||||
'./src/modules/mfa/*.routes.ts',
|
||||
'./src/modules/identity/*.routes.ts',
|
||||
'./src/modules/access/*.routes.ts',
|
||||
'./src/modules/governance/*.routes.ts'
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -357,7 +517,7 @@ export const setupSwagger = (app: Application, basePath: string = '/api-docs') =
|
||||
res.send(JSON.stringify(specs, null, 2));
|
||||
});
|
||||
|
||||
console.log(`📚 Swagger documentation available at: http://localhost:5000${basePath}`);
|
||||
console.log(`📚 Swagger documentation available at: http://localhost:${appConfig.port}${basePath}`);
|
||||
};
|
||||
|
||||
export { specs };
|
||||
|
||||
591
services/iam-service/src/modules/access/access.routes.ts
Normal file
591
services/iam-service/src/modules/access/access.routes.ts
Normal file
@@ -0,0 +1,591 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { requirePermission } from '../../middlewares/rbac.middleware';
|
||||
import { accessRequestController } from './request';
|
||||
import { accessReviewController } from './review';
|
||||
import { accessAnalyticsController } from './analytics';
|
||||
|
||||
/**
|
||||
* EN: Create and configure Access Management routes
|
||||
* VI: Tạo và cấu hình routes cho Access Management
|
||||
*/
|
||||
export const createAccessRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
// =============================================================================
|
||||
// EN: Access Request Endpoints
|
||||
// VI: Endpoints Yêu Cầu Truy Cập
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests:
|
||||
* get:
|
||||
* summary: List access requests
|
||||
* description: List access requests visible to the current user
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: query
|
||||
* name: status
|
||||
* schema:
|
||||
* type: string
|
||||
* enum: [PENDING, APPROVED, REJECTED, CANCELLED]
|
||||
* - in: query
|
||||
* name: page
|
||||
* schema:
|
||||
* type: integer
|
||||
* - in: query
|
||||
* name: limit
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Requests list
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/AccessRequest'
|
||||
*/
|
||||
router.get('/requests', authenticate(), accessRequestController.list.bind(accessRequestController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests:
|
||||
* post:
|
||||
* summary: Create access request
|
||||
* description: Submit a new access request
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/CreateAccessRequest'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Request created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/AccessRequest'
|
||||
*/
|
||||
router.post('/requests', authenticate(), accessRequestController.create.bind(accessRequestController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests/{id}:
|
||||
* get:
|
||||
* summary: Get access request
|
||||
* description: Get access request details
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Request ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Request details
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/AccessRequest'
|
||||
*/
|
||||
router.get('/requests/:id', authenticate(), accessRequestController.get.bind(accessRequestController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests/{id}/approve:
|
||||
* put:
|
||||
* summary: Approve access request
|
||||
* description: Approve a pending access request
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Request ID
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* comment:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Request approved
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.put('/requests/:id/approve', authenticate(), requirePermission('access', 'approve'), accessRequestController.approve.bind(accessRequestController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests/{id}/reject:
|
||||
* put:
|
||||
* summary: Reject access request
|
||||
* description: Reject a pending access request
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Request ID
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* comment:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Request rejected
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.put('/requests/:id/reject', authenticate(), requirePermission('access', 'approve'), accessRequestController.reject.bind(accessRequestController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/requests/{id}:
|
||||
* delete:
|
||||
* summary: Cancel access request
|
||||
* description: Cancel a pending access request
|
||||
* tags: [Access - Requests]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Request ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Request cancelled
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.delete('/requests/:id', authenticate(), accessRequestController.cancel.bind(accessRequestController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Access Review Endpoints
|
||||
// VI: Endpoints Đánh Giá Truy Cập
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews:
|
||||
* get:
|
||||
* summary: List access reviews
|
||||
* description: List access reviews
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Reviews list
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/AccessReview'
|
||||
*/
|
||||
router.get('/reviews', authenticate(), requirePermission('access', 'read'), accessReviewController.list.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews:
|
||||
* post:
|
||||
* summary: Create access review
|
||||
* description: Create a new access review campaign
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/CreateAccessReviewRequest'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Review created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/AccessReview'
|
||||
*/
|
||||
router.post('/reviews', authenticate(), requirePermission('access', 'create'), accessReviewController.create.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews/{id}:
|
||||
* get:
|
||||
* summary: Get access review
|
||||
* description: Get access review details
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Review ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Review details
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/AccessReview'
|
||||
*/
|
||||
router.get('/reviews/:id', authenticate(), requirePermission('access', 'read'), accessReviewController.get.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews/{id}/start:
|
||||
* post:
|
||||
* summary: Start access review
|
||||
* description: Start an access review campaign
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Review ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Review started
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/reviews/:id/start', authenticate(), requirePermission('access', 'update'), accessReviewController.start.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews/{id}/complete:
|
||||
* post:
|
||||
* summary: Complete access review
|
||||
* description: Complete an access review campaign
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Review ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Review completed
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/reviews/:id/complete', authenticate(), requirePermission('access', 'update'), accessReviewController.complete.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews/{id}/items:
|
||||
* get:
|
||||
* summary: Get review items
|
||||
* description: Get items in an access review
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Review ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Review items
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/AccessReviewItem'
|
||||
*/
|
||||
router.get('/reviews/:id/items', authenticate(), requirePermission('access', 'read'), accessReviewController.getItems.bind(accessReviewController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/reviews/{id}/items/{itemId}/review:
|
||||
* put:
|
||||
* summary: Review item
|
||||
* description: Make a decision on a review item (Certify/Revoke)
|
||||
* tags: [Access - Reviews]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Review ID
|
||||
* - in: path
|
||||
* name: itemId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Item ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [decision]
|
||||
* properties:
|
||||
* decision:
|
||||
* type: string
|
||||
* enum: [CERTIFY, REVOKE]
|
||||
* comment:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Item reviewed
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.put('/reviews/:id/items/:itemId/review', authenticate(), requirePermission('access', 'update'), accessReviewController.reviewItem.bind(accessReviewController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Analytics Endpoints
|
||||
// VI: Endpoints Analytics
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/analytics/usage:
|
||||
* get:
|
||||
* summary: Access usage analytics
|
||||
* description: Get access usage analytics
|
||||
* tags: [Access - Analytics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Usage analytics
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/analytics/usage', authenticate(), requirePermission('access', 'read'), accessAnalyticsController.usage.bind(accessAnalyticsController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/access/analytics/permissions:
|
||||
* get:
|
||||
* summary: Permissions analytics
|
||||
* description: Get permissions analytics
|
||||
* tags: [Access - Analytics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Permissions analytics
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/analytics/permissions', authenticate(), requirePermission('access', 'read'), accessAnalyticsController.permissions.bind(accessAnalyticsController));
|
||||
|
||||
return router;
|
||||
};
|
||||
313
services/iam-service/src/modules/auth/auth.routes.ts
Normal file
313
services/iam-service/src/modules/auth/auth.routes.ts
Normal file
@@ -0,0 +1,313 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { authController } from './auth.controller';
|
||||
import { changePasswordController } from './change-password.controller';
|
||||
import { socialAuthController } from '../social/social.controller';
|
||||
|
||||
/**
|
||||
* EN: Create and configure auth routes
|
||||
* VI: Tạo và cấu hình routes cho auth
|
||||
*/
|
||||
export const createAuthRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
// =============================================================================
|
||||
// EN: Authentication Endpoints
|
||||
// VI: Endpoints Xác Thực
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/register:
|
||||
* post:
|
||||
* summary: Register a new user
|
||||
* description: Register a new user account with email and password
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/RegisterRequest'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: User registered successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/RegisterResponse'
|
||||
* 400:
|
||||
* description: Validation error or email already in use
|
||||
* 500:
|
||||
* description: Internal server error
|
||||
*/
|
||||
router.post('/register', authController.register.bind(authController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/login:
|
||||
* post:
|
||||
* summary: Login user
|
||||
* description: Authenticate user with email and password to receive access tokens
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LoginRequest'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Login successful
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LoginResponse'
|
||||
* 401:
|
||||
* description: Invalid credentials
|
||||
* 500:
|
||||
* description: Internal server error
|
||||
*/
|
||||
router.post('/login', authController.login.bind(authController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/logout:
|
||||
* post:
|
||||
* summary: Logout user
|
||||
* description: Invalidate current user session and tokens
|
||||
* tags: [Authentication]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Logout successful
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/logout', authenticate(), authController.logout.bind(authController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/refresh:
|
||||
* post:
|
||||
* summary: Refresh access token
|
||||
* description: Get a new access token using a valid refresh token
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [refreshToken]
|
||||
* properties:
|
||||
* refreshToken:
|
||||
* type: string
|
||||
* description: The refresh token
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Token refreshed successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LoginResponse'
|
||||
* 401:
|
||||
* description: Invalid or expired refresh token
|
||||
*/
|
||||
router.post('/refresh', authController.refreshToken.bind(authController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/change-password:
|
||||
* post:
|
||||
* summary: Change password
|
||||
* description: Change the password for the currently authenticated user
|
||||
* tags: [Authentication]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [currentPassword, newPassword]
|
||||
* properties:
|
||||
* currentPassword:
|
||||
* type: string
|
||||
* newPassword:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Password changed successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 400:
|
||||
* description: Validation error or wrong password
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/change-password', authenticate(), changePasswordController.changePassword.bind(changePasswordController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/me:
|
||||
* get:
|
||||
* summary: Get current user
|
||||
* description: Get information about the currently authenticated user
|
||||
* tags: [Authentication]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User information retrieved
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* description: User payload from token
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.get('/me', authenticate(), (req, res) => {
|
||||
res.json({
|
||||
success: true,
|
||||
data: req.user,
|
||||
message: 'User information retrieved / Thông tin người dùng đã được lấy',
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
// EN: Social Authentication Endpoints
|
||||
// VI: Endpoints Xác Thực Mạng Xã Hội
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/google:
|
||||
* get:
|
||||
* summary: Initiate Google OAuth
|
||||
* description: Redirects to Google login page for OAuth2 authentication
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 302:
|
||||
* description: Redirects to Google
|
||||
*/
|
||||
router.get('/google', socialAuthController.googleAuth.bind(socialAuthController));
|
||||
router.get('/google/callback', socialAuthController.googleCallback.bind(socialAuthController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/facebook:
|
||||
* get:
|
||||
* summary: Initiate Facebook OAuth
|
||||
* description: Redirects to Facebook login page for OAuth2 authentication
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 302:
|
||||
* description: Redirects to Facebook
|
||||
*/
|
||||
router.get('/facebook', socialAuthController.facebookAuth.bind(socialAuthController));
|
||||
router.get('/facebook/callback', socialAuthController.facebookCallback.bind(socialAuthController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/auth/github:
|
||||
* get:
|
||||
* summary: Initiate GitHub OAuth
|
||||
* description: Redirects to GitHub login page for OAuth2 authentication
|
||||
* tags: [Authentication]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 302:
|
||||
* description: Redirects to GitHub
|
||||
*/
|
||||
router.get('/github', socialAuthController.githubAuth.bind(socialAuthController));
|
||||
router.get('/github/callback', socialAuthController.githubCallback.bind(socialAuthController));
|
||||
|
||||
return router;
|
||||
};
|
||||
619
services/iam-service/src/modules/governance/governance.routes.ts
Normal file
619
services/iam-service/src/modules/governance/governance.routes.ts
Normal file
@@ -0,0 +1,619 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { requirePermission } from '../../middlewares/rbac.middleware';
|
||||
import { complianceController } from './compliance';
|
||||
import { policyGovernanceController } from './policy';
|
||||
import { riskController } from './risk';
|
||||
import { reportingController } from './reporting';
|
||||
|
||||
/**
|
||||
* EN: Create and configure Governance routes
|
||||
* VI: Tạo và cấu hình routes cho Governance
|
||||
*/
|
||||
export const createGovernanceRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
// =============================================================================
|
||||
// EN: Compliance Reports Endpoints
|
||||
// VI: Endpoints Báo Cáo Tuân Thủ
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/compliance/reports:
|
||||
* get:
|
||||
* summary: List compliance reports
|
||||
* description: List compliance reports
|
||||
* tags: [Governance - Compliance]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Reports list
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/ComplianceReport'
|
||||
*/
|
||||
router.get('/compliance/reports', authenticate(), requirePermission('governance', 'read'), complianceController.list.bind(complianceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/compliance/reports/generate:
|
||||
* post:
|
||||
* summary: Generate compliance report
|
||||
* description: Generate a new compliance report
|
||||
* tags: [Governance - Compliance]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Report generation started
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/compliance/reports/generate', authenticate(), requirePermission('governance', 'create'), complianceController.generate.bind(complianceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/compliance/reports/{id}:
|
||||
* get:
|
||||
* summary: Get compliance report
|
||||
* description: Get compliance report details
|
||||
* tags: [Governance - Compliance]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Report ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report details
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/ComplianceReport'
|
||||
*/
|
||||
router.get('/compliance/reports/:id', authenticate(), requirePermission('governance', 'read'), complianceController.get.bind(complianceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/compliance/reports/{id}/export:
|
||||
* get:
|
||||
* summary: Export compliance report
|
||||
* description: Export compliance report to file
|
||||
* tags: [Governance - Compliance]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Report ID
|
||||
* - in: query
|
||||
* name: format
|
||||
* schema:
|
||||
* type: string
|
||||
* enum: [pdf, csv]
|
||||
* default: pdf
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Export successful
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object // File download
|
||||
*/
|
||||
router.get('/compliance/reports/:id/export', authenticate(), requirePermission('governance', 'read'), complianceController.export.bind(complianceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/compliance/reports/{id}/publish:
|
||||
* post:
|
||||
* summary: Publish compliance report
|
||||
* description: Publish a compliance report
|
||||
* tags: [Governance - Compliance]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Report ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report published
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/compliance/reports/:id/publish', authenticate(), requirePermission('governance', 'update'), complianceController.publish.bind(complianceController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Policy Governance Endpoints
|
||||
// VI: Endpoints Quản Trị Policy
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/policies/templates:
|
||||
* get:
|
||||
* summary: List policy templates
|
||||
* description: List available policy templates
|
||||
* tags: [Governance - Policy]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Templates list
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/PolicyTemplate'
|
||||
*/
|
||||
router.get('/policies/templates', authenticate(), requirePermission('governance', 'read'), policyGovernanceController.getTemplates.bind(policyGovernanceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/policies/templates:
|
||||
* post:
|
||||
* summary: Create policy template
|
||||
* description: Create a new policy template
|
||||
* tags: [Governance - Policy]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Template created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/policies/templates', authenticate(), requirePermission('governance', 'create'), policyGovernanceController.createTemplate.bind(policyGovernanceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/policies/{id}/versions:
|
||||
* get:
|
||||
* summary: Get policy versions
|
||||
* description: Get version history of a policy
|
||||
* tags: [Governance - Policy]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Policy ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Policy versions
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/PolicyVersion'
|
||||
*/
|
||||
router.get('/policies/:id/versions', authenticate(), requirePermission('governance', 'read'), policyGovernanceController.getVersions.bind(policyGovernanceController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/policies/{id}/test:
|
||||
* post:
|
||||
* summary: Test policy
|
||||
* description: Test a policy against a context
|
||||
* tags: [Governance - Policy]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Policy ID
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* context:
|
||||
* type: object
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Test result
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* allowed:
|
||||
* type: boolean
|
||||
*/
|
||||
router.post('/policies/:id/test', authenticate(), requirePermission('governance', 'read'), policyGovernanceController.test.bind(policyGovernanceController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Risk Management Endpoints
|
||||
// VI: Endpoints Quản Lý Rủi Ro
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/risk/scores:
|
||||
* get:
|
||||
* summary: List risk scores
|
||||
* description: List user risk scores
|
||||
* tags: [Governance - Risk]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Risk scores
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/RiskScore'
|
||||
*/
|
||||
router.get('/risk/scores', authenticate(), requirePermission('governance', 'read'), riskController.list.bind(riskController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/risk/scores/{userId}:
|
||||
* get:
|
||||
* summary: Get user risk score
|
||||
* description: Get risk score for a specific user
|
||||
* tags: [Governance - Risk]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: userId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: User ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User risk score
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* $ref: '#/components/schemas/RiskScore'
|
||||
*/
|
||||
router.get('/risk/scores/:userId', authenticate(), requirePermission('governance', 'read'), riskController.getScore.bind(riskController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/risk/calculate:
|
||||
* post:
|
||||
* summary: Calculate risk score
|
||||
* description: Trigger risk score calculation
|
||||
* tags: [Governance - Risk]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Calculation started
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.post('/risk/calculate', authenticate(), requirePermission('governance', 'update'), riskController.calculate.bind(riskController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/risk/dashboard:
|
||||
* get:
|
||||
* summary: Risk dashboard
|
||||
* description: Get risk dashboard data
|
||||
* tags: [Governance - Risk]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Dashboard data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/risk/dashboard', authenticate(), requirePermission('governance', 'read'), riskController.dashboard.bind(riskController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Reporting Endpoints
|
||||
// VI: Endpoints Báo Cáo
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/reports/access-summary:
|
||||
* get:
|
||||
* summary: Access summary report
|
||||
* description: Get access summary report
|
||||
* tags: [Governance - Reports]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/reports/access-summary', authenticate(), requirePermission('governance', 'read'), reportingController.accessSummary.bind(reportingController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/reports/user-activity:
|
||||
* get:
|
||||
* summary: User activity report
|
||||
* description: Get user activity report
|
||||
* tags: [Governance - Reports]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/reports/user-activity', authenticate(), requirePermission('governance', 'read'), reportingController.userActivity.bind(reportingController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/reports/security-events:
|
||||
* get:
|
||||
* summary: Security events report
|
||||
* description: Get security events report
|
||||
* tags: [Governance - Reports]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/reports/security-events', authenticate(), requirePermission('governance', 'read'), reportingController.securityEvents.bind(reportingController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/reports/compliance-status:
|
||||
* get:
|
||||
* summary: Compliance status report
|
||||
* description: Get compliance status report
|
||||
* tags: [Governance - Reports]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/reports/compliance-status', authenticate(), requirePermission('governance', 'read'), reportingController.complianceStatus.bind(reportingController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/governance/reports/risk-overview:
|
||||
* get:
|
||||
* summary: Risk overview report
|
||||
* description: Get risk overview report
|
||||
* tags: [Governance - Reports]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Report data
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
*/
|
||||
router.get('/reports/risk-overview', authenticate(), requirePermission('governance', 'read'), reportingController.riskOverview.bind(reportingController));
|
||||
|
||||
return router;
|
||||
};
|
||||
1252
services/iam-service/src/modules/identity/identity.routes.ts
Normal file
1252
services/iam-service/src/modules/identity/identity.routes.ts
Normal file
File diff suppressed because it is too large
Load Diff
220
services/iam-service/src/modules/mfa/mfa.routes.ts
Normal file
220
services/iam-service/src/modules/mfa/mfa.routes.ts
Normal file
@@ -0,0 +1,220 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { mfaController } from './mfa.controller';
|
||||
|
||||
/**
|
||||
* EN: Create and configure MFA routes
|
||||
* VI: Tạo và cấu hình routes cho MFA
|
||||
*/
|
||||
export const createMfaRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/mfa/totp/enable:
|
||||
* post:
|
||||
* summary: Enable TOTP
|
||||
* description: Initiate process to enable TOTP (Time-based One-Time Password) for the user
|
||||
* tags: [MFA]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: TOTP setup initiated (returns QR code URL or secret)
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* secret:
|
||||
* type: string
|
||||
* qrCode:
|
||||
* type: string
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/totp/enable', authenticate(), mfaController.enableTOTP.bind(mfaController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/mfa/totp/verify:
|
||||
* post:
|
||||
* summary: Verify and Enable TOTP
|
||||
* description: Verify the TOTP code and finalize enabling MFA
|
||||
* tags: [MFA]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [code]
|
||||
* properties:
|
||||
* code:
|
||||
* type: string
|
||||
* description: The 6-digit TOTP code
|
||||
* responses:
|
||||
* 200:
|
||||
* description: TOTP verified and enabled successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 400:
|
||||
* description: Invalid code
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/totp/verify', authenticate(), mfaController.verifyAndEnableTOTP.bind(mfaController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/mfa/totp/validate:
|
||||
* post:
|
||||
* summary: Validate TOTP
|
||||
* description: Validate a TOTP code (for login or step-up auth)
|
||||
* tags: [MFA]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [code]
|
||||
* properties:
|
||||
* code:
|
||||
* type: string
|
||||
* description: The 6-digit TOTP code
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Code valid
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* valid:
|
||||
* type: boolean
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/totp/validate', authenticate(), mfaController.verifyTOTP.bind(mfaController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/mfa/disable:
|
||||
* post:
|
||||
* summary: Disable MFA
|
||||
* description: Disable Multi-Factor Authentication for the user
|
||||
* tags: [MFA]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [password]
|
||||
* properties:
|
||||
* password:
|
||||
* type: string
|
||||
* description: Current password for confirmation
|
||||
* responses:
|
||||
* 200:
|
||||
* description: MFA disabled successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 400:
|
||||
* description: Invalid password
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.post('/disable', authenticate(), mfaController.disableMFA.bind(mfaController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/mfa/devices:
|
||||
* get:
|
||||
* summary: Get MFA devices
|
||||
* description: List registered MFA devices
|
||||
* tags: [MFA]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Devices listed successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.get('/devices', authenticate(), mfaController.getMFADevices.bind(mfaController));
|
||||
|
||||
return router;
|
||||
};
|
||||
197
services/iam-service/src/modules/oidc/oidc.routes.ts
Normal file
197
services/iam-service/src/modules/oidc/oidc.routes.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { oidcController } from './oidc.controller';
|
||||
|
||||
/**
|
||||
* EN: Create and configure OIDC routes
|
||||
* VI: Tạo và cấu hình routes cho OIDC
|
||||
*/
|
||||
export const createOidcRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /.well-known/openid-configuration:
|
||||
* get:
|
||||
* summary: OIDC Discovery
|
||||
* description: Get OpenID Connect configuration and metadata
|
||||
* tags: [OIDC]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OIDC configuration
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* issuer:
|
||||
* type: string
|
||||
* authorization_endpoint:
|
||||
* type: string
|
||||
* token_endpoint:
|
||||
* type: string
|
||||
* userinfo_endpoint:
|
||||
* type: string
|
||||
* jwks_uri:
|
||||
* type: string
|
||||
*/
|
||||
// Note: This route is usually mounted at root, not under /api/{version}
|
||||
// If mounted under /api/{version}, adjust paths accordingly
|
||||
router.get('/.well-known/openid-configuration', oidcController.discovery.bind(oidcController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/oidc/authorize:
|
||||
* get:
|
||||
* summary: OIDC Authorization
|
||||
* description: Authorization endpoint for OIDC flow
|
||||
* tags: [OIDC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: query
|
||||
* name: response_type
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: client_id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: redirect_uri
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: scope
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: state
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 302:
|
||||
* description: Redirect to callback
|
||||
* 400:
|
||||
* description: Invalid request
|
||||
*/
|
||||
router.get('/authorize', authenticate(), oidcController.authorize.bind(oidcController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/oidc/token:
|
||||
* post:
|
||||
* summary: OIDC Token
|
||||
* description: Token endpoint for OIDC flow
|
||||
* tags: [OIDC]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/x-www-form-urlencoded:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* grant_type:
|
||||
* type: string
|
||||
* code:
|
||||
* type: string
|
||||
* redirect_uri:
|
||||
* type: string
|
||||
* client_id:
|
||||
* type: string
|
||||
* client_secret:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: ID Token and Access Token
|
||||
* 400:
|
||||
* description: Invalid request
|
||||
*/
|
||||
router.post('/token', oidcController.token.bind(oidcController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/oidc/userinfo:
|
||||
* get:
|
||||
* summary: OIDC UserInfo
|
||||
* description: Get claims about the authenticated end-user
|
||||
* tags: [OIDC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User information
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sub:
|
||||
* type: string
|
||||
* name:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.get('/userinfo', authenticate(), oidcController.userinfo.bind(oidcController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/oidc/jwks:
|
||||
* get:
|
||||
* summary: OIDC JWKS
|
||||
* description: JSON Web Key Set for verifying signatures
|
||||
* tags: [OIDC]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: JWKS
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* keys:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
*/
|
||||
router.get('/jwks', oidcController.jwks.bind(oidcController));
|
||||
|
||||
return router;
|
||||
};
|
||||
234
services/iam-service/src/modules/rbac/rbac.routes.ts
Normal file
234
services/iam-service/src/modules/rbac/rbac.routes.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { requirePermission } from '../../middlewares/rbac.middleware';
|
||||
import { rbacController } from './rbac.controller';
|
||||
|
||||
/**
|
||||
* EN: Create and configure RBAC routes
|
||||
* VI: Tạo và cấu hình routes cho RBAC
|
||||
*/
|
||||
export const createRbacRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/rbac/permissions:
|
||||
* get:
|
||||
* summary: Get user permissions
|
||||
* description: Get list of permissions assigned to the current user
|
||||
* tags: [RBAC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Permissions retrieved successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.get('/permissions', authenticate(), rbacController.getUserPermissions.bind(rbacController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/rbac/roles/assign:
|
||||
* post:
|
||||
* summary: Assign role to user
|
||||
* description: Assign a specific role to a user. Requires 'rbac:assign' permission.
|
||||
* tags: [RBAC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [userId, roleId]
|
||||
* properties:
|
||||
* userId:
|
||||
* type: string
|
||||
* roleId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role assigned successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* 403:
|
||||
* description: Forbidden - Insufficient permissions
|
||||
* 404:
|
||||
* description: User or Role not found
|
||||
*/
|
||||
router.post('/roles/assign', authenticate(), requirePermission('rbac', 'assign'), rbacController.assignRole.bind(rbacController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/rbac/roles/revoke:
|
||||
* post:
|
||||
* summary: Revoke role from user
|
||||
* description: Revoke a specific role from a user. Requires 'rbac:revoke' permission.
|
||||
* tags: [RBAC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [userId, roleId]
|
||||
* properties:
|
||||
* userId:
|
||||
* type: string
|
||||
* roleId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Role revoked successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* 403:
|
||||
* description: Forbidden - Insufficient permissions
|
||||
* 404:
|
||||
* description: User or Role not found
|
||||
*/
|
||||
router.post('/roles/revoke', authenticate(), requirePermission('rbac', 'revoke'), rbacController.revokeRole.bind(rbacController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/rbac/permissions/grant:
|
||||
* post:
|
||||
* summary: Grant permission to role
|
||||
* description: Grant a specific permission to a role. Requires 'rbac:grant' permission.
|
||||
* tags: [RBAC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [roleId, permissionId]
|
||||
* properties:
|
||||
* roleId:
|
||||
* type: string
|
||||
* permissionId:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Permission granted successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* 403:
|
||||
* description: Forbidden - Insufficient permissions
|
||||
* 404:
|
||||
* description: Role or Permission not found
|
||||
*/
|
||||
router.post('/permissions/grant', authenticate(), requirePermission('rbac', 'grant'), rbacController.grantPermission.bind(rbacController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/rbac/permissions/check:
|
||||
* get:
|
||||
* summary: Check permission
|
||||
* description: Check if the current user has a specific permission
|
||||
* tags: [RBAC]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: query
|
||||
* name: resource
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: action
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Permission check result
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* allowed:
|
||||
* type: boolean
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* 403:
|
||||
* description: Forbidden
|
||||
*/
|
||||
router.get('/permissions/check', authenticate(), rbacController.checkPermission.bind(rbacController));
|
||||
|
||||
return router;
|
||||
};
|
||||
115
services/iam-service/src/modules/session/session.routes.ts
Normal file
115
services/iam-service/src/modules/session/session.routes.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticate } from '../../middlewares/auth.middleware';
|
||||
import { sessionsController } from './sessions.controller';
|
||||
|
||||
/**
|
||||
* EN: Create and configure session routes
|
||||
* VI: Tạo và cấu hình routes cho session
|
||||
*/
|
||||
export const createSessionRouter = (): Router => {
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/sessions:
|
||||
* get:
|
||||
* summary: Get active sessions
|
||||
* description: List all active sessions for the current user
|
||||
* tags: [Sessions]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Sessions retrieved successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/ApiResponse'
|
||||
* - type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Session'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.get('/', authenticate(), sessionsController.getUserSessions.bind(sessionsController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/sessions:
|
||||
* delete:
|
||||
* summary: Revoke all sessions
|
||||
* description: Revoke all active sessions for the current user except the current one
|
||||
* tags: [Sessions]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* responses:
|
||||
* 200:
|
||||
* description: All sessions revoked successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
*/
|
||||
router.delete('/', authenticate(), sessionsController.revokeAllSessions.bind(sessionsController));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/{version}/sessions/{sessionId}:
|
||||
* delete:
|
||||
* summary: Revoke session
|
||||
* description: Revoke a specific session
|
||||
* tags: [Sessions]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: version
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* default: v1
|
||||
* description: API version
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Session ID to revoke
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Session revoked successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiResponse'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* 404:
|
||||
* description: Session not found
|
||||
*/
|
||||
router.delete('/:sessionId', authenticate(), sessionsController.revokeSession.bind(sessionsController));
|
||||
|
||||
return router;
|
||||
};
|
||||
@@ -1,304 +1,57 @@
|
||||
import { ApiResponse } from '@goodgo/types';
|
||||
import { Router } from 'express';
|
||||
import { createAuthRouter } from '../modules/auth/auth.routes';
|
||||
import { createIdentityRouter } from '../modules/identity/identity.routes';
|
||||
import { createAccessRouter } from '../modules/access/access.routes';
|
||||
import { createGovernanceRouter } from '../modules/governance/governance.routes';
|
||||
import { createSessionRouter } from '../modules/session/session.routes';
|
||||
import { createOidcRouter } from '../modules/oidc/oidc.routes';
|
||||
import { createRbacRouter } from '../modules/rbac/rbac.routes';
|
||||
import { createMfaRouter } from '../modules/mfa/mfa.routes';
|
||||
|
||||
|
||||
import { authenticate } from '../middlewares/auth.middleware';
|
||||
import { dynamicRateLimit } from '../middlewares/rate-limit.middleware';
|
||||
import { requirePermission } from '../middlewares/rbac.middleware';
|
||||
import { zeroTrustMiddleware } from '../middlewares/zero-trust.middleware';
|
||||
import { accessAnalyticsController } from '../modules/access/analytics';
|
||||
import { accessRequestController } from '../modules/access/request';
|
||||
import { accessReviewController } from '../modules/access/review';
|
||||
import { authController } from '../modules/auth/auth.controller';
|
||||
import { changePasswordController } from '../modules/auth/change-password.controller';
|
||||
import { complianceController } from '../modules/governance/compliance';
|
||||
import { policyGovernanceController } from '../modules/governance/policy';
|
||||
import { reportingController } from '../modules/governance/reporting';
|
||||
import { riskController } from '../modules/governance/risk';
|
||||
import { HealthController } from '../modules/health/health.controller';
|
||||
import { groupController } from '../modules/identity/group';
|
||||
import { organizationController } from '../modules/identity/organization';
|
||||
import { profileController } from '../modules/identity/profile';
|
||||
import { userManagementController } from '../modules/identity/user';
|
||||
import { verificationController } from '../modules/identity/verification';
|
||||
import { MetricsController } from '../modules/metrics/metrics.controller';
|
||||
import { mfaController } from '../modules/mfa/mfa.controller';
|
||||
import { oidcController } from '../modules/oidc/oidc.controller';
|
||||
import { rbacController } from '../modules/rbac/rbac.controller';
|
||||
import { sessionsController } from '../modules/session/sessions.controller';
|
||||
import { socialAuthController } from '../modules/social/social.controller';
|
||||
|
||||
|
||||
/**
|
||||
* EN: Create and configure main application router
|
||||
* VI: Tạo và cấu hình router chính cho ứng dụng
|
||||
*/
|
||||
export const createRouter = (): Router => {
|
||||
const router = Router();
|
||||
const healthController = new HealthController();
|
||||
|
||||
const apiVersion = process.env.API_VERSION || 'v1';
|
||||
|
||||
// EN: Health check endpoints
|
||||
// VI: Endpoints kiểm tra sức khỏe
|
||||
/**
|
||||
* @swagger
|
||||
* /health:
|
||||
* get:
|
||||
* summary: Basic liveness probe
|
||||
* description: Returns basic health status for liveness probes
|
||||
* tags: [Health]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Service is healthy
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/HealthResponse'
|
||||
*/
|
||||
router.get('/health', healthController.health);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /health/ready:
|
||||
* get:
|
||||
* summary: Readiness probe
|
||||
* description: Checks if service is ready to handle requests (includes database connectivity)
|
||||
* tags: [Health]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Service is ready
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ReadinessResponse'
|
||||
* 503:
|
||||
* description: Service is not ready
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ErrorResponse'
|
||||
*/
|
||||
router.get('/health/ready', healthController.ready);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /health/live:
|
||||
* get:
|
||||
* summary: Liveness probe
|
||||
* description: Basic liveness check for container orchestration
|
||||
* tags: [Health]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Service is alive
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LivenessResponse'
|
||||
*/
|
||||
router.get('/health/live', healthController.live);
|
||||
|
||||
// EN: Apply zero-trust and rate limiting to all routes
|
||||
// VI: Áp dụng zero-trust và rate limiting cho tất cả routes
|
||||
router.use(zeroTrustMiddleware);
|
||||
router.use(dynamicRateLimit);
|
||||
|
||||
// EN: Auth endpoints
|
||||
// VI: Endpoints xác thực
|
||||
router.post(`/api/${apiVersion}/auth/register`, authController.register.bind(authController));
|
||||
router.post(`/api/${apiVersion}/auth/login`, authController.login.bind(authController));
|
||||
router.post(`/api/${apiVersion}/auth/logout`, authenticate(), authController.logout.bind(authController));
|
||||
router.post(`/api/${apiVersion}/auth/refresh`, authController.refreshToken.bind(authController));
|
||||
|
||||
// EN: Change password
|
||||
// VI: Đổi mật khẩu
|
||||
router.post(`/api/${apiVersion}/auth/change-password`, authenticate(), changePasswordController.changePassword.bind(changePasswordController));
|
||||
|
||||
// EN: Session management endpoints
|
||||
// VI: Endpoints quản lý session
|
||||
router.get(`/api/${apiVersion}/sessions`, authenticate(), sessionsController.getUserSessions.bind(sessionsController));
|
||||
router.delete(`/api/${apiVersion}/sessions/:sessionId`, authenticate(), sessionsController.revokeSession.bind(sessionsController));
|
||||
router.delete(`/api/${apiVersion}/sessions`, authenticate(), sessionsController.revokeAllSessions.bind(sessionsController));
|
||||
|
||||
// EN: Get current user
|
||||
// VI: Lấy thông tin người dùng hiện tại
|
||||
router.get(`/api/${apiVersion}/auth/me`, authenticate(), (req, res) => {
|
||||
const response: ApiResponse = {
|
||||
success: true,
|
||||
data: req.user,
|
||||
message: 'User information retrieved / Thông tin người dùng đã được lấy',
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
res.json(response);
|
||||
// EN: Health Check
|
||||
// VI: Kiểm tra trạng thái
|
||||
router.get('/health', (req, res) => {
|
||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
});
|
||||
|
||||
// EN: Social Auth endpoints
|
||||
// VI: Endpoints xác thực mạng xã hội
|
||||
router.get(`/api/${apiVersion}/auth/google`, socialAuthController.googleAuth.bind(socialAuthController));
|
||||
router.get(`/api/${apiVersion}/auth/google/callback`, socialAuthController.googleCallback.bind(socialAuthController));
|
||||
router.get(`/api/${apiVersion}/auth/facebook`, socialAuthController.facebookAuth.bind(socialAuthController));
|
||||
router.get(`/api/${apiVersion}/auth/facebook/callback`, socialAuthController.facebookCallback.bind(socialAuthController));
|
||||
router.get(`/api/${apiVersion}/auth/github`, socialAuthController.githubAuth.bind(socialAuthController));
|
||||
router.get(`/api/${apiVersion}/auth/github/callback`, socialAuthController.githubCallback.bind(socialAuthController));
|
||||
// EN: Auth Routes
|
||||
// VI: Routes xác thực
|
||||
router.use('/auth', createAuthRouter());
|
||||
|
||||
// EN: OIDC endpoints
|
||||
// VI: Endpoints OIDC
|
||||
router.get('/.well-known/openid-configuration', oidcController.discovery.bind(oidcController));
|
||||
router.get(`/api/${apiVersion}/oidc/authorize`, authenticate(), oidcController.authorize.bind(oidcController));
|
||||
router.post(`/api/${apiVersion}/oidc/token`, oidcController.token.bind(oidcController));
|
||||
router.get(`/api/${apiVersion}/oidc/userinfo`, authenticate(), oidcController.userinfo.bind(oidcController));
|
||||
router.get(`/api/${apiVersion}/oidc/jwks`, oidcController.jwks.bind(oidcController));
|
||||
// EN: Session Routes
|
||||
// VI: Routes phiên làm việc
|
||||
router.use('/session', createSessionRouter());
|
||||
|
||||
// EN: RBAC endpoints
|
||||
// VI: Endpoints RBAC
|
||||
router.get(`/api/${apiVersion}/rbac/permissions`, authenticate(), rbacController.getUserPermissions.bind(rbacController));
|
||||
router.post(`/api/${apiVersion}/rbac/roles/assign`, authenticate(), requirePermission('rbac', 'assign'), rbacController.assignRole.bind(rbacController));
|
||||
router.post(`/api/${apiVersion}/rbac/roles/revoke`, authenticate(), requirePermission('rbac', 'revoke'), rbacController.revokeRole.bind(rbacController));
|
||||
router.post(`/api/${apiVersion}/rbac/permissions/grant`, authenticate(), requirePermission('rbac', 'grant'), rbacController.grantPermission.bind(rbacController));
|
||||
router.get(`/api/${apiVersion}/rbac/permissions/check`, authenticate(), rbacController.checkPermission.bind(rbacController));
|
||||
// EN: OIDC Routes
|
||||
// VI: Routes OpenID Connect
|
||||
router.use('/oidc', createOidcRouter());
|
||||
|
||||
// EN: MFA endpoints
|
||||
// VI: Endpoints MFA
|
||||
router.post(`/api/${apiVersion}/mfa/totp/enable`, authenticate(), mfaController.enableTOTP.bind(mfaController));
|
||||
router.post(`/api/${apiVersion}/mfa/totp/verify`, authenticate(), mfaController.verifyAndEnableTOTP.bind(mfaController));
|
||||
router.post(`/api/${apiVersion}/mfa/totp/validate`, authenticate(), mfaController.verifyTOTP.bind(mfaController));
|
||||
router.post(`/api/${apiVersion}/mfa/disable`, authenticate(), mfaController.disableMFA.bind(mfaController));
|
||||
router.get(`/api/${apiVersion}/mfa/devices`, authenticate(), mfaController.getMFADevices.bind(mfaController));
|
||||
// EN: RBAC Routes
|
||||
// VI: Routes phân quyền
|
||||
router.use('/rbac', createRbacRouter());
|
||||
|
||||
// =============================================================================
|
||||
// EN: Identity Management Endpoints
|
||||
// VI: Endpoints Quản Lý Danh Tính
|
||||
// =============================================================================
|
||||
// EN: MFA Routes
|
||||
// VI: Routes xác thực đa yếu tố
|
||||
router.use('/mfa', createMfaRouter());
|
||||
|
||||
// EN: User Management
|
||||
// VI: Quản lý người dùng
|
||||
router.get(`/api/${apiVersion}/identity/users`, authenticate(), requirePermission('identity', 'read'), userManagementController.list.bind(userManagementController));
|
||||
router.get(`/api/${apiVersion}/identity/users/:id`, authenticate(), requirePermission('identity', 'read'), userManagementController.get.bind(userManagementController));
|
||||
router.put(`/api/${apiVersion}/identity/users/:id`, authenticate(), requirePermission('identity', 'update'), userManagementController.update.bind(userManagementController));
|
||||
router.delete(`/api/${apiVersion}/identity/users/:id`, authenticate(), requirePermission('identity', 'delete'), userManagementController.delete.bind(userManagementController));
|
||||
router.post(`/api/${apiVersion}/identity/users/:id/deactivate`, authenticate(), requirePermission('identity', 'update'), userManagementController.deactivate.bind(userManagementController));
|
||||
router.post(`/api/${apiVersion}/identity/users/:id/reactivate`, authenticate(), requirePermission('identity', 'update'), userManagementController.reactivate.bind(userManagementController));
|
||||
router.post(`/api/${apiVersion}/identity/users/bulk-import`, authenticate(), requirePermission('identity', 'create'), userManagementController.bulkImport.bind(userManagementController));
|
||||
router.get(`/api/${apiVersion}/identity/users/bulk-export`, authenticate(), requirePermission('identity', 'read'), userManagementController.bulkExport.bind(userManagementController));
|
||||
// EN: Identity Routes
|
||||
// VI: Routes định danh
|
||||
router.use('/identity', createIdentityRouter());
|
||||
|
||||
// EN: Profile Management
|
||||
// VI: Quản lý profile
|
||||
router.get(`/api/${apiVersion}/identity/users/:id/profile`, authenticate(), profileController.get.bind(profileController));
|
||||
router.put(`/api/${apiVersion}/identity/users/:id/profile`, authenticate(), profileController.update.bind(profileController));
|
||||
router.post(`/api/${apiVersion}/identity/users/:id/profile/avatar`, authenticate(), profileController.uploadAvatar.bind(profileController));
|
||||
router.delete(`/api/${apiVersion}/identity/users/:id/profile/avatar`, authenticate(), profileController.deleteAvatar.bind(profileController));
|
||||
// EN: Access Routes
|
||||
// VI: Routes truy cập
|
||||
router.use('/access', createAccessRouter());
|
||||
|
||||
// EN: Identity Verification
|
||||
// VI: Xác thực danh tính
|
||||
router.post(`/api/${apiVersion}/identity/verification/email/request`, authenticate(), verificationController.requestEmail.bind(verificationController));
|
||||
router.post(`/api/${apiVersion}/identity/verification/email/verify`, verificationController.verifyEmail.bind(verificationController));
|
||||
router.post(`/api/${apiVersion}/identity/verification/phone/request`, authenticate(), verificationController.requestPhone.bind(verificationController));
|
||||
router.post(`/api/${apiVersion}/identity/verification/phone/verify`, verificationController.verifyPhone.bind(verificationController));
|
||||
router.get(`/api/${apiVersion}/identity/verification/:id/status`, authenticate(), verificationController.getStatus.bind(verificationController));
|
||||
|
||||
// EN: Organizations
|
||||
// VI: Tổ chức
|
||||
router.get(`/api/${apiVersion}/identity/organizations`, authenticate(), requirePermission('identity', 'read'), organizationController.list.bind(organizationController));
|
||||
router.post(`/api/${apiVersion}/identity/organizations`, authenticate(), requirePermission('identity', 'create'), organizationController.create.bind(organizationController));
|
||||
router.get(`/api/${apiVersion}/identity/organizations/:id`, authenticate(), requirePermission('identity', 'read'), organizationController.get.bind(organizationController));
|
||||
router.put(`/api/${apiVersion}/identity/organizations/:id`, authenticate(), requirePermission('identity', 'update'), organizationController.update.bind(organizationController));
|
||||
router.delete(`/api/${apiVersion}/identity/organizations/:id`, authenticate(), requirePermission('identity', 'delete'), organizationController.delete.bind(organizationController));
|
||||
router.get(`/api/${apiVersion}/identity/organizations/:id/users`, authenticate(), requirePermission('identity', 'read'), organizationController.getUsers.bind(organizationController));
|
||||
|
||||
// EN: Groups
|
||||
// VI: Nhóm
|
||||
router.get(`/api/${apiVersion}/identity/organizations/:id/groups`, authenticate(), requirePermission('identity', 'read'), groupController.list.bind(groupController));
|
||||
router.post(`/api/${apiVersion}/identity/organizations/:id/groups`, authenticate(), requirePermission('identity', 'create'), groupController.create.bind(groupController));
|
||||
router.get(`/api/${apiVersion}/identity/groups/:id`, authenticate(), requirePermission('identity', 'read'), groupController.get.bind(groupController));
|
||||
router.put(`/api/${apiVersion}/identity/groups/:id`, authenticate(), requirePermission('identity', 'update'), groupController.update.bind(groupController));
|
||||
router.delete(`/api/${apiVersion}/identity/groups/:id`, authenticate(), requirePermission('identity', 'delete'), groupController.delete.bind(groupController));
|
||||
router.get(`/api/${apiVersion}/identity/groups/:id/members`, authenticate(), requirePermission('identity', 'read'), groupController.getMembers.bind(groupController));
|
||||
router.post(`/api/${apiVersion}/identity/groups/:id/members`, authenticate(), requirePermission('identity', 'update'), groupController.addMember.bind(groupController));
|
||||
router.delete(`/api/${apiVersion}/identity/groups/:id/members/:userId`, authenticate(), requirePermission('identity', 'update'), groupController.removeMember.bind(groupController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Access Management Endpoints
|
||||
// VI: Endpoints Quản Lý Truy Cập
|
||||
// =============================================================================
|
||||
|
||||
// EN: Access Requests
|
||||
// VI: Yêu cầu truy cập
|
||||
router.get(`/api/${apiVersion}/access/requests`, authenticate(), accessRequestController.list.bind(accessRequestController));
|
||||
router.post(`/api/${apiVersion}/access/requests`, authenticate(), accessRequestController.create.bind(accessRequestController));
|
||||
router.get(`/api/${apiVersion}/access/requests/:id`, authenticate(), accessRequestController.get.bind(accessRequestController));
|
||||
router.put(`/api/${apiVersion}/access/requests/:id/approve`, authenticate(), requirePermission('access', 'approve'), accessRequestController.approve.bind(accessRequestController));
|
||||
router.put(`/api/${apiVersion}/access/requests/:id/reject`, authenticate(), requirePermission('access', 'approve'), accessRequestController.reject.bind(accessRequestController));
|
||||
router.delete(`/api/${apiVersion}/access/requests/:id`, authenticate(), accessRequestController.cancel.bind(accessRequestController));
|
||||
|
||||
// EN: Access Reviews
|
||||
// VI: Đánh giá truy cập
|
||||
router.get(`/api/${apiVersion}/access/reviews`, authenticate(), requirePermission('access', 'read'), accessReviewController.list.bind(accessReviewController));
|
||||
router.post(`/api/${apiVersion}/access/reviews`, authenticate(), requirePermission('access', 'create'), accessReviewController.create.bind(accessReviewController));
|
||||
router.get(`/api/${apiVersion}/access/reviews/:id`, authenticate(), requirePermission('access', 'read'), accessReviewController.get.bind(accessReviewController));
|
||||
router.post(`/api/${apiVersion}/access/reviews/:id/start`, authenticate(), requirePermission('access', 'update'), accessReviewController.start.bind(accessReviewController));
|
||||
router.post(`/api/${apiVersion}/access/reviews/:id/complete`, authenticate(), requirePermission('access', 'update'), accessReviewController.complete.bind(accessReviewController));
|
||||
router.get(`/api/${apiVersion}/access/reviews/:id/items`, authenticate(), requirePermission('access', 'read'), accessReviewController.getItems.bind(accessReviewController));
|
||||
router.put(`/api/${apiVersion}/access/reviews/:id/items/:itemId/review`, authenticate(), requirePermission('access', 'update'), accessReviewController.reviewItem.bind(accessReviewController));
|
||||
|
||||
// EN: Access Analytics
|
||||
// VI: Phân tích truy cập
|
||||
router.get(`/api/${apiVersion}/access/analytics/usage`, authenticate(), requirePermission('access', 'read'), accessAnalyticsController.usage.bind(accessAnalyticsController));
|
||||
router.get(`/api/${apiVersion}/access/analytics/permissions`, authenticate(), requirePermission('access', 'read'), accessAnalyticsController.permissions.bind(accessAnalyticsController));
|
||||
router.get(`/api/${apiVersion}/access/analytics/users/:id/summary`, authenticate(), requirePermission('access', 'read'), accessAnalyticsController.userSummary.bind(accessAnalyticsController));
|
||||
router.get(`/api/${apiVersion}/access/analytics/risks`, authenticate(), requirePermission('access', 'read'), accessAnalyticsController.risks.bind(accessAnalyticsController));
|
||||
|
||||
// =============================================================================
|
||||
// EN: Governance Endpoints
|
||||
// VI: Endpoints Quản Trị
|
||||
// =============================================================================
|
||||
|
||||
// EN: Compliance Reports
|
||||
// VI: Báo cáo tuân thủ
|
||||
router.get(`/api/${apiVersion}/governance/compliance/reports`, authenticate(), requirePermission('governance', 'read'), complianceController.list.bind(complianceController));
|
||||
router.post(`/api/${apiVersion}/governance/compliance/reports/generate`, authenticate(), requirePermission('governance', 'create'), complianceController.generate.bind(complianceController));
|
||||
router.get(`/api/${apiVersion}/governance/compliance/reports/:id`, authenticate(), requirePermission('governance', 'read'), complianceController.get.bind(complianceController));
|
||||
router.get(`/api/${apiVersion}/governance/compliance/reports/:id/export`, authenticate(), requirePermission('governance', 'read'), complianceController.export.bind(complianceController));
|
||||
router.post(`/api/${apiVersion}/governance/compliance/reports/:id/publish`, authenticate(), requirePermission('governance', 'update'), complianceController.publish.bind(complianceController));
|
||||
|
||||
// EN: Policy Governance
|
||||
// VI: Quản trị policy
|
||||
router.get(`/api/${apiVersion}/governance/policies/templates`, authenticate(), requirePermission('governance', 'read'), policyGovernanceController.getTemplates.bind(policyGovernanceController));
|
||||
router.post(`/api/${apiVersion}/governance/policies/templates`, authenticate(), requirePermission('governance', 'create'), policyGovernanceController.createTemplate.bind(policyGovernanceController));
|
||||
router.get(`/api/${apiVersion}/governance/policies/:id/versions`, authenticate(), requirePermission('governance', 'read'), policyGovernanceController.getVersions.bind(policyGovernanceController));
|
||||
router.post(`/api/${apiVersion}/governance/policies/:id/test`, authenticate(), requirePermission('governance', 'read'), policyGovernanceController.test.bind(policyGovernanceController));
|
||||
|
||||
// EN: Risk Management
|
||||
// VI: Quản lý rủi ro
|
||||
router.get(`/api/${apiVersion}/governance/risk/scores`, authenticate(), requirePermission('governance', 'read'), riskController.list.bind(riskController));
|
||||
router.get(`/api/${apiVersion}/governance/risk/scores/:userId`, authenticate(), requirePermission('governance', 'read'), riskController.getScore.bind(riskController));
|
||||
router.post(`/api/${apiVersion}/governance/risk/calculate`, authenticate(), requirePermission('governance', 'update'), riskController.calculate.bind(riskController));
|
||||
router.get(`/api/${apiVersion}/governance/risk/dashboard`, authenticate(), requirePermission('governance', 'read'), riskController.dashboard.bind(riskController));
|
||||
|
||||
// EN: Reporting
|
||||
// VI: Báo cáo
|
||||
router.get(`/api/${apiVersion}/governance/reports/access-summary`, authenticate(), requirePermission('governance', 'read'), reportingController.accessSummary.bind(reportingController));
|
||||
router.get(`/api/${apiVersion}/governance/reports/user-activity`, authenticate(), requirePermission('governance', 'read'), reportingController.userActivity.bind(reportingController));
|
||||
router.get(`/api/${apiVersion}/governance/reports/security-events`, authenticate(), requirePermission('governance', 'read'), reportingController.securityEvents.bind(reportingController));
|
||||
router.get(`/api/${apiVersion}/governance/reports/compliance-status`, authenticate(), requirePermission('governance', 'read'), reportingController.complianceStatus.bind(reportingController));
|
||||
router.get(`/api/${apiVersion}/governance/reports/risk-overview`, authenticate(), requirePermission('governance', 'read'), reportingController.riskOverview.bind(reportingController));
|
||||
|
||||
// EN: Metrics endpoint
|
||||
// VI: Endpoint metrics
|
||||
/**
|
||||
* @swagger
|
||||
* /metrics:
|
||||
* get:
|
||||
* summary: Get Prometheus metrics
|
||||
* description: Returns application metrics in Prometheus format for monitoring
|
||||
* tags: [Monitoring]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Metrics in Prometheus format
|
||||
* content:
|
||||
* text/plain:
|
||||
* schema:
|
||||
* type: string
|
||||
* example: "# HELP http_requests_total Total number of HTTP requests\n# TYPE http_requests_total counter\nhttp_requests_total{method=\"GET\",route=\"/health\",status=\"200\"} 42"
|
||||
*/
|
||||
const metricsController = new MetricsController();
|
||||
router.get('/metrics', metricsController.getMetrics);
|
||||
// EN: Governance Routes
|
||||
// VI: Routes quản trị
|
||||
router.use('/governance', createGovernanceRouter());
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user