From a930f4347719ff21a28cfc9da21d01516e453506 Mon Sep 17 00:00:00 2001 From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:53:10 +0800 Subject: [PATCH] update --- packages/backend/Dockerfile | 63 +++++++++++++++++++ packages/frontend/Dockerfile | 47 ++++++++++++++ packages/frontend/nginx.conf | 20 ++++++ packages/frontend/package.json | 3 +- .../src/components/StyleCustomizer.vue | 2 +- .../appearance/config/iterm-themes.ts | 2 +- .../frontend/src/stores/appearance.store.ts | 4 +- .../src/stores/quickCommands.store.ts | 2 +- .../frontend/src/types/appearance.types.ts | 18 ++++++ packages/frontend/src/types/audit.types.ts | 54 ++++++++++++++++ .../src/types/quick-commands.types.ts | 11 ++++ .../src/types/terminal-theme.types.ts | 13 ++++ packages/frontend/src/views/DashboardView.vue | 2 +- packages/frontend/tsconfig.json | 6 +- 14 files changed, 237 insertions(+), 10 deletions(-) create mode 100644 packages/backend/Dockerfile create mode 100644 packages/frontend/Dockerfile create mode 100644 packages/frontend/nginx.conf create mode 100644 packages/frontend/src/types/appearance.types.ts create mode 100644 packages/frontend/src/types/audit.types.ts create mode 100644 packages/frontend/src/types/quick-commands.types.ts create mode 100644 packages/frontend/src/types/terminal-theme.types.ts diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile new file mode 100644 index 0000000..9dd72ee --- /dev/null +++ b/packages/backend/Dockerfile @@ -0,0 +1,63 @@ +# Stage 1: Build the application using npm workspaces +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy root package.json and package-lock.json +COPY package.json package-lock.json* ./ + +# Copy backend package definition and frontend (needed for workspace install) +# We need frontend's package.json for npm ci to resolve the workspace correctly +COPY packages/backend/package.json ./packages/backend/ +COPY packages/frontend/package.json ./packages/frontend/ +# If there are other packages backend depends on, copy their package.json too +# COPY packages/types/package.json ./packages/types/ # Example if types existed and was a package + +# Install ALL workspace dependencies using the root lock file +# This ensures all dependencies are correctly installed according to the lock file +RUN npm ci + +# Copy the rest of the source code needed for the backend build +COPY packages/backend/src ./packages/backend/src +COPY packages/backend/tsconfig.json ./packages/backend/ + +# Build only the backend package +# Use --workspace flag to specify which package to build +RUN npm run build --workspace=@nexus-terminal/backend + +# Prune devDependencies for the entire workspace might be complex. +# Instead, we'll copy only the necessary production files in the next stage. + + +# Stage 2: Create the final production image +FROM node:20-alpine + +# Install build dependencies needed for native addons like sqlite3 on Alpine +# python3, make, g++ are common requirements. +# We install them temporarily, run npm install, then remove them. +RUN apk add --no-cache --virtual .build-deps python3 make g++ + +WORKDIR /app + +# Copy built backend code and package definitions from builder stage +COPY --from=builder /app/packages/backend/dist ./dist +COPY --from=builder /app/packages/backend/package.json ./package.json +# Copy the root lock file for consistent installs +COPY --from=builder /app/package-lock.json ./package-lock.json + +# Install ONLY production dependencies. Native addons like sqlite3 should be rebuilt here. +# Removed --ignore-scripts to allow sqlite3's install script to run. +# Using --omit=dev is the modern equivalent of --production. +RUN npm install --omit=dev --prefer-offline + +# Remove temporary build dependencies after npm install +RUN apk del .build-deps + +# Expose the port the app runs on +EXPOSE 3001 + +# Define the command to run the application +CMD ["node", "dist/index.js"] + +# Note: Environment variables like ENCRYPTION_KEY, SESSION_SECRET, and PORT +# should be provided when running the container. \ No newline at end of file diff --git a/packages/frontend/Dockerfile b/packages/frontend/Dockerfile new file mode 100644 index 0000000..1ed3039 --- /dev/null +++ b/packages/frontend/Dockerfile @@ -0,0 +1,47 @@ +# Stage 1: Build the frontend application using npm workspaces +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy root package.json and package-lock.json +COPY package.json package-lock.json* ./ + +# Copy frontend package definition and backend (needed for workspace install) +# We need backend's package.json for npm ci to resolve the workspace correctly +COPY packages/frontend/package.json ./packages/frontend/ +COPY packages/backend/package.json ./packages/backend/ +# If there are other packages frontend depends on, copy their package.json too + +# Install ALL workspace dependencies using the root lock file +RUN npm ci + +# Copy the rest of the frontend source code needed for the build +COPY packages/frontend/src ./packages/frontend/src +COPY packages/frontend/index.html ./packages/frontend/ +COPY packages/frontend/tsconfig.json ./packages/frontend/ +COPY packages/frontend/vite.config.ts ./packages/frontend/ +# Assuming postcss.config.js exists at the root or frontend level if needed +# COPY postcss.config.js ./ # Or ./packages/frontend/ if it's there + +# Build only the frontend package +RUN npm run build --workspace=@nexus-terminal/frontend + +# Stage 2: Serve the static files with Nginx +FROM nginx:stable-alpine + +# Remove default Nginx welcome page +RUN rm -rf /usr/share/nginx/html/* + +# Copy built assets from builder stage to Nginx html directory +COPY --from=builder /app/packages/frontend/dist /usr/share/nginx/html + +# Copy custom Nginx configuration +# This file needs to be present in the build context (project root) +# We created it in packages/frontend/, so adjust the COPY source path +COPY packages/frontend/nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Start Nginx +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/packages/frontend/nginx.conf b/packages/frontend/nginx.conf new file mode 100644 index 0000000..3ce1c1e --- /dev/null +++ b/packages/frontend/nginx.conf @@ -0,0 +1,20 @@ +server { + listen 80; + server_name localhost; + + # Root directory for static files + root /usr/share/nginx/html; + index index.html index.htm; + + # Serve static files directly + location / { + try_files $uri $uri/ /index.html; + } + + # Optional: Add headers for caching, security, etc. + # Example: Cache assets aggressively + location ~* \.(?:css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public"; + } +} \ No newline at end of file diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 515493f..cb6d2d1 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -33,6 +33,7 @@ "@vitejs/plugin-vue": "^4.2.0", "typescript": "^5.0.0", "vite": "^5.2.0", - "vue-tsc": "^2.2.8" + "vue-tsc": "^2.2.8", +"@types/node": "^20" } } diff --git a/packages/frontend/src/components/StyleCustomizer.vue b/packages/frontend/src/components/StyleCustomizer.vue index b99e3ca..74de6f4 100644 --- a/packages/frontend/src/components/StyleCustomizer.vue +++ b/packages/frontend/src/components/StyleCustomizer.vue @@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n'; import { useAppearanceStore } from '../stores/appearance.store'; // 使用新的 store import { storeToRefs } from 'pinia'; import type { ITheme } from 'xterm'; -import type { TerminalTheme } from '../../../backend/src/types/terminal-theme.types'; // 引入类型 +import type { TerminalTheme } from '../types/terminal-theme.types'; // 引入本地类型 import { defaultXtermTheme } from '../features/appearance/config/default-themes'; // 引入默认主题 const { t } = useI18n(); diff --git a/packages/frontend/src/features/appearance/config/iterm-themes.ts b/packages/frontend/src/features/appearance/config/iterm-themes.ts index 5bac3c9..a08e8da 100644 --- a/packages/frontend/src/features/appearance/config/iterm-themes.ts +++ b/packages/frontend/src/features/appearance/config/iterm-themes.ts @@ -1,6 +1,6 @@ // Generated by scripts/generate-iterm-themes.js // Source: https://github.com/mbadolato/iTerm2-Color-Schemes -import type { TerminalTheme } from '../../../backend/src/types/terminal-theme.types'; +import type { TerminalTheme } from '../../../types/terminal-theme.types'; // 引用本地类型 export const Theme_0x96fPreset: TerminalTheme = { _id: 'preset-0x96f', diff --git a/packages/frontend/src/stores/appearance.store.ts b/packages/frontend/src/stores/appearance.store.ts index 3cdcb4a..7353de9 100644 --- a/packages/frontend/src/stores/appearance.store.ts +++ b/packages/frontend/src/stores/appearance.store.ts @@ -2,8 +2,8 @@ import { defineStore } from 'pinia'; import apiClient from '../utils/apiClient'; // 使用统一的 apiClient import { ref, computed, watch, nextTick } from 'vue'; // 导入 nextTick import type { ITheme } from 'xterm'; -import type { TerminalTheme } from '../../../backend/src/types/terminal-theme.types'; // 引用后端类型 -import type { AppearanceSettings, UpdateAppearanceDto } from '../../../backend/src/types/appearance.types'; // 引用后端类型 +import type { TerminalTheme } from '../types/terminal-theme.types'; // 引用本地类型 +import type { AppearanceSettings, UpdateAppearanceDto } from '../types/appearance.types'; // 引用本地类型 import { defaultXtermTheme, defaultUiTheme } from '../features/appearance/config/default-themes'; // 保持 .ts import { presetTerminalThemes } from '../features/appearance/config/iterm-themes'; // <-- 导入预设主题 diff --git a/packages/frontend/src/stores/quickCommands.store.ts b/packages/frontend/src/stores/quickCommands.store.ts index e2e6556..2f3d570 100644 --- a/packages/frontend/src/stores/quickCommands.store.ts +++ b/packages/frontend/src/stores/quickCommands.store.ts @@ -2,7 +2,7 @@ import { defineStore } from 'pinia'; import apiClient from '../utils/apiClient'; // 使用统一的 apiClient import { ref, computed } from 'vue'; import { useUiNotificationsStore } from './uiNotifications.store'; -import type { QuickCommand } from '../../../backend/src/repositories/quick-commands.repository'; // 复用后端类型定义 +import type { QuickCommand } from '../types/quick-commands.types'; // 引入本地 QuickCommand 类型 // 定义前端使用的快捷指令接口 (可以与后端一致) export type QuickCommandFE = QuickCommand; diff --git a/packages/frontend/src/types/appearance.types.ts b/packages/frontend/src/types/appearance.types.ts new file mode 100644 index 0000000..9ea2f58 --- /dev/null +++ b/packages/frontend/src/types/appearance.types.ts @@ -0,0 +1,18 @@ +// packages/frontend/src/types/appearance.types.ts + +// 前端使用的外观设置结构 (对应 API 响应) +export interface AppearanceSettings { + // 注意:前端可能不需要 _id, userId, updatedAt 等数据库相关的字段 + // 但为了与后端导入保持一致,暂时保留,后续可根据 API 精简 + customUiTheme?: string; // CSS 变量 JSON 字符串 + activeTerminalThemeId?: number | null; // 终端主题 ID + terminalFontFamily?: string; + terminalFontSize?: number; + terminalBackgroundImage?: string; + pageBackgroundImage?: string; + editorFontSize?: number; +} + +// 前端用于更新外观设置的数据结构 (对应 API 请求体) +// 使用 Partial 也可以,但明确定义更清晰 +export type UpdateAppearanceDto = Partial; \ No newline at end of file diff --git a/packages/frontend/src/types/audit.types.ts b/packages/frontend/src/types/audit.types.ts new file mode 100644 index 0000000..1d087d4 --- /dev/null +++ b/packages/frontend/src/types/audit.types.ts @@ -0,0 +1,54 @@ +// packages/frontend/src/types/audit.types.ts + +// 定义审计日志记录的操作类型 (与后端保持一致,但独立定义) +export type AuditLogActionType = + // Authentication + | 'LOGIN_SUCCESS' + | 'LOGIN_FAILURE' + | 'LOGOUT' + | 'PASSWORD_CHANGED' + | '2FA_ENABLED' + | '2FA_DISABLED' + | 'PASSKEY_REGISTERED' + | 'PASSKEY_DELETED' + // Connections + | 'CONNECTION_CREATED' + | 'CONNECTION_UPDATED' + | 'CONNECTION_DELETED' + | 'CONNECTION_TESTED' + | 'CONNECTIONS_IMPORTED' + | 'CONNECTIONS_EXPORTED' + // Proxies + | 'PROXY_CREATED' + | 'PROXY_UPDATED' + | 'PROXY_DELETED' + // Tags + | 'TAG_CREATED' + | 'TAG_UPDATED' + | 'TAG_DELETED' + // Settings + | 'SETTINGS_UPDATED' + | 'IP_WHITELIST_UPDATED' + // Notifications + | 'NOTIFICATION_SETTING_CREATED' + | 'NOTIFICATION_SETTING_UPDATED' + | 'NOTIFICATION_SETTING_DELETED' + // SFTP + | 'SFTP_ACTION' + // SSH Actions + | 'SSH_CONNECT_SUCCESS' + | 'SSH_CONNECT_FAILURE' + | 'SSH_SHELL_FAILURE' + // System/Error + | 'SERVER_STARTED' + | 'SERVER_ERROR' + | 'DATABASE_MIGRATION' + | 'ADMIN_SETUP_COMPLETE'; + +// 前端使用的审计日志条目结构 (对应 API 响应) +export interface AuditLogEntry { + id: number; + timestamp: number; // Unix timestamp (seconds) + action_type: AuditLogActionType; + details: string | null; // JSON string or null (前端可能需要解析) +} \ No newline at end of file diff --git a/packages/frontend/src/types/quick-commands.types.ts b/packages/frontend/src/types/quick-commands.types.ts new file mode 100644 index 0000000..6e17467 --- /dev/null +++ b/packages/frontend/src/types/quick-commands.types.ts @@ -0,0 +1,11 @@ +// packages/frontend/src/types/quick-commands.types.ts + +// 前端使用的快捷指令结构 (对应 API 响应) +export interface QuickCommand { + id: number; + name: string | null; + command: string; + usage_count: number; + created_at: number; // Unix 时间戳 (秒) + updated_at: number; // Unix 时间戳 (秒) +} \ No newline at end of file diff --git a/packages/frontend/src/types/terminal-theme.types.ts b/packages/frontend/src/types/terminal-theme.types.ts new file mode 100644 index 0000000..ad673d0 --- /dev/null +++ b/packages/frontend/src/types/terminal-theme.types.ts @@ -0,0 +1,13 @@ +// packages/frontend/src/types/terminal-theme.types.ts +import type { ITheme } from 'xterm'; + +// 前端使用的终端主题结构 (对应 API 响应) +export interface TerminalTheme { + // 注意:前端可能不需要 _id, createdAt, updatedAt 等数据库相关的字段 + // 但为了与后端导入保持一致,暂时保留,后续可根据 API 精简 + _id?: string; // NeDB ID (前端通常不直接使用) + name: string; + themeData: ITheme; + isPreset: boolean; + isSystemDefault?: boolean; +} \ No newline at end of file diff --git a/packages/frontend/src/views/DashboardView.vue b/packages/frontend/src/views/DashboardView.vue index 8543bdf..ec6f429 100644 --- a/packages/frontend/src/views/DashboardView.vue +++ b/packages/frontend/src/views/DashboardView.vue @@ -6,7 +6,7 @@ import { useSessionStore } from '../stores/session.store'; // +++ 引入 Session import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; import type { ConnectionInfo } from '../stores/connections.store'; // 只导入 ConnectionInfo -import type { AuditLogEntry } from '../../../backend/src/types/audit.types'; // 引入 AuditLogEntry 类型 +import type { AuditLogEntry } from '../types/audit.types'; // 引入本地 AuditLogEntry 类型 import { storeToRefs } from 'pinia'; import { formatDistanceToNow } from 'date-fns'; import { zhCN, enUS } from 'date-fns/locale'; // 导入语言包 diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json index fbdd864..f31a406 100644 --- a/packages/frontend/tsconfig.json +++ b/packages/frontend/tsconfig.json @@ -13,11 +13,11 @@ "lib": ["ESNext", "DOM", "DOM.Iterable"], // 包含的库定义 "skipLibCheck": true, // 跳过对声明文件 (*.d.ts) 的类型检查 "noEmit": true, // 不输出编译后的文件 (由 Vite 处理构建) - "baseUrl": ".", // 基础目录,用于解析非相对模块名 + "baseUrl": ".", // 恢复基础目录 "paths": { - "@/*": ["src/*"] // 路径别名,例如 @/components/* 指向 src/components/* + "@/*": ["src/*"] // 恢复原始前端别名路径 }, - "types": ["vite/client", "pinia-plugin-persistedstate"] // **关键:包含 Vite 客户端和 Pinia 持久化插件类型定义** + "types": ["vite/client", "pinia-plugin-persistedstate", "node"] // 重新添加 "node" 类型 }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], // 需要进行类型检查的文件 "exclude": ["node_modules"] // 排除检查的目录