# Frontend Audit 2026-05-12

## Scope

- Audit date: `2026-05-12`
- Frontend root: `Z:\dk_project\dk_app\ubuntu\data\sme-omnistore-p0-remediated-20260509\frontend`
- Admin app: `Z:\dk_project\dk_app\ubuntu\data\sme-omnistore-p0-remediated-20260509\frontend\admin`
- Store app: `Z:\dk_project\dk_app\ubuntu\data\sme-omnistore-p0-remediated-20260509\frontend\store`
- Backend docs used for API verification: `http://8.138.234.47:8000/docs`
- OpenAPI source checked: `http://8.138.234.47:8000/openapi.json`

## Project Map

### Admin

- Stack: Vue 3 + Vite + Vue Router + Pinia + Element Plus
- Entry: `src/main.js`
- Layout: `src/layouts/AdminLayout.vue`
- Route map: `src/router/index.js`
- Shared API layer: `src/api/index.js`
- Major screens:
  - `src/views/dashboard/Dashboard.vue`
  - `src/views/products/ProductList.vue`
  - `src/views/products/ProductForm.vue`
  - `src/views/orders/OrderList.vue`
  - `src/views/orders/OrderDetail.vue`
  - `src/views/customers/*`
  - `src/views/brands/BrandList.vue`
  - `src/views/categories/Categories.vue`
  - `src/views/banners/Banners.vue`
  - `src/views/coupons/CouponList.vue`
  - `src/views/reviews/ReviewList.vue`
  - `src/views/refunds/RefundList.vue`
  - `src/views/settings/Settings.vue`
  - `src/views/audit/AuditLog.vue`

### Store

- Stack: Nuxt 3 + Pinia + Tailwind CSS
- Entry: `app.vue`
- Runtime config: `nuxt.config.ts`
- Shared API composable: `composables/useApi.ts`
- Main folders:
  - `pages/`
  - `components/`
  - `composables/`
  - `layouts/`
  - `middleware/`
  - `plugins/`
  - `stores/`
- Important routes/pages:
  - `pages/index.vue`
  - `pages/products/index.vue`
  - `pages/products/[slug].vue`
  - `pages/category/[slug].vue`
  - `pages/brands/index.vue`
  - `pages/brands/[slug].vue`
  - `pages/cart.vue`
  - `pages/checkout/index.vue`
  - `pages/account/index.vue`
  - `pages/account/logistics/index.vue`
  - `pages/auth/login.vue`
  - `pages/auth/register.vue`
  - `pages/pages/[slug].vue`

## Runtime / API Config

### Admin

- `.env`
  - `VITE_API_BASE=http://8.138.234.47:8000/api`
  - `VITE_USE_MOCK=false`

### Store

- `.env`
  - `NUXT_BACKEND_INTERNAL_URL=http://8.138.234.47:8000`
  - `NUXT_PUBLIC_API_BASE=/api`
  - `NUXT_PUBLIC_USE_MOCK=false`
- `nuxt.config.ts`
  - Nitro proxy: `/api/** -> ${NUXT_BACKEND_INTERNAL_URL}/api/**`

## API Verification Notes

Verified against OpenAPI that the following backend groups exist and match frontend intent:

- Admin/auth: `/api/auth/*`
- Admin/dashboard: `/api/dashboard/*`
- Admin/products: `/api/products*`
- Admin/orders: `/api/orders*`
- Admin/customers: `/api/customers*`
- Admin/categories: `/api/categories*`
- Admin/brands: `/api/brands*`
- Admin/member levels: `/api/member-levels*`
- Admin/coupons: `/api/coupons*`
- Admin/reviews: `/api/reviews*`
- Admin/settings: `/api/admin/settings`
- Admin/audit logs: `/api/admin/audit-logs`
- Admin/inventory alerts: `/api/admin/inventory-alerts*`
- Admin/refunds: `/api/admin/refund-requests*`
- Store APIs: `/api/store/*`

## Bugs Fixed In This Audit

### 1. Admin pages bypassed shared API client

Problem:

- Several admin pages were calling `fetch('/api/...')` directly.
- That bypassed the shared `axios` client in `src/api/index.js`.
- Resulting risk: missing token injection, inconsistent 401 handling, inconsistent error handling.

Files fixed:

- `admin/src/api/index.js`
- `admin/src/views/banners/Banners.vue`
- `admin/src/views/categories/Categories.vue`
- `admin/src/views/coupons/CouponList.vue`
- `admin/src/views/reviews/ReviewList.vue`
- `admin/src/views/orders/OrderDetail.vue`

Changes made:

- Added admin API helpers for:
  - category create/update/delete
  - banner list/create/update/delete
  - review list/status update/reply
  - order logistics update
- Rewired affected pages to use the shared API layer instead of ad hoc `fetch`.

### 2. Banner and category delete actions were only changing local UI

Problem:

- Banner/category delete buttons only removed rows from frontend state.
- Backend data was not actually deleted.

Fix:

- `Banners.vue` now calls `bannerApi.delete(id)`
- `Categories.vue` now calls `categoryApi.delete(id)`

### 3. Admin order detail page had fragile direct fetch logic

Problem:

- Order detail used direct `fetch` for load, status update, and logistics update.
- Logistics update expected a JSON body with `res.ok`, which is not how the shared API layer behaves.
- The script block also contained damaged encoded text and was at risk of becoming unmaintainable.

Fix:

