Files

87 lines
4.7 KiB
Markdown
Raw Permalink Normal View History

2026-08-24 08:07:23 +07:00
# 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
```bash
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
2026-09-12 19:38:11 +07:00
Two sibling layout shells (`src/layouts/`) sharing the same sidebar + topbar chrome:
2026-08-24 08:07:23 +07:00
2026-09-12 19:38:11 +07:00
- `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.
2026-08-24 08:07:23 +07:00
2026-09-12 19:38:11 +07:00
`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/:id``MainLayout`: `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.
2026-08-24 08:07:23 +07:00
Domain areas (each is a folder under `views/`):
- `auth/``LoginView.vue`
2026-09-12 19:38:11 +07:00
- `projects/``ProjectsListView.vue` (admin), `MembersView.vue`, `ProjectSelectView.vue`
2026-08-24 08:07:23 +07:00
- `documents/` — tree + editor
2026-09-12 19:38:11 +07:00
- `tasks/` — kanban board + detail dialog
- `users/`, `settings/` — admin management
2026-08-24 08:07:23 +07:00
## 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).
2026-09-12 19:38:11 +07:00
- 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.
2026-08-24 08:07:23 +07:00
- `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.
2026-09-12 19:38:11 +07:00
3. Register the route in `router/index.ts` — pick the right layout (`AdminLayout` for admin/top-level pages, `MainLayout` for project-scoped tabs).
2026-08-24 08:07:23 +07:00
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`.