feat: scaffold FastAPI backend and Vue 3 frontend
Backend (backend/):
- FastAPI app with layered app/{api,core,crud,db,models,schemas} structure
- TiDB connection via SQLAlchemy. The URL is built with URL.create rather
than string formatting: the password contains '@', which would otherwise be
parsed as the user/host separator and silently truncate the credential.
- Alembic environment wired to Base.metadata and the app settings, so
backend/.env stays the single source of truth for credentials
- /api/health endpoint reporting database reachability
- models/ and crud/ are intentionally empty: no model classes are defined and
no tables are created, at import time or otherwise
Frontend (frontend/):
- Vue 3 + Vite + TypeScript scaffold (create-vue, --bare)
- axios instance with a normalized error shape
- vue-router with a home route and a catch-all 404
- pinia + pinia-plugin-persistedstate; the app store persists selected keys
- Element Plus with its icons registered globally
- dev proxy forwards /api to the FastAPI service on port 8000
The database paper_doc was created in TiDB out of band; no table exists yet.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-container class="app-shell">
|
||||
<el-header class="app-header">
|
||||
<div class="brand">paper-doc</div>
|
||||
<el-menu mode="horizontal" :ellipsis="false" router class="app-nav">
|
||||
<el-menu-item index="/">Home</el-menu-item>
|
||||
</el-menu>
|
||||
<el-button link @click="appStore.toggleSidebar()">
|
||||
{{ appStore.sidebarCollapsed ? 'Expand' : 'Collapse' }}
|
||||
</el-button>
|
||||
</el-header>
|
||||
|
||||
<el-main>
|
||||
<RouterView />
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.brand {
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.app-nav {
|
||||
flex: 1;
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user