ptitlutins/CLAUDE.md
2026-06-10 00:56:44 +02:00

2.8 KiB

ptitlutins (frontend)

Nuxt 4 SPA for ptitlutins, a collaborative trip-planning app. Talks to the Django backend in ../ptitlutins-backend (sibling repo).

Stack

  • Nuxt 4 (Vue 3, <script setup lang="ts">), Pinia, Vue Router (file-based)
  • @nuxtjs/i18n (locales in i18n/locales/{en,fr}.json, default en, use $t())
  • @nuxt/icon, @nuxt/fonts, vue-tippy (tooltips/popovers, registered via app/plugins/vue-tippy.client.ts)

Commands

npm install
npm run dev        # http://localhost:3000
npm run build
npm run generate   # static
npx nuxt typecheck # types
npx eslint .       # lint

The backend must be running on http://localhost:8000 (hardcoded in app/services/api.ts as baseURL).

Layout (atomic design under app/)

  • components/{atoms,molecules,organisms,templates}/pathPrefix: false, so components are referenced by bare name (e.g. <Voyage>, <Button>) with no import. app.config.ts-style auto-import is on.
  • pages/ — routes. pages/voyages/[id].vue is the main view; [id] is a VoyageLink id, not a voyage id (see architecture).
  • stores/ — Pinia (option-store style). services/ — thin API wrappers.
  • types/index.ts — shared TS types.
  • assets/css/main.css imports reset.css, variables.css, global.css.

A user never addresses a Voyage directly — always through a VoyageLink, a shareable handle carrying its own permission (view/change). This mirrors the backend.

  • voyagesLinksStore — list of links + currentVoyageLink. setCurrentVoyageLink(id) loads one. Routes key off the link id.
  • voyageStore — holds a voyage's entities (events, trips, needs, locations), each normalized as Record<voyageId, Record<entityId, Entity>>. Generic CRUD via fetchItems/addItem/updateItem/removeItem, keyed by the VoyageEntitiesNames enum. The per-entity actions (addEvent, etc.) just delegate to these generics — extend the generics, not each entity by hand.
  • services/voyageService.ts hits the nested REST routes voyages/{voyageLinkId}/{entity}/. services/voyagesLinksService.ts hits voyages/.

Conventions

  • Prettier: no semicolons (.prettierrc"semi": false). ESLint via withNuxt (eslint.config.mjs).
  • TS interface fields are camelCase; note the backend (DRF) serializes snake_case (postal_address, proposed_by, start_date) — there is no auto-mapping yet, so some types in types/index.ts are inconsistent with the wire format. Check the actual JSON when wiring new fields.
  • User-facing strings go through $t() / i18n; don't hardcode.

State of the code

Early WIP. VoyageMap.vue is a stub. Some store/service methods (update/delete voyage) are commented out. No tests yet.