Files
mws.frontend.vue/CLAUDE.md
T
2026-09-12 19:38:11 +07:00

4.7 KiB

CLAUDE.md

Vue 3 + TypeScript SPA — frontend of MWS (My Workspace), an internal tool for small teams to manage projects, documents, and tasks. Talks to a .NET 10 backend over REST + JWT.

Commands

npm install            # install deps
npm run dev            # vite dev server on :5173, calls backend at http://localhost:5000
npm run build          # vue-tsc typecheck + vite build → dist/
npm run preview        # serve built dist locally

No test runner, no linter configured. vue-tsc -b during build is the only static check.

Environment

  • VITE_API_BASE_URL — backend base URL (default http://localhost:5000). Set in .env.local for dev, or pass --build-arg VITE_API_BASE_URL=... to Docker.
  • Backend dev port is 5000, not the production 8080. The api.ts interceptor reads localStorage.mws_token and attaches Authorization: Bearer …; 401s clear storage and redirect to /login.

Layout & routing

Two sibling layout shells (src/layouts/) sharing the same sidebar + topbar chrome:

  • AdminLayout — global/admin shell. Sidebar: Projects (/projects), Users (/users), Settings (/settings/*).
  • MainLayout — project-workspace shell. Sidebar: Tasks / Documents / Members for the current :id project; topbar has the project switcher.

App.vue hosts the global Toast, ConfirmDialog, and LoadingOverlay. LoadingOverlay is non-blocking (pointer-events: none) and driven by useLoading, a counter incremented/decremented by the axios interceptors.

Routes (src/router/index.ts):

  • /login — public.
  • /select-project — standalone, read-only project picker (no CRUD) for non-admin users.
  • /AdminLayout: /projects (admin-only project list with full CRUD), /users, /settings/{masterdata,roles,permissions}.
  • /projects/:idMainLayout: tasks/board, documents, members.

Role-based landing: auth.isAdmin (a user whose roleName contains Admin) lands on /projects; everyone else on /select-project. meta.adminOnly on /projects is enforced in the guard. Guards redirect unauthenticated users to /login; unknown paths redirect to the role landing page.

Domain areas (each is a folder under views/):

  • auth/LoginView.vue
  • projects/ProjectsListView.vue (admin), MembersView.vue, ProjectSelectView.vue
  • documents/ — tree + editor
  • tasks/ — kanban board + detail dialog
  • users/, settings/ — admin management

Service layer pattern

Three files in src/services/:

  • api.ts — shared axios instance + interceptors + errorMessage(error) helper for surfacing backend { message } errors.
  • backend.ts — auth, projects, members, users (small subset).
  • modules.ts — documents + tasks (split here to keep files scannable).

Every API call is a thin typed wrapper around api.get/post/put/delete. Views call these directly — there is no separate data layer / composable cache. New endpoints → add a typed function to backend.ts or modules.ts and a matching interface in src/types/index.ts.

State

Only one Pinia store: src/stores/auth.ts. Token + user object, persisted to localStorage under mws_token / mws_user. Everything else (projects, documents, tasks) is fetched per-view — no client cache. Add a new store only if cross-view shared state actually appears.

Auto-imports

vite.config.ts auto-imports:

  • Vue / vue-router / pinia globals
  • PrimeVue composables: useToast, useConfirm, useDialog (call them without imports in components)
  • PrimeVue components via @primevue/auto-import-resolver (no need to import <Button>, <DataTable>, etc. — Components() resolves them)

Generated types live in src/auto-imports.d.ts and src/components.d.ts — do not hand-edit.

Styling

  • Tailwind v4 via @tailwindcss/vite plugin (no tailwind.config.js — theme is CSS-only).
  • PrimeVue Aura preset (customized in src/theme.ts) wired in main.ts. Use PrimeVue components first; reach for raw HTML when PrimeVue has no equivalent.
  • src/style.css defines a .field label helper used across forms.

Adding a new view / feature

  1. Add typed function(s) to services/backend.ts or services/modules.ts, types to types/index.ts.
  2. Create the .vue under the matching views/<area>/ folder.
  3. Register the route in router/index.ts — pick the right layout (AdminLayout for admin/top-level pages, MainLayout for project-scoped tabs).
  4. Use auto-imported PrimeVue components and composables — no manual import for them.

Container

Dockerfile is a multi-stage build (node:24-alpine → nginx:1.27-alpine). nginx.conf serves the SPA and proxies /api/ and /openapi/ to http://backend:8080. Production container listens on 80; docker-compose.yml maps host :5173 → 80.