docs/agents/portal-code-style.md
Portal Conventions
Nuxt 3 SSR app. Vue 3 Composition API, TanStack Query, Pinia, shadcn-nuxt, Tailwind, i18n, Supabase.
Portal Conventions
Nuxt 3 SSR app. Vue 3 Composition API, TanStack Query, Pinia, shadcn-nuxt, Tailwind, i18n, Supabase.
SSR & Hydration
- Write SSR-friendly code: no
window/document/localStoragewithoutonMountedor<ClientOnly> - Never cause hydration errors
Auto-Imports
- Never import from
#components- Nuxt auto-imports all (check.nuxt/components.d.ts) - Exception: multiple
<script>tags require explicit imports
Translations
- NO dynamic keys - use static strings:
t('key.subkey') - Component-specific: local
<i18n>blocks - Composables: pass
tfunction as param, add to globali18n/*.json - Respect translation rules in
../../.cursor/rules/translations.mdc
Type Safety
- No
as unknown,as any,@ts-ignore- fix at source - Use Zod for validation of JSON objects
Code Quality
- Before complex tasks: analyze context, ask questions
- After changes: verify existing flows work, consolidate logic (merge computed/props/emits), rename if purpose changes
<script setup lang="ts">only, Composition API, prefix unused vars with_- Respect Nuxt naming: composables
useX, storesuseXStore, files in correct dirs (middleware/, plugins/, utils/)
Control Flow
- Avoid Vue watchers by default. Prefer render precedence, computed state, events, or lifecycle hooks. If a watcher is needed, prefer VueUse helpers where applicable.
API Calls
- Use
callEdgeFunctionwrapper:callEdgeFunction(() => honoClient.api.endpoint.$post()) - Access via
useHonoClient()composable
Async Buttons
- Wrap in
useMutation, useisPendingto disable button
Styling
- Use
cn()for class composition - NEVER hard code colors, use Tailwind tokens only