diff --git a/docs/gns3-copilot/README.md b/docs/gns3-copilot/README.md
new file mode 100644
index 000000000..a0eb27373
--- /dev/null
+++ b/docs/gns3-copilot/README.md
@@ -0,0 +1,136 @@
+# GNS3 AI Copilot Documentation
+
+This directory contains design documentation, implementation guides, and future plans for the GNS3 AI Copilot feature.
+
+## Directory Structure
+
+```
+docs/gns3-copilot/
+├── README.md # This file
+├── implemented/ # Implemented features and designs
+│ ├── chat-api.md # Chat API design (SSE, session management)
+│ ├── llm-model-configs.md # LLM model configuration system
+│ ├── command-security.md # Command security and filtering
+│ └── context-window-management.md # Context window optimization
+├── todo/ # Planned features and designs
+│ ├── jinja2-config-templates-system.md # Config template system
+│ ├── config-templates-implementation-guide.md # Template implementation
+│ ├── ai-prompting-for-config-templates.md # AI prompts for templates
+│ ├── acl-web-ui-implementation-guide.md # ACL/ACL Web UI
+│ ├── hitl-implementation-plan.md # HITL (Human-in-the-Loop)
+│ ├── vision-topology-creation.md # Vision-based topology
+│ └── ... # More planned features
+└── guides/ # User and developer guides (TBD)
+```
+
+## Implemented Features
+
+### Chat API (`implemented/chat-api.md`)
+The core Chat API that enables AI-powered conversations within GNS3 projects.
+
+**Key Features:**
+- Server-Sent Events (SSE) for streaming responses
+- Project-level session isolation
+- Session management (CRUD operations)
+- Statistics tracking (messages, tokens, LLM calls)
+- User-level LLM configuration
+
+**Status:** ✅ Implemented
+
+### LLM Model Configs (`implemented/llm-model-configs.md`)
+Multi-level LLM model configuration system.
+
+**Key Features:**
+- System-wide defaults
+- Group-level configurations
+- User-level overrides
+- Runtime parameter adjustment
+- Model provider abstraction
+
+**Status:** ✅ Implemented
+
+### Command Security (`implemented/command-security.md`)
+Security framework for AI-generated commands.
+
+**Key Features:**
+- Command filtering and validation
+- Dangerous operation detection
+- HITL (Human-in-the-Loop) confirmations
+- Audit logging
+
+**Status:** ✅ Implemented
+
+### Context Window Management (`implemented/context-window-management.md`)
+Optimization strategies for handling large project contexts.
+
+**Key Features:**
+- Intelligent content filtering
+- Token usage optimization
+- Summary generation
+- Context compression
+
+**Status:** ✅ Implemented
+
+## Planned Features
+
+### Jinja2 Configuration Templates (`todo/jinja2-config-templates-system.md`)
+Template-based configuration generation system.
+
+**Planned Features:**
+- Vendor-specific templates (Cisco, Juniper, Huawei, etc.)
+- JSON schema validation
+- AI generates structured data → Templates render configs
+- Multi-vendor support
+
+**Status:** 📋 Design Complete, Implementation Pending
+
+### ACL Web UI (`todo/acl-web-ui-implementation-guide.md`)
+Web-based ACL (Access Control List) management interface.
+
+**Status:** 📋 Design Complete
+
+### HITL Implementation (`todo/hitl-implementation-plan.md`)
+Enhanced Human-in-the-Loop confirmation workflows.
+
+**Status:** 📋 Design Complete
+
+### Vision Topology Creation (`todo/vision-topology-creation.md`)
+Create network topologies from images/diagrams.
+
+**Status:** 📋 Design Complete
+
+## Contributing
+
+When adding new documentation:
+
+1. **Design Phase:** Add new documents to `todo/`
+2. **Implementation:** Move to `implemented/` when feature is complete
+3. **Naming:**
+ - `todo/`: Use descriptive names like `{feature}-implementation-guide.md`
+ - `implemented/`: Use concise names like `{feature}.md`
+
+## Document Status Legend
+
+| Status | Description |
+|--------|-------------|
+| ✅ Implemented | Feature is fully implemented and deployed |
+| 📋 Design Complete | Design is done, awaiting implementation |
+| 🚧 In Progress | Currently being implemented |
+| 💡 Proposed | Initial idea or proposal |
+
+## Related Documentation
+
+- [GNS3 Server API Documentation](https://api.gns3.com/)
+- [GNS3 Web UI Documentation](https://docs.gns3.com/)
+- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/)
+- [FastAPI Documentation](https://fastapi.tiangolo.com/)
+
+## Quick Links
+
+- **Current Feature Branch:** `feature/ai-copilot-bridge`
+- **Main Branch:** `master`
+- **Issue Tracker:** [GitHub Issues](https://github.com/GNS3/gns3-server/issues)
+
+---
+
+_Last updated: 2026-03-10_
diff --git a/docs/gns3-copilot/ai-chat-api-design.md b/docs/gns3-copilot/implemented/chat-api.md
similarity index 100%
rename from docs/gns3-copilot/ai-chat-api-design.md
rename to docs/gns3-copilot/implemented/chat-api.md
diff --git a/docs/gns3-copilot/command-security.md b/docs/gns3-copilot/implemented/command-security.md
similarity index 100%
rename from docs/gns3-copilot/command-security.md
rename to docs/gns3-copilot/implemented/command-security.md
diff --git a/docs/gns3-copilot/context-window-management.md b/docs/gns3-copilot/implemented/context-window-management.md
similarity index 100%
rename from docs/gns3-copilot/context-window-management.md
rename to docs/gns3-copilot/implemented/context-window-management.md
diff --git a/docs/gns3-copilot/llm-model-configs-api.md b/docs/gns3-copilot/implemented/llm-model-configs.md
similarity index 100%
rename from docs/gns3-copilot/llm-model-configs-api.md
rename to docs/gns3-copilot/implemented/llm-model-configs.md
diff --git a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md b/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md
deleted file mode 100644
index ead926d9a..000000000
--- a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md
+++ /dev/null
@@ -1,1235 +0,0 @@
-# ACL Web UI Implementation Guide
-
-**Document Status**: Design Phase
-**Priority**: High
-**Created**: 2026-03-06
-**Target Audience**: Frontend Developers
-
----
-
-## Table of Contents
-
-- [Feature Overview](#feature-overview)
-- [API Endpoints Details](#api-endpoints-details)
-- [Data Structures](#data-structures)
-- [Frontend Implementation Guide](#frontend-implementation-guide)
-- [UI/UX Design Recommendations](#uiux-design-recommendations)
-- [Common Scenarios](#common-scenarios)
-- [Error Handling](#error-handling)
-- [Example Code](#example-code)
-
----
-
-## Feature Overview
-
-### Objective
-
-Implement ACL (Access Control List) management functionality in the GNS3 Web UI, allowing administrators to manage user permissions through a graphical interface.
-
-### Core Features
-
-1. **View ACL List** - Display all ACEs (Access Control Entries)
-2. **Create ACE** - Add new access control entries
-3. **Edit ACE** - Modify existing ACE properties
-4. **Delete ACE** - Remove unwanted access control entries
-5. **Get Available Endpoints** - Retrieve list of resources that can be configured with ACL
-
-### User Flow
-
-```
-Administrator Login
- ↓
-Navigate to "Permission Management" page
- ↓
-View existing ACL list
- ↓
-Select action:
- - Create new ACE → Fill form → Submit
- - Edit existing ACE → Modify form → Save
- - Delete ACE → Confirm → Delete
-```
-
----
-
-## API Endpoints Details
-
-### Base URL
-
-```
-http://localhost:3080/v3/access/aces
-```
-
-### 1. Get All ACEs
-
-**Endpoint**: `GET /v3/access/aces`
-
-**Privilege**: `ACE.Audit`
-
-**Request Example**:
-```javascript
-const response = await fetch('/v3/access/aces', {
- headers: {
- 'Authorization': `Bearer ${token}`
- }
-});
-const aces = await response.json();
-```
-
-**Response Example**:
-```json
-[
- {
- "ace_id": "550e8400-e29b-41d4-a716-446655440000",
- "path": "/projects",
- "user_id": "650e8400-e29b-41d4-a716-446655440001",
- "group_id": null,
- "role_id": "750e8400-e29b-41d4-a716-446655440002",
- "allowed": true,
- "propagate": true,
- "ace_type": "user",
- "created_at": "2026-03-06T10:00:00Z",
- "updated_at": "2026-03-06T10:00:00Z"
- }
-]
-```
-
----
-
-### 2. Get Single ACE
-
-**Endpoint**: `GET /v3/access/aces/{ace_id}`
-
-**Privilege**: `ACE.Audit`
-
-**Request Example**:
-```javascript
-const response = await fetch(`/v3/access/aces/${aceId}`, {
- headers: {
- 'Authorization': `Bearer ${token}`
- }
-});
-const ace = await response.json();
-```
-
----
-
-### 3. Create ACE
-
-**Endpoint**: `POST /v3/access/aces`
-
-**Privilege**: `ACE.Allocate`
-
-**Request Example**:
-```javascript
-const newAce = {
- path: "/projects",
- user_id: "550e8400-e29b-41d4-a716-446655440000",
- role_id: "750e8400-e29b-41d4-a716-446655440002",
- allowed: true,
- propagate: true
-};
-
-const response = await fetch('/v3/access/aces', {
- method: 'POST',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(newAce)
-});
-const createdAce = await response.json();
-```
-
-**Response**: `201 Created` + Created ACE object
-
----
-
-### 4. Update ACE ⭐ Core Feature
-
-**Endpoint**: `PUT /v3/access/aces/{ace_id}`
-
-**Privilege**: `ACE.Modify`
-
-**Request Example**:
-```javascript
-const updatedAce = {
- path: "/projects/updated",
- allowed: false,
- propagate: false
-};
-
-const response = await fetch(`/v3/access/aces/${aceId}`, {
- method: 'PUT',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(updatedAce)
-});
-const updated = await response.json();
-```
-
-**Important**:
-- Supports **partial updates** - only submit fields to modify
-- `user_id` and `group_id` cannot both be present (choose one)
-- `path` must match an existing API endpoint
-
----
-
-### 5. Delete ACE
-
-**Endpoint**: `DELETE /v3/access/aces/{ace_id}`
-
-**Privilege**: `ACE.Allocate`
-
-**Request Example**:
-```javascript
-const response = await fetch(`/v3/access/aces/${aceId}`, {
- method: 'DELETE',
- headers: {
- 'Authorization': `Bearer ${token}`
- }
-});
-// Response: 204 No Content
-```
-
----
-
-### 6. Get Available Endpoints (for Path Selection)
-
-**Endpoint**: `GET /v3/access/aces/endpoints`
-
-**Privilege**: `ACE.Audit`
-
-**Request Example**:
-```javascript
-const response = await fetch('/v3/access/aces/endpoints', {
- headers: {
- 'Authorization': `Bearer ${token}`
- }
-});
-const endpoints = await response.json();
-```
-
-**Response Example**:
-```json
-[
- {
- "endpoint": "/",
- "name": "All endpoints",
- "endpoint_type": "root"
- },
- {
- "endpoint": "/projects",
- "name": "All projects",
- "endpoint_type": "project"
- },
- {
- "endpoint": "/projects/123e4567-e89b-12d3-a456-426614174000",
- "name": "Project \"My Project\"",
- "endpoint_type": "project"
- },
- {
- "endpoint": "/projects/123e4567-e89b-12d3-a456-426614174000/nodes",
- "name": "All nodes in project \"My Project\"",
- "endpoint_type": "node"
- },
- {
- "endpoint": "/pools",
- "name": "All resource pools",
- "endpoint_type": "pool"
- }
-]
-```
-
----
-
-### 7. Get Related Data
-
-#### Get Users List
-
-**Endpoint**: `GET /v3/access/users`
-
-**Privilege**: `User.Audit`
-
-```javascript
-const response = await fetch('/v3/access/users', {
- headers: { 'Authorization': `Bearer ${token}` }
-});
-const users = await response.json();
-```
-
-#### Get User Groups List
-
-**Endpoint**: `GET /v3/access/groups`
-
-**Privilege**: `Group.Audit`
-
-```javascript
-const response = await fetch('/v3/access/groups', {
- headers: { 'Authorization': `Bearer ${token}` }
-});
-const groups = await response.json();
-```
-
-#### Get Roles List
-
-**Endpoint**: `GET /v3/access/roles`
-
-**Privilege**: `Role.Audit`
-
-```javascript
-const response = await fetch('/v3/access/roles', {
- headers: { 'Authorization': `Bearer ${token}` }
-});
-const roles = await response.json();
-```
-
----
-
-## Data Structures
-
-### ACE Object
-
-```typescript
-interface ACE {
- ace_id: string; // UUID
- path: string; // Resource path, e.g., "/projects"
- user_id?: string; // User ID (choose one with group_id)
- group_id?: string; // User group ID (choose one with user_id)
- role_id: string; // Role ID
- allowed: boolean; // Whether allowed (default true)
- propagate: boolean; // Whether to propagate to child paths (default true)
- ace_type: "user" | "group"; // "user" or "group"
- created_at: string; // ISO 8601 timestamp
- updated_at: string; // ISO 8601 timestamp
-}
-```
-
-### ACECreate (Creating ACE)
-
-```typescript
-interface ACECreate {
- path: string;
- user_id?: string;
- group_id?: string;
- role_id: string;
- allowed?: boolean;
- propagate?: boolean;
-}
-```
-
-### ACEUpdate (Updating ACE)
-
-```typescript
-interface ACEUpdate {
- path?: string;
- user_id?: string;
- group_id?: string;
- role_id?: string;
- allowed?: boolean;
- propagate?: boolean;
-}
-```
-
-### Endpoint Object
-
-```typescript
-interface Endpoint {
- endpoint: string; // Endpoint path
- name: string; // Display name
- endpoint_type: string; // "root" | "project" | "node" | "link" | "user" | "group" | "role" | "pool"
-}
-```
-
----
-
-## Frontend Implementation Guide
-
-### Recommended Tech Stack
-
-- **Framework**: React / Vue / Angular
-- **State Management**: Redux / Vuex / NgRx
-- **UI Components**: Material-UI / Ant Design / Element Plus
-- **HTTP Client**: Axios / Fetch API
-
-### Core Component Design
-
-#### 1. ACE List Component
-
-```
-
- ├── # Filter
- ├── # ACE table
- │ ├──
- │ ├──
- │ └── ...
- └── # Create button
-```
-
-#### 2. ACE Form Component (Create/Edit)
-
-```
- # or mode="edit"
- ├── # Path selector
- ├── # User/group selector
- ├── # Role selector
- ├── # Allow/deny toggle
- ├── # Propagate switch
- └──
-```
-
-#### 3. Endpoint Selector Component
-
-```
-
- ├── # Tree structure showing endpoints
- │ ├──
- │ ├──
- │ └── ...
- └── # Search box
-```
-
----
-
-### State Management
-
-```typescript
-// Redux example
-interface ACLState {
- aces: ACE[];
- endpoints: Endpoint[];
- users: User[];
- groups: Group[];
- roles: Role[];
- loading: boolean;
- error: string | null;
-}
-
-// Actions
-const loadACEs = () => async (dispatch) => {
- dispatch({ type: 'ACL_LOAD_START' });
- try {
- const aces = await api.getACEs();
- dispatch({ type: 'ACL_LOAD_SUCCESS', payload: aces });
- } catch (error) {
- dispatch({ type: 'ACL_LOAD_ERROR', payload: error.message });
- }
-};
-
-const createACE = (ace: ACECreate) => async (dispatch) => {
- const newAce = await api.createACE(ace);
- dispatch({ type: 'ACL_CREATE_SUCCESS', payload: newAce });
-};
-
-const updateACE = (aceId: string, updates: ACEUpdate) => async (dispatch) => {
- const updated = await api.updateACE(aceId, updates);
- dispatch({ type: 'ACL_UPDATE_SUCCESS', payload: updated });
-};
-
-const deleteACE = (aceId: string) => async (dispatch) => {
- await api.deleteACE(aceId);
- dispatch({ type: 'ACL_DELETE_SUCCESS', payload: aceId });
-};
-```
-
----
-
-## UI/UX Design Recommendations
-
-### 1. List Page Layout
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ Permission Management [New ACE] │
-├─────────────────────────────────────────────────────────┤
-│ Filters: [User/Group] [Role] [Path Type] [Status] │
-├─────────────────────────────────────────────────────────┤
-│ ┌───────────────────────────────────────────────────┐ │
-│ │ Path │ User/Group │ Role │ Allow │ Action│ │
-│ ├───────────────────────────────────────────────────┤ │
-│ │ /projects │ user1 │ User │ ✓ │ Edit │ │
-│ │ /projects/123 │ group1 │ Auditor│ ✓ │ Edit │ │
-│ │ /pools/456 │ user2 │ User │ ✗ │ Edit │ │
-│ └───────────────────────────────────────────────────┘ │
-│ [Load More] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 2. Create/Edit Form
-
-```
-┌────────────────────────────────────────────┐
-│ New Access Control Entry (ACE) [Cancel]│
-├────────────────────────────────────────────┤
-│ │
-│ Resource Path * │
-│ ┌──────────────────────────────────────┐ │
-│ │ ▼ Select Endpoint [Search]│ │
-│ └──────────────────────────────────────┘ │
-│ Hint: Select the resource path to control │
-│ │
-│ Apply To * │
-│ ○ User □ User Group │
-│ ┌──────────────────────────────────────┐ │
-│ │ ▼ Select User │ │
-│ └──────────────────────────────────────┘ │
-│ │
-│ Role * │
-│ ┌──────────────────────────────────────┐ │
-│ │ User ▼ │ │
-│ └──────────────────────────────────────┘ │
-│ Note: This role includes Project.Audit │
-│ and other privileges │
-│ │
-│ Permission Settings │
-│ ○ Allow Access ● Deny Access │
-│ │
-│ □ Propagate to Child Paths │
-│ Note: When checked, permission applies │
-│ to all child resources │
-│ │
-│ [Cancel] [Save] │
-└────────────────────────────────────────────┘
-```
-
-### 3. Endpoint Selector (Tree Structure)
-
-```
-┌────────────────────────────────────────────┐
-│ Select Resource Path [Search] │
-├────────────────────────────────────────────┤
-│ 📁 / (All endpoints) │
-│ 📁 /projects (All projects) │
-│ 📁 My Project │
-│ 📁 /nodes (All nodes) │
-│ 📄 Router1 │
-│ 📄 Switch1 │
-│ 📁 /links (All links) │
-│ 📁 /pools (All resource pools) │
-│ 📄 Production Pool │
-│ 📁 /templates (All templates) │
-└────────────────────────────────────────────┘
-```
-
-### 4. Interaction Design Points
-
-#### Loading States
-```javascript
-// Show skeleton screen
-
-
-// Or progress bar
-
-```
-
-#### Error Messages
-```javascript
-// Form validation error
-
- Path cannot be empty
-
-
-// API error
-
-```
-
-#### Confirmation Dialog
-```javascript
-// Delete confirmation
-
-```
-
----
-
-## Common Scenarios
-
-### Scenario 1: Create User-Level ACE
-
-```javascript
-async function createUserACE() {
- const newAce = {
- path: "/projects",
- user_id: selectedUserId,
- role_id: userRoleId,
- allowed: true,
- propagate: true
- };
-
- try {
- const ace = await api.createACE(newAce);
- showSuccess('ACE created successfully');
- loadACEList(); // Refresh list
- } catch (error) {
- showError(`Creation failed: ${error.message}`);
- }
-}
-```
-
-### Scenario 2: Create Group-Level ACE
-
-```javascript
-async function createGroupACE() {
- const newAce = {
- path: "/templates",
- group_id: usersGroupId,
- role_id: userRoleId,
- allowed: true,
- propagate: false
- };
-
- try {
- const ace = await api.createACE(newAce);
- showSuccess('Group ACE created successfully');
- loadACEList();
- } catch (error) {
- showError(`Creation failed: ${error.message}`);
- }
-}
-```
-
-### Scenario 3: Edit Existing ACE
-
-```javascript
-async function editACE(aceId, updates) {
- try {
- const updated = await api.updateACE(aceId, updates);
- showSuccess('ACE updated successfully');
- loadACEList();
- } catch (error) {
- showError(`Update failed: ${error.message}`);
- }
-}
-
-// Example: Toggle allowed status
-async function toggleAllowed(ace) {
- await editACE(ace.ace_id, {
- allowed: !ace.allowed
- });
-}
-
-// Example: Change path
-async function changePath(aceId, newPath) {
- await editACE(aceId, {
- path: newPath
- });
-}
-```
-
-### Scenario 4: Delete ACE
-
-```javascript
-async function deleteACE(aceId) {
- if (!confirm('Are you sure you want to delete this ACE?')) {
- return;
- }
-
- try {
- await api.deleteACE(aceId);
- showSuccess('ACE deleted successfully');
- loadACEList();
- } catch (error) {
- showError(`Deletion failed: ${error.message}`);
- }
-}
-```
-
-### Scenario 5: Batch Operations
-
-```javascript
-// Batch delete
-async function batchDelete(aceIds) {
- const promises = aceIds.map(id => api.deleteACE(id));
- await Promise.all(promises);
- showSuccess(`Deleted ${aceIds.length} ACEs`);
- loadACEList();
-}
-
-// Batch toggle allowed status
-async function batchToggleAllowed(aceIds, allowed) {
- const promises = aceIds.map(id =>
- api.updateACE(id, { allowed })
- );
- await Promise.all(promises);
- showSuccess(`Updated ${aceIds.length} ACEs`);
- loadACEList();
-}
-```
-
----
-
-## Error Handling
-
-### Common Error Types
-
-| HTTP Status | Error Description | Handling |
-|-------------|-------------------|----------|
-| 400 Bad Request | Path doesn't match any endpoint | Prompt user to select valid path |
-| 400 Bad Request | Both user_id and group_id present | Prompt user to choose one |
-| 403 Forbidden | Insufficient privileges | Prompt user to contact administrator |
-| 404 Not Found | ACE doesn't exist | Refresh list, notify resource deleted |
-| 422 Unprocessable Entity | Validation failed | Display specific field errors |
-
-### Error Handling Example
-
-```javascript
-async function handleAPICall(apiFunction) {
- try {
- const result = await apiFunction();
- return { success: true, data: result };
- } catch (error) {
- if (error.response) {
- const { status, data } = error.response;
-
- switch (status) {
- case 400:
- return {
- success: false,
- error: data.detail || 'Invalid request parameters'
- };
-
- case 403:
- return {
- success: false,
- error: 'Insufficient privileges, please contact administrator'
- };
-
- case 404:
- return {
- success: false,
- error: 'Resource not found, may have been deleted'
- };
-
- case 422:
- return {
- success: false,
- error: formatValidationError(data.detail)
- };
-
- default:
- return {
- success: false,
- error: 'Unknown error, please try again later'
- };
- }
- }
-
- return {
- success: false,
- error: 'Network error, please check connection'
- };
- }
-}
-
-function formatValidationError(errors) {
- // Format validation error messages
- return errors.map(err => err.msg).join(', ');
-}
-```
-
----
-
-## Example Code
-
-### Complete React Component Example
-
-```jsx
-import React, { useState, useEffect } from 'react';
-import {
- Table,
- Button,
- Dialog,
- DialogTitle,
- DialogContent,
- DialogActions,
- Select,
- MenuItem,
- Switch,
- FormControlLabel,
- TextField,
- IconButton
-} from '@mui/material';
-import { Edit, Delete, Add } from '@mui/icons-material';
-
-// API Client
-const api = {
- async getACEs(token) {
- const res = await fetch('/v3/access/aces', {
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error(res.statusText);
- return res.json();
- },
-
- async getEndpoints(token) {
- const res = await fetch('/v3/access/aces/endpoints', {
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error(res.statusText);
- return res.json();
- },
-
- async getUsers(token) {
- const res = await fetch('/v3/access/users', {
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error(res.statusText);
- return res.json();
- },
-
- async getGroups(token) {
- const res = await fetch('/v3/access/groups', {
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error(res.statusText);
- return res.json();
- },
-
- async getRoles(token) {
- const res = await fetch('/v3/access/roles', {
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error(res.statusText);
- return res.json();
- },
-
- async createACE(token, data) {
- const res = await fetch('/v3/access/aces', {
- method: 'POST',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(data)
- });
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.detail || 'Creation failed');
- }
- return res.json();
- },
-
- async updateACE(token, aceId, data) {
- const res = await fetch(`/v3/access/aces/${aceId}`, {
- method: 'PUT',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(data)
- });
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.detail || 'Update failed');
- }
- return res.json();
- },
-
- async deleteACE(token, aceId) {
- const res = await fetch(`/v3/access/aces/${aceId}`, {
- method: 'DELETE',
- headers: { 'Authorization': `Bearer ${token}` }
- });
- if (!res.ok) throw new Error('Deletion failed');
- }
-};
-
-// ACE Form Component
-function ACEForm({ token, ace, onSave, onCancel }) {
- const [endpoints, setEndpoints] = useState([]);
- const [users, setUsers] = useState([]);
- const [groups, setGroups] = useState([]);
- const [roles, setRoles] = useState([]);
- const [formData, setFormData] = useState({
- path: ace?.path || '',
- user_id: ace?.user_id || '',
- group_id: ace?.group_id || '',
- role_id: ace?.role_id || '',
- allowed: ace?.allowed ?? true,
- propagate: ace?.propagate ?? true,
- ace_type: ace?.ace_type || 'user'
- });
-
- useEffect(() => {
- Promise.all([
- api.getEndpoints(token),
- api.getUsers(token),
- api.getGroups(token),
- api.getRoles(token)
- ]).then(([endpoints, users, groups, roles]) => {
- setEndpoints(endpoints);
- setUsers(users);
- setGroups(groups);
- setRoles(roles);
- });
- }, [token]);
-
- const handleSubmit = async (e) => {
- e.preventDefault();
-
- const data = {
- ...formData,
- [formData.ace_type === 'user' ? 'user_id' : 'group_id']:
- formData.ace_type === 'user' ? formData.user_id : formData.group_id
- };
- delete data.ace_type;
- delete data.user_id;
- delete data.group_id;
-
- if (formData.ace_type === 'user') {
- data.user_id = formData.user_id;
- } else {
- data.group_id = formData.group_id;
- }
-
- try {
- if (ace) {
- await api.updateACE(token, ace.ace_id, data);
- } else {
- await api.createACE(token, data);
- }
- onSave();
- } catch (error) {
- alert(error.message);
- }
- };
-
- return (
-
- );
-}
-
-// ACE List Component
-export default function ACLManagement({ token }) {
- const [aces, setAces] = useState([]);
- const [loading, setLoading] = useState(false);
- const [dialogOpen, setDialogOpen] = useState(false);
- const [editingACE, setEditingACE] = useState(null);
-
- const loadACEs = async () => {
- setLoading(true);
- try {
- const data = await api.getACEs(token);
- setAces(data);
- } catch (error) {
- alert(`Loading failed: ${error.message}`);
- } finally {
- setLoading(false);
- }
- };
-
- useEffect(() => {
- loadACEs();
- }, [token]);
-
- const handleCreate = () => {
- setEditingACE(null);
- setDialogOpen(true);
- };
-
- const handleEdit = (ace) => {
- setEditingACE(ace);
- setDialogOpen(true);
- };
-
- const handleDelete = async (aceId) => {
- if (!confirm('Are you sure you want to delete this ACE?')) return;
-
- try {
- await api.deleteACE(token, aceId);
- loadACEs();
- } catch (error) {
- alert(`Deletion failed: ${error.message}`);
- }
- };
-
- const handleSave = () => {
- setDialogOpen(false);
- loadACEs();
- };
-
- return (
-
-
-
Access Control List (ACL)
- }
- onClick={handleCreate}
- >
- New ACE
-
-
-
- {loading ? (
-
Loading...
- ) : (
-
-
-
- | Path |
- User/Group |
- Role |
- Allowed |
- Propagate |
- Actions |
-
-
-
- {aces.map((ace) => (
-
- | {ace.path} |
- {ace.ace_type === 'user' ? ace.user_id : ace.group_id} |
- {ace.role_id} |
- {ace.allowed ? '✓' : '✗'} |
- {ace.propagate ? '✓' : '✗'} |
-
- handleEdit(ace)}>
-
-
- handleDelete(ace.ace_id)}>
-
-
- |
-
- ))}
-
-
- )}
-
-
-
- );
-}
-```
-
----
-
-## Implementation Checklist
-
-### Basic Features
-- [ ] Fetch and display ACE list
-- [ ] Create new ACE
-- [ ] Edit existing ACE
-- [ ] Delete ACE
-- [ ] Fetch and display available endpoints
-
-### Form Features
-- [ ] Path selector (dropdown/tree)
-- [ ] User/group selector
-- [ ] Role selector
-- [ ] Allow/deny toggle
-- [ ] Propagate switch
-- [ ] Form validation
-
-### User Experience
-- [ ] Loading state display
-- [ ] Error notifications
-- [ ] Success notifications
-- [ ] Delete confirmation dialog
-- [ ] List filtering/search
-
-### Advanced Features
-- [ ] Batch operations
-- [ ] ACE export/import
-- [ ] Permission preview
-- [ ] Change history
-
----
-
-## References
-
-### Related Documentation
-- [RBAC + ACL Permission System Implementation Guide](../gns3-server/rbac-acl-权限系统实现说明.md)
-- [RBAC + ACL Implementation Guide](../gns3-server/rbac-acl-implementation-guide.md)
-
-### API Specifications
-- OpenAPI/Swagger: `/static/swagger-ui-bundle.js`
-- ReDoc: `/static/redoc.standalone.js`
-
-### Test Data
-```javascript
-// Example ACEs for testing
-const exampleACEs = [
- {
- path: "/projects",
- ace_type: "user",
- user_id: "admin-user-id",
- role_id: "user-role-id",
- allowed: true,
- propagate: true
- },
- {
- path: "/projects/sensitive",
- ace_type: "group",
- group_id: "auditors-group-id",
- role_id: "auditor-role-id",
- allowed: false,
- propagate: false
- }
-];
-```
-
----
-
-**Document Version**: 1.0
-**Last Updated**: 2026-03-06
-
-
----
-
-## License
-
-**Copyright © 2025 Yue Guobin (岳国宾)**
-
-This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
-International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
-
-
-
-### Summary
-
-You are free to:
-
-- **Share** — Copy and redistribute the material in any medium or format
-- **Adapt** — Remix, transform, and build upon the material for any purpose
-
-Under the following terms:
-
-- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
- a link to the license, and indicate if changes were made.
-- **ShareAlike** — If you remix, transform, or build upon the material, you must
- distribute your contributions under the **same license** (CC BY-SA 4.0).
-
-Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
-
diff --git a/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md b/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md
index a0bee83bf..6245f4cee 100644
--- a/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md
+++ b/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md
@@ -795,3 +795,30 @@ test_cases = [
| Assume vendor/OS | Ask or detect from node |
| Mix features in one dict | Separate by feature key |
| Use string for numbers | Use int: `process_id: 100` not `"process_id": "100"` |
+
+---
+
+## License
+
+**Copyright © 2025 Yue Guobin (岳国宾)**
+
+This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
+International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
+
+
+
+### Summary
+
+You are free to:
+
+- **Share** — Copy and redistribute the material in any medium or format
+- **Adapt** — Remix, transform, and build upon the material for any purpose
+
+Under the following terms:
+
+- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
+ a link to the license, and indicate if changes were made.
+- **ShareAlike** — If you remix, transform, or build upon the material, you must
+ distribute your contributions under the **same license** (CC BY-SA 4.0).
+
+Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
diff --git a/docs/gns3-copilot/todo/config-templates-implementation-guide.md b/docs/gns3-copilot/todo/config-templates-implementation-guide.md
index b4ffb3139..8e9859636 100644
--- a/docs/gns3-copilot/todo/config-templates-implementation-guide.md
+++ b/docs/gns3-copilot/todo/config-templates-implementation-guide.md
@@ -707,3 +707,30 @@ Solution: Check if feature flag "enabled" is set to True
```
Solution: Review template logic, check conditional statements
```
+
+---
+
+## License
+
+**Copyright © 2025 Yue Guobin (岳国宾)**
+
+This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
+International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
+
+
+
+### Summary
+
+You are free to:
+
+- **Share** — Copy and redistribute the material in any medium or format
+- **Adapt** — Remix, transform, and build upon the material for any purpose
+
+Under the following terms:
+
+- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
+ a link to the license, and indicate if changes were made.
+- **ShareAlike** — If you remix, transform, or build upon the material, you must
+ distribute your contributions under the **same license** (CC BY-SA 4.0).
+
+Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
diff --git a/docs/gns3-copilot/todo/jinja2-config-templates-system.md b/docs/gns3-copilot/todo/jinja2-config-templates-system.md
index 68d1b2164..af7c766e6 100644
--- a/docs/gns3-copilot/todo/jinja2-config-templates-system.md
+++ b/docs/gns3-copilot/todo/jinja2-config-templates-system.md
@@ -1082,3 +1082,31 @@ include network 192.168.1.0/24 in area 0. Output as structured JSON data."
```
Then the agent calls `render_device_config` tool to get the actual configuration.
+
+
+---
+
+## License
+
+**Copyright © 2025 Yue Guobin (岳国宾)**
+
+This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
+International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
+
+
+
+### Summary
+
+You are free to:
+
+- **Share** — Copy and redistribute the material in any medium or format
+- **Adapt** — Remix, transform, and build upon the material for any purpose
+
+Under the following terms:
+
+- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
+ a link to the license, and indicate if changes were made.
+- **ShareAlike** — If you remix, transform, or build upon the material, you must
+ distribute your contributions under the **same license** (CC BY-SA 4.0).
+
+Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
diff --git a/docs/gns3-server/rbac-acl-权限系统实现说明.md b/docs/gns3-server/rbac-acl-权限系统实现说明.md
deleted file mode 100644
index 2967211fc..000000000
--- a/docs/gns3-server/rbac-acl-权限系统实现说明.md
+++ /dev/null
@@ -1,571 +0,0 @@
-# GNS3 RBAC + ACL 权限系统实现说明
-
-**文档版本**: 1.0
-**创建日期**: 2026-03-06
-**适用版本**: GNS3 Server v3.0+
-
----
-
-## 目录
-
-- [系统概述](#系统概述)
-- [核心概念](#核心概念)
-- [数据模型](#数据模型)
-- [权限检查流程](#权限检查流程)
-- [使用示例](#使用示例)
-- [最佳实践](#最佳实践)
-- [常见问题](#常见问题)
-
----
-
-## 系统概述
-
-GNS3 Server 实现了一个**两层权限控制系统**,结合了 **RBAC**(基于角色的访问控制)和 **ACL**(访问控制列表)的特性:
-
-```
-┌─────────────────────────────────────────────────────┐
-│ 第 1 层:RBAC (定义能力) │
-│ │
-│ 角色 → 权限 │
-│ 回答问题:"用户能做什么操作?" │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 第 2 层:ACL (明确授权) │
-│ │
-│ 默认:拒绝所有 (Deny All) │
-│ 除非:ACE 明确允许 (Explicitly Allow) │
-│ 回答问题:"能在哪些资源上使用这些操作?" │
-└─────────────────────────────────────────────────────┘
-```
-
-### 核心原则
-
-**默认拒绝,明确允许**
-
-就像网络设备的 ACL,默认情况下拒绝所有访问请求,除非有明确的 ACE(访问控制条目)允许。
-
-```
-没有 ACE → ❌ 拒绝访问
-有 ACE (allowed=False) → ❌ 拒绝访问
-有 ACE (allowed=True) → ✅ 允许访问
-```
-
----
-
-## 核心概念
-
-### 1. 权限 (Privilege)
-
-权限定义了用户可以执行的操作。
-
-```python
-权限命名格式: <资源>.<操作>
-
-示例:
-- Project.Audit # 查看项目
-- Project.Allocate # 创建/删除项目
-- Project.Modify # 修改项目
-- Node.Console # 访问节点控制台
-- Link.Capture # 捕获链路流量
-```
-
-**预定义权限**: 38 个内置权限(详见 `gns3server/db/models/privileges.py`)
-
-### 2. 角色 (Role)
-
-角色是权限的集合,用于简化权限管理。
-
-```python
-内置角色:
-- Administrator: 所有权限
-- User: 项目、节点、链路、快照等常用权限
-- Auditor: 只读权限 (*.Audit)
-- Template manager: 模板和符号管理
-- User manager: 用户和组管理
-- ACL manager: 角色和 ACE 管理
-- No Access: 无任何权限
-```
-
-### 3. 用户组 (User Group)
-
-用户组用于批量管理用户。
-
-```python
-内置组:
-- Administrators: 管理员组
-- Users: 普通用户组
-```
-
-### 4. ACE (Access Control Entry)
-
-ACE 是访问控制的核心,定义了**在哪些资源上可以使用哪些角色**。
-
-```python
-ACE 结构:
-{
- "path": "/projects", # 资源路径
- "user_id": "uuid", # 用户 ID (与 group_id 二选一)
- "group_id": "uuid", # 用户组 ID (与 user_id 二选一)
- "role_id": "uuid", # 角色 ID
- "allowed": true, # 是否允许 (默认 true)
- "propagate": true, # 是否传播到子路径 (默认 true)
- "ace_type": "user" # "user" 或 "group"
-}
-```
-
-**重要**:
-- `path`: 使用文件系统风格的路径,如 `/projects`、`/projects/123`
-- `role_id`: ACE 关联的角色,角色定义了可用权限
-- `allowed`: 显式允许或拒绝(默认 true)
-- `propagate`: 权限是否继承到子路径(默认 true)
-
----
-
-## 数据模型
-
-### 实体关系
-
-```
-User ────< UserGroup > (many-to-many via user_group_map)
- │ │
- │ └───< ACE (group_id)
- │
- └───< ACE (user_id)
- │
- ├── path (资源路径)
- ├── role → Role → Privilege (权限)
- ├── allowed (允许/拒绝)
- └── propagate (是否传播)
-```
-
-### 数据库表
-
-| 表名 | 说明 | 关键字段 |
-|------|------|----------|
-| `users` | 用户 | `user_id`, `username`, `is_superadmin` |
-| `user_groups` | 用户组 | `user_group_id`, `name` |
-| `roles` | 角色 | `role_id`, `name`, `is_builtin` |
-| `privileges` | 权限 | `privilege_id`, `name` |
-| `acl` (ACE) | 访问控制条目 | `ace_id`, `path`, `user_id`, `group_id`, `role_id`, `allowed`, `propagate` |
-| `privilege_role_map` | 角色-权限关联 | `privilege_id`, `role_id` |
-| `user_group_map` | 用户-组关联 | `user_id`, `user_group_id` |
-
----
-
-## 权限检查流程
-
-### 完整流程图
-
-```
-用户请求: GET /projects/123,需要 Project.Audit 权限
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 1. 提取请求信息 │
-│ - 用户 ID │
-│ - 路径: /projects/123 │
-│ - 所需权限: Project.Audit │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 2. 特殊检查: Superadmin │
-│ 如果 is_superadmin = True │
-│ → ✅ 直接允许(绕过 RBAC + ACL) │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 3. 查询用户 ACE │
-│ SELECT * FROM ace │
-│ JOIN privilege_role_map ON ace.role_id = ... │
-│ JOIN privileges ON ... │
-│ WHERE │
-│ ace.user_id = │
-│ AND privileges.name = 'Project.Audit' │
-│ AND ace.path 匹配 /projects/123 │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 4. 检查用户 ACE │
-│ 如果找到匹配的 ACE: │
-│ - if allowed = False → ❌ 拒绝 │
-│ - if allowed = True → ✅ 允许 │
-│ 如果没找到: │
-│ → 继续检查组 ACE │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 5. 查询组 ACE │
-│ 查询用户所属的所有组的 ACE │
-│ (查询逻辑与用户 ACE 相同) │
-└─────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────┐
-│ 6. 检查组 ACE │
-│ 如果找到匹配的组 ACE: │
-│ - if allowed = False → ❌ 拒绝 │
-│ - if allowed = True → ✅ 允许 │
-│ 如果没找到: │
-│ → ❌ 拒绝访问(默认拒绝所有) │
-└─────────────────────────────────────────────────────┘
-```
-
-### 路径匹配规则
-
-路径匹配遵循**从具体到通用**的原则:
-
-```
-请求路径: /projects/123/nodes/456
-
-检查顺序:
-1. /projects/123/nodes/456 (最具体)
-2. /projects/123/nodes
-3. /projects/123
-4. /projects
-5. / (最通用)
-```
-
-**propagate 参数的影响**:
-
-```python
-# ACE 1: path="/projects", propagate=True
-✅ 允许访问: /projects, /projects/123, /projects/123/nodes
-# 权限传播到所有子路径
-
-# ACE 2: path="/projects", propagate=False
-✅ 允许访问: /projects
-❌ 拒绝访问: /projects/123, /projects/123/nodes
-# 权限不传播,只允许精确匹配
-```
-
----
-
-## 使用示例
-
-### 场景 1: 允许用户访问所有项目
-
-```python
-# 创建 ACE
-POST /v3/access/aces
-{
- "path": "/projects",
- "user_id": "550e8400-e29b-41d4-a716-446655440000",
- "role_id": "",
- "allowed": true,
- "propagate": true
-}
-
-# 结果: 用户可以访问所有项目 (/projects/*)
-```
-
-### 场景 2: 允许用户只访问特定项目
-
-```python
-# 创建 ACE(精确路径)
-POST /v3/access/aces
-{
- "path": "/projects/my-project-id",
- "user_id": "550e8400-e29b-41d4-a716-446655440000",
- "role_id": "",
- "allowed": true,
- "propagate": false
-}
-
-# 结果: 用户只能访问 /projects/my-project-id
-# 不能访问其他项目
-```
-
-### 场景 3: 使用组权限
-
-```python
-# 为组创建 ACE
-POST /v3/access/aces
-{
- "path": "/projects",
- "group_id": "",
- "role_id": "",
- "allowed": true,
- "propagate": true
-}
-
-# 结果: "Users" 组的所有成员都可以访问所有项目
-```
-
-### 场景 4: 显式拒绝特定资源
-
-```python
-# 用户可以访问所有项目
-ACE: path="/projects", user=A, allowed=true, propagate=true
-
-# 但拒绝访问某个秘密项目
-ACE: path="/projects/secret", user=A, allowed=false
-
-# 结果: 用户可以访问所有项目,除了 /projects/secret
-```
-
-### 场景 5: 使用资源池
-
-```python
-# 为用户分配资源池访问权限
-POST /v3/access/aces
-{
- "path": "/pools/pool-123",
- "user_id": "550e8400-e29b-41d4-a716-446655440000",
- "role_id": "",
- "allowed": true,
- "propagate": true
-}
-
-# 结果: 用户可以访问 pool-123 中的所有资源
-```
-
----
-
-## 最佳实践
-
-### 1. 使用组管理权限(推荐)
-
-**推荐** ✅:
-```python
-# 为 "Users" 组创建 ACE
-ACE(path="/projects", group="Users", role="User", allowed=true)
-```
-
-**不推荐** ❌:
-```python
-# 为每个用户单独创建 ACE
-ACE(path="/projects", user="user1", role="User", allowed=true)
-ACE(path="/projects", user="user2", role="User", allowed=true)
-ACE(path="/projects", user="user3", role="User", allowed=true)
-# ... 为数百个用户重复
-```
-
-### 2. 使用 propagate 减少配置
-
-**推荐** ✅:
-```python
-# 使用 propagate=True
-ACE(path="/projects", group="Users", role="User", allowed=true, propagate=true)
-# 一个 ACE 覆盖所有项目和子资源
-```
-
-**不推荐** ❌:
-```python
-# 为每个项目单独创建 ACE
-ACE(path="/projects/1", group="Users", role="User", allowed=true)
-ACE(path="/projects/2", group="Users", role="User", allowed=true)
-ACE(path="/projects/3", group="Users", role="User", allowed=true)
-# ... 难以维护
-```
-
-### 3. 使用默认 ACE
-
-**问题**: 新安装的系统,默认没有任何 ACE,用户无法访问任何资源。
-
-**解决方案**: 为默认用户组创建默认 ACE
-
-```python
-# 初始化脚本
-async def create_default_aces():
- users_group = await get_group_by_name("Users")
- user_role = await get_role_by_name("User")
-
- # 为 "Users" 组创建默认 ACE
- await create_ace({
- "path": "/",
- "group_id": users_group.id,
- "role_id": user_role.id,
- "allowed": true,
- "propagate": true
- })
-```
-
-### 4. 审计权限配置
-
-定期检查 ACE 配置:
-
-```python
-# 查询所有 ACE
-GET /v3/access/aces
-
-# 检查用户的实际权限
-GET /v3/access/users/me
-# 返回用户所属组、可访问池、ACE 列表
-```
-
----
-
-## 常见问题
-
-### Q1: 为什么用户有角色权限,但无法访问资源?
-
-**A**: 这是最常见的问题。RBAC 定义了"能做什么",但 ACL 限定了"能在哪里做"。
-
-**检查清单**:
-1. 用户是否有匹配的 ACE?
-2. ACE 的 `path` 是否匹配请求路径?
-3. ACE 的 `allowed` 是否为 `true`?
-4. ACE 关联的 `role` 是否有所需权限?
-
-```bash
-# 检查用户的 ACE
-curl -X GET http://localhost:3080/v3/access/aces \
- -H "Authorization: Bearer "
-
-# 检查用户的组
-curl -X GET http://localhost:3080/v3/access/users/me \
- -H "Authorization: Bearer "
-```
-
-### Q2: propagate 参数有什么用?
-
-**A**: `propagate` 控制权限是否继承到子路径。
-
-- `propagate=true`: 权限传播到所有子路径
-- `propagate=false`: 权限只应用于精确路径
-
-```
-ACE: path="/projects", propagate=true
-→ 允许: /projects, /projects/1, /projects/1/nodes, ...
-
-ACE: path="/projects", propagate=false
-→ 允许: /projects
-→ 拒绝: /projects/1, /projects/1/nodes, ...
-```
-
-### Q3: 用户 ACE 和组 ACE 的优先级?
-
-**A**: 用户 ACE 优先于组 ACE。
-
-```python
-# 用户 ACE
-ACE(path="/projects", user=A, role=Auditor, allowed=true)
-
-# 组 ACE(同一用户的组)
-ACE(path="/projects", group=Users, role=User, allowed=true)
-
-# 结果: 用户 ACE 优先,用户使用 Auditor 角色
-```
-
-### Q4: 如何拒绝访问特定资源?
-
-**A**: 创建 `allowed=false` 的 ACE。
-
-```python
-# 用户可以访问所有项目
-ACE(path="/projects", user=A, role=User, allowed=true, propagate=true)
-
-# 但拒绝访问秘密项目
-ACE(path="/projects/secret", user=A, role=User, allowed=false)
-```
-
-**注意**: 拒绝 ACE 的路径必须更具体(更长的路径)。
-
-### Q5: Superadmin 是否受 RBAC + ACL 限制?
-
-**A**: 不受限制。`is_superadmin=true` 的用户绕过所有权限检查。
-
-```python
-# Superadmin
-{
- "username": "admin",
- "is_superadmin": true
-}
-
-# 访问任何资源都不需要 ACE
-```
-
-### Q6: 资源池的路径格式是什么?
-
-**A**: 资源池使用 `/pools/{pool_id}` 格式。
-
-```python
-# 为用户分配资源池访问权限
-ACE(path="/pools/pool-123", user=A, role=User, allowed=true)
-
-# 池中的项目路径
-# /pools/pool-123/projects/project-1
-```
-
-**注意**: 代码中有 `/pool` 和 `/pools` 的不一致问题,建议使用 `/pools`(复数形式)。
-
-### Q7: 如何调试权限问题?
-
-**A**: 启用调试日志并检查权限检查流程。
-
-```python
-# 启用调试日志
-import logging
-logging.getLogger("gns3server.db.repositories.rbac").setLevel(logging.DEBUG)
-
-# 查看日志
-# DEBUG:gns3server.db.repositories.rbac:Checking user admin has privilege Project.Audit on '/projects/123'
-```
-
----
-
-## API 参考
-
-### 权限检查相关的 API 端点
-
-| 端点 | 方法 | 说明 | 所需权限 |
-|------|------|------|----------|
-| `/v3/access/users/me` | GET | 获取当前用户信息(包含组、池、ACE) | 无(认证用户) |
-| `/v3/access/users` | GET | 获取所有用户 | User.Audit |
-| `/v3/access/users/{user_id}` | GET | 获取指定用户 | User.Audit |
-| `/v3/access/groups` | GET | 获取所有组 | Group.Audit |
-| `/v3/access/roles` | GET | 获取所有角色 | Role.Audit |
-| `/v3/access/privileges` | GET | 获取所有权限 | Role.Audit |
-| `/v3/access/aces` | GET | 获取所有 ACE | ACE.Audit |
-| `/v3/access/aces` | POST | 创建 ACE | ACE.Allocate |
-| `/v3/access/aces/{ace_id}` | PUT | 更新 ACE | ACE.Modify |
-| `/v3/access/aces/{ace_id}` | DELETE | 删除 ACE | ACE.Allocate |
-
----
-
-## 代码位置参考
-
-| 组件 | 文件路径 |
-|------|----------|
-| 数据模型 | `gns3server/db/models/` |
-| - 用户和组 | `users.py` |
-| - 角色和权限 | `roles.py`, `privileges.py` |
-| - ACE | `acl.py` |
-| RBAC 仓库 | `gns3server/db/repositories/rbac.py` |
-| 权限检查依赖 | `gns3server/api/routes/controller/dependencies/rbac.py` |
-| API 路由 | `gns3server/api/routes/controller/` |
-| - 用户路由 | `users.py` |
-| - RBAC 路由 | `roles.py`, `acl.py` |
-| Schemas | `gns3server/schemas/controller/rbac.py` |
-
----
-
-## 总结
-
-GNS3 的 RBAC + ACL 系统是一个强大且灵活的权限控制框架:
-
-### 关键要点
-
-1. **两层防护**: RBAC 定义能力,ACL 限定范围
-2. **默认拒绝**: 没有 ACE = 拒绝访问
-3. **明确允许**: 必须有 ACE(allowed=true)才能访问
-4. **角色优先**: ACE 通过角色授予权限
-5. **路径继承**: propagate 控制权限传播
-
-### 设计优势
-
-- ✅ 细粒度控制:精确到具体资源的权限
-- ✅ 灵活性强:支持用户和组级别的权限
-- ✅ 集中管理:通过角色集中定义权限
-- ✅ 安全性高:默认拒绝所有,显式允许
-
-### 注意事项
-
-- ⚠️ 新系统需要创建默认 ACE
-- ⚠️ 必须为每个用户/组配置 ACE
-- ⚠️ 定期审计权限配置
-- ⚠️ Superadmin 绕过所有限制
-
----
-
-**文档版本**: 1.0
-**最后更新**: 2026-03-06