Skip to content

Commit 80a85bf

Browse files
authored
feat: backend-nodejs
feat: backend-nodejs
2 parents b9ea160 + d24d77d commit 80a85bf

File tree

120 files changed

+21888
-232
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+21888
-232
lines changed

.github/workflows/frontend-e2e.yml

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ name: Frontend E2E Tests
22

33
on:
44
push:
5-
branches: [main, develop, master]
5+
branches: [main, develop, master, feat-node]
66
paths:
77
- 'frontend/web/**'
88
- 'backend/**'
9+
- 'backend-nodejs/**'
910
- 'docker/e2e/**'
1011
- '.github/workflows/frontend-e2e.yml'
1112
pull_request:
1213
branches: [main, develop, master]
1314
paths:
1415
- 'frontend/web/**'
1516
- 'backend/**'
17+
- 'backend-nodejs/**'
1618
- 'docker/e2e/**'
1719
# 允许手动触发
1820
workflow_dispatch:
@@ -24,9 +26,21 @@ concurrency:
2426

2527
jobs:
2628
e2e:
27-
name: E2E Tests (Docker)
29+
name: E2E Tests (${{ matrix.backend }})
2830
runs-on: ubuntu-latest
2931
timeout-minutes: 20
32+
strategy:
33+
matrix:
34+
backend: [go, nodejs]
35+
include:
36+
- backend: go
37+
backend_url: http://localhost:8081
38+
backend_name: Go Backend
39+
container_name: go-genai-stack-backend-e2e
40+
- backend: nodejs
41+
backend_url: http://localhost:8082
42+
backend_name: Node.js Backend
43+
container_name: go-genai-stack-backend-nodejs-e2e
3044

3145
steps:
3246
- name: Checkout code
@@ -116,62 +130,117 @@ jobs:
116130
COMPOSE_DOCKER_CLI_BUILD: 1
117131
run: |
118132
echo "🐳 Building and starting E2E environment..."
133+
echo "📋 Testing against: ${{ matrix.backend_name }}"
119134
docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
120135
docker compose up -d
121136
122137
echo "⏳ Waiting for Postgres to be healthy..."
123138
timeout 60s bash -c 'until [ "$(docker inspect --format="{{.State.Health.Status}}" go-genai-stack-postgres-e2e)" == "healthy" ]; do echo -n "."; sleep 2; done'
124139
echo " ✅"
125140
126-
echo "⏳ Waiting for Backend to be healthy..."
127-
timeout 90s bash -c 'until [ "$(docker inspect --format="{{.State.Health.Status}}" go-genai-stack-backend-e2e)" == "healthy" ]; do echo -n "."; sleep 2; done'
141+
echo "⏳ Waiting for Redis to be healthy..."
142+
timeout 30s bash -c 'until [ "$(docker inspect --format="{{.State.Health.Status}}" go-genai-stack-redis-e2e)" == "healthy" ]; do echo -n "."; sleep 2; done'
128143
echo " ✅"
129144
145+
echo "⏳ Waiting for ${{ matrix.backend_name }} to be healthy..."
146+
timeout 180s bash -c "
147+
max_attempts=90
148+
attempt=0
149+
container_name='${{ matrix.container_name }}'
150+
while [ \$attempt -lt \$max_attempts ]; do
151+
if ! docker ps --format '{{.Names}}' | grep -q \"^\${container_name}\$\"; then
152+
echo \" ❌ Container \${container_name} not found\"
153+
exit 1
154+
fi
155+
status=\$(docker inspect --format='{{.State.Health.Status}}' \${container_name} 2>/dev/null || echo 'starting')
156+
if [ \"\$status\" == 'healthy' ]; then
157+
echo \" ✅\"
158+
exit 0
159+
fi
160+
if [ \$((attempt % 10)) -eq 0 ] && [ \$attempt -gt 0 ]; then
161+
echo \"\"
162+
echo \" Attempt \$attempt/\$max_attempts, Status: \$status\"
163+
if [ \"\$status\" == 'unhealthy' ] || [ \"\$status\" == 'starting' ]; then
164+
echo \" Health check details:\"
165+
health_log=\$(docker inspect \${container_name} --format='{{range .State.Health.Log}}{{.ExitCode}}|{{.Output}}{{end}}' 2>/dev/null | tail -1)
166+
if [ -n \"\$health_log\" ]; then
167+
exit_code=\$(echo \"\$health_log\" | cut -d'|' -f1)
168+
output=\$(echo \"\$health_log\" | cut -d'|' -f2-)
169+
echo \" ExitCode: \${exit_code}\"
170+
echo \" Output: \${output}\"
171+
fi
172+
echo \" Container state:\"
173+
docker inspect \${container_name} --format='Status: {{.State.Status}}, Health: {{.State.Health.Status}}, Started: {{.State.StartedAt}}' 2>/dev/null || true
174+
fi
175+
fi
176+
echo -n \".\"
177+
sleep 2
178+
attempt=\$((attempt + 1))
179+
done
180+
echo \"\"
181+
echo \" ❌ Health check timeout after \$((max_attempts * 2)) seconds\"
182+
echo \"Container: \${container_name}\"
183+
echo \"Final status: \$(docker inspect --format='{{.State.Health.Status}}' \${container_name} 2>/dev/null || echo 'unknown')\"
184+
echo \"\"
185+
echo \"Container logs (last 50 lines):\"
186+
docker logs --tail=50 \${container_name} || true
187+
echo \"\"
188+
echo \"Health check history (last 5 attempts):\"
189+
docker inspect \${container_name} --format='{{range .State.Health.Log}}[{{.Start}}] ExitCode: {{.ExitCode}} Output: {{.Output}}{{end}}' 2>/dev/null | tail -5 || true
190+
echo \"\"
191+
echo \"Testing health endpoint directly:\"
192+
docker exec \${container_name} node -e \"require('http').get('http://localhost:8080/health', (r) => {let d='';r.on('data',x=>d+=x);r.on('end',()=>{console.log('Status:',r.statusCode);console.log('Response:',d);process.exit(r.statusCode===200?0:1)})}).on('error',e=>{console.error('Error:',e.message);process.exit(1)})\" 2>&1 || true
193+
exit 1
194+
"
195+
130196
echo "✅ All services are ready"
131197
docker compose ps
132198
133199
- name: Verify backend health
134200
run: |
135-
echo "🔍 Checking backend health..."
136-
curl -f http://localhost:8081/health || (echo "❌ Backend health check failed" && exit 1)
137-
echo "✅ Backend is healthy"
201+
echo "🔍 Checking ${{ matrix.backend_name }} health..."
202+
curl -f ${{ matrix.backend_url }}/health || (echo "❌ ${{ matrix.backend_name }} health check failed" && exit 1)
203+
echo "✅ ${{ matrix.backend_name }} is healthy"
138204
139205
- name: Run E2E tests
140206
working-directory: frontend/web
141207
env:
142208
CI: true
209+
E2E_BACKEND_URL: ${{ matrix.backend_url }}
143210
run: |
144-
echo "🧪 Running E2E tests..."
211+
echo "🧪 Running E2E tests against ${{ matrix.backend_name }}..."
212+
echo "📡 Backend URL: ${{ matrix.backend_url }}"
145213
pnpm e2e:ci
146214
147215
- name: Upload Playwright Report
148216
if: always()
149217
uses: actions/upload-artifact@v4
150218
with:
151-
name: playwright-report
219+
name: playwright-report-${{ matrix.backend }}
152220
path: frontend/web/playwright-report/
153221
retention-days: 7
154222

155223
- name: Upload Test Results
156224
if: always()
157225
uses: actions/upload-artifact@v4
158226
with:
159-
name: test-results
227+
name: test-results-${{ matrix.backend }}
160228
path: frontend/web/test-results/
161229
retention-days: 7
162230

163231
- name: E2E Test Summary
164232
if: always()
165233
run: |
166-
echo "## 🎭 E2E Test Results" >> $GITHUB_STEP_SUMMARY
234+
echo "## 🎭 E2E Test Results (${{ matrix.backend_name }})" >> $GITHUB_STEP_SUMMARY
167235
echo "" >> $GITHUB_STEP_SUMMARY
168236
169237
if [ -f frontend/web/test-results/results.json ]; then
170-
echo "✅ E2E tests completed" >> $GITHUB_STEP_SUMMARY
238+
echo "✅ E2E tests completed for ${{ matrix.backend_name }}" >> $GITHUB_STEP_SUMMARY
171239
echo "" >> $GITHUB_STEP_SUMMARY
240+
echo "📊 Backend: ${{ matrix.backend_url }}" >> $GITHUB_STEP_SUMMARY
172241
echo "📊 [View Playwright Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
173242
else
174-
echo "⚠️ No test results found" >> $GITHUB_STEP_SUMMARY
243+
echo "⚠️ No test results found for ${{ matrix.backend_name }}" >> $GITHUB_STEP_SUMMARY
175244
fi
176245
177246
- name: Show Docker logs on failure
@@ -183,13 +252,22 @@ jobs:
183252
echo ""
184253
echo "🔍 Health Status:"
185254
docker inspect --format='{{.Name}}: {{.State.Health.Status}}' go-genai-stack-postgres-e2e || echo "postgres-e2e: not found"
255+
docker inspect --format='{{.Name}}: {{.State.Health.Status}}' go-genai-stack-redis-e2e || echo "redis-e2e: not found"
186256
docker inspect --format='{{.Name}}: {{.State.Health.Status}}' go-genai-stack-backend-e2e || echo "backend-e2e: not found"
257+
docker inspect --format='{{.Name}}: {{.State.Health.Status}}' go-genai-stack-backend-nodejs-e2e || echo "backend-nodejs-e2e: not found"
187258
echo ""
188259
echo "📋 Postgres Logs:"
189260
docker compose logs --tail=50 postgres-e2e
190261
echo ""
191-
echo "📋 Backend Logs:"
192-
docker compose logs --tail=100 backend-e2e
262+
echo "📋 Redis Logs:"
263+
docker compose logs --tail=50 redis-e2e
264+
echo ""
265+
echo "📋 ${{ matrix.backend_name }} Logs:"
266+
if [ "${{ matrix.backend }}" == "nodejs" ]; then
267+
docker compose logs --tail=100 backend-nodejs-e2e || echo "Could not retrieve logs for backend-nodejs-e2e"
268+
else
269+
docker compose logs --tail=100 backend-e2e || echo "Could not retrieve logs for backend-e2e"
270+
fi
193271
194272
- name: Stop E2E environment
195273
if: always()

backend-nodejs/.eslintrc.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"parser": "@typescript-eslint/parser",
3+
"parserOptions": {
4+
"ecmaVersion": 2022,
5+
"sourceType": "module"
6+
},
7+
"plugins": ["@typescript-eslint"],
8+
"extends": [
9+
"eslint:recommended",
10+
"plugin:@typescript-eslint/recommended"
11+
],
12+
"rules": {
13+
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
14+
"@typescript-eslint/explicit-function-return-type": "off",
15+
"@typescript-eslint/no-explicit-any": "warn",
16+
"no-console": "off"
17+
},
18+
"env": {
19+
"node": true,
20+
"es2022": true
21+
}
22+
}
23+

backend-nodejs/.gitignore

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Dependencies
2+
node_modules/
3+
.pnp
4+
.pnp.js
5+
6+
# Build output
7+
dist/
8+
build/
9+
*.tsbuildinfo
10+
11+
# Environment variables
12+
.env
13+
.env.local
14+
.env.*.local
15+
16+
# Logs
17+
logs/
18+
*.log
19+
npm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*
22+
pnpm-debug.log*
23+
lerna-debug.log*
24+
25+
# Testing
26+
coverage/
27+
.nyc_output/
28+
test-results/
29+
playwright-report/
30+
31+
# IDE
32+
.vscode/
33+
.idea/
34+
*.swp
35+
*.swo
36+
*~
37+
.DS_Store
38+
39+
# TypeScript
40+
*.tsbuildinfo
41+
42+
# Misc
43+
.cache/
44+
.temp/
45+
.tmp/
46+

backend-nodejs/.prettierrc.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "es5",
4+
"singleQuote": true,
5+
"printWidth": 100,
6+
"tabWidth": 2,
7+
"useTabs": false,
8+
"arrowParens": "avoid"
9+
}
10+

0 commit comments

Comments
 (0)