✨ feat(frontend): scaffold minimal Nuxt 3 frontend with healthz dashboard (#25)
First Vue 3 / Nuxt 3 / Playwright frontend layer for dance-lessons-coach. Minimal: 1 page, 1 component fetching /api/healthz, 1 e2e test. Out of scope: Storybook, design system, auth pages, deploy. ~95% Mistral autonomous via ICM workspace ~/Work/Vibe/workspaces/frontend-nuxt-scaffold/. Mistral handled the npx nuxi init TUI by falling back to manual file creation (Q-032 documented). Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
This commit was merged in pull request #25.
This commit is contained in:
10
.gitignore
vendored
10
.gitignore
vendored
@@ -34,3 +34,13 @@ config/runner
|
|||||||
coverage.txt
|
coverage.txt
|
||||||
trigger.txt
|
trigger.txt
|
||||||
test_trigger.txt
|
test_trigger.txt
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
frontend/node_modules/
|
||||||
|
frontend/.nuxt/
|
||||||
|
frontend/.output/
|
||||||
|
frontend/dist/
|
||||||
|
frontend/.env
|
||||||
|
frontend/.cache/
|
||||||
|
frontend/test-results/
|
||||||
|
frontend/playwright-report/
|
||||||
|
|||||||
3
frontend/app.vue
Normal file
3
frontend/app.vue
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<NuxtPage />
|
||||||
|
</template>
|
||||||
22
frontend/components/HealthDashboard.vue
Normal file
22
frontend/components/HealthDashboard.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface HealthInfo {
|
||||||
|
status: string
|
||||||
|
version: string
|
||||||
|
uptime_seconds: number
|
||||||
|
timestamp: string
|
||||||
|
}
|
||||||
|
const { data, pending, error } = await useFetch<HealthInfo>('/api/healthz')
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<section data-testid="health-dashboard">
|
||||||
|
<h2>Server Health</h2>
|
||||||
|
<p v-if="pending">Loading...</p>
|
||||||
|
<p v-else-if="error">Error loading health: {{ error.message }}</p>
|
||||||
|
<ul v-else-if="data" data-testid="health-info">
|
||||||
|
<li><strong>Status:</strong> <span data-testid="health-status">{{ data.status }}</span></li>
|
||||||
|
<li><strong>Version:</strong> {{ data.version }}</li>
|
||||||
|
<li><strong>Uptime:</strong> {{ data.uptime_seconds }} seconds</li>
|
||||||
|
<li><strong>Last check:</strong> {{ data.timestamp }}</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
11
frontend/nuxt.config.ts
Normal file
11
frontend/nuxt.config.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default defineNuxtConfig({
|
||||||
|
devtools: { enabled: true },
|
||||||
|
nitro: {
|
||||||
|
devProxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:8080',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
11237
frontend/package-lock.json
generated
Normal file
11237
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
frontend/package.json
Normal file
18
frontend/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "dance-lessons-coach-frontend",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "nuxt dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.59.1",
|
||||||
|
"@types/node": "^25.6.0",
|
||||||
|
"nuxt": "^3.13.0",
|
||||||
|
"typescript": "^6.0.3"
|
||||||
|
},
|
||||||
|
"packageManager": "npm@11.5.2"
|
||||||
|
}
|
||||||
6
frontend/pages/index.vue
Normal file
6
frontend/pages/index.vue
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<template>
|
||||||
|
<main>
|
||||||
|
<h1>dance-lessons-coach</h1>
|
||||||
|
<HealthDashboard />
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
14
frontend/playwright.config.ts
Normal file
14
frontend/playwright.config.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { defineConfig } from '@playwright/test'
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests/e2e',
|
||||||
|
timeout: 30_000,
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000',
|
||||||
|
},
|
||||||
|
webServer: {
|
||||||
|
command: 'npm run dev',
|
||||||
|
url: 'http://localhost:3000',
|
||||||
|
timeout: 60_000,
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
})
|
||||||
8
frontend/tests/e2e/health.spec.ts
Normal file
8
frontend/tests/e2e/health.spec.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('home page loads and shows server health info', async ({ page }) => {
|
||||||
|
await page.goto('/')
|
||||||
|
await expect(page.getByTestId('health-dashboard')).toBeVisible()
|
||||||
|
const heading = page.getByRole('heading', { name: /dance-lessons-coach/i })
|
||||||
|
await expect(heading).toBeVisible()
|
||||||
|
})
|
||||||
6
frontend/tsconfig.json
Normal file
6
frontend/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.nuxt/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user