create-dwy 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +31 -0
- package/package.json +29 -0
- package/src/create.js +93 -0
- package/src/sync.js +75 -0
- package/src/utils.js +61 -0
- package/templates/claude-global/commands/.gitkeep +0 -0
- package/templates/claude-global/hooks/.gitkeep +0 -0
- package/templates/claude-global/rules/git-security.md +144 -0
- package/templates/claude-global/rules/python-code-style.md +875 -0
- package/templates/claude-global/rules/server-security.md +376 -0
- package/templates/claude-global/skills/.gitkeep +0 -0
- package/templates/project/web/.claude/commands/deploy.md +4 -0
- package/templates/project/web/.dwy.hbs +5 -0
- package/templates/project/web/CLAUDE.md.hbs +52 -0
- package/templates/project/web/backend/.python-version +1 -0
- package/templates/project/web/backend/Dockerfile +17 -0
- package/templates/project/web/backend/alembic/env.py.hbs +44 -0
- package/templates/project/web/backend/alembic/script.py.mako +24 -0
- package/templates/project/web/backend/alembic/versions/.gitkeep +0 -0
- package/templates/project/web/backend/alembic.ini.hbs +36 -0
- package/templates/project/web/backend/pyproject.toml.hbs +52 -0
- package/templates/project/web/backend/src/app/__init__.py +0 -0
- package/templates/project/web/backend/src/app/config.py.hbs +12 -0
- package/templates/project/web/backend/src/app/main.py.hbs +40 -0
- package/templates/project/web/backend/src/app/models/__init__.py +0 -0
- package/templates/project/web/backend/src/app/models/base.py +5 -0
- package/templates/project/web/backend/src/app/routers/__init__.py +0 -0
- package/templates/project/web/backend/src/app/routers/health.py +11 -0
- package/templates/project/web/backend/src/app/schemas/__init__.py +0 -0
- package/templates/project/web/backend/src/app/services/__init__.py +0 -0
- package/templates/project/web/backend/tests/__init__.py +0 -0
- package/templates/project/web/backend/tests/conftest.py.hbs +16 -0
- package/templates/project/web/deploy.sh.hbs +113 -0
- package/templates/project/web/docker-compose.dev.yml.hbs +19 -0
- package/templates/project/web/docker-compose.prod.yml.hbs +31 -0
- package/templates/project/web/frontend/index.html.hbs +12 -0
- package/templates/project/web/frontend/package.json.hbs +28 -0
- package/templates/project/web/frontend/src/App.vue +3 -0
- package/templates/project/web/frontend/src/api/client.ts +13 -0
- package/templates/project/web/frontend/src/components/.gitkeep +0 -0
- package/templates/project/web/frontend/src/main.ts +10 -0
- package/templates/project/web/frontend/src/router/index.ts +14 -0
- package/templates/project/web/frontend/src/stores/auth.ts +20 -0
- package/templates/project/web/frontend/src/style.css +1 -0
- package/templates/project/web/frontend/src/views/HomeView.vue +5 -0
- package/templates/project/web/frontend/tsconfig.app.json +14 -0
- package/templates/project/web/frontend/tsconfig.json +4 -0
- package/templates/project/web/frontend/vite.config.ts.hbs +16 -0
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Test fixtures."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from httpx import ASGITransport, AsyncClient
|
|
5
|
+
|
|
6
|
+
from app.main import app
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
async def client():
|
|
11
|
+
"""Async HTTP client for testing."""
|
|
12
|
+
async with AsyncClient(
|
|
13
|
+
transport=ASGITransport(app=app),
|
|
14
|
+
base_url="http://test",
|
|
15
|
+
) as ac:
|
|
16
|
+
yield ac
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
PROJECT_NAME="{{projectName}}"
|
|
5
|
+
SSH_ALIAS="{{sshAlias}}"
|
|
6
|
+
REMOTE_DIR="/opt/{{projectName}}"
|
|
7
|
+
BACKEND_PORT={{backendPort}}
|
|
8
|
+
HEALTH_CHECK_PATH="/api/health"
|
|
9
|
+
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
NC='\033[0m'
|
|
14
|
+
|
|
15
|
+
log() { echo -e "${GREEN}[DEPLOY]${NC} $1"; }
|
|
16
|
+
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
17
|
+
err() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
|
18
|
+
|
|
19
|
+
push_code() {
|
|
20
|
+
log "推送代码到 Gitee..."
|
|
21
|
+
git push origin master || err "git push 失败"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pull_remote() {
|
|
25
|
+
log "远程拉取代码..."
|
|
26
|
+
ssh $SSH_ALIAS "cd $REMOTE_DIR && git pull origin master" || err "远程 git pull 失败"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
build_frontend() {
|
|
30
|
+
log "构建前端..."
|
|
31
|
+
cd frontend && pnpm build || err "前端构建失败"
|
|
32
|
+
cd ..
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
upload_frontend() {
|
|
36
|
+
log "上传前端构建产物..."
|
|
37
|
+
tar czf /tmp/frontend-dist.tar.gz -C frontend dist/
|
|
38
|
+
scp /tmp/frontend-dist.tar.gz $SSH_ALIAS:$REMOTE_DIR/ || err "上传失败"
|
|
39
|
+
ssh $SSH_ALIAS "cd $REMOTE_DIR && mkdir -p frontend && tar xzf frontend-dist.tar.gz -C frontend/ && rm frontend-dist.tar.gz"
|
|
40
|
+
rm /tmp/frontend-dist.tar.gz
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
run_migrations() {
|
|
44
|
+
log "执行数据库迁移..."
|
|
45
|
+
ssh $SSH_ALIAS "cd $REMOTE_DIR && docker compose -f docker-compose.prod.yml run --rm backend alembic upgrade head" || err "迁移失败"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
restart_backend() {
|
|
49
|
+
log "重建后端容器..."
|
|
50
|
+
ssh $SSH_ALIAS "cd $REMOTE_DIR && docker compose -f docker-compose.prod.yml up -d --build backend"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
verify() {
|
|
54
|
+
log "验证部署..."
|
|
55
|
+
sleep 3
|
|
56
|
+
|
|
57
|
+
HEALTH=$(ssh $SSH_ALIAS "curl -s http://localhost${HEALTH_CHECK_PATH}" 2>/dev/null)
|
|
58
|
+
if echo "$HEALTH" | grep -q '"ok"'; then
|
|
59
|
+
log "API 健康检查: ✅"
|
|
60
|
+
else
|
|
61
|
+
err "API 健康检查失败: $HEALTH"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
GIT_CODE=$(ssh $SSH_ALIAS "curl -s -o /dev/null -w '%{http_code}' http://localhost/.git/config" 2>/dev/null)
|
|
65
|
+
ENV_CODE=$(ssh $SSH_ALIAS "curl -s -o /dev/null -w '%{http_code}' http://localhost/.env" 2>/dev/null)
|
|
66
|
+
if [ "$GIT_CODE" = "404" ] && [ "$ENV_CODE" = "404" ]; then
|
|
67
|
+
log "安全检查: ✅ (.git/.env 已屏蔽)"
|
|
68
|
+
else
|
|
69
|
+
warn "安全检查: .git=$GIT_CODE .env=$ENV_CODE"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
log "部署完成!"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
case "${1:-all}" in
|
|
76
|
+
--backend)
|
|
77
|
+
log "=== 仅部署后端 ==="
|
|
78
|
+
push_code
|
|
79
|
+
pull_remote
|
|
80
|
+
run_migrations
|
|
81
|
+
restart_backend
|
|
82
|
+
verify
|
|
83
|
+
;;
|
|
84
|
+
--frontend)
|
|
85
|
+
log "=== 仅部署前端 ==="
|
|
86
|
+
build_frontend
|
|
87
|
+
upload_frontend
|
|
88
|
+
verify
|
|
89
|
+
;;
|
|
90
|
+
--restart)
|
|
91
|
+
log "=== 仅重启容器 ==="
|
|
92
|
+
ssh $SSH_ALIAS "cd $REMOTE_DIR && docker compose -f docker-compose.prod.yml up -d --force-recreate"
|
|
93
|
+
verify
|
|
94
|
+
;;
|
|
95
|
+
--check)
|
|
96
|
+
log "=== 安全检查 ==="
|
|
97
|
+
verify
|
|
98
|
+
;;
|
|
99
|
+
all|"")
|
|
100
|
+
log "=== 全量部署 ==="
|
|
101
|
+
push_code
|
|
102
|
+
pull_remote
|
|
103
|
+
build_frontend
|
|
104
|
+
upload_frontend
|
|
105
|
+
run_migrations
|
|
106
|
+
restart_backend
|
|
107
|
+
verify
|
|
108
|
+
;;
|
|
109
|
+
*)
|
|
110
|
+
echo "用法: ./deploy.sh [--backend|--frontend|--restart|--check]"
|
|
111
|
+
exit 1
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
services:
|
|
2
|
+
db:
|
|
3
|
+
image: postgres:16-alpine
|
|
4
|
+
ports:
|
|
5
|
+
- "127.0.0.1:{{devDbPort}}:5432"
|
|
6
|
+
environment:
|
|
7
|
+
POSTGRES_USER: dev
|
|
8
|
+
POSTGRES_PASSWORD: dev123
|
|
9
|
+
POSTGRES_DB: {{dbName}}
|
|
10
|
+
volumes:
|
|
11
|
+
- pgdata:/var/lib/postgresql/data
|
|
12
|
+
|
|
13
|
+
redis:
|
|
14
|
+
image: redis:7-alpine
|
|
15
|
+
ports:
|
|
16
|
+
- "127.0.0.1:{{devRedisPort}}:6379"
|
|
17
|
+
|
|
18
|
+
volumes:
|
|
19
|
+
pgdata:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
services:
|
|
2
|
+
backend:
|
|
3
|
+
build: ./backend
|
|
4
|
+
ports:
|
|
5
|
+
- "127.0.0.1:{{backendPort}}:8000"
|
|
6
|
+
env_file: .env
|
|
7
|
+
depends_on:
|
|
8
|
+
db:
|
|
9
|
+
condition: service_healthy
|
|
10
|
+
restart: unless-stopped
|
|
11
|
+
|
|
12
|
+
db:
|
|
13
|
+
image: postgres:16-alpine
|
|
14
|
+
environment:
|
|
15
|
+
POSTGRES_USER: $POSTGRES_USER
|
|
16
|
+
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
|
|
17
|
+
POSTGRES_DB: $POSTGRES_DB
|
|
18
|
+
volumes:
|
|
19
|
+
- pgdata:/var/lib/postgresql/data
|
|
20
|
+
healthcheck:
|
|
21
|
+
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
|
|
22
|
+
interval: 5s
|
|
23
|
+
retries: 5
|
|
24
|
+
restart: unless-stopped
|
|
25
|
+
|
|
26
|
+
redis:
|
|
27
|
+
image: redis:7-alpine
|
|
28
|
+
restart: unless-stopped
|
|
29
|
+
|
|
30
|
+
volumes:
|
|
31
|
+
pgdata:
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}-frontend",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vue-tsc -b && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@danweiyuan/core": "^0.1.0",
|
|
13
|
+
"@danweiyuan/eui": "^0.2.0",
|
|
14
|
+
"axios": "^1.13.0",
|
|
15
|
+
"lucide-vue-next": "^0.500.0",
|
|
16
|
+
"pinia": "^3.0.0",
|
|
17
|
+
"vue": "^3.5.0",
|
|
18
|
+
"vue-router": "^4.6.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@tailwindcss/vite": "^4.2.0",
|
|
22
|
+
"@vitejs/plugin-vue": "^6.0.0",
|
|
23
|
+
"tailwindcss": "^4.2.0",
|
|
24
|
+
"typescript": "^5.9.0",
|
|
25
|
+
"vite": "^8.0.0",
|
|
26
|
+
"vue-tsc": "^2.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
const client = axios.create({ baseURL: '/api' })
|
|
4
|
+
|
|
5
|
+
client.interceptors.request.use((config) => {
|
|
6
|
+
const token = localStorage.getItem('token')
|
|
7
|
+
if (token) {
|
|
8
|
+
config.headers.Authorization = `Bearer ${token}`
|
|
9
|
+
}
|
|
10
|
+
return config
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export default client
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
+
|
|
3
|
+
const router = createRouter({
|
|
4
|
+
history: createWebHistory(),
|
|
5
|
+
routes: [
|
|
6
|
+
{
|
|
7
|
+
path: '/',
|
|
8
|
+
name: 'home',
|
|
9
|
+
component: () => import('../views/HomeView.vue'),
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export default router
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
export const useAuthStore = defineStore('auth', () => {
|
|
5
|
+
const token = ref<string | null>(localStorage.getItem('token'))
|
|
6
|
+
const user = ref<Record<string, unknown> | null>(null)
|
|
7
|
+
|
|
8
|
+
function setToken(t: string) {
|
|
9
|
+
token.value = t
|
|
10
|
+
localStorage.setItem('token', t)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function logout() {
|
|
14
|
+
token.value = null
|
|
15
|
+
user.value = null
|
|
16
|
+
localStorage.removeItem('token')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return { token, user, setToken, logout }
|
|
20
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "preserve",
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"paths": { "@/*": ["./src/*"] },
|
|
11
|
+
"baseUrl": "."
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts", "src/**/*.vue"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import vue from '@vitejs/plugin-vue'
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [vue(), tailwindcss()],
|
|
7
|
+
server: {
|
|
8
|
+
port: 5173,
|
|
9
|
+
proxy: {
|
|
10
|
+
'/api': {
|
|
11
|
+
target: 'http://127.0.0.1:8000',
|
|
12
|
+
changeOrigin: true,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
})
|