# CLAUDE.md - LogShip ERP Nuxt Frontend ## Project Overview **LogShip ERP** is an enterprise resource planning web application built with **Nuxt 3** and **Vue 3 Composition API**. It connects to an **iDempiere** ERP backend via REST API. The app also integrates with Strapi (CMS/media), Laravel, PostgREST, Elasticsearch, DHL, Sendcloud, Shopify, and PlentyOne. - **App Name:** LogShip WMS / ERP Solutions - **Company:** LogYou - **Production URL:** https://app.logship.de - **Dev URL:** https://dev-app.logship.de --- ## Tech Stack | Layer | Technology | |-------|-----------| | Framework | Nuxt 3.17+ (Vue 3.5+, Composition API, ` ``` ### Create Page Pattern ```vue ``` --- ## Component Patterns ### Form Component Pattern **Naming:** `components/[domain]/[Entity]Form.vue` ```vue ``` ### Action Component Pattern (AG Grid context menu) **Naming:** `components/[domain]/[Entity]Action.vue` ```vue ``` ### Detail Record Tab Pattern **Naming:** `components/[domain]/[Entity]DetailRecord.vue` Manages sub-tabs for complex entity views (e.g., Partner → Locations, Bank Accounts, Users). --- ## State Management **NO Pinia/Vuex.** All state uses Nuxt's `useState()` in `composables/states.ts`: ```typescript export const useSideBar = () => useState('sideBar', () => false) export const useTabs = () => useState('tabs', () => [{ link: '/', text: 'Home', active: true }]) export const usePrintPreview = () => useState('printPreview', () => false) export const usePrintParam = () => useState('printParam', () => {}) // ... 33 total state composables ``` **State persistence strategy:** - **Cookies:** Auth data, user, org, role, language (persistent, cross-tab) - **localStorage:** Theme (`logship_theme`), language (`logship_lang`), tabs, scanner preference - **sessionStorage:** Detail record active tab - **useState:** UI runtime state (sidebar, modals, active menus) --- ## Data Fetching ### Client-side (pages/components) ```typescript // SSR-safe initial data load const { data, pending, error, refresh } = await useFetch('/api/endpoint', { headers: useRequestHeaders(['cookie']) // ALWAYS include cookies for auth }) // Client-side mutations const res = await $fetch('/api/endpoint', { method: 'POST', headers: useRequestHeaders(['cookie']), body: { /* data */ } }) ``` ### Server-side (API routes) ```typescript // Using fetchHelper (for iDempiere) const res = await fetchHelper(event, 'models/c_bpartner?$filter=...', 'GET', token, null) // Using event.context.fetch (middleware-provided, auto-handles cookies) const res = await event.context.fetch('models/c_bpartner?$filter=...', 'GET', token, null) // Other backend helpers const res = await postgrestHelper(event, '/rpc/function_name', 'POST', body) const res = await strapiHelper(event, 'endpoint', 'GET', null) const res = await laravelHelper(event, 'api/endpoint', 'POST', body) const res = await elasticHelper(event, 'index/_search', 'POST', body) ``` --- ## Layouts | Layout | Usage | Components | |--------|-------|-----------| | `app` | Default authenticated pages | NavBar + SideBar + TabBar + Footer | | `admin` | Admin panel | NavBarAdmin + SideBarAdmin | | `org` | Organization selection | NavBarOrg + SideBarOrg | | `auth` / `new-auth` | Login/register pages | Centered form | | `mobile` | Mobile routes (`/mobile/*`) | Portrait-locked, landscape warning | | `tracking` | Public tracking page | Minimal layout | | `new-dash` | New dashboard | TopMegaBar + NewSideBar + MainNavigationMenu | **Usage in pages:** ```typescript definePageMeta({ layout: 'admin' }) ``` --- ## Middleware - **`auth.ts`** — Checks `/api/idempiere-auth/authenticated`; redirects to `/signin` if not authenticated. Mobile pages fall back to cookie check on network errors. - **`guest.ts`** — Redirects authenticated users away from signin/register pages. - **`org.ts`** — Organization context check (currently disabled/commented out). **Page usage:** ```typescript definePageMeta({ middleware: ['auth', 'org'] }) ``` --- ## Styling Conventions - **Primary CSS:** Bulma classes (`field`, `label`, `input`, `button is-primary`, `columns`, `column`) - **Theme variables:** `--theme-bg-primary`, `--theme-bg-secondary`, `--theme-text-primary`, `--theme-border`, etc. - **Dark mode:** CSS variables switch values; classes `.dark` / `[data-mode="dark"]` - **Scoped styles:** Use `