- Replaced the page logic to use `orderApi.get`, `orderApi.updateStatus`, and `orderApi.setLogistics`.
- Rebuilt the script block into a stable version.
- Added local sync logic for logistics form and delivery events after save.

### 4. Admin product image preview/upload was broken in Vite dev mode

Problem:

- Product image upload succeeded against `POST /api/upload`, and the backend returned image URLs like `/api/static/uploads/<file>.webp`.
- The admin Vite dev proxy rewrote `/api/*` requests by stripping the `/api` prefix before forwarding.
- Result: uploaded image preview requests were proxied as `/static/uploads/<file>.webp`, but the FastAPI route actually serves files from `/api/static/uploads/{filename}`.
- Visible symptom: Vite logged `http proxy error: /static/uploads/...`, and the product form could not reliably preview/save uploaded images during add/edit flows.

Fix:

- Extracted the dev proxy behavior into `admin/devProxyConfig.mjs`.
- Removed the Vite proxy `rewrite` step so `/api/static/uploads/...` keeps the `/api` prefix all the way to the backend.
- Switched `admin/vite.config.js` to `loadEnv(...)` instead of relying on `process.env.VITE_API_BASE`, so dev proxy target correctly uses `frontend/admin/.env`.
- Added a regression test in `admin/tests/devProxyConfig.test.mjs` to verify that uploaded image URLs keep the `/api` prefix in dev.
- Added regression coverage for env resolution so the proxy target does not silently fall back to `127.0.0.1:8000` when `.env` is present.

### 5. Admin product form could lose images when reopening an edited product

Problem:

- Product save could succeed, but reopening the product edit page sometimes showed no images.
- The admin form only trusted `data.images` on reload and had no fallback to `cover_url`.
- The backend update route also mixed `images` into the generic ORM field assignment before calling `_apply_images(...)`, which was unsafe for the `Product.images` relationship.

Fix:

- `admin/src/views/products/ProductForm.vue` now normalizes edit-page images from `data.images` first and falls back to `data.cover_url`.
- The same form now always sends `cover_url` from the first uploaded image so legacy reads and detail reloads stay aligned.
- `backend/app/api/routers/products.py` now excludes `images` from the generic update payload and lets `_apply_images(...)` own image synchronization.
- `admin/src/components/ImageUploader.vue` now keeps a local synchronized image list during uploads, preventing later upload completions from overwriting earlier images in multi-image flows.
- `admin/src/views/products/ProductForm.vue` now also reads and writes product gallery data through `/api/products/{id}/images`, so multi-image persistence no longer depends on the remote `PUT /api/products/{id}` implementation returning or storing `images` correctly.

## Verification Performed

### Admin build

Command:

- `npm.cmd run build`
- `node --test .\tests\devProxyConfig.test.mjs`

Result:

- Passed

Notes:

- Vite emitted large chunk warnings for `Dashboard` and main bundle.
- This is not a blocker, but it is a performance follow-up item.

### Store build

Command:

- `npm.cmd run build`

Result:

- Passed

Notes:

- There was a stale Nuxt build lock from an older `node` process.
- The stale process was terminated and a clean build was rerun successfully.
- Build produced a Node deprecation warning related to trailing slash export mapping in dependencies. Non-blocking for now.

## Remaining Observations

### Admin

- After this audit, `admin/src` no longer has remaining direct `fetch(` usage for `/api` calls in the audited screens.
- There are still incomplete UI behaviors in some pages, such as add/edit dialogs that currently show placeholder messages instead of full CRUD forms.
- These are not compile blockers, but they are feature-completion follow-up items.

### Store

- Store build is green, but the architecture is still mixed:
  - shared API via `composables/useApi.ts`
  - multiple pages/components still use direct `$fetch(...)`
- Notable direct API consumers include:
  - `pages/account/index.vue`
  - `pages/account/logistics/index.vue`
  - `pages/checkout/index.vue`
  - `pages/auth/login.vue`
  - `pages/auth/register.vue`
  - `components/account/RefundPage.vue`
  - `pages/products/[slug].vue`
  - `pages/pages/[slug].vue`
- This is not currently broken, but it means store-side auth/error handling is less centralized than admin-side.

### Cleanup candidates

- `store/pages/products/[slug].vue.bak` appears to be a leftover backup file.
- Both `store/stores.client.ts` and `store/plugins/stores.client.ts` exist; worth confirming whether both are still needed.

## Files Modified In This Audit

- `admin/src/api/index.js`
- `admin/src/views/banners/Banners.vue`
- `admin/src/views/categories/Categories.vue`
- `admin/src/views/coupons/CouponList.vue`
- `admin/src/views/reviews/ReviewList.vue`
- `admin/src/views/orders/OrderDetail.vue`
- `admin/src/components/ImageUploader.vue`
- `admin/src/views/products/ProductForm.vue`
- `admin/devProxyConfig.mjs`
- `admin/tests/devProxyConfig.test.mjs`
- `admin/vite.config.js`
- `admin/src/api/index.js`
- `backend/app/api/routers/products.py`
- `frontend/FRONTEND_AUDIT_2026-05-12.md`

## Recommended Next Steps

1. Continue the same API unification on the store side by routing direct `$fetch` usage through shared composables/helpers.
2. Decide whether to fully implement admin banner/category add/edit dialogs or explicitly hide unfinished actions.
3. Reduce admin bundle size warnings with route-level splitting or manual chunking.
