About
Coding Standards
Conventions for readable, consistent code across the Nucleify monorepo. When in doubt, match surrounding files in the package you are editing.
Monorepo structure
nucleify/
├── web/ # @nucleify/web — Nuxt landing
├── admin/ # @nucleify/admin — Nuxt admin
├── docs/ # @nucleify/docs — Astro docs
├── compiler/ # @nucleify/compiler — portable UI compiler
├── shared_modules/ # six exported nuc_* feature modules
├── portable/nui/ # design tokens
├── overrides/ # per-package file overrides
├── supabase/ # merged DB config
└── .config/ # shared toolingCanonical product paths: web/src/ (not root modules/ or nuxt/ as srcDir). UI primitives are nui-*, not an ad-* tree. Auth lives in nuc_api.
Package commands
| Package | Dev command |
|---|---|
web/ |
make web or pnpm dev |
admin/ |
make admin or pnpm admin |
docs/ |
make docs or pnpm docs |
compiler/ |
make compiler |
Bootstrap: make run. Product shell: make web. (make nuxt / make next / … are portable emit demos, not the product app.)
Shared module structure
shared_modules/nuc_example/
├── config.json
├── nuc_example.ts # registerNucExample (Vue plugin)
├── index.ts # Vue barrel
├── index.react.ts # React barrel (when needed)
├── _index.scss
├── supabase/api/handle.ts
├── constants/
├── types/
├── utils/
├── components/ # optional
└── vitests/Import rules:
- Inside modules: relative imports only
- Never import from
web/,admin/, ordocs/inside modules - Never
import from 'nucleify'inside modules (circular) - Apps import via
modules/…alias or explicitshared_modules/…paths
Web app structure
web/src/
├── pages/[lang]/ # thin i18n wrappers
├── pages/home/ # landing composition
├── plugins/modules.ts # registerNuc*
├── composables/ # app-specific only
├── layouts/
├── assets/ # SCSS entry
├── nucleify.ts # re-exports
└── server/api/[...slug].ts # gateway- Vue SFCs:
<script setup lang="ts"> - UI:
nui-*fromnucleify-ui - Domain logic:
shared_modules/, notweb/src/
File and folder naming
| Kind | Convention | Example |
|---|---|---|
| Vue SFC | PascalCase | NucHomeHero.vue |
| Composable | use_ + snake_case |
use_dark_mode.ts |
| React hook sibling | .react.ts |
use_dark_mode.react.ts |
| Portable component | PascalCase + .nuc.tsx |
Counter.nuc.tsx |
| Utils | snake_case | api_request.ts |
| Types | snake_case files | interfaces.ts, variables.ts |
| Tests | *.test.ts in vitests/ |
darken_color.test.ts |
| SCSS partials | _name.scss |
_mixins.scss |
TypeScript
- Strict typing — avoid
anyunless Nuxt config forces it (document with biome-ignore) - Export types from
types/— do not duplicate interfaces across files - Use
.react.tstype siblings when React props diverge from Vue
Vue components
<script setup lang="ts">
import { ref } from 'vue'
import type { SomeType } from 'modules/nuc_example/types/interfaces'
const props = defineProps<{ id: string }>()
const open = ref(false)
</script>
<template>
<nui-button @click="open = !open">{{ props.id }}</nui-button>
</template>- Prefer composition API with
<script setup> - Use
nui-*for primitives; module components for domain UI
Portable components
Author in *.nuc.tsx per compiler/PORTABLE.md:
- No stores, routers, or Supabase inside portable files
- Props + events only for external coupling
- Run
pnpm compiler:buildafter changes; commit authoring + emit - Import edits:
pnpm compiler -- import --from=vue|react
API handlers
- Entry:
handle.tsexportshandle*Api - Register in
shared_modules/nuc_api/supabase/api/gateway_dispatch.ts - Return
apiNotHandled()for non-matching prefixes - Use
withGatewayUserfor authenticated routes - Enable RLS on exposed tables
SCSS
- Module styles:
shared_modules/nuc_*/styles/ - App entry imports module
_index.scssfiles - Lint:
pnpm slint
Testing
- Module tests:
shared_modules/nuc_*/vitests/ - Nuxt tests:
web/vitests/ - Run
pnpm testsbefore commit - Meaningful behavior tests — avoid asserting implementation details
Lint & format
pnpm check # Biome (lint + format check)
pnpm write # Biome auto-fix
pnpm typeslint # tsc --noEmit -p web/tsconfig.json
pnpm slint # Stylelint on SCSS
pnpm tests # VitestHusky runs these on pre-commit via .config/bash/hook-checks.sh (pre-push is a no-op).
Git & commits
- Focused commits — one concern per change when possible
- Do not commit
.env, emit demos (vue/demo, etc.), or*.ir.json - Follow existing commit message style in the repo
Cursor rules & agents
- Monorepo rules:
.cursor/rules/ - Package rules:
{pkg}/.config/rules/ - Sync:
pnpm sync-rules - Feature workflow agents:
web/.cursor/agents/
Related docs
Root reference: CODE_STANDARDS.md in the repository (keep in sync with this page).