Initial commit: MengStack official website
This commit is contained in:
commit
05c300435c
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
node_modules/
|
||||
.vitepress/dist/
|
||||
.vitepress/cache/
|
||||
*.local
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
172
.vitepress/config.ts
Normal file
172
.vitepress/config.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
const seoPages: Record<string, { title: string; description: string; keywords: string }> = {
|
||||
'/': {
|
||||
title: 'MengStack - 企业级Go语言微服务开发框架 | 开源模块化开发底座',
|
||||
description: 'MengStack是软盟SoftUnis开源的企业级Go语言微服务开发框架,基于Gin+GORM+uber-go/fx构建,内置三层隔离架构、多租户支持、JWT认证、API文档、Docker部署等能力,开箱即用,帮助开发者快速搭建企业级后端服务。',
|
||||
keywords: 'Go微服务框架,Go企业级开发框架,MengStack,开源Go框架,Go模块化开发',
|
||||
},
|
||||
'/guide/what-is-mengstack': {
|
||||
title: '什么是MengStack | 架构设计与核心特性介绍 - MengStack官方文档',
|
||||
description: 'MengStack入门指南,详细介绍框架设计理念、三层隔离 Kernel/App/Modules 架构、四层模块模式、核心特性清单、适用场景与完整技术栈选型,帮助开发者快速了解MengStack框架。',
|
||||
keywords: 'MengStack教程,MengStack架构,Go框架架构设计,DDD四层架构,Go微服务入门',
|
||||
},
|
||||
'/guide/getting-started': {
|
||||
title: '快速开始 | 5分钟搭建MengStack项目环境 - MengStack官方文档',
|
||||
description: 'MengStack快速开始教程,包含环境要求、项目克隆、依赖安装、配置修改、服务启动完整步骤,帮助开发者5分钟跑通第一个MengStack项目,快速体验框架能力。',
|
||||
keywords: 'MengStack快速开始,MengStack安装,Go项目搭建,Go框架入门教程',
|
||||
},
|
||||
'/guide/project-structure': {
|
||||
title: '项目结构说明 | MengStack目录规范详解 - MengStack官方文档',
|
||||
description: '详细介绍MengStack标准项目目录结构,各目录职责划分、模块组织规范、依赖注入配置方式,帮助开发者遵循统一规范开发,降低团队协作成本。',
|
||||
keywords: 'MengStack项目结构,Go项目目录规范,Go项目架构,模块化开发规范',
|
||||
},
|
||||
'/api/overview': {
|
||||
title: 'API接口概览 | 统一响应格式与错误码说明 - MengStack官方文档',
|
||||
description: 'MengStack API接口参考文档,包含接口基础信息、统一响应格式规范、HTTP状态码与错误码说明、JWT认证方式说明、完整接口列表,以及在线Swagger UI调试入口。',
|
||||
keywords: 'MengStack API,Go接口文档,RESTful API规范,JWT认证接口,Swagger接口文档',
|
||||
},
|
||||
'/changelog': {
|
||||
title: '更新日志 | 版本迭代记录与路线图 - MengStack开源框架',
|
||||
description: 'MengStack各版本更新记录,包含v0.1.0首发版本技术栈说明、功能特性清单,以及后续版本路线图规划,跟进MengStack框架最新功能动态。',
|
||||
keywords: 'MengStack更新日志,MengStack版本,Go框架更新,开源项目路线图',
|
||||
},
|
||||
'/demo': {
|
||||
title: '在线演示 | 免费体验MengStack接口服务 - MengStack官方',
|
||||
description: 'MengStack官方在线演示环境,提供公开API服务地址、Swagger UI在线调试入口、健康检查地址,附快速体验步骤指引,无需本地部署即可直接体验框架接口能力。',
|
||||
keywords: 'MengStack在线演示,Go框架体验,Swagger在线调试,API接口测试',
|
||||
},
|
||||
'/community': {
|
||||
title: '开发者社区 | 交流渠道与贡献指南 - MengStack开源社区',
|
||||
description: 'MengStack开源开发者社区,提供代码仓库地址、问题反馈渠道、功能建议入口,以及Bug报告、代码提交、代码规范等贡献指引,欢迎所有开发者参与MengStack共建。',
|
||||
keywords: 'MengStack社区,Go开源社区,Go开发者交流,开源项目贡献',
|
||||
},
|
||||
}
|
||||
|
||||
function getPagePath(relativePath: string) {
|
||||
let p = '/' + relativePath.replace(/\.md$/, '').replace(/\/index$/, '')
|
||||
if (p === '/index') p = '/'
|
||||
return p
|
||||
}
|
||||
|
||||
function getSeo(pagePath: string) {
|
||||
return seoPages[pagePath] || seoPages['/']
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
title: 'MengStack',
|
||||
titleTemplate: ':title',
|
||||
description: 'MengStack - 企业级 Go 语言微服务开发框架',
|
||||
lang: 'zh-CN',
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', href: '/favicon.png' }],
|
||||
['meta', { property: 'og:image', content: '/og-image.png' }],
|
||||
['meta', { name: 'theme-color', content: '#C8963E' }],
|
||||
],
|
||||
|
||||
transformHead({ pageData }) {
|
||||
const path = getPagePath(pageData.relativePath)
|
||||
const seo = getSeo(path)
|
||||
const url = `https://mengstack.softunis.com${path === '/' ? '/' : path + '.html'}`
|
||||
const head: [string, Record<string, string>][] = [
|
||||
['meta', { name: 'description', content: seo.description }],
|
||||
['meta', { name: 'keywords', content: seo.keywords }],
|
||||
['link', { rel: 'canonical', href: url }],
|
||||
['meta', { property: 'og:title', content: seo.title }],
|
||||
['meta', { property: 'og:description', content: seo.description }],
|
||||
['meta', { property: 'og:url', content: url }],
|
||||
]
|
||||
return head
|
||||
},
|
||||
|
||||
themeConfig: {
|
||||
logo: {
|
||||
light: '/logo-light.png',
|
||||
dark: '/logo-dark.png',
|
||||
alt: 'MengStack 企业级Go语言微服务开发框架',
|
||||
},
|
||||
siteTitle: 'MengStack',
|
||||
|
||||
nav: [
|
||||
{ text: '首页', link: '/' },
|
||||
{ text: '指南', link: '/guide/what-is-mengstack' },
|
||||
{ text: 'API 参考', link: '/api/overview' },
|
||||
{ text: '更新日志', link: '/changelog' },
|
||||
{ text: '在线演示', link: '/demo' },
|
||||
{ text: '社区', link: '/community' },
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{
|
||||
text: '入门',
|
||||
items: [
|
||||
{ text: '什么是 MengStack', link: '/guide/what-is-mengstack' },
|
||||
{ text: '快速开始', link: '/guide/getting-started' },
|
||||
{ text: '项目结构', link: '/guide/project-structure' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '架构设计',
|
||||
items: [
|
||||
{ text: '三层隔离架构', link: '/guide/architecture' },
|
||||
{ text: '模块四层模式', link: '/guide/module-pattern' },
|
||||
{ text: '依赖注入', link: '/guide/dependency-injection' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '核心功能',
|
||||
items: [
|
||||
{ text: '认证与授权', link: '/guide/auth' },
|
||||
{ text: '多租户系统', link: '/guide/multi-tenancy' },
|
||||
{ text: '配置管理', link: '/guide/configuration' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '部署',
|
||||
items: [
|
||||
{ text: 'Docker 部署', link: '/guide/docker-deploy' },
|
||||
{ text: 'CI/CD 流水线', link: '/guide/cicd' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/api/': [
|
||||
{
|
||||
text: 'API 参考',
|
||||
items: [
|
||||
{ text: '概览', link: '/api/overview' },
|
||||
{ text: '认证接口', link: '/api/auth' },
|
||||
{ text: '系统接口', link: '/api/system' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://gitea.softunis.com/mengstack' },
|
||||
],
|
||||
|
||||
footer: {
|
||||
message: 'Released under the MIT License.',
|
||||
copyright: `Copyright © 2026 <a href="https://www.softunis.com/" target="_blank" rel="noopener">软盟 SoftUnis</a><br><a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">粤ICP备2023054965号</a> | <a href="https://beian.mps.gov.cn/" target="_blank" rel="noopener">粤公网安备 44030502010466号</a>`,
|
||||
},
|
||||
|
||||
search: {
|
||||
provider: 'local',
|
||||
},
|
||||
|
||||
outline: {
|
||||
label: '页面导航',
|
||||
},
|
||||
|
||||
docFooter: {
|
||||
prev: '上一页',
|
||||
next: '下一页',
|
||||
},
|
||||
|
||||
lastUpdated: {
|
||||
text: '最后更新',
|
||||
},
|
||||
},
|
||||
})
|
||||
796
.vitepress/theme/Home.vue
Normal file
796
.vitepress/theme/Home.vue
Normal file
@ -0,0 +1,796 @@
|
||||
<template>
|
||||
<div class="home-new">
|
||||
<!-- ============ Navbar ============ -->
|
||||
<header class="nav" :class="{ scrolled }" ref="navEl">
|
||||
<div class="nav-inner">
|
||||
<a class="brand" href="#top" aria-label="MengStack 首页">
|
||||
<img class="light-logo" src="/logo-light.png" alt="" width="30" height="30" />
|
||||
<img class="dark-logo" src="/logo-dark.png" alt="" width="30" height="30" />
|
||||
MengStack
|
||||
</a>
|
||||
<nav class="nav-links" aria-label="主导航">
|
||||
<a href="#top" class="active">首页</a>
|
||||
<a href="/guide/what-is-mengstack.html">指南</a>
|
||||
<a href="/api/overview.html">API 参考</a>
|
||||
<a href="/changelog.html">更新日志</a>
|
||||
<a href="/demo.html">在线演示</a>
|
||||
<a href="/community.html">社区</a>
|
||||
</nav>
|
||||
<div class="nav-actions">
|
||||
<button class="icon-btn" @click="toggleTheme" aria-label="切换明暗主题" title="切换主题">
|
||||
<svg aria-hidden="true" class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="4" /><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" /></svg>
|
||||
<svg aria-hidden="true" class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z" /></svg>
|
||||
</button>
|
||||
<button class="icon-btn hamburger" ref="menuBtn" aria-label="展开菜单" aria-expanded="false" @click="toggleMenu">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="top">
|
||||
<!-- ============ Hero ============ -->
|
||||
<section class="hero">
|
||||
<div class="wrap hero-grid">
|
||||
<div>
|
||||
<span class="badge"><span class="dot"></span>云原生 × AI 原生 · MIT 开源</span>
|
||||
<h1><span class="grad">MengStack</span><br />企业级 Go 语言微服务开发框架</h1>
|
||||
<p class="sub">面向云原生与 AI 时代的一站式全栈开发底座</p>
|
||||
<p class="tagline">组件化集成、零侵入依赖注入、全链路国产化适配——开箱即用,让团队专注核心业务,不再重复造轮子。</p>
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/guide/getting-started.html">
|
||||
快速开始
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
|
||||
</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/demo.html">在线演示</a>
|
||||
<a class="btn btn-ghost btn-lg" href="https://gitea.softunis.com/mengstack" target="_blank" rel="noopener noreferrer">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" width="17" height="17" fill="currentColor"><path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.55v-2.15c-3.2.7-3.87-1.36-3.87-1.36-.52-1.33-1.28-1.69-1.28-1.69-1.05-.71.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.55-.29-5.23-1.28-5.23-5.68 0-1.26.45-2.28 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18a11 11 0 0 1 5.79 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.12 3.05.74.81 1.18 1.83 1.18 3.09 0 4.41-2.69 5.38-5.25 5.67.41.36.78 1.06.78 2.14v3.17c0 .3.21.67.8.55A11.51 11.51 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5z" /></svg>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="terminal" aria-label="代码示例终端">
|
||||
<div class="terminal-bar"><i></i><i></i><i></i><span>main.go — mengstack</span></div>
|
||||
<div class="terminal-body">
|
||||
<div class="ln"><span class="kw">package</span> main</div>
|
||||
<div class="ln"> </div>
|
||||
<div class="ln"><span class="kw">import</span> <span class="str">"github.com/mengstack/mengstack"</span></div>
|
||||
<div class="ln"> </div>
|
||||
<div class="ln"><span class="kw">func</span> <span class="fn">main</span>() {</div>
|
||||
<div class="ln"> app := mengstack.<span class="fn">New</span>()</div>
|
||||
<div class="ln"> app.<span class="fn">Run</span>(<span class="num">":2222"</span>) <span class="cursor"></span></div>
|
||||
<div class="ln">}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ Trust strip ============ -->
|
||||
<div class="trust">
|
||||
<div class="trust-inner">
|
||||
<span class="trust-label">运行环境</span>
|
||||
<span class="chip">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 9V3m0 18v-2M3 12h2m14 0h2M6 6l1.5 1.5M16.5 16.5 18 18M18 6l-1.5 1.5M7.5 16.5 6 18" /><circle cx="12" cy="12" r="3.2" /></svg>
|
||||
Go 1.23+
|
||||
</span>
|
||||
<span class="chip">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="6" rx="8" ry="3" /><path d="M4 6v6c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6" /></svg>
|
||||
PostgreSQL 14+
|
||||
</span>
|
||||
<span class="chip">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0-6 6v3a6 6 0 0 0 12 0V9" /><path d="M9 21h6M12 18v3" /></svg>
|
||||
Redis 7+
|
||||
</span>
|
||||
<span class="chip">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><rect x="3" y="9" width="4" height="4" /><rect x="10" y="9" width="4" height="4" /><rect x="17" y="9" width="4" height="4" /><rect x="3" y="15.5" width="4" height="4" /><rect x="10" y="15.5" width="4" height="4" /><rect x="17" y="15.5" width="4" height="4" /><path d="M7 11h3m4 0h3M7 17.5h3m4 0h3" /></svg>
|
||||
Docker Compose
|
||||
</span>
|
||||
<span class="chip">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 11 4.6-2.5 8-6 8-11V5z" /></svg>
|
||||
MIT 开源
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ Features ============ -->
|
||||
<section class="section features" id="features">
|
||||
<div class="wrap">
|
||||
<div class="section-head reveal">
|
||||
<span class="eyebrow">Core Capabilities</span>
|
||||
<h2>七大核心能力,覆盖企业级开发全链路</h2>
|
||||
<p>从架构搭建到 AI 集成,生产验证的模块开箱即用,大幅降低中大型项目的架构成本。</p>
|
||||
</div>
|
||||
<div class="feature-grid stagger">
|
||||
<article class="feature reveal" style="--i:0">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.5" /><rect x="14" y="3" width="7" height="7" rx="1.5" /><rect x="3" y="14" width="7" height="7" rx="1.5" /><path d="M17.5 14v7M14 17.5h7" /></svg>
|
||||
</div>
|
||||
<h3>全栈组件化集成</h3>
|
||||
<p>内置前端模板、API 网关、分布式缓存、消息队列、定时任务等模块,生产验证,开箱即用。</p>
|
||||
<a class="more" href="/guide/what-is-mengstack.html">了解架构<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg></a>
|
||||
</article>
|
||||
|
||||
<article class="feature reveal" style="--i:1">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M13 2 4.5 13.5H11l-1 8.5 8.5-11.5H12z" /></svg>
|
||||
</div>
|
||||
<h3>零侵入依赖注入</h3>
|
||||
<p>兼容 Wire 编译时注入与 uber-go/fx 运行时管理,按需切换,兼顾性能与便捷。</p>
|
||||
<a class="more" href="/guide/dependency-injection.html">查看文档<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg></a>
|
||||
</article>
|
||||
|
||||
<article class="feature reveal" style="--i:2">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="5" width="14" height="14" rx="3" /><path d="M9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3" /><circle cx="12" cy="12" r="3" /></svg>
|
||||
</div>
|
||||
<h3>AI 原生开发支持</h3>
|
||||
<p>内置大模型调用、Agent 内存管理、向量数据库集成,快速落地智能业务场景。</p>
|
||||
</article>
|
||||
|
||||
<article class="feature reveal" style="--i:3">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 11 4.6-2.5 8-6 8-11V5z" /><path d="m9 12 2 2 4-4" /></svg>
|
||||
</div>
|
||||
<h3>全链路国产化适配</h3>
|
||||
<p>兼容国产操作系统、数据库、中间件,满足政企金融等保合规要求。</p>
|
||||
</article>
|
||||
|
||||
<article class="feature reveal" style="--i:4">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z" /><path d="M8 7h7M8 11h7M4 5v14" /></svg>
|
||||
</div>
|
||||
<h3>极低学习门槛</h3>
|
||||
<p>统一代码规范与完善中文文档,新成员接入周期缩短 70% 以上。</p>
|
||||
<a class="more" href="/guide/getting-started.html">快速开始<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg></a>
|
||||
</article>
|
||||
|
||||
<article class="feature reveal" style="--i:5">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19V5" /><path d="M4 19h16" /><rect x="7" y="11" width="3" height="5" /><rect x="12" y="7" width="3" height="9" /><rect x="17" y="13" width="3" height="3" /></svg>
|
||||
</div>
|
||||
<h3>生产级可观测</h3>
|
||||
<p>内置链路追踪、指标监控、日志聚合,无需额外搭建监控体系。</p>
|
||||
</article>
|
||||
|
||||
<article class="feature feature--wide reveal" style="--i:6">
|
||||
<div class="ficon">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="2" /><path d="M8 11V8a4 4 0 0 1 7.7-1.5" /></svg>
|
||||
</div>
|
||||
<div class="wtext">
|
||||
<h3>完全开源开放</h3>
|
||||
<p>核心代码 MIT 协议开源,无商业限制,社区持续迭代,可自由定制扩展。</p>
|
||||
</div>
|
||||
<a class="btn btn-primary wcta" href="/community.html">加入社区</a>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ Architecture ============ -->
|
||||
<section class="section arch" id="architecture">
|
||||
<div class="wrap">
|
||||
<div class="section-head reveal">
|
||||
<span class="eyebrow">Architecture</span>
|
||||
<h2>三层隔离架构,全链路一站打通</h2>
|
||||
<p>覆盖从前端交互、后端服务、数据治理到 AI 能力集成的全链路开发场景,层间解耦、演进自由。</p>
|
||||
</div>
|
||||
<div class="arch-layers stagger">
|
||||
<div class="layer reveal" style="--i:0">
|
||||
<div class="layer-num">LAYER 01</div>
|
||||
<h3>前端交互层</h3>
|
||||
<p>内置前端模板,统一交互规范,与后端接口无缝对接。</p>
|
||||
<ul><li>前端模板</li><li>API 网关</li><li>认证鉴权</li></ul>
|
||||
</div>
|
||||
<div class="layer reveal" style="--i:1">
|
||||
<div class="layer-num">LAYER 02</div>
|
||||
<h3>后端服务层</h3>
|
||||
<p>模块四层模式配合零侵入依赖注入,业务边界清晰,按需装配。</p>
|
||||
<ul><li>模块四层模式</li><li>Wire / fx 注入</li><li>消息队列 · 定时任务</li></ul>
|
||||
</div>
|
||||
<div class="layer reveal" style="--i:2">
|
||||
<div class="layer-num">LAYER 03</div>
|
||||
<h3>数据与 AI 层</h3>
|
||||
<p>数据治理与智能能力一体集成,并完成全链路国产化适配。</p>
|
||||
<ul><li>分布式缓存</li><li>向量数据库</li><li>大模型 · Agent</li></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arch-flow reveal">
|
||||
前端交互
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
|
||||
后端服务
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
|
||||
数据治理 · AI 能力
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ Quick start ============ -->
|
||||
<section class="section qs" id="quickstart">
|
||||
<div class="wrap">
|
||||
<div class="section-head reveal">
|
||||
<span class="eyebrow">Quick Start</span>
|
||||
<h2>三步启动,5 分钟跑起项目环境</h2>
|
||||
<p>推荐使用 Docker Compose 一键拉起 API、PostgreSQL 与 Redis,无需手动配置依赖。</p>
|
||||
</div>
|
||||
<div class="qs-grid stagger">
|
||||
<div class="qs-step reveal" style="--i:0">
|
||||
<h3><span class="step-no">1</span>克隆项目</h3>
|
||||
<p>从 Gitea 仓库拉取最新代码。</p>
|
||||
<div class="codeblock">
|
||||
<button class="copy-btn" aria-label="复制命令" @click="copyCode($event)"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></svg></button>
|
||||
<pre>git clone https://gitea.softunis.com/mengstack/mengstack.git
|
||||
cd mengstack</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qs-step reveal" style="--i:1">
|
||||
<h3><span class="step-no">2</span>启动服务</h3>
|
||||
<p>一条命令启动全部依赖服务。</p>
|
||||
<div class="codeblock">
|
||||
<button class="copy-btn" aria-label="复制命令" @click="copyCode($event)"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></svg></button>
|
||||
<pre><span class="c-comment"># 启动所有服务</span>
|
||||
docker-compose up -d
|
||||
|
||||
<span class="c-comment"># 查看日志</span>
|
||||
docker-compose logs -f app</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qs-step reveal" style="--i:2">
|
||||
<h3><span class="step-no">3</span>验证访问</h3>
|
||||
<p>打开浏览器或调用健康检查接口。</p>
|
||||
<div class="codeblock">
|
||||
<button class="copy-btn" aria-label="复制命令" @click="copyCode($event)"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></svg></button>
|
||||
<pre>API http://localhost:2222
|
||||
Docs /swagger/index.html
|
||||
Check /health</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ Stats ============ -->
|
||||
<section class="stats">
|
||||
<div class="wrap stats-grid">
|
||||
<div class="stat reveal">
|
||||
<div class="v">5<small style="font-size:.55em">分钟</small></div>
|
||||
<div class="l">完成项目环境搭建</div>
|
||||
</div>
|
||||
<div class="stat reveal">
|
||||
<div class="v">70%+</div>
|
||||
<div class="l">新成员接入周期缩短</div>
|
||||
</div>
|
||||
<div class="stat reveal">
|
||||
<div class="v">MIT</div>
|
||||
<div class="l">核心代码开源协议 · 无商业限制</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ About ============ -->
|
||||
<section class="section about" id="about">
|
||||
<div class="wrap">
|
||||
<div class="section-head reveal">
|
||||
<span class="eyebrow">About</span>
|
||||
<h2>关于 MengStack</h2>
|
||||
</div>
|
||||
<div class="about-card reveal">
|
||||
<p>MengStack 是面向云原生与 AI 时代的一站式全栈开发底座,整合主流开源技术能力,为开发者提供开箱即用的组件化开发体验,大幅降低中大型项目的架构搭建成本,让团队专注于核心业务逻辑落地,无需重复造轮子。</p>
|
||||
<p>我们坚持全栈开源、无厂商锁定的设计理念,覆盖从前端交互、后端服务、数据治理到 AI 能力集成的全链路开发场景,适配国产化软硬件生态,为企业级项目提供稳定、高效、可扩展的技术支撑。</p>
|
||||
<div class="about-points">
|
||||
<div>
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
|
||||
全栈开源,无厂商锁定
|
||||
</div>
|
||||
<div>
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
|
||||
组件开箱即用
|
||||
</div>
|
||||
<div>
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
|
||||
国产化生态适配
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ CTA ============ -->
|
||||
<section class="cta-band">
|
||||
<div class="wrap">
|
||||
<div class="cta-card reveal">
|
||||
<h2>现在开始,用 MengStack 搭建你的下一个项目</h2>
|
||||
<p>完善中文文档与活跃社区,陪你从第一行代码走到生产上线。</p>
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/guide/getting-started.html">5 分钟快速开始</a>
|
||||
<a class="btn btn-ghost btn-lg" href="https://gitea.softunis.com/mengstack" target="_blank" rel="noopener noreferrer">访问 Gitea 仓库</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- ============ Footer ============ -->
|
||||
<footer class="footer">
|
||||
<div class="wrap footer-inner">
|
||||
<div>
|
||||
<p>Released under the MIT License.</p>
|
||||
<p>Copyright © 2026 <a href="https://www.softunis.com/" target="_blank" rel="noopener noreferrer">软盟 SoftUnis</a><br />
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">粤ICP备2023054965号</a> |
|
||||
<a href="https://beian.mps.gov.cn/" target="_blank" rel="noopener noreferrer">粤公网安备 44030502010466号</a></p>
|
||||
</div>
|
||||
<nav class="footer-links" aria-label="页脚导航">
|
||||
<a href="/guide/what-is-mengstack.html">指南</a>
|
||||
<a href="/api/overview.html">API 参考</a>
|
||||
<a href="/demo.html">在线演示</a>
|
||||
<a href="/community.html">社区</a>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { isDark } = useData()
|
||||
|
||||
const navEl = ref(null)
|
||||
const menuBtn = ref(null)
|
||||
const scrolled = ref(false)
|
||||
|
||||
let scrollHandler = null
|
||||
let observer = null
|
||||
let mutationObserver = null
|
||||
|
||||
function toggleTheme() {
|
||||
const el = document.documentElement
|
||||
el.classList.toggle('dark')
|
||||
const dark = el.classList.contains('dark')
|
||||
isDark.value = dark
|
||||
try { localStorage.setItem('ms-theme', dark ? 'dark' : 'light') } catch (e) {}
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
const nav = navEl.value
|
||||
if (!nav) return
|
||||
const open = nav.classList.toggle('nav-menu-open')
|
||||
menuBtn.value?.setAttribute('aria-expanded', open ? 'true' : 'false')
|
||||
}
|
||||
|
||||
function copyCode(event) {
|
||||
const btn = event.currentTarget
|
||||
const pre = btn.parentElement.querySelector('pre')
|
||||
const text = pre ? pre.innerText : ''
|
||||
const done = () => {
|
||||
btn.classList.add('copied')
|
||||
btn.innerHTML = '<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
||||
setTimeout(() => {
|
||||
btn.classList.remove('copied')
|
||||
btn.innerHTML = '<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>'
|
||||
}, 1600)
|
||||
}
|
||||
try {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(text).then(done).catch(done)
|
||||
} else { done() }
|
||||
} catch (e) { done() }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const root = document.documentElement
|
||||
|
||||
try {
|
||||
const saved = localStorage.getItem('ms-theme')
|
||||
if (saved === 'dark' || (!saved && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
root.classList.add('dark')
|
||||
isDark.value = true
|
||||
} else {
|
||||
root.classList.remove('dark')
|
||||
isDark.value = false
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
mutationObserver = new MutationObserver(() => {
|
||||
isDark.value = root.classList.contains('dark')
|
||||
})
|
||||
mutationObserver.observe(root, { attributes: true, attributeFilter: ['class'] })
|
||||
|
||||
scrollHandler = () => { scrolled.value = window.scrollY > 8 }
|
||||
window.addEventListener('scroll', scrollHandler, { passive: true })
|
||||
scrollHandler()
|
||||
|
||||
const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
if (reduce || !('IntersectionObserver' in window)) {
|
||||
root.querySelectorAll('.reveal').forEach(el => el.classList.add('in'))
|
||||
} else {
|
||||
observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('in')
|
||||
observer.unobserve(entry.target)
|
||||
}
|
||||
})
|
||||
}, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' })
|
||||
root.querySelectorAll('.reveal').forEach(el => observer.observe(el))
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (scrollHandler) window.removeEventListener('scroll', scrollHandler)
|
||||
if (observer) observer.disconnect()
|
||||
if (mutationObserver) mutationObserver.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ============ Design Tokens ============ */
|
||||
:root{
|
||||
--ms-gold:#C8963E;
|
||||
--ms-gold-light:#E0B86A;
|
||||
--ms-gold-dark:#A07830;
|
||||
--ms-bronze:#B87333;
|
||||
--ms-bronze-dark:#8B5A2B;
|
||||
--ms-cream:#FDF8EF;
|
||||
--ms-cream-dark:#F5EDD8;
|
||||
|
||||
--home-bg:#ffffff;
|
||||
--home-bg-soft:#FAF7F1;
|
||||
--home-bg-elev:#ffffff;
|
||||
--home-ink:#211d16;
|
||||
--home-ink-soft:#5c564b;
|
||||
--home-ink-faint:#8a8275;
|
||||
--home-border:#ece5d8;
|
||||
--home-border-strong:#ddd2bc;
|
||||
--home-code-bg:#1d1a14;
|
||||
--home-code-ink:#f3ead8;
|
||||
--home-hero-glow:rgba(200,150,62,.16);
|
||||
--home-shadow:0 1px 2px rgba(60,45,15,.05),0 12px 32px -12px rgba(120,86,30,.16);
|
||||
--home-shadow-lg:0 2px 4px rgba(60,45,15,.06),0 24px 56px -16px rgba(120,86,30,.22);
|
||||
--home-radius:16px;
|
||||
--home-radius-sm:12px;
|
||||
--home-maxw:1180px;
|
||||
--home-font:"Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
|
||||
--home-mono:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,"Liberation Mono",monospace;
|
||||
}
|
||||
html.dark{
|
||||
--home-bg:#16140f;
|
||||
--home-bg-soft:#1d1a13;
|
||||
--home-bg-elev:#221e16;
|
||||
--home-ink:#f4ede0;
|
||||
--home-ink-soft:#bfb5a2;
|
||||
--home-ink-faint:#8d8472;
|
||||
--home-border:#312b20;
|
||||
--home-border-strong:#443b2a;
|
||||
--home-hero-glow:rgba(200,150,62,.22);
|
||||
--home-shadow:0 1px 2px rgba(0,0,0,.3),0 12px 32px -12px rgba(0,0,0,.55);
|
||||
--home-shadow-lg:0 2px 4px rgba(0,0,0,.35),0 24px 56px -16px rgba(0,0,0,.65);
|
||||
}
|
||||
|
||||
/* ============ Hide VitePress nav/footer on homepage ============ */
|
||||
.home-layout .VPNav,
|
||||
.home-layout .VPFooter {
|
||||
display: none !important;
|
||||
}
|
||||
.home-layout .VPContent {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
/* ============ Home Page Base ============ */
|
||||
.home-new{
|
||||
font-family:var(--home-font);
|
||||
color:var(--home-ink);
|
||||
background:var(--home-bg);
|
||||
line-height:1.7;
|
||||
font-size:16px;
|
||||
-webkit-font-smoothing:antialiased;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
.home-new *,.home-new *::before,.home-new *::after{box-sizing:border-box}
|
||||
.home-new a{color:inherit;text-decoration:none}
|
||||
.home-new img{max-width:100%;display:block}
|
||||
.home-new h1,.home-new h2,.home-new h3{line-height:1.25;margin:0;font-weight:800;letter-spacing:-.01em}
|
||||
.home-new p{margin:0}
|
||||
.home-new .wrap{max-width:var(--home-maxw);margin:0 auto;padding:0 24px}
|
||||
|
||||
/* ============ Navbar ============ */
|
||||
.home-new .nav{
|
||||
position:fixed;top:0;left:0;right:0;z-index:100;
|
||||
background:color-mix(in srgb,var(--home-bg) 82%,transparent);
|
||||
backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
|
||||
border-bottom:1px solid transparent;transition:border-color .25s;
|
||||
}
|
||||
.home-new .nav.scrolled{border-bottom-color:var(--home-border)}
|
||||
.home-new .nav-inner{max-width:var(--home-maxw);margin:0 auto;padding:0 24px;height:64px;display:flex;align-items:center;gap:28px}
|
||||
.home-new .brand{display:flex;align-items:center;gap:10px;font-weight:800;font-size:18px;letter-spacing:-.01em}
|
||||
.home-new .brand img{width:30px;height:30px}
|
||||
.home-new .brand .dark-logo{display:none}
|
||||
html.dark .home-new .brand .light-logo{display:none}
|
||||
html.dark .home-new .brand .dark-logo{display:block}
|
||||
.home-new .nav-links{display:flex;gap:4px;margin-left:auto}
|
||||
.home-new .nav-links a{
|
||||
padding:7px 13px;border-radius:8px;font-size:14.5px;font-weight:500;color:var(--home-ink-soft);
|
||||
transition:color .2s,background .2s;
|
||||
}
|
||||
.home-new .nav-links a:hover{color:var(--ms-gold-dark);background:var(--home-bg-soft)}
|
||||
html.dark .home-new .nav-links a:hover{color:var(--ms-gold-light)}
|
||||
.home-new .nav-links a.active{color:var(--ms-gold-dark);font-weight:600}
|
||||
html.dark .home-new .nav-links a.active{color:var(--ms-gold-light)}
|
||||
.home-new .nav-actions{display:flex;align-items:center;gap:8px}
|
||||
.home-new .icon-btn{
|
||||
width:38px;height:38px;border-radius:10px;border:1px solid var(--home-border);background:var(--home-bg);
|
||||
display:grid;place-items:center;cursor:pointer;color:var(--home-ink-soft);transition:all .2s;
|
||||
}
|
||||
.home-new .icon-btn:hover{border-color:var(--home-border-strong);color:var(--ms-gold-dark);transform:translateY(-1px)}
|
||||
.home-new .icon-btn .moon{display:none}
|
||||
html.dark .home-new .icon-btn .sun{display:none}
|
||||
html.dark .home-new .icon-btn .moon{display:block}
|
||||
.home-new .hamburger{display:none}
|
||||
|
||||
/* ============ Buttons ============ */
|
||||
.home-new .btn{
|
||||
display:inline-flex;align-items:center;gap:8px;padding:12px 22px;border-radius:12px;
|
||||
font-size:15px;font-weight:600;cursor:pointer;border:1px solid transparent;
|
||||
transition:transform .2s,box-shadow .2s,background .2s,border-color .2s;white-space:nowrap;
|
||||
}
|
||||
.home-new .btn:hover{transform:translateY(-2px)}
|
||||
.home-new .btn-primary{
|
||||
background:linear-gradient(135deg,var(--ms-gold) 0%,var(--ms-bronze) 100%);
|
||||
color:#fff;box-shadow:0 6px 20px -6px rgba(200,150,62,.55);
|
||||
}
|
||||
.home-new .btn-primary:hover{box-shadow:0 10px 28px -6px rgba(200,150,62,.65)}
|
||||
.home-new .btn-ghost{background:var(--home-bg-elev);border-color:var(--home-border-strong);color:var(--home-ink)}
|
||||
.home-new .btn-ghost:hover{border-color:var(--ms-gold);color:var(--ms-gold-dark)}
|
||||
html.dark .home-new .btn-ghost:hover{color:var(--ms-gold-light)}
|
||||
.home-new .btn-lg{padding:14px 28px;font-size:16px}
|
||||
|
||||
/* ============ Hero ============ */
|
||||
.home-new .hero{position:relative;padding:148px 0 88px;overflow:hidden}
|
||||
.home-new .hero::before{
|
||||
content:"";position:absolute;inset:0;pointer-events:none;
|
||||
background:
|
||||
radial-gradient(640px 380px at 82% -8%,var(--home-hero-glow),transparent 70%),
|
||||
radial-gradient(520px 360px at 8% 12%,rgba(184,115,51,.08),transparent 70%);
|
||||
}
|
||||
.home-new .hero::after{
|
||||
content:"";position:absolute;inset:0;pointer-events:none;opacity:.5;
|
||||
background-image:linear-gradient(var(--home-border) 1px,transparent 1px),linear-gradient(90deg,var(--home-border) 1px,transparent 1px);
|
||||
background-size:56px 56px;
|
||||
-webkit-mask-image:radial-gradient(720px 420px at 70% 0%,#000 0%,transparent 72%);
|
||||
mask-image:radial-gradient(720px 420px at 70% 0%,#000 0%,transparent 72%);
|
||||
}
|
||||
.home-new .hero-grid{position:relative;display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}
|
||||
.home-new .badge{
|
||||
display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;
|
||||
background:var(--ms-cream);border:1px solid var(--home-border-strong);color:var(--ms-bronze-dark);
|
||||
font-size:13.5px;font-weight:600;margin-bottom:22px;
|
||||
}
|
||||
html.dark .home-new .badge{background:rgba(200,150,62,.12);color:var(--ms-gold-light);border-color:var(--home-border-strong)}
|
||||
.home-new .badge .dot{width:7px;height:7px;border-radius:50%;background:var(--ms-gold);box-shadow:0 0 0 4px rgba(200,150,62,.2)}
|
||||
.home-new .hero h1{font-size:clamp(34px,4.6vw,54px)}
|
||||
.home-new .hero h1 .grad{
|
||||
background:linear-gradient(120deg,var(--ms-gold) 10%,var(--ms-bronze) 55%,var(--ms-gold-dark) 95%);
|
||||
-webkit-background-clip:text;background-clip:text;color:transparent;
|
||||
}
|
||||
.home-new .hero .sub{font-size:clamp(17px,2vw,21px);color:var(--home-ink-soft);margin-top:14px;font-weight:500}
|
||||
.home-new .hero .tagline{font-size:15.5px;color:var(--home-ink-faint);margin-top:12px;max-width:520px}
|
||||
.home-new .hero-actions{display:flex;flex-wrap:wrap;gap:14px;margin-top:34px}
|
||||
|
||||
/* Terminal */
|
||||
.home-new .terminal{
|
||||
background:var(--home-code-bg);border-radius:14px;overflow:hidden;box-shadow:var(--home-shadow-lg);
|
||||
border:1px solid #3a3326;font-family:var(--home-mono);
|
||||
}
|
||||
.home-new .terminal-bar{display:flex;align-items:center;gap:8px;padding:13px 16px;background:#26211a;border-bottom:1px solid #3a3326}
|
||||
.home-new .terminal-bar i{width:11px;height:11px;border-radius:50%;display:block}
|
||||
.home-new .terminal-bar i:nth-child(1){background:#ff5f57}
|
||||
.home-new .terminal-bar i:nth-child(2){background:#febc2e}
|
||||
.home-new .terminal-bar i:nth-child(3){background:#28c840}
|
||||
.home-new .terminal-bar span{margin-left:8px;font-size:12.5px;color:#8d8472;font-family:var(--home-font)}
|
||||
.home-new .terminal-body{padding:20px 20px 22px;font-size:13.5px;line-height:1.85;color:var(--home-code-ink);overflow-x:auto}
|
||||
.home-new .terminal-body .ln{white-space:pre;opacity:0;transform:translateY(6px);animation:termIn .45s ease forwards}
|
||||
.home-new .terminal-body .cmt{color:#8d8472}
|
||||
.home-new .terminal-body .prompt{color:var(--ms-gold-light);user-select:none}
|
||||
.home-new .terminal-body .ok{color:#7fd49c}
|
||||
.home-new .terminal-body .kw{color:#c792ea}
|
||||
.home-new .terminal-body .fn{color:#82b4ff}
|
||||
.home-new .terminal-body .str{color:#a5d6a0}
|
||||
.home-new .terminal-body .num{color:#f0b97a}
|
||||
.home-new .terminal-body .ln:nth-child(1){animation-delay:.15s}
|
||||
.home-new .terminal-body .ln:nth-child(2){animation-delay:.35s}
|
||||
.home-new .terminal-body .ln:nth-child(3){animation-delay:.55s}
|
||||
.home-new .terminal-body .ln:nth-child(4){animation-delay:.85s}
|
||||
.home-new .terminal-body .ln:nth-child(5){animation-delay:1.1s}
|
||||
.home-new .terminal-body .ln:nth-child(6){animation-delay:1.5s}
|
||||
.home-new .terminal-body .ln:nth-child(7){animation-delay:1.9s}
|
||||
.home-new .terminal-body .ln:nth-child(8){animation-delay:2.25s}
|
||||
.home-new .terminal-body .cursor{display:inline-block;width:8px;height:16px;background:var(--ms-gold-light);vertical-align:-2px;animation:blink 1.1s steps(1) infinite}
|
||||
@keyframes termIn{to{opacity:1;transform:none}}
|
||||
@keyframes blink{50%{opacity:0}}
|
||||
|
||||
/* ============ Trust strip ============ */
|
||||
.home-new .trust{border-top:1px solid var(--home-border);border-bottom:1px solid var(--home-border);background:var(--home-bg-soft)}
|
||||
.home-new .trust-inner{padding:22px 24px;max-width:var(--home-maxw);margin:0 auto;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:14px 30px}
|
||||
.home-new .trust-label{font-size:13.5px;color:var(--home-ink-faint);font-weight:600;letter-spacing:.04em}
|
||||
.home-new .chip{
|
||||
display:inline-flex;align-items:center;gap:7px;font-size:14px;font-weight:600;color:var(--home-ink-soft);
|
||||
padding:6px 14px;border-radius:999px;border:1px solid var(--home-border);background:var(--home-bg);
|
||||
}
|
||||
.home-new .chip svg{width:15px;height:15px;color:var(--ms-gold)}
|
||||
|
||||
/* ============ Sections ============ */
|
||||
.home-new .section{padding:92px 0}
|
||||
.home-new .section-head{max-width:680px;margin:0 auto 56px;text-align:center}
|
||||
.home-new .eyebrow{
|
||||
display:inline-block;font-size:13px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
|
||||
color:var(--ms-bronze);margin-bottom:14px;
|
||||
}
|
||||
html.dark .home-new .eyebrow{color:var(--ms-gold-light)}
|
||||
.home-new .section-head h2{font-size:clamp(26px,3.2vw,38px)}
|
||||
.home-new .section-head p{margin-top:14px;color:var(--home-ink-soft);font-size:16.5px}
|
||||
|
||||
/* ============ Features ============ */
|
||||
.home-new .features{background:var(--home-bg)}
|
||||
.home-new .feature-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:20px}
|
||||
.home-new .feature{
|
||||
grid-column:span 4;position:relative;padding:30px 26px;border-radius:var(--home-radius);
|
||||
background:var(--home-bg-elev);border:1px solid var(--home-border);box-shadow:var(--home-shadow);
|
||||
transition:transform .25s ease,box-shadow .25s ease,border-color .25s;
|
||||
display:flex;flex-direction:column;
|
||||
}
|
||||
.home-new .feature:hover{transform:translateY(-5px);box-shadow:var(--home-shadow-lg);border-color:var(--home-border-strong)}
|
||||
.home-new .feature:hover .ficon{transform:scale(1.08) rotate(-3deg)}
|
||||
.home-new .ficon{
|
||||
width:48px;height:48px;border-radius:13px;display:grid;place-items:center;margin-bottom:18px;
|
||||
background:linear-gradient(135deg,var(--ms-cream),var(--ms-cream-dark));
|
||||
color:var(--ms-bronze);transition:transform .3s ease;flex:none;
|
||||
}
|
||||
html.dark .home-new .ficon{background:rgba(200,150,62,.14);color:var(--ms-gold-light)}
|
||||
.home-new .ficon svg{width:24px;height:24px}
|
||||
.home-new .feature h3{font-size:18px;margin-bottom:9px}
|
||||
.home-new .feature p{font-size:14.5px;color:var(--home-ink-soft)}
|
||||
.home-new .feature .more{margin-top:auto;padding-top:16px;font-size:13.5px;font-weight:600;color:var(--ms-gold-dark);display:inline-flex;align-items:center;gap:6px}
|
||||
html.dark .home-new .feature .more{color:var(--ms-gold-light)}
|
||||
.home-new .feature .more svg{width:14px;height:14px;transition:transform .2s}
|
||||
.home-new .feature:hover .more svg{transform:translateX(4px)}
|
||||
.home-new .feature--wide{grid-column:span 12;flex-direction:row;align-items:center;gap:28px;padding:34px 38px;
|
||||
background:linear-gradient(120deg,var(--ms-cream) 0%,var(--home-bg-elev) 62%)}
|
||||
html.dark .home-new .feature--wide{background:linear-gradient(120deg,rgba(200,150,62,.13) 0%,var(--home-bg-elev) 62%)}
|
||||
.home-new .feature--wide .ficon{margin-bottom:0}
|
||||
.home-new .feature--wide .wtext{flex:1}
|
||||
.home-new .feature--wide .wcta{flex:none}
|
||||
|
||||
/* ============ Architecture ============ */
|
||||
.home-new .arch{background:var(--home-bg-soft)}
|
||||
.home-new .arch-layers{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
|
||||
.home-new .layer{
|
||||
position:relative;padding:32px 28px;border-radius:var(--home-radius);background:var(--home-bg-elev);
|
||||
border:1px solid var(--home-border);box-shadow:var(--home-shadow);
|
||||
}
|
||||
.home-new .layer-num{
|
||||
font-family:var(--home-mono);font-size:13px;font-weight:700;color:var(--ms-gold);
|
||||
display:flex;align-items:center;gap:10px;margin-bottom:16px;
|
||||
}
|
||||
.home-new .layer-num::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--home-border-strong),transparent)}
|
||||
.home-new .layer h3{font-size:19px;margin-bottom:10px}
|
||||
.home-new .layer p{font-size:14.5px;color:var(--home-ink-soft);margin-bottom:16px}
|
||||
.home-new .layer ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
|
||||
.home-new .layer li{
|
||||
font-size:12.5px;font-weight:600;padding:5px 12px;border-radius:8px;
|
||||
background:var(--home-bg-soft);border:1px solid var(--home-border);color:var(--home-ink-soft);
|
||||
}
|
||||
.home-new .arch-flow{
|
||||
margin-top:34px;display:flex;align-items:center;justify-content:center;gap:14px;flex-wrap:wrap;
|
||||
font-size:14px;color:var(--home-ink-faint);font-weight:600;
|
||||
}
|
||||
.home-new .arch-flow svg{width:18px;height:18px;color:var(--ms-gold)}
|
||||
|
||||
/* ============ Quick start ============ */
|
||||
.home-new .qs{background:var(--home-bg)}
|
||||
.home-new .qs-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;align-items:stretch}
|
||||
.home-new .qs-step{
|
||||
padding:26px;border-radius:var(--home-radius);background:var(--home-bg-elev);border:1px solid var(--home-border);
|
||||
box-shadow:var(--home-shadow);display:flex;flex-direction:column;
|
||||
}
|
||||
.home-new .qs-step h3{font-size:16.5px;margin:14px 0 6px;display:flex;align-items:center;gap:10px}
|
||||
.home-new .step-no{
|
||||
width:30px;height:30px;border-radius:9px;display:grid;place-items:center;flex:none;
|
||||
background:linear-gradient(135deg,var(--ms-gold),var(--ms-bronze));color:#fff;
|
||||
font-family:var(--home-mono);font-size:13.5px;font-weight:700;
|
||||
}
|
||||
.home-new .qs-step>p{font-size:13.5px;color:var(--home-ink-faint);margin-bottom:14px}
|
||||
.home-new .codeblock{margin-top:auto;position:relative;background:var(--home-code-bg);border-radius:10px;padding:14px 16px;overflow-x:auto}
|
||||
.home-new .codeblock pre{margin:0;font-family:var(--home-mono);font-size:12.5px;line-height:1.7;color:var(--home-code-ink);white-space:pre}
|
||||
.home-new .codeblock .c-comment{color:#8d8472}
|
||||
.home-new .copy-btn{
|
||||
position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:7px;border:1px solid #4a4232;
|
||||
background:#2c271e;color:#b3a88e;display:grid;place-items:center;cursor:pointer;opacity:0;
|
||||
transition:opacity .2s,color .2s;
|
||||
}
|
||||
.home-new .codeblock:hover .copy-btn,.home-new .copy-btn:focus-visible{opacity:1}
|
||||
.home-new .copy-btn:hover{color:var(--ms-gold-light)}
|
||||
.home-new .copy-btn svg{width:14px;height:14px}
|
||||
.home-new .copy-btn.copied{color:#7fd49c;opacity:1}
|
||||
|
||||
/* ============ Stats ============ */
|
||||
.home-new .stats{background:var(--home-bg-soft);border-top:1px solid var(--home-border);border-bottom:1px solid var(--home-border)}
|
||||
.home-new .stats-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;padding:64px 0}
|
||||
.home-new .stat{text-align:center;padding:0 20px}
|
||||
.home-new .stat .v{font-size:clamp(34px,4vw,46px);font-weight:800;letter-spacing:-.02em;
|
||||
background:linear-gradient(120deg,var(--ms-gold),var(--ms-bronze));
|
||||
-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
.home-new .stat .l{margin-top:8px;font-size:15px;color:var(--home-ink-soft);font-weight:500}
|
||||
|
||||
/* ============ About ============ */
|
||||
.home-new .about .about-card{
|
||||
max-width:880px;margin:0 auto;padding:48px 52px;border-radius:20px;
|
||||
background:var(--home-bg-elev);border:1px solid var(--home-border);box-shadow:var(--home-shadow);
|
||||
}
|
||||
.home-new .about-card p{color:var(--home-ink-soft);font-size:16px}
|
||||
.home-new .about-card p+p{margin-top:18px}
|
||||
.home-new .about-points{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:32px}
|
||||
.home-new .about-points div{display:flex;gap:11px;align-items:flex-start;font-size:14px;font-weight:600;color:var(--home-ink)}
|
||||
.home-new .about-points svg{width:19px;height:19px;color:var(--ms-gold);flex:none;margin-top:3px}
|
||||
|
||||
/* ============ CTA ============ */
|
||||
.home-new .cta-band{padding:0 0 96px}
|
||||
.home-new .cta-card{
|
||||
position:relative;overflow:hidden;text-align:center;padding:64px 32px;border-radius:22px;
|
||||
background:linear-gradient(130deg,#2b2315 0%,#3d2f17 55%,#2b2315 100%);
|
||||
border:1px solid #4d3f23;
|
||||
}
|
||||
.home-new .cta-card::before{
|
||||
content:"";position:absolute;inset:0;
|
||||
background:radial-gradient(520px 240px at 50% -30%,rgba(224,184,106,.32),transparent 70%);
|
||||
}
|
||||
.home-new .cta-card h2{position:relative;color:#fbf3e2;font-size:clamp(25px,3vw,34px)}
|
||||
.home-new .cta-card p{position:relative;color:#c9bca0;margin-top:12px}
|
||||
.home-new .cta-card .hero-actions{justify-content:center;margin-top:30px}
|
||||
.home-new .cta-card .btn-ghost{background:transparent;border-color:#6b5a38;color:#f0e6d0}
|
||||
.home-new .cta-card .btn-ghost:hover{border-color:var(--ms-gold-light);color:var(--ms-gold-light)}
|
||||
|
||||
/* ============ Footer ============ */
|
||||
.home-new .footer{border-top:1px solid var(--home-border);background:var(--home-bg-soft);padding:44px 0}
|
||||
.home-new .footer-inner{display:flex;flex-wrap:wrap;gap:20px;align-items:center;justify-content:space-between}
|
||||
.home-new .footer p{font-size:13.5px;color:var(--home-ink-faint);line-height:1.9}
|
||||
.home-new .footer a{color:var(--home-ink-soft)}
|
||||
.home-new .footer a:hover{color:var(--ms-gold-dark)}
|
||||
html.dark .home-new .footer a:hover{color:var(--ms-gold-light)}
|
||||
.home-new .footer-links{display:flex;gap:18px;flex-wrap:wrap}
|
||||
.home-new .footer-links a{font-size:13.5px;font-weight:500}
|
||||
|
||||
/* ============ Reveal animation ============ */
|
||||
.home-new .reveal{opacity:0;transform:translateY(22px);transition:opacity .7s ease,transform .7s ease}
|
||||
.home-new .reveal.in{opacity:1;transform:none}
|
||||
.home-new .stagger>*{transition-delay:calc(var(--i,0)*70ms)}
|
||||
|
||||
/* ============ Responsive ============ */
|
||||
@media (max-width:980px){
|
||||
.home-new .hero{padding:120px 0 64px}
|
||||
.home-new .hero-grid{grid-template-columns:1fr;gap:44px}
|
||||
.home-new .feature{grid-column:span 6}
|
||||
.home-new .feature--wide{grid-column:span 12;flex-direction:column;align-items:flex-start;gap:18px}
|
||||
.home-new .arch-layers,.home-new .qs-grid,.home-new .stats-grid,.home-new .about-points{grid-template-columns:1fr}
|
||||
.home-new .stat{padding:10px 0}
|
||||
.home-new .nav-links{display:none}
|
||||
.home-new .hamburger{display:grid}
|
||||
.home-new .nav-menu-open .nav-links{
|
||||
display:flex;flex-direction:column;position:absolute;top:64px;left:0;right:0;
|
||||
background:var(--home-bg);border-bottom:1px solid var(--home-border);padding:12px 20px 18px;gap:2px;
|
||||
box-shadow:var(--home-shadow);
|
||||
}
|
||||
.home-new .about .about-card{padding:32px 24px}
|
||||
}
|
||||
@media (max-width:560px){
|
||||
.home-new .feature{grid-column:span 12}
|
||||
.home-new .section{padding:68px 0}
|
||||
.home-new .hero-actions .btn{width:100%;justify-content:center}
|
||||
.home-new .footer-inner{flex-direction:column;align-items:flex-start}
|
||||
}
|
||||
@media (prefers-reduced-motion:reduce){
|
||||
*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
|
||||
.home-new .reveal{opacity:1;transform:none}
|
||||
.home-new .terminal-body .ln{opacity:1;transform:none}
|
||||
}
|
||||
</style>
|
||||
27
.vitepress/theme/Layout.vue
Normal file
27
.vitepress/theme/Layout.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<script setup>
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { useRoute } from 'vitepress'
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import Home from './Home.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const isHome = computed(() => route.path === '/' || route.path === '/index.html')
|
||||
|
||||
function applyLayout() {
|
||||
if (isHome.value) {
|
||||
document.documentElement.classList.add('home-layout')
|
||||
} else {
|
||||
document.documentElement.classList.remove('home-layout')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(applyLayout)
|
||||
onUnmounted(() => {
|
||||
document.documentElement.classList.remove('home-layout')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Home v-if="isHome" />
|
||||
<DefaultTheme.Layout v-else />
|
||||
</template>
|
||||
554
.vitepress/theme/custom.css
Normal file
554
.vitepress/theme/custom.css
Normal file
@ -0,0 +1,554 @@
|
||||
/* ========================================
|
||||
MengStack Brand Theme — Gold & Bronze
|
||||
======================================== */
|
||||
|
||||
:root {
|
||||
/* Brand palette */
|
||||
--ms-gold: #C8963E;
|
||||
--ms-gold-light: #E0B86A;
|
||||
--ms-gold-dark: #A07830;
|
||||
--ms-bronze: #B87333;
|
||||
--ms-bronze-dark: #8B5A2B;
|
||||
--ms-cream: #FDF8EF;
|
||||
--ms-cream-dark: #F5EDD8;
|
||||
|
||||
/* Override VitePress brand colors */
|
||||
--vp-c-brand-1: var(--ms-gold);
|
||||
--vp-c-brand-2: var(--ms-gold-dark);
|
||||
--vp-c-brand-3: var(--ms-bronze);
|
||||
--vp-c-brand-soft: rgba(200, 150, 62, 0.14);
|
||||
--vp-c-brand-soft-2: rgba(200, 150, 62, 0.25);
|
||||
}
|
||||
|
||||
/* ============ NAV BAR ============ */
|
||||
.VPNav {
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.VPNavBar {
|
||||
border-bottom: 1px solid rgba(200, 150, 62, 0.1) !important;
|
||||
background: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.dark .VPNavBar {
|
||||
background: rgba(27, 27, 30, 0.88) !important;
|
||||
border-bottom-color: rgba(200, 150, 62, 0.12) !important;
|
||||
}
|
||||
|
||||
.VPNavBarTitle a.title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.VPNavBarTitle a.title span {
|
||||
background: linear-gradient(135deg, var(--ms-gold-dark), var(--ms-gold-light));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.VPNavBar .VPNavBarMenuLink,
|
||||
.VPNavBar .VPNavBarMenuGroup .title {
|
||||
font-weight: 500;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.VPNavBar .VPNavBarMenuLink:hover,
|
||||
.VPNavBar .VPNavBarMenuGroup .title:hover {
|
||||
color: var(--ms-gold) !important;
|
||||
}
|
||||
|
||||
.VPNavBar .VPNavBarMenuLink.active {
|
||||
color: var(--ms-gold) !important;
|
||||
}
|
||||
|
||||
.VPNavBar .VPNavBarMenuLink.active::after {
|
||||
background: var(--ms-gold) !important;
|
||||
}
|
||||
|
||||
/* Social icon */
|
||||
.VPNavBar .VPSocialLink:hover {
|
||||
color: var(--ms-gold) !important;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.VPNavBar .VPSocialLink {
|
||||
transition: color 0.25s, transform 0.25s;
|
||||
}
|
||||
|
||||
/* ============ HERO SECTION ============ */
|
||||
.VPHero {
|
||||
padding-top: 48px;
|
||||
padding-bottom: 40px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPHero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -40%;
|
||||
left: -20%;
|
||||
width: 140%;
|
||||
height: 180%;
|
||||
background: radial-gradient(ellipse at 30% 20%, rgba(200, 150, 62, 0.06) 0%, transparent 60%),
|
||||
radial-gradient(ellipse at 70% 80%, rgba(184, 115, 51, 0.04) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.dark .VPHero::before {
|
||||
background: radial-gradient(ellipse at 30% 20%, rgba(200, 150, 62, 0.08) 0%, transparent 60%),
|
||||
radial-gradient(ellipse at 70% 80%, rgba(184, 115, 51, 0.05) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.VPHero .main {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Hide empty image column, make content full-width */
|
||||
.VPHero .image {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.VPHero .container {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 0 !important;
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
flex-grow: 1 !important;
|
||||
}
|
||||
|
||||
.VPHero .content {
|
||||
max-width: 100% !important;
|
||||
flex: 1 1 100% !important;
|
||||
}
|
||||
|
||||
/* Hero name — premium gold gradient text */
|
||||
.VPHero .heading {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.VPHero .heading .name {
|
||||
font-size: 4.2rem !important;
|
||||
line-height: 1.1 !important;
|
||||
letter-spacing: -0.03em;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #B8862D 0%, #D4A84B 25%, #F0D078 50%, #D4A84B 75%, #A07020 100%);
|
||||
-webkit-background-clip: text !important;
|
||||
background-clip: text !important;
|
||||
color: transparent !important;
|
||||
text-shadow: none;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Decorative accent line under the name */
|
||||
.VPHero .heading .name::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 0;
|
||||
width: 80px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--ms-gold), var(--ms-gold-light), transparent);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.VPHero .text {
|
||||
font-size: 1.6rem !important;
|
||||
line-height: 1.4 !important;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.dark .VPHero .text {
|
||||
color: rgba(255, 255, 255, 0.88) !important;
|
||||
}
|
||||
|
||||
.VPHero .tagline {
|
||||
font-size: 1.1rem !important;
|
||||
color: var(--ms-gold-dark) !important;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.03em;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.dark .VPHero .tagline {
|
||||
color: var(--ms-gold-light) !important;
|
||||
}
|
||||
|
||||
/* Hero buttons */
|
||||
.VPHero .actions .action a.VPButton.brand {
|
||||
background: linear-gradient(135deg, var(--ms-gold-dark), var(--ms-gold)) !important;
|
||||
border: none !important;
|
||||
color: #fff !important;
|
||||
font-weight: 600;
|
||||
border-radius: 10px !important;
|
||||
padding: 0 28px !important;
|
||||
height: 44px !important;
|
||||
line-height: 44px !important;
|
||||
font-size: 0.95rem !important;
|
||||
box-shadow: 0 4px 14px rgba(200, 150, 62, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.VPHero .actions .action a.VPButton.brand:hover {
|
||||
box-shadow: 0 6px 20px rgba(200, 150, 62, 0.45);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.VPHero .actions .action a.VPButton.alt {
|
||||
border: 1.5px solid var(--ms-gold) !important;
|
||||
color: var(--ms-gold-dark) !important;
|
||||
border-radius: 10px !important;
|
||||
padding: 0 28px !important;
|
||||
height: 44px !important;
|
||||
line-height: 42px !important;
|
||||
font-size: 0.95rem !important;
|
||||
font-weight: 600;
|
||||
background: transparent !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark .VPHero .actions .action a.VPButton.alt {
|
||||
color: var(--ms-gold-light) !important;
|
||||
border-color: var(--ms-gold-light) !important;
|
||||
}
|
||||
|
||||
.VPHero .actions .action a.VPButton.alt:hover {
|
||||
background: rgba(200, 150, 62, 0.08) !important;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* ============ FEATURES SECTION ============ */
|
||||
.VPFeatures {
|
||||
padding: 48px 0 56px !important;
|
||||
}
|
||||
|
||||
.VPFeatures .VPFeature .box {
|
||||
border: 1px solid rgba(200, 150, 62, 0.12) !important;
|
||||
border-radius: 14px !important;
|
||||
padding: 28px 24px 24px !important;
|
||||
background: rgba(255, 255, 255, 0.7) !important;
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dark .VPFeatures .VPFeature .box {
|
||||
background: rgba(40, 40, 44, 0.6) !important;
|
||||
border-color: rgba(200, 150, 62, 0.1) !important;
|
||||
}
|
||||
|
||||
.VPFeatures .VPFeature .box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--ms-gold-dark), var(--ms-gold-light), var(--ms-bronze));
|
||||
opacity: 0;
|
||||
transition: opacity 0.35s;
|
||||
}
|
||||
|
||||
.VPFeatures .VPFeature:hover .box {
|
||||
border-color: rgba(200, 150, 62, 0.3) !important;
|
||||
box-shadow: 0 8px 30px rgba(200, 150, 62, 0.1), 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.dark .VPFeatures .VPFeature:hover .box {
|
||||
border-color: rgba(200, 150, 62, 0.25) !important;
|
||||
box-shadow: 0 8px 30px rgba(200, 150, 62, 0.08), 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.VPFeatures .VPFeature:hover .box::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Feature icon */
|
||||
.VPFeatures .VPFeature .icon {
|
||||
width: 52px !important;
|
||||
height: 52px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.6rem;
|
||||
background: linear-gradient(135deg, rgba(200, 150, 62, 0.08), rgba(184, 115, 51, 0.05)) !important;
|
||||
border: 1px solid rgba(200, 150, 62, 0.12);
|
||||
border-radius: 12px !important;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.dark .VPFeatures .VPFeature .icon {
|
||||
background: linear-gradient(135deg, rgba(200, 150, 62, 0.12), rgba(184, 115, 51, 0.08)) !important;
|
||||
border-color: rgba(200, 150, 62, 0.15);
|
||||
}
|
||||
|
||||
/* Feature title */
|
||||
.VPFeatures .VPFeature .title {
|
||||
font-size: 1.05rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ms-bronze-dark) !important;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.dark .VPFeatures .VPFeature .title {
|
||||
color: var(--ms-gold-light) !important;
|
||||
}
|
||||
|
||||
/* Feature details — prevent truncation */
|
||||
.VPFeatures .details {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
line-height: 1.65;
|
||||
font-size: 0.88rem !important;
|
||||
color: var(--vp-c-text-2) !important;
|
||||
}
|
||||
|
||||
/* Feature link arrow */
|
||||
.VPFeatures .VPFeature .link-text {
|
||||
color: var(--ms-gold) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ============ ABOUT SECTION ============ */
|
||||
.VPDoc:has(.content-container) .main .content .content-body {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.VPHome .VPHomeContent {
|
||||
max-width: 1152px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
/* Style the "关于 MengStack" section */
|
||||
.VPHome .vp-doc h2 {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
margin: 48px 0 24px;
|
||||
background: linear-gradient(135deg, var(--ms-gold-dark), var(--ms-bronze));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.VPHome .vp-doc h2::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--ms-gold), var(--ms-bronze));
|
||||
margin: 12px auto 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.VPHome .vp-doc p {
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.85;
|
||||
color: var(--vp-c-text-1);
|
||||
max-width: 720px;
|
||||
margin: 0 auto 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ============ FOOTER ============ */
|
||||
.VPFooter {
|
||||
border-top: 1px solid rgba(200, 150, 62, 0.1) !important;
|
||||
background: rgba(250, 247, 240, 0.6) !important;
|
||||
padding: 28px 0 !important;
|
||||
}
|
||||
|
||||
.dark .VPFooter {
|
||||
background: rgba(20, 20, 22, 0.8) !important;
|
||||
border-top-color: rgba(200, 150, 62, 0.08) !important;
|
||||
}
|
||||
|
||||
.VPFooter .message {
|
||||
color: var(--ms-gold-dark) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.dark .VPFooter .message {
|
||||
color: var(--ms-gold-light) !important;
|
||||
}
|
||||
|
||||
.VPFooter a {
|
||||
color: var(--vp-c-text-2);
|
||||
text-decoration: none;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.VPFooter a:hover {
|
||||
color: var(--ms-gold) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-extra {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.footer-extra a {
|
||||
color: var(--vp-c-text-2);
|
||||
text-decoration: none;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.footer-extra a:hover {
|
||||
color: var(--ms-gold);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ============ DOC PAGES ============ */
|
||||
/* Sidebar active item */
|
||||
.VPSidebarItem.is-active > .item .link .link-text {
|
||||
color: var(--ms-gold) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.VPSidebarItem.is-active > .item .link {
|
||||
background: rgba(200, 150, 62, 0.06) !important;
|
||||
border-left-color: var(--ms-gold) !important;
|
||||
}
|
||||
|
||||
/* Sidebar hover */
|
||||
.VPSidebarItem .item .link:hover {
|
||||
background: rgba(200, 150, 62, 0.04) !important;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
.vp-doc code {
|
||||
background: rgba(200, 150, 62, 0.08) !important;
|
||||
color: var(--ms-bronze-dark) !important;
|
||||
border: 1px solid rgba(200, 150, 62, 0.1);
|
||||
border-radius: 5px;
|
||||
padding: 2px 6px;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
|
||||
.dark .vp-doc code {
|
||||
background: rgba(200, 150, 62, 0.1) !important;
|
||||
color: var(--ms-gold-light) !important;
|
||||
border-color: rgba(200, 150, 62, 0.12);
|
||||
}
|
||||
|
||||
/* Blockquote / custom containers */
|
||||
.vp-doc blockquote {
|
||||
border-left: 3px solid var(--ms-gold) !important;
|
||||
background: rgba(200, 150, 62, 0.04);
|
||||
padding: 12px 16px;
|
||||
border-radius: 0 8px 8px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
/* Links in content */
|
||||
.vp-doc a {
|
||||
color: var(--ms-gold) !important;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
.vp-doc a:hover {
|
||||
border-bottom-color: var(--ms-gold);
|
||||
}
|
||||
|
||||
/* Headings in doc pages */
|
||||
.vp-doc h1, .vp-doc h2, .vp-doc h3, .vp-doc h4 {
|
||||
color: var(--ms-bronze-dark);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dark .vp-doc h1, .dark .vp-doc h2, .dark .vp-doc h3, .dark .vp-doc h4 {
|
||||
color: var(--ms-gold-light);
|
||||
}
|
||||
|
||||
.vp-doc h2 {
|
||||
border-bottom: 1px solid rgba(200, 150, 62, 0.15) !important;
|
||||
}
|
||||
|
||||
/* Table styling */
|
||||
.vp-doc table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vp-doc table th {
|
||||
background: rgba(200, 150, 62, 0.06) !important;
|
||||
color: var(--ms-bronze-dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dark .vp-doc table th {
|
||||
background: rgba(200, 150, 62, 0.08) !important;
|
||||
color: var(--ms-gold-light);
|
||||
}
|
||||
|
||||
.vp-doc table tr {
|
||||
border-bottom: 1px solid rgba(200, 150, 62, 0.08);
|
||||
}
|
||||
|
||||
/* ============ SEARCH ============ */
|
||||
.VPLocalSearchBox .filter {
|
||||
background: rgba(200, 150, 62, 0.08) !important;
|
||||
border-color: rgba(200, 150, 62, 0.15) !important;
|
||||
color: var(--ms-gold-dark);
|
||||
}
|
||||
|
||||
/* ============ SCROLLBAR ============ */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(200, 150, 62, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(200, 150, 62, 0.35);
|
||||
}
|
||||
|
||||
/* ============ SELECTION ============ */
|
||||
::selection {
|
||||
background: rgba(200, 150, 62, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* ============ TRANSITIONS ============ */
|
||||
.VPNavBar, .VPFeatures .VPFeature, .VPHero .actions a, .VPFooter {
|
||||
transition-property: background, border-color, box-shadow, transform;
|
||||
transition-duration: 0.3s;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
/* ============ RESPONSIVE ============ */
|
||||
@media (max-width: 768px) {
|
||||
.VPHero .heading .name {
|
||||
font-size: 2.8rem !important;
|
||||
}
|
||||
.VPHero .text {
|
||||
font-size: 1.3rem !important;
|
||||
}
|
||||
.VPFeatures .VPFeature .box {
|
||||
padding: 22px 18px 18px !important;
|
||||
}
|
||||
}
|
||||
4
.vitepress/theme/index.js
Normal file
4
.vitepress/theme/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './custom.css'
|
||||
|
||||
export default DefaultTheme
|
||||
181
api/auth.md
Normal file
181
api/auth.md
Normal file
@ -0,0 +1,181 @@
|
||||
# 认证接口
|
||||
|
||||
## 用户注册
|
||||
|
||||
注册新用户并返回 JWT 令牌。
|
||||
|
||||
**`POST /api/v1/auth/register`**
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"username": "johndoe",
|
||||
"nickname": "John Doe",
|
||||
"password": "securepass123"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 |
|
||||
|------|------|------|------|
|
||||
| `email` | string | 是 | 有效邮箱格式 |
|
||||
| `username` | string | 是 | 3-64 字符 |
|
||||
| `nickname` | string | 否 | - |
|
||||
| `password` | string | 是 | 8-128 字符 |
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"expires_in": 7200
|
||||
},
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 400 | 参数校验失败 |
|
||||
| 409 | 邮箱或用户名已存在 |
|
||||
|
||||
---
|
||||
|
||||
## 用户登录
|
||||
|
||||
使用邮箱和密码登录。
|
||||
|
||||
**`POST /api/v1/auth/login`**
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "securepass123"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 |
|
||||
|------|------|------|
|
||||
| `email` | string | 是 |
|
||||
| `password` | string | 是 |
|
||||
|
||||
### 响应
|
||||
|
||||
同注册接口,返回 TokenPair。
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 400 | 参数校验失败 |
|
||||
| 401 | 邮箱或密码错误 |
|
||||
|
||||
---
|
||||
|
||||
## 刷新令牌
|
||||
|
||||
使用 refresh_token 获取新的令牌对。
|
||||
|
||||
**`POST /api/v1/auth/refresh`**
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
|
||||
}
|
||||
```
|
||||
|
||||
### 响应
|
||||
|
||||
同注册接口,返回新的 TokenPair。
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 400 | 参数校验失败 |
|
||||
| 401 | Refresh Token 无效或过期 |
|
||||
|
||||
---
|
||||
|
||||
## 修改密码
|
||||
|
||||
修改当前用户密码,需要认证。
|
||||
|
||||
**`POST /api/v1/password`**
|
||||
|
||||
### 请求头
|
||||
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
X-Tenant-ID: <tenant_id>
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"old_password": "oldpass123",
|
||||
"new_password": "newpass456"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 |
|
||||
|------|------|------|------|
|
||||
| `old_password` | string | 是 | - |
|
||||
| `new_password` | string | 是 | 8-128 字符 |
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null,
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取当前用户
|
||||
|
||||
获取当前认证用户的个人资料。
|
||||
|
||||
**`GET /api/v1/profile`**
|
||||
|
||||
### 请求头
|
||||
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
X-Tenant-ID: <tenant_id>
|
||||
```
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"email": "user@example.com",
|
||||
"username": "johndoe",
|
||||
"nickname": "John Doe",
|
||||
"avatar": "",
|
||||
"status": 1,
|
||||
"tenant_id": "tenant-001"
|
||||
},
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
73
api/overview.md
Normal file
73
api/overview.md
Normal file
@ -0,0 +1,73 @@
|
||||
---
|
||||
title: API接口概览 | 统一响应格式与错误码说明 - MengStack官方文档
|
||||
---
|
||||
|
||||
# API 概览
|
||||
|
||||
MengStack API 基于 RESTful 设计,所有接口统一前缀 `/api/v1`。
|
||||
|
||||
## 基础信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|------|
|
||||
| Base URL | `http://localhost:2222/api/v1` |
|
||||
| 数据格式 | JSON |
|
||||
| 认证方式 | Bearer Token (JWT) |
|
||||
| API 文档 | `http://localhost:2222/swagger/index.html` |
|
||||
|
||||
## 统一响应格式
|
||||
|
||||
所有接口返回统一格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {},
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `code` | int | 状态码,0 表示成功 |
|
||||
| `message` | string | 状态描述 |
|
||||
| `data` | any | 响应数据 |
|
||||
| `trace_id` | string | 请求追踪 ID |
|
||||
|
||||
## 错误码
|
||||
|
||||
| HTTP 状态码 | 说明 |
|
||||
|------------|------|
|
||||
| 200 | 成功 |
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未认证或 Token 过期 |
|
||||
| 403 | 无权限 |
|
||||
| 404 | 资源不存在 |
|
||||
| 409 | 资源冲突(如邮箱已注册) |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 认证
|
||||
|
||||
需要认证的接口,在请求头中携带:
|
||||
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
X-Tenant-ID: <tenant_id>
|
||||
```
|
||||
|
||||
## 接口列表
|
||||
|
||||
| 模块 | 端点 | 说明 |
|
||||
|------|------|------|
|
||||
| 认证 | `POST /auth/register` | 用户注册,详见[认证接口](/api/auth) |
|
||||
| 认证 | `POST /auth/login` | 用户登录,详见[认证接口](/api/auth) |
|
||||
| 认证 | `POST /auth/refresh` | 刷新令牌,详见[认证接口](/api/auth) |
|
||||
| 认证 | `POST /password` | 修改密码,详见[认证接口](/api/auth) |
|
||||
| 认证 | `GET /profile` | 获取当前用户,详见[认证接口](/api/auth) |
|
||||
| 系统 | `GET /health` | 健康检查,详见[系统接口](/api/system) |
|
||||
| 系统 | `GET /ping` | 连通性测试,详见[系统接口](/api/system) |
|
||||
|
||||
## Swagger UI
|
||||
|
||||
启动服务后访问 `http://localhost:2222/swagger/index.html` 查看交互式 API 文档。
|
||||
66
api/system.md
Normal file
66
api/system.md
Normal file
@ -0,0 +1,66 @@
|
||||
# 系统接口
|
||||
|
||||
## 健康检查
|
||||
|
||||
检查 PostgreSQL 和 Redis 连接状态。
|
||||
|
||||
**`GET /health`**
|
||||
|
||||
无需认证。
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"database": "connected",
|
||||
"redis": "connected",
|
||||
"timestamp": 1727856000,
|
||||
"version": "0.1.0",
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
### 状态说明
|
||||
|
||||
| 字段 | 可能值 |
|
||||
|------|--------|
|
||||
| `status` | `ok` / `degraded` / `down` |
|
||||
| `database` | `connected` / `disconnected` |
|
||||
| `redis` | `connected` / `disconnected` |
|
||||
|
||||
---
|
||||
|
||||
## 连通性测试
|
||||
|
||||
返回 pong,用于验证认证和多租户中间件是否正常工作。
|
||||
|
||||
**`GET /api/v1/ping`**
|
||||
|
||||
需要认证和租户头。
|
||||
|
||||
### 请求头
|
||||
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
X-Tenant-ID: <tenant_id>
|
||||
```
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "pong"
|
||||
},
|
||||
"trace_id": "req-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
### 用途
|
||||
|
||||
- 验证 Token 是否有效
|
||||
- 验证多租户中间件是否正常
|
||||
- 客户端心跳检测
|
||||
81
changelog.md
Normal file
81
changelog.md
Normal file
@ -0,0 +1,81 @@
|
||||
---
|
||||
title: 更新日志 | 版本迭代记录与路线图 - MengStack开源框架
|
||||
---
|
||||
|
||||
# 更新日志
|
||||
|
||||
## v0.1.0 (2026-10-02)
|
||||
|
||||
**初始版本** — 项目骨架 + 认证模块
|
||||
|
||||
### 新增
|
||||
|
||||
- **三层隔离架构**:Kernel / App / Modules 层间依赖方向单一
|
||||
- **模块四层模式**:Domain / Application / Infrastructure / Interfaces
|
||||
- **依赖注入**:基于 uber-go/fx 的自动依赖解析和生命周期管理
|
||||
- **配置管理**:Viper 分层配置,支持 YAML + 环境变量覆盖
|
||||
- **结构化日志**:Zap 结构化输出,请求级 trace_id
|
||||
- **多租户支持**:基于 X-Tenant-ID 的租户隔离中间件
|
||||
- **认证模块**:
|
||||
- 用户注册(邮箱 + 用户名 + 密码)
|
||||
- 用户登录(邮箱 + 密码)
|
||||
- JWT 双 Token 机制(Access + Refresh)
|
||||
- Token 刷新
|
||||
- 密码修改
|
||||
- 用户资料查询
|
||||
- **统一响应格式**:`{code, message, data, trace_id}`
|
||||
- **Swagger API 文档**:swaggo 注解驱动,自动生成 Swagger UI
|
||||
- **Docker Compose**:PostgreSQL + Redis + 应用一键启动
|
||||
- **健康检查**:PostgreSQL + Redis 连接状态检测
|
||||
- **CORS 中间件**:跨域请求支持
|
||||
- **请求追踪**:每个请求自动分配 trace_id
|
||||
|
||||
### 技术栈
|
||||
|
||||
| 组件 | 版本 |
|
||||
|------|------|
|
||||
| Go | 1.23 |
|
||||
| Gin | 1.10 |
|
||||
| GORM | 1.25 |
|
||||
| PostgreSQL | 14+ |
|
||||
| Redis | 7+ |
|
||||
| uber-go/fx | 1.23 |
|
||||
| Zap | 1.27 |
|
||||
| Viper | 1.19 |
|
||||
| golang-jwt | 5.2 |
|
||||
|
||||
---
|
||||
|
||||
## 路线图
|
||||
|
||||
### v0.2.0 — RBAC 权限模型
|
||||
|
||||
- Role / Permission 数据模型
|
||||
- 用户角色分配
|
||||
- RBAC 中间件
|
||||
- 权限校验装饰器
|
||||
|
||||
### v0.3.0 — 组织管理 + 审计日志
|
||||
|
||||
- 组织 CRUD
|
||||
- 用户-组织关系
|
||||
- 操作审计日志
|
||||
|
||||
### v0.4.0 — 配置管理增强
|
||||
|
||||
- 运行时配置 API
|
||||
- 全局默认 + 租户覆盖
|
||||
- 配置变更历史
|
||||
|
||||
### v0.5.0 — 用户示例模块
|
||||
|
||||
- 完整用户 CRUD
|
||||
- 单元测试 + 集成测试
|
||||
- 示例代码
|
||||
|
||||
### v1.0.0 — 正式发布
|
||||
|
||||
- 完整测试覆盖
|
||||
- 安全审计
|
||||
- 性能基准测试
|
||||
- 生产部署文档
|
||||
56
community.md
Normal file
56
community.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: 开发者社区 | 交流渠道与贡献指南 - MengStack开源社区
|
||||
---
|
||||
|
||||
# 社区
|
||||
|
||||
MengStack 正在积极建设中,欢迎参与!
|
||||
|
||||
## 交流渠道
|
||||
|
||||
| 渠道 | 链接 |
|
||||
|------|------|
|
||||
| Gitea 仓库 | [mengstackgit.softunis.com/mengstack](https://mengstackgit.softunis.com/mengstack) |
|
||||
| 问题反馈 | [Gitea Issues](https://mengstackgit.softunis.com/mengstack/issues) |
|
||||
| 功能建议 | [Gitea Issues](https://mengstackgit.softunis.com/mengstack/issues/new) |
|
||||
|
||||
## 参与贡献
|
||||
|
||||
### 报告 Bug
|
||||
|
||||
1. 在 Gitea 上创建 Issue
|
||||
2. 描述复现步骤
|
||||
3. 附上错误日志
|
||||
4. 标注环境信息(Go 版本、OS、数据库版本)
|
||||
|
||||
### 提交代码
|
||||
|
||||
1. Fork 仓库
|
||||
2. 创建功能分支:`git checkout -b feature/my-feature`
|
||||
3. 提交变更:`git commit -am 'Add my feature'`
|
||||
4. 推送分支:`git push origin feature/my-feature`
|
||||
5. 创建 Pull Request
|
||||
|
||||
### 代码规范
|
||||
|
||||
- 遵循项目三层隔离架构
|
||||
- 新模块遵循四层模式(Domain / Application / Infrastructure / Interfaces)
|
||||
- 所有公开函数添加 swaggo 注解
|
||||
- 提交前运行 `make lint` 和 `make test`
|
||||
|
||||
## 问答社区(即将上线)
|
||||
|
||||
我们正在筹备在线问答社区,届时将提供:
|
||||
|
||||
- 技术问答
|
||||
- 最佳实践分享
|
||||
- 版本发布公告
|
||||
- 开发者交流
|
||||
|
||||
敬请期待!
|
||||
|
||||
## 关于软盟
|
||||
|
||||
MengStack 由 [软盟 SoftUnis](https://www.softunis.com) 团队开发和维护。
|
||||
|
||||
软盟专注于企业级解决方案,致力于开源生态建设。
|
||||
69
demo.md
Normal file
69
demo.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
title: 在线演示 | 免费体验MengStack接口服务 - MengStack官方
|
||||
---
|
||||
|
||||
# 在线演示
|
||||
|
||||
## 演示地址
|
||||
|
||||
| 服务 | 地址 |
|
||||
|------|------|
|
||||
| API 服务 | `https://mengstackdemo.softunis.com` |
|
||||
| Swagger UI | `https://mengstackdemo.softunis.com/swagger/index.html` |
|
||||
| 健康检查 | `https://mengstackdemo.softunis.com/health` |
|
||||
|
||||
::: warning 注意
|
||||
演示数据会定期重置,请勿存储重要数据。
|
||||
:::
|
||||
|
||||
## 快速体验
|
||||
|
||||
### 1. 注册账号
|
||||
|
||||
```bash
|
||||
curl -X POST https://mengstackdemo.softunis.com/api/v1/auth/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "demo@example.com",
|
||||
"username": "demo_user",
|
||||
"nickname": "Demo User",
|
||||
"password": "demo12345"
|
||||
}'
|
||||
```
|
||||
|
||||
### 2. 登录获取 Token
|
||||
|
||||
```bash
|
||||
curl -X POST https://mengstackdemo.softunis.com/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "demo@example.com",
|
||||
"password": "demo12345"
|
||||
}'
|
||||
```
|
||||
|
||||
### 3. 访问受保护接口
|
||||
|
||||
```bash
|
||||
curl https://mengstackdemo.softunis.com/api/v1/profile \
|
||||
-H "Authorization: Bearer <your_access_token>" \
|
||||
-H "X-Tenant-ID: demo-tenant"
|
||||
```
|
||||
|
||||
## Swagger UI 交互
|
||||
|
||||
打开 [Swagger UI](https://mengstackdemo.softunis.com/swagger/index.html),可以:
|
||||
|
||||
- 浏览所有 API 端点
|
||||
- 在线发送请求测试
|
||||
- 查看请求/响应模型
|
||||
- 下载 OpenAPI 规范文件
|
||||
|
||||
### 使用步骤
|
||||
|
||||
1. 打开 Swagger UI
|
||||
2. 点击 `/auth/register` 端点
|
||||
3. 点击 "Try it out"
|
||||
4. 填写请求参数
|
||||
5. 点击 "Execute"
|
||||
6. 查看响应结果
|
||||
73
guide/architecture.md
Normal file
73
guide/architecture.md
Normal file
@ -0,0 +1,73 @@
|
||||
# 三层隔离架构
|
||||
|
||||
MengStack 采用三层隔离架构,从外到内依次为:**Kernel → App → Modules**。
|
||||
|
||||
## 架构总览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Modules │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ Auth │ │ Org │ │ User │ ... │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │
|
||||
├───────┼───────────┼───────────┼──────────────────┤
|
||||
│ └───────────┼───────────┘ │
|
||||
│ │ │
|
||||
│ App │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Database │ │ Cache │ │Middleware│ ... │
|
||||
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
|
||||
│ │ │ │ │
|
||||
├───────┼────────────┼────────────┼────────────────┤
|
||||
│ └────────────┼────────────┘ │
|
||||
│ │ │
|
||||
│ Kernel │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Response │ │ Error │ │ Paginator│ ... │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 依赖规则
|
||||
|
||||
**只能从上到下依赖,禁止反向依赖。**
|
||||
|
||||
| 层 | 可以依赖 | 禁止依赖 |
|
||||
|---|---|---|
|
||||
| Modules | App, Kernel | 其他 Modules |
|
||||
| App | Kernel | Modules |
|
||||
| Kernel | 标准库 | App, Modules |
|
||||
|
||||
## Kernel 层
|
||||
|
||||
零业务语义的基础组件。判断标准:**这个组件是否知道"用户"、"租户"、"订单"等业务概念?** 如果知道,它就不属于 Kernel。
|
||||
|
||||
Kernel 提供的都是纯粹的技术工具:
|
||||
|
||||
- 统一响应格式
|
||||
- 通用错误类型
|
||||
- 分页工具
|
||||
- 字符串/时间工具
|
||||
|
||||
## App 层
|
||||
|
||||
应用基础设施,负责连接外部世界:
|
||||
|
||||
- 数据库连接(GORM + PostgreSQL)
|
||||
- 缓存连接(Redis)
|
||||
- 全局中间件
|
||||
- 健康检查
|
||||
|
||||
App 层可以引用 Kernel,但不知道任何业务模块的存在。
|
||||
|
||||
## Modules 层
|
||||
|
||||
业务模块,每个模块独立自包含。模块间不能直接引用,只能通过接口或事件通信。
|
||||
|
||||
## 为什么这样分?
|
||||
|
||||
1. **Kernel 可复用**:换一个项目,Kernel 可以直接搬过去
|
||||
2. **App 可替换**:换数据库、换缓存,只改 App 层
|
||||
3. **Modules 可删除**:删除一个业务模块,不影响其他模块和基础设施
|
||||
107
guide/auth.md
Normal file
107
guide/auth.md
Normal file
@ -0,0 +1,107 @@
|
||||
# 认证与授权
|
||||
|
||||
MengStack 内置完整的认证授权系统,基于 JWT 双 Token 机制。
|
||||
|
||||
## 认证流程
|
||||
|
||||
```
|
||||
┌────────┐ POST /auth/register ┌────────┐
|
||||
│ Client │ ──────────────────────────→ │ Server │
|
||||
│ │ ←────────────────────────── │ │
|
||||
│ │ { access_token, refresh } │ │
|
||||
│ │ │ │
|
||||
│ │ POST /auth/login │ │
|
||||
│ │ ──────────────────────────→ │ │
|
||||
│ │ ←────────────────────────── │ │
|
||||
│ │ { access_token, refresh } │ │
|
||||
│ │ │ │
|
||||
│ │ GET /api/v1/profile │ │
|
||||
│ │ Authorization: Bearer xxx │ │
|
||||
│ │ ──────────────────────────→ │ │
|
||||
│ │ ←────────────────────────── │ │
|
||||
│ │ { user data } │ │
|
||||
│ │ │ │
|
||||
│ │ POST /auth/refresh │ │
|
||||
│ │ { refresh_token } │ │
|
||||
│ │ ──────────────────────────→ │ │
|
||||
│ │ ←────────────────────────── │ │
|
||||
│ │ { new token pair } │ │
|
||||
└────────┘ └────────┘
|
||||
```
|
||||
|
||||
## API 端点
|
||||
|
||||
| 端点 | 方法 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| `/api/v1/auth/register` | POST | 用户注册 | 无 |
|
||||
| `/api/v1/auth/login` | POST | 用户登录 | 无 |
|
||||
| `/api/v1/auth/refresh` | POST | 刷新令牌 | 无 |
|
||||
| `/api/v1/password` | POST | 修改密码 | Bearer |
|
||||
| `/api/v1/profile` | GET | 获取当前用户 | Bearer |
|
||||
|
||||
## 注册
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:2222/api/v1/auth/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "user@example.com",
|
||||
"username": "johndoe",
|
||||
"nickname": "John Doe",
|
||||
"password": "securepass123"
|
||||
}'
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"expires_in": 7200
|
||||
},
|
||||
"trace_id": "abc-123-def"
|
||||
}
|
||||
```
|
||||
|
||||
## 登录
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:2222/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "user@example.com",
|
||||
"password": "securepass123"
|
||||
}'
|
||||
```
|
||||
|
||||
## 使用 Access Token
|
||||
|
||||
在请求头中携带 `Authorization: Bearer <access_token>`:
|
||||
|
||||
```bash
|
||||
curl http://localhost:2222/api/v1/profile \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
|
||||
```
|
||||
|
||||
## 刷新 Token
|
||||
|
||||
Access Token 过期后,使用 Refresh Token 获取新的令牌对:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:2222/api/v1/auth/refresh \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
|
||||
}'
|
||||
```
|
||||
|
||||
## 安全特性
|
||||
|
||||
- **密码哈希**:使用 bcrypt 加密存储,永不明文
|
||||
- **双 Token**:Access Token 短期有效(2h),Refresh Token 长期有效(7d)
|
||||
- **Token 轮换**:每次刷新都生成全新的令牌对
|
||||
- **验证约束**:用户名 3-64 字符,密码 8-128 字符,邮箱格式校验
|
||||
53
guide/cicd.md
Normal file
53
guide/cicd.md
Normal file
@ -0,0 +1,53 @@
|
||||
# CI/CD 流水线
|
||||
|
||||
MengStack 使用 Gitea Actions 实现持续集成和部署。
|
||||
|
||||
## 流水线概览
|
||||
|
||||
```
|
||||
代码推送 → 代码检查 → 构建 → 测试 → Docker 镜像 → 部署
|
||||
```
|
||||
|
||||
## Gitea Actions 配置
|
||||
|
||||
仓库地址:`https://mengstackgit.softunis.com/mengstack`
|
||||
|
||||
### 流水线阶段
|
||||
|
||||
| 阶段 | 说明 |
|
||||
|------|------|
|
||||
| Lint | 代码风格检查 |
|
||||
| Build | 编译 Go 二进制 |
|
||||
| Test | 运行单元测试和集成测试 |
|
||||
| Docker | 构建 Docker 镜像 |
|
||||
| Deploy | 部署到目标服务器 |
|
||||
|
||||
## 本地验证
|
||||
|
||||
在推送代码前,本地运行检查:
|
||||
|
||||
```bash
|
||||
# 代码检查
|
||||
make lint
|
||||
|
||||
# 运行测试
|
||||
make test
|
||||
|
||||
# 构建
|
||||
make build
|
||||
```
|
||||
|
||||
## 部署策略
|
||||
|
||||
当前采用单服务器部署:
|
||||
|
||||
1. 代码推送到 Gitea 仓库
|
||||
2. CI 流水线自动触发
|
||||
3. 通过 SSH 部署到目标服务器
|
||||
4. Docker Compose 重启服务
|
||||
|
||||
## 后续规划
|
||||
|
||||
- **多环境支持**:dev / staging / production 环境隔离
|
||||
- **蓝绿部署**:零停机更新
|
||||
- **自动回滚**:部署失败自动回退
|
||||
102
guide/configuration.md
Normal file
102
guide/configuration.md
Normal file
@ -0,0 +1,102 @@
|
||||
# 配置管理
|
||||
|
||||
MengStack 使用 [Viper](https://github.com/spf13/viper) 进行配置管理,支持多来源、分层配置。
|
||||
|
||||
## 配置优先级
|
||||
|
||||
从高到低:
|
||||
|
||||
1. 环境变量(`MENGSTACK_` 前缀)
|
||||
2. `.env` 文件
|
||||
3. `configs/config.yaml`
|
||||
4. 默认值
|
||||
|
||||
## 配置文件
|
||||
|
||||
### `configs/config.yaml`
|
||||
|
||||
```yaml
|
||||
server:
|
||||
port: 2222
|
||||
mode: debug # debug / release / test
|
||||
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
name: mengstack
|
||||
user: postgres
|
||||
password: ""
|
||||
sslmode: disable
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: "change-me-in-production"
|
||||
access_ttl: 7200 # 2 hours
|
||||
refresh_ttl: 604800 # 7 days
|
||||
|
||||
log:
|
||||
level: debug # debug / info / warn / error
|
||||
format: console # console / json
|
||||
```
|
||||
|
||||
### 环境变量覆盖
|
||||
|
||||
所有配置项都可以通过环境变量覆盖,规则:
|
||||
|
||||
- 前缀 `MENGSTACK_`
|
||||
- 大写
|
||||
- 用 `_` 连接层级
|
||||
|
||||
```bash
|
||||
# 等价于 server.port: 3000
|
||||
export MENGSTACK_SERVER_PORT=3000
|
||||
|
||||
# 等价于 database.host: db.example.com
|
||||
export MENGSTACK_DB_HOST=db.example.com
|
||||
|
||||
# 等价于 jwt.secret: my-secret
|
||||
export MENGSTACK_JWT_SECRET=my-secret
|
||||
```
|
||||
|
||||
## 代码中使用
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Server ServerConfig
|
||||
Database DatabaseConfig
|
||||
Redis RedisConfig
|
||||
JWT JWTConfig
|
||||
Log LogConfig
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
v := viper.New()
|
||||
v.SetConfigFile("configs/config.yaml")
|
||||
v.SetEnvPrefix("MENGSTACK")
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **不要硬编码**:所有可变配置走 Viper
|
||||
2. **生产环境用环境变量**:敏感信息(密码、密钥)不写入代码仓库
|
||||
3. **提供合理默认值**:开发环境零配置即可启动
|
||||
4. **使用 `.env.example`**:提供配置模板,方便新人上手
|
||||
111
guide/dependency-injection.md
Normal file
111
guide/dependency-injection.md
Normal file
@ -0,0 +1,111 @@
|
||||
# 依赖注入
|
||||
|
||||
MengStack 使用 [uber-go/fx](https://github.com/uber-go/fx) 进行依赖注入,自动管理组件的生命周期和依赖关系。
|
||||
|
||||
## 为什么用依赖注入?
|
||||
|
||||
没有 DI 框架时,组装应用需要手动 wiring:
|
||||
|
||||
```go
|
||||
// 手动 wiring — 容易遗漏,难以维护
|
||||
db := database.New(cfg.DB)
|
||||
rdb := cache.New(cfg.Redis)
|
||||
repo := infrastructure.NewUserRepo(db)
|
||||
svc := application.NewService(repo, rdb, cfg.JWT)
|
||||
handler := interfaces.NewHandler(svc)
|
||||
```
|
||||
|
||||
使用 fx 后,依赖关系由框架自动解析:
|
||||
|
||||
```go
|
||||
// fx 自动解析依赖
|
||||
fx.Provide(
|
||||
database.New,
|
||||
cache.New,
|
||||
application.NewService,
|
||||
interfaces.NewHandler,
|
||||
)
|
||||
```
|
||||
|
||||
## fx.Module 组织
|
||||
|
||||
每个模块通过 `fx.Module` 声明自己的依赖:
|
||||
|
||||
```go
|
||||
// internal/modules/auth/interfaces/module.go
|
||||
var Module = fx.Module("auth",
|
||||
fx.Provide(
|
||||
infrastructure.NewUserRepository,
|
||||
infrastructure.NewTokenRepository,
|
||||
application.NewService,
|
||||
NewHandler,
|
||||
NewAuthMiddleware,
|
||||
SetupRoutes,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
主应用组装所有模块:
|
||||
|
||||
```go
|
||||
// internal/app/app.go
|
||||
func NewApp() *fx.App {
|
||||
return fx.New(
|
||||
fx.Provide(config.Load, logger.New),
|
||||
database.Module,
|
||||
cache.Module,
|
||||
authinterfaces.Module,
|
||||
Module,
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 生命周期管理
|
||||
|
||||
fx 自动管理组件的启动和停止顺序:
|
||||
|
||||
```go
|
||||
func newServer(lc fx.Lifecycle, engine *gin.Engine) *http.Server {
|
||||
srv := &http.Server{Addr: ":2222", Handler: engine}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(ctx context.Context) error {
|
||||
go srv.ListenAndServe()
|
||||
return nil
|
||||
},
|
||||
OnStop: func(ctx context.Context) error {
|
||||
return srv.Shutdown(ctx)
|
||||
},
|
||||
})
|
||||
|
||||
return srv
|
||||
}
|
||||
```
|
||||
|
||||
fx 会确保:
|
||||
- **OnStart** 按依赖顺序执行(先数据库,后应用)
|
||||
- **OnStop** 按逆序执行(先应用,后数据库)
|
||||
|
||||
## 参数注入
|
||||
|
||||
通过函数参数声明依赖,fx 自动注入:
|
||||
|
||||
```go
|
||||
func newEngine(
|
||||
cfg *config.Config, // fx 自动提供
|
||||
log *zap.Logger, // fx 自动提供
|
||||
db *gorm.DB, // fx 自动提供
|
||||
rdb *redis.Client, // fx 自动提供
|
||||
authHandler *Handler, // fx 自动提供
|
||||
authMW gin.HandlerFunc, // fx 自动提供
|
||||
) *gin.Engine {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **构造函数注入**:通过 `fx.Provide` 注册构造函数
|
||||
2. **接口传递**:尽量传递接口而非具体实现
|
||||
3. **模块隔离**:每个业务模块声明自己的 `fx.Module`
|
||||
4. **避免全局状态**:所有依赖通过注入获取
|
||||
72
guide/docker-deploy.md
Normal file
72
guide/docker-deploy.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Docker 部署
|
||||
|
||||
MengStack 提供开箱即用的 Docker Compose 配置,一键启动完整开发/生产环境。
|
||||
|
||||
## 快速启动
|
||||
|
||||
```bash
|
||||
# 启动所有服务(后台运行)
|
||||
docker-compose up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f app
|
||||
```
|
||||
|
||||
## 服务组成
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app: # MengStack 应用(端口 2222)
|
||||
postgres: # PostgreSQL 数据库(端口 5432)
|
||||
redis: # Redis 缓存(端口 6379)
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 启动
|
||||
docker-compose up -d
|
||||
|
||||
# 停止
|
||||
docker-compose down
|
||||
|
||||
# 重新构建并启动
|
||||
docker-compose up -d --build
|
||||
|
||||
# 查看应用日志
|
||||
docker-compose logs -f app
|
||||
|
||||
# 进入应用容器
|
||||
docker-compose exec app sh
|
||||
|
||||
# 进入数据库
|
||||
docker-compose exec postgres psql -U postgres -d mengstack
|
||||
```
|
||||
|
||||
## 数据持久化
|
||||
|
||||
PostgreSQL 和 Redis 数据通过 Docker Volume 持久化:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
清除数据重新开始:
|
||||
|
||||
```bash
|
||||
docker-compose down -v
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 生产部署建议
|
||||
|
||||
1. **修改默认密码**:`docker-compose.yml` 中的数据库密码
|
||||
2. **设置 release 模式**:`MENGSTACK_SERVER_MODE=release`
|
||||
3. **配置 HTTPS**:在反向代理(Nginx/Caddy)层处理
|
||||
4. **限制端口暴露**:数据库和 Redis 不对外暴露
|
||||
5. **定期备份**:PostgreSQL 数据定时备份
|
||||
111
guide/getting-started.md
Normal file
111
guide/getting-started.md
Normal file
@ -0,0 +1,111 @@
|
||||
---
|
||||
title: 快速开始 | 5分钟搭建MengStack项目环境 - MengStack官方文档
|
||||
---
|
||||
|
||||
# 快速开始
|
||||
|
||||
## 环境要求
|
||||
|
||||
- Go 1.23+
|
||||
- PostgreSQL 14+
|
||||
- Redis 7+
|
||||
- Docker & Docker Compose(可选)
|
||||
|
||||
## 使用 Docker Compose 启动(推荐)
|
||||
|
||||
最简单的方式是使用 Docker Compose 一键启动所有服务:
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://gitea.softunis.com/mengstack/mengstack.git
|
||||
cd mengstack
|
||||
|
||||
# 启动所有服务
|
||||
docker-compose up -d
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f app
|
||||
```
|
||||
|
||||
服务启动后:
|
||||
|
||||
- API 服务:`http://localhost:2222`
|
||||
- Swagger UI:`http://localhost:2222/swagger/index.html`
|
||||
- 健康检查:`http://localhost:2222/health`
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 1. 安装依赖
|
||||
|
||||
```bash
|
||||
# 下载 Go 模块
|
||||
go mod download
|
||||
|
||||
# 确保 PostgreSQL 和 Redis 已启动
|
||||
```
|
||||
|
||||
### 2. 配置环境变量
|
||||
|
||||
复制 `.env.example` 为 `.env` 并修改:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
关键配置项:
|
||||
|
||||
```env
|
||||
MENGSTACK_SERVER_PORT=2222
|
||||
|
||||
# PostgreSQL
|
||||
MENGSTACK_DB_HOST=localhost
|
||||
MENGSTACK_DB_PORT=5432
|
||||
MENGSTACK_DB_NAME=mengstack
|
||||
MENGSTACK_DB_USER=postgres
|
||||
MENGSTACK_DB_PASSWORD=your_password
|
||||
|
||||
# Redis
|
||||
MENGSTACK_REDIS_HOST=localhost
|
||||
MENGSTACK_REDIS_PORT=6379
|
||||
|
||||
# JWT
|
||||
MENGSTACK_JWT_SECRET=your_jwt_secret_key
|
||||
```
|
||||
|
||||
### 3. 启动服务
|
||||
|
||||
```bash
|
||||
# 直接运行
|
||||
go run cmd/server/main.go
|
||||
|
||||
# 或使用 Makefile
|
||||
make run
|
||||
```
|
||||
|
||||
### 4. 验证
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl http://localhost:2222/health
|
||||
|
||||
# 注册新用户
|
||||
curl -X POST http://localhost:2222/api/v1/auth/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "admin@example.com",
|
||||
"username": "admin",
|
||||
"password": "password123"
|
||||
}'
|
||||
```
|
||||
|
||||
## 项目命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `make run` | 启动开发服务 |
|
||||
| `make build` | 编译二进制文件 |
|
||||
| `make test` | 运行测试 |
|
||||
| `make swagger` | 重新生成 API 文档 |
|
||||
| `make lint` | 代码检查 |
|
||||
| `make docker-up` | Docker 启动所有服务 |
|
||||
| `make docker-down` | Docker 停止所有服务 |
|
||||
112
guide/module-pattern.md
Normal file
112
guide/module-pattern.md
Normal file
@ -0,0 +1,112 @@
|
||||
# 模块四层模式
|
||||
|
||||
每个业务模块内部采用四层结构:**Domain → Application → Infrastructure → Interfaces**。
|
||||
|
||||
## 四层结构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Interfaces │ ← HTTP Handler, 路由注册
|
||||
├─────────────────────────────────────┤
|
||||
│ Application │ ← 业务逻辑编排
|
||||
├─────────────────────────────────────┤
|
||||
│ Infrastructure │ ← GORM Model, Redis 实现
|
||||
├─────────────────────────────────────┤
|
||||
│ Domain │ ← 实体, 值对象, 接口定义
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 依赖方向
|
||||
|
||||
**从上到下依赖,Domain 在最底层,不依赖任何外部包。**
|
||||
|
||||
| 层 | 职责 | 可以依赖 | 禁止依赖 |
|
||||
|---|---|---|---|
|
||||
| Interfaces | HTTP 入口 | Application, Domain | Infrastructure |
|
||||
| Application | 业务编排 | Domain | Infrastructure, Interfaces |
|
||||
| Infrastructure | 数据持久化 | Domain | Application, Interfaces |
|
||||
| Domain | 业务核心 | 标准库 | 所有外部包 |
|
||||
|
||||
## Domain 层
|
||||
|
||||
定义业务的核心概念和契约:
|
||||
|
||||
```go
|
||||
// domain/entity.go
|
||||
type User struct {
|
||||
ID uint
|
||||
Email string
|
||||
Username string
|
||||
Password string
|
||||
TenantID string
|
||||
}
|
||||
|
||||
// domain/repository.go — 定义接口,不定义实现
|
||||
type UserRepository interface {
|
||||
Create(ctx context.Context, user *User) error
|
||||
FindByEmail(ctx context.Context, email string) (*User, error)
|
||||
}
|
||||
```
|
||||
|
||||
Domain 层**零外部依赖**,只使用 Go 标准库。这使得业务逻辑可以独立于框架和数据库进行单元测试。
|
||||
|
||||
## Application 层
|
||||
|
||||
编排业务流程,调用 Domain 层定义的接口:
|
||||
|
||||
```go
|
||||
// application/service.go
|
||||
type Service struct {
|
||||
repo domain.UserRepository
|
||||
hasher domain.PasswordHasher
|
||||
jwt domain.TokenManager
|
||||
}
|
||||
|
||||
func (s *Service) Register(ctx context.Context, req domain.RegisterRequest) (*domain.TokenPair, error) {
|
||||
// 1. 验证邮箱唯一性
|
||||
// 2. 密码哈希
|
||||
// 3. 创建用户
|
||||
// 4. 生成 JWT
|
||||
// 5. 返回 Token
|
||||
}
|
||||
```
|
||||
|
||||
Application 层不知道数据是怎么存的(GORM?Redis?),它只依赖 Domain 层定义的接口。
|
||||
|
||||
## Infrastructure 层
|
||||
|
||||
提供 Domain 层接口的具体实现:
|
||||
|
||||
```go
|
||||
// infrastructure/repository.go
|
||||
type GormUserRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (r *GormUserRepository) Create(ctx context.Context, user *domain.User) error {
|
||||
// GORM 实现
|
||||
}
|
||||
```
|
||||
|
||||
Infrastructure 层实现 Domain 层定义的接口,但 Domain 层不知道 Infrastructure 的存在。
|
||||
|
||||
## Interfaces 层
|
||||
|
||||
HTTP 入口,负责请求解析和响应:
|
||||
|
||||
```go
|
||||
// interfaces/handler.go
|
||||
func (h *Handler) Register(c *gin.Context) {
|
||||
var req domain.RegisterRequest
|
||||
c.ShouldBindJSON(&req)
|
||||
tokens, err := h.svc.Register(c.Request.Context(), req)
|
||||
response.Success(c, tokens)
|
||||
}
|
||||
```
|
||||
|
||||
## 好处
|
||||
|
||||
1. **可测试**:Domain 层可以脱离数据库进行单元测试
|
||||
2. **可替换**:换数据库只需写新的 Infrastructure 实现
|
||||
3. **边界清晰**:每层职责明确,新人容易理解
|
||||
4. **防止腐败**:Gin 的 `c *gin.Context` 不会渗透到业务逻辑中
|
||||
58
guide/multi-tenancy.md
Normal file
58
guide/multi-tenancy.md
Normal file
@ -0,0 +1,58 @@
|
||||
# 多租户系统
|
||||
|
||||
MengStack 内置多租户支持,通过 `X-Tenant-ID` 请求头实现租户隔离。
|
||||
|
||||
## 工作原理
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐
|
||||
│ Tenant A │──X-Tenant-ID: A──→│ │──WHERE tenant_id='A'──→ DB
|
||||
├─────────┤ │ MengStack │
|
||||
│ Tenant B │──X-Tenant-ID: B──→│ Server │──WHERE tenant_id='B'──→ DB
|
||||
├─────────┤ │ │
|
||||
│ Tenant C │──X-Tenant-ID: C──→│ │──WHERE tenant_id='C'──→ DB
|
||||
└─────────┘ └─────────┘
|
||||
```
|
||||
|
||||
每个请求必须携带 `X-Tenant-ID` 头,中间件自动提取并注入到上下文中。
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 请求示例
|
||||
|
||||
```bash
|
||||
curl http://localhost:2222/api/v1/profile \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "X-Tenant-ID: tenant-001"
|
||||
```
|
||||
|
||||
### 中间件处理
|
||||
|
||||
认证中间件自动验证:
|
||||
|
||||
1. 解析 JWT Token 获取用户信息
|
||||
2. 验证 `X-Tenant-ID` 头是否存在
|
||||
3. 将 `user_id` 和 `tenant_id` 注入到 Gin Context
|
||||
4. 下游 Handler 可直接使用 `c.GetUint("user_id")` 和 `c.GetString("tenant_id")`
|
||||
|
||||
### 数据层隔离
|
||||
|
||||
Repository 层自动添加租户过滤:
|
||||
|
||||
```go
|
||||
func (r *GormUserRepository) FindByTenant(ctx context.Context, tenantID string) ([]*domain.User, error) {
|
||||
var users []*domain.User
|
||||
err := r.db.Where("tenant_id = ?", tenantID).Find(&users).Error
|
||||
return users, err
|
||||
}
|
||||
```
|
||||
|
||||
## 租户注册
|
||||
|
||||
租户管理是独立模块(M4 里程碑),当前版本通过手动在数据库创建租户记录。
|
||||
|
||||
## 安全考虑
|
||||
|
||||
- 中间件强制校验 `X-Tenant-ID`,缺失则返回 401
|
||||
- 数据查询自动过滤,防止跨租户数据泄露
|
||||
- JWT Token 中包含租户信息,服务端二次验证
|
||||
75
guide/project-structure.md
Normal file
75
guide/project-structure.md
Normal file
@ -0,0 +1,75 @@
|
||||
---
|
||||
title: 项目结构说明 | MengStack目录规范详解 - MengStack官方文档
|
||||
---
|
||||
|
||||
# 项目结构
|
||||
|
||||
```
|
||||
mengstack/
|
||||
├── cmd/
|
||||
│ └── server/
|
||||
│ └── main.go # 应用入口,Swagger 注解
|
||||
├── configs/
|
||||
│ └── config.yaml # 默认配置文件
|
||||
├── docs/ # Swagger 自动生成文档
|
||||
│ ├── docs.go
|
||||
│ ├── swagger.json
|
||||
│ └── swagger.yaml
|
||||
├── internal/
|
||||
│ ├── kernel/ # 第一层:零业务语义基础组件
|
||||
│ │ └── response/ # 统一响应格式
|
||||
│ ├── app/ # 第二层:应用基础设施
|
||||
│ │ ├── cache/ # Redis 缓存模块
|
||||
│ │ ├── database/ # PostgreSQL 数据库模块
|
||||
│ │ ├── health/ # 健康检查
|
||||
│ │ ├── middleware/ # 全局中间件(CORS、请求ID、日志)
|
||||
│ │ └── app.go # fx 容器组装
|
||||
│ ├── config/ # 配置加载(Viper)
|
||||
│ ├── logger/ # 日志初始化(Zap)
|
||||
│ └── modules/ # 第三层:业务模块
|
||||
│ └── auth/ # 认证模块
|
||||
│ ├── domain/ # 领域层:实体、值对象、接口定义
|
||||
│ ├── application/ # 应用层:业务逻辑编排
|
||||
│ ├── infrastructure/ # 基础设施层:GORM/Redis 实现
|
||||
│ └── interfaces/ # 接口层:HTTP Handler + 路由
|
||||
├── migrations/ # 数据库迁移文件
|
||||
├── test/ # 集成测试
|
||||
├── docker-compose.yml # Docker 编排
|
||||
├── Makefile # 构建命令
|
||||
├── AGENTS.md # AI 辅助开发指南
|
||||
└── go.mod # Go 模块定义
|
||||
```
|
||||
|
||||
## 目录职责
|
||||
|
||||
### `cmd/server/`
|
||||
|
||||
应用入口,仅负责组装和启动。包含 Swagger 全局注解。
|
||||
|
||||
### `internal/kernel/`
|
||||
|
||||
**零业务语义**的基础组件。不包含任何业务概念,只提供通用工具:
|
||||
|
||||
- `response/` — 统一响应格式 `{code, message, data, trace_id}`
|
||||
- 后续可扩展:`paginator/`、`errors/` 等
|
||||
|
||||
### `internal/app/`
|
||||
|
||||
应用基础设施,连接 kernel 和外部世界:
|
||||
|
||||
- `database/` — GORM + PostgreSQL 初始化和生命周期
|
||||
- `cache/` — Redis 客户端初始化和生命周期
|
||||
- `middleware/` — 请求 ID、请求日志、CORS
|
||||
- `health/` — 健康检查端点
|
||||
|
||||
### `internal/modules/`
|
||||
|
||||
业务模块目录,每个模块独立自包含,遵循四层模式。
|
||||
|
||||
### `configs/`
|
||||
|
||||
默认配置文件,运行时可通过环境变量覆盖。
|
||||
|
||||
### `migrations/`
|
||||
|
||||
数据库迁移文件,使用 golang-migrate 管理。
|
||||
68
guide/what-is-mengstack.md
Normal file
68
guide/what-is-mengstack.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
title: 什么是MengStack | 架构设计与核心特性介绍 - MengStack官方文档
|
||||
---
|
||||
|
||||
# 什么是 MengStack
|
||||
|
||||
MengStack 是一个基于 Go 语言的企业级微服务开发框架,采用模块化架构设计,提供多租户、认证授权、配置管理等开箱即用的基础能力。作为面向云原生与 AI 时代的一站式全栈开发底座,MengStack 整合主流开源技术能力,帮助开发者快速搭建企业级后端服务。
|
||||
|
||||
## 设计理念
|
||||
|
||||
### 为什么选择 Go?
|
||||
|
||||
Go 语言以其简洁的语法、高效的并发模型和快速的编译速度,成为构建现代后端服务的理想选择。MengStack 充分利用 Go 的生态和特性:
|
||||
|
||||
- **高性能**:Go 的 goroutine 和 channel 提供轻量级并发
|
||||
- **强类型**:编译期发现错误,减少运行时意外
|
||||
- **标准库丰富**:net/http、encoding/json 等开箱即用
|
||||
- **生态成熟**:Gin、GORM、Zap 等优秀第三方库
|
||||
|
||||
### 为什么模块化?
|
||||
|
||||
传统的分层架构(Controller → Service → Repository)在项目规模增长后容易出现:
|
||||
|
||||
- 模块间边界模糊,耦合严重
|
||||
- 删除一个功能需要改动多个层
|
||||
- 难以独立测试和替换
|
||||
|
||||
MengStack 的[三层隔离架构](/guide/architecture)让每个业务模块都是自包含的,模块间通过明确的接口通信。每个模块遵循[四层模式](/guide/module-pattern)(Domain / Application / Infrastructure / Interfaces),确保依赖方向单一。
|
||||
|
||||
## 核心特性
|
||||
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
| 三层隔离 | Kernel / App / Modules 层间依赖方向单一,详见[架构设计](/guide/architecture) |
|
||||
| 四层模块 | Domain / Application / Infrastructure / Interfaces,详见[模块模式](/guide/module-pattern) |
|
||||
| 多租户 | 基于 Header 的租户隔离,数据自动过滤,详见[多租户系统](/guide/multi-tenancy) |
|
||||
| JWT 认证 | Access Token + Refresh Token 双令牌机制,详见[认证与授权](/guide/auth) |
|
||||
| 依赖注入 | uber-go/fx 自动管理组件生命周期,详见[依赖注入](/guide/dependency-injection) |
|
||||
| API 文档 | swaggo 注解驱动,自动生成 Swagger UI |
|
||||
| 配置管理 | Viper 分层配置,支持环境变量覆盖,详见[配置管理](/guide/configuration) |
|
||||
| 结构化日志 | Zap 结构化输出,请求级 trace_id |
|
||||
| Docker 部署 | 开箱即用的 docker-compose,详见[Docker 部署](/guide/docker-deploy) |
|
||||
|
||||
## 适用场景
|
||||
|
||||
- **SaaS 平台**:[多租户隔离](/guide/multi-tenancy)开箱即用
|
||||
- **中后台系统**:[认证](/guide/auth)、权限、审计日志完备
|
||||
- **微服务集群**:模块化设计便于拆分和独立部署
|
||||
- **开源项目**:清晰的架构便于社区贡献
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 组件 | 选型 | 用途 |
|
||||
|------|------|------|
|
||||
| Web 框架 | Gin | HTTP 路由和中间件 |
|
||||
| ORM | GORM | 数据库操作 |
|
||||
| 数据库 | PostgreSQL | 主数据存储 |
|
||||
| 缓存 | Redis | 缓存和会话管理 |
|
||||
| 认证 | golang-jwt | JWT 令牌生成和验证 |
|
||||
| DI | uber-go/fx | 依赖注入 |
|
||||
| 配置 | Viper | 配置加载和管理 |
|
||||
| 日志 | Zap | 结构化日志 |
|
||||
| API 文档 | swaggo | Swagger 文档生成 |
|
||||
| 容器化 | Docker Compose | 开发和部署环境 |
|
||||
|
||||
## 快速开始
|
||||
|
||||
准备好开始使用 MengStack?查看[快速开始指南](/guide/getting-started),5 分钟即可跑通第一个项目。也可以访问[在线演示](/demo)直接体验 API 接口能力。
|
||||
52
index.md
Normal file
52
index.md
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
title: MengStack - 企业级Go语言微服务开发框架 | 开源模块化开发底座
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: MengStack
|
||||
text: 企业级 Go 语言微服务开发框架
|
||||
tagline: 面向云原生与 AI 时代的一站式全栈开发底座
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 快速开始
|
||||
link: /guide/getting-started
|
||||
- theme: alt
|
||||
text: 在线演示
|
||||
link: /demo
|
||||
- theme: alt
|
||||
text: GitHub
|
||||
link: https://gitea.softunis.com/mengstack
|
||||
|
||||
features:
|
||||
- icon: 🧩
|
||||
title: 全栈组件化集成
|
||||
details: 内置前端模板、API 网关、分布式缓存、消息队列、定时任务等模块,生产验证,开箱即用
|
||||
link: /guide/what-is-mengstack
|
||||
- icon: ⚡
|
||||
title: 零侵入依赖注入
|
||||
details: 兼容 Wire 编译时注入与 uber-go/fx 运行时管理,按需切换,兼顾性能与便捷
|
||||
link: /guide/dependency-injection
|
||||
- icon: 🤖
|
||||
title: AI 原生开发支持
|
||||
details: 内置大模型调用、Agent 内存管理、向量数据库集成,快速落地智能业务场景
|
||||
- icon: 🇳
|
||||
title: 全链路国产化适配
|
||||
details: 兼容国产操作系统、数据库、中间件,满足政企金融等保合规要求
|
||||
- icon: 📚
|
||||
title: 极低学习门槛
|
||||
details: 统一代码规范与完善中文文档,新成员接入周期缩短 70% 以上
|
||||
link: /guide/getting-started
|
||||
- icon: 📊
|
||||
title: 生产级可观测
|
||||
details: 内置链路追踪、指标监控、日志聚合,无需额外搭建监控体系
|
||||
- icon: 🔓
|
||||
title: 完全开源开放
|
||||
details: 核心代码 MIT 协议开源,无商业限制,社区持续迭代,可自由定制扩展
|
||||
link: /community
|
||||
---
|
||||
|
||||
## 关于 MengStack
|
||||
|
||||
MengStack 是面向云原生与 AI 时代的一站式全栈开发底座,整合主流开源技术能力,为开发者提供开箱即用的组件化开发体验,大幅降低中大型项目的架构搭建成本,让团队专注于核心业务逻辑落地,无需重复造轮子。
|
||||
|
||||
我们坚持全栈开源、无厂商锁定的设计理念,覆盖从前端交互、后端服务、数据治理到 AI 能力集成的全链路开发场景,适配国产化软硬件生态,为企业级项目提供稳定、高效、可扩展的技术支撑。
|
||||
2565
package-lock.json
generated
Normal file
2565
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "mengstack-website",
|
||||
"version": "0.1.0",
|
||||
"description": "MengStack 官方网站",
|
||||
"scripts": {
|
||||
"dev": "vitepress dev",
|
||||
"build": "vitepress build",
|
||||
"preview": "vitepress preview"
|
||||
},
|
||||
"keywords": ["mengstack", "golang", "framework"],
|
||||
"author": "SoftUnis",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.4",
|
||||
"vue": "^3.5.43"
|
||||
}
|
||||
}
|
||||
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
BIN
public/logo-dark.png
Normal file
BIN
public/logo-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 181 KiB |
BIN
public/logo-hero.png
Normal file
BIN
public/logo-hero.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
BIN
public/logo-light.png
Normal file
BIN
public/logo-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
public/og-image.png
Normal file
BIN
public/og-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Disallow: /404.html
|
||||
Sitemap: https://mengstack.softunis.com/sitemap.xml
|
||||
111
public/sitemap.xml
Normal file
111
public/sitemap.xml
Normal file
@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/what-is-mengstack.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/getting-started.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/project-structure.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/architecture.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/module-pattern.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/dependency-injection.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/auth.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/multi-tenancy.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/configuration.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/docker-deploy.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/guide/cicd.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/api/overview.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/api/auth.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/api/system.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/changelog.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/demo.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mengstack.softunis.com/community.html</loc>
|
||||
<lastmod>2026-10-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
Loading…
Reference in New Issue
Block a user