This file gives AI coding assistants a stable working contract for this repository.
This repository is a reusable fullstack framework for enterprise management systems. It combines:
- Vue 3 + TypeScript + Vite frontend
- Element Plus UI components
- Pinia state management
- Vue Router navigation and guards
- Axios-based request wrapper
- Python FastAPI backend
- PostgreSQL persistence
- Scaffold scripts for backend, frontend, and fullstack CRUD modules
- A packaged Agent Skill under
skills/universal-fullstack-framework/
The repository includes several example business domains to demonstrate how modules attach to the shared foundation. Treat those domains as samples for extension patterns. The framework core is authentication, user/role/menu/permission management, system configuration, logs, backups, baseline CRUD, route/menu/permission registries, and validation scripts.
npm run dev # Start frontend dev server
npm run dev:local # Start frontend dev server on localhost only
npm run backend:dev # Start FastAPI backend with PostgreSQL defaults
npm run backend:dev:pg # Explicit PostgreSQL backend startup
npm run build # Type-check plus production build
npm run preview # Preview production buildnpm run lint # ESLint check and auto-fix
npm run format # Prettier format for src/
npm run type-check # Vue TypeScript checknpm run test:unit
vitest run <file>
vitest run -t "test name"Use the repository-level baseline gate for framework, scaffold, router, menu, backend, or auth changes:
bash scripts/verify_framework_baseline.shThe script runs Python compile checks, backend regression tests, HTTP smoke tests, frontend type-check, and production build.
Preserve the shared framework foundation:
- authentication and token storage
- request wrapper and API response normalization
- route guards
- menu and permission registries
- shared layout components
- common dialog/form/table patterns
- scaffold scripts and templates
scripts/verify_framework_baseline.sh
When adding business functionality, keep extension code isolated under module-oriented directories:
backend/app/modules/<domain>/src/api/<bucket>/src/types/<bucket>/src/stores/<bucket>/src/views/<view-bucket>/
Prefer the repo-local fullstack scaffold when both backend and frontend are involved:
./backend/.venv/bin/python scripts/scaffold_fullstack_module.py example_record \
--tag "Example Record" \
--api-base-path /manage/api/exampleRecord \
--table-name example_records \
--menu-parent system \
--route-path /system/example-record \
--route-name system-example-record \
--function-code APP-FUNC-EXAMPLE-RECORD \
--with-storeAfter generation:
- Replace placeholder fields such as
name,code,status, andremark. - Replace placeholder labels, columns, forms, validation rules, SQL, and error messages.
- Confirm frontend
meta.functionCodematches backendpermission. - Confirm route path, menu parent, backend menu entry, and layout filtering agree.
- Run targeted scaffold tests and the baseline gate.
Use single-sided scaffolds only for intentionally single-sided work:
./backend/.venv/bin/python backend/scripts/scaffold_backend_module.py <module_name>
./backend/.venv/bin/python scripts/scaffold_frontend_module.py <module_name>Route/menu/permission/layout must move together. For any new page or path change, check:
- Frontend route registry:
src/router/scaffoldedRoutes.tsorsrc/router/index.ts - Frontend menu registry:
src/config/scaffoldMenuRegistry.tsorsrc/config/menuConfig.ts - Backend menu registry:
backend/app/modules/system_admin/scaffold_menu_registry.pyorbackend/app/modules/system_admin/menu.py - Layout and guard allowlist:
src/layouts/MainLayout.vue,src/config/frameworkConfig.ts, menu store helpers
Also verify:
- frontend
meta.functionCode - backend
permission - role-menu default mappings
/admin/menu/tree/admin/menu/tree/{roleId}
Recommended order:
- Vue core
- third-party libraries
- local types
- local API modules
- local stores
- local components
- local utilities
- local composables
Use @/ aliases for source imports.
Use explicit types for refs, state, API payloads, and table rows.
const records = ref<RecordItem[]>([])
const loading = ref<boolean>(false)
const total = ref<number>(0)Use interface for structured data unless a union or mapped type is needed. Keep ID fields as string for frontend/backend consistency.
Use <script setup lang="ts"> and Composition API. Keep component order:
<template>
<script setup lang="ts">
<style scoped>Prefer Composition-style stores:
export const useExampleStore = defineStore('example', () => {
const records = ref<ExampleRecord[]>([])
const loading = ref(false)
const fetchRecords = async () => {
loading.value = true
try {
// API call
} finally {
loading.value = false
}
}
return { records, loading, fetchRecords }
})Use src/utils/request.ts:
const result = await request.get<ResponseType>('/api/path', params)
const saved = await request.post<ResponseType>('/api/path', payload)Treat code === 0 and code === 200 as success.
Backend modules should follow this structure:
backend/app/modules/<domain>/
├── router.py
├── deps.py
├── helpers.py
├── serializers.py
├── routes/
├── services/
└── repositories/
Layer responsibilities:
router.py: create and register routesdeps.py: collect route dependencieshelpers.py: parse and normalize inputsserializers.py: map rows to API response structuresroutes/: read HTTP inputs and call servicesservices/: coordinate business logic and transactionsrepositories/: own SQL
Keep response shape consistent:
{ "code": 0, "msg": "success", "data": {} }All async frontend operations need full loading and error handling:
const fetchData = async () => {
loading.value = true
try {
const res = await api()
if (res.code === 0 || res.code === 200) {
records.value = res.data || []
} else {
ElMessage.error(res.msg || 'Operation failed')
}
} catch (error) {
console.error('Fetch failed:', error)
ElMessage.error('Network error')
} finally {
loading.value = false
}
}- Use
ElMessagefor lightweight feedback. - Use
ElMessageBox.confirmfor destructive operations. - Use form
:rulesfor validation. - Use striped and highlightable tables.
- Import shared page styles with
@import '@/styles/common.css'. - Put shared table/container spacing in
src/styles/common.css. - Keep new module pages visually aligned with existing scaffold pages.
Use src/utils/constants.ts:
export const PAGE_SIZE_CONFIG = {
LARGE_PAGE_SIZE: 100000,
DEFAULT_PAGE_SIZE: 20,
SMALL_PAGE_SIZE: 10,
} as constDefault list pages use normal pagination. Selector APIs can request large page sizes when necessary.
Seed data should live in backend initialization code and use empty-table checks:
SELECT COUNT(1) AS cnt FROM table_nameProvide complete demo chains for example domains so pages are testable immediately. Prefer backend seed data over frontend-only mocks for integration scenarios.
Use conventional commits:
feat:fix:docs:style:refactor:test:chore:
Before closing framework or module work, run or report:
python3 -m py_compile backend/main.py- targeted backend tests when backend changed
npm run type-checknpm run build-onlybash scripts/verify_framework_baseline.shfor shared framework changes
Manual smoke:
- Login.
- Open protected user info.
- Open menu tree.
- Open one list page.
- Create, update, delete one demo record when the module supports CRUD.
README.mdFRAMEWORK_GUIDE.mddocs/fullstack-module-template.mddocs/frontend-module-template.mdbackend/docs/backend-module-template.mdskills/universal-fullstack-framework/SKILL.md