Core Concepts
Modules
Nucleify dostarcza sześć eksportowanych modułów funkcjonalnych z @nucleify/shared-modules. Każdy to samodzielny pakiet domenowy z narzędziami frontendowymi, opcjonalnymi handlerami API Supabase, migracjami, typami i testami — konsumowany przez web/, admin/, docs/ i generowane shelle (Next, Solid, …), żeby migrować frameworki bez przepisywania biznesu.
Nie ma katalogu modules/ w root. Aplikacje importują przez ścieżki względne lub alias Nuxt modules → shared_modules/. Flow auth żyje w nuc_api (nie ma osobnego nuc_users / nuc_auth).
Moduły
| Moduł | Domena | Kluczowe ścieżki |
|---|---|---|
nuc_api |
Klient API, dispatch gateway, formularze auth, requesty encji, toasty | supabase/api/gateway_dispatch.ts, utils/api_request.ts |
nuc_colors |
System motywów/kolorów, zmienne SCSS, utils kolorów | styles/, supabase/api/handle.ts |
nuc_dark_mode |
Preferencja trybu ciemnego (load, persist, apply) | utils/use_dark_mode.ts, nuc_dark_mode.ts |
nuc_globals |
Media queries, helpery obrazów, globalne style, wspólne typy | media/, styles/, nuc_globals.ts |
nuc_languages |
i18n, komunikaty locale, API tłumaczeń | plugins/nuc_translations.ts, supabase/api/handle.ts |
nuc_stores |
Helpery Pinia/Zustand, utils cookie/localStorage/session | pinia/, zustand/, cookie/ |
Te sześć jest w shared_modules/index.ts i w exports w package.json. Inne foldery pod shared_modules/ bez publicznego barrela nie są jeszcze częścią wspieranego API.
Anatomia modułu
Każdy katalog nuc_* ma spójny układ:
shared_modules/nuc_example/
├── config.json # name, version, category, enabled
├── nuc_example.ts # plugin Vue (registerNucExample)
├── index.ts # barrel export Vue
├── index.react.ts # barrel export React (gdy potrzebny)
├── _index.scss # opcjonalne globalne style modułu
├── README.md
├── constants/
├── types/
│ ├── interfaces.ts
│ ├── interfaces.react.ts # gdy typy React się różnią
│ └── variables.ts
├── utils/ # composables, hooki, funkcje czyste
├── components/ # opcjonalne UI wielokrotnego użytku
├── supabase/
│ ├── api/
│ │ ├── handle.ts # wejście gateway (handleExampleApi)
│ │ └── *_handlers.ts # tabele tras
│ ├── migrations/
│ ├── factories/
│ └── seeders/
└── vitests/Rejestracja w Nuxt
web/src/plugins/modules.ts rejestruje cztery moduły przy starcie aplikacji:
import { registerNucColors } from '../../../shared_modules/nuc_colors/nuc_colors'
import { registerNucDarkMode } from '../../../shared_modules/nuc_dark_mode/nuc_dark_mode'
import { registerNucGlobals } from '../../../shared_modules/nuc_globals/nuc_globals'
import { registerNucLanguages } from '../../../shared_modules/nuc_languages/nuc_languages'
export default defineNuxtPlugin({
name: 'modules-registration',
enforce: 'pre',
setup(nuxtApp) {
registerNucGlobals(nuxtApp.vueApp)
registerNucColors(nuxtApp.vueApp)
registerNucDarkMode(nuxtApp.vueApp)
registerNucLanguages(nuxtApp)
},
})nuc_api i nuc_stores są importowane na żądanie — bez globalnego pluginu.
Tłumaczenia ładują się też przez ścieżkę pluginu Nuxt w konfiguracji:
// web/.config/nuxt/structure.ts
plugins: [
resolve(process.cwd(), '../shared_modules/nuc_languages/plugins/nuc_translations.ts'),
],Zasady importów
Wewnątrz modułu — tylko importy względne. Nigdy z web/, admin/ ani docs/.
Z aplikacji — alias lub ścieżka względna:
// przez alias (Nuxt)
import { useDarkMode } from 'modules/nuc_dark_mode/utils/use_dark_mode'
// jawna względna (też OK)
import { apiRequest } from '../../../shared_modules/nuc_api/utils/api_request'Publiczne API — eksport przez index.ts i root barrel shared_modules/index.ts. Nie importuj from 'nucleify' w modułach (zależność cykliczna).
Integracja z bramką API
Handlery modułów eksportują async handle*Api(ctx). Zarejestruj w rejestrze gateway:
// shared_modules/nuc_api/supabase/api/gateway_dispatch.ts
export const supabaseApiGatewayHandlers = [
handleColorsApi,
handleLanguagesApi,
] as constPunkt wejścia Nitro:
web/src/server/api/[...slug].ts
→ parseApiSlug()
→ dispatchSupabaseApiGateway(ctx)
→ pierwszy handler gdzie result.handled === trueWzorzec handlera
import { apiMethodNotAllowed, apiNotHandled, withGatewayUser } from 'nuc_api'
import type { ApiContext, ApiHandlerResult } from 'nuc_server'
export async function handleExampleApi(ctx: ApiContext): Promise<ApiHandlerResult> {
if (ctx.segments[0] !== 'example') return apiNotHandled()
return withGatewayUser(ctx, async (gatewayCtx, userId) => {
// dispatch tablicy tras …
return apiMethodNotAllowed()
})
}Kod klienta woła /api/example/... przez helpery request nuc_api — nie service keys Supabase w przeglądarce.
Supabase per moduł
Każdy moduł może mieć własne artefakty SQL:
| Katalog | Cel |
|---|---|
supabase/migrations/ |
Zmiany schematu |
supabase/factories/ |
SQL factory test/dev |
supabase/seeders/ |
Dane seed |
Lokalnie:
pnpm supabase:migrations:apply:local
pnpm supabase:seeders:apply:local
# lub razem:
pnpm supabase:setup:localSkrypty scalają SQL modułów przez .config/bash/merge-module-supabase-sql.sh.
Warianty React
Moduły wspierające Tryb B eksponują odpowiedniki .react.ts:
index.react.ts— barrel Reactutils/use_*.react.ts— hooki React odzwierciedlające composables Vuetypes/interfaces.react.ts— typy React gdy potrzebne
Kompilator i convert produktu używają ich przy emisji powłok Next.
Tworzenie nowego modułu
- Skopiuj strukturę z istniejącego modułu
nuc_* - Dodaj metadane
config.json - Zaimplementuj
nuc_example.tszregisterNucExample - Eksportuj publiczne API z
index.ts - Dodaj do
shared_modules/index.tsjeśli potrzebne globalnie - Zarejestruj plugin w
web/src/plugins/modules.tsjeśli wymaga setupu app-wide - Dodaj handler gateway w
gateway_dispatch.tsjeśli eksponuje trasy API - Dodaj
vitests/i uruchompnpm test:shared
Zob. Feature-Sliced Design dla uzasadnienia architektonicznego.
Powiązane docs
- Feature-Sliced Design
- Supabase
- Nadpisywanie — patch modułów bez edycji upstream