create-kuckit-app 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/bin.js +1 -1
  2. package/dist/{create-project-DTm05G7D.js → create-project-CP-h4Ygi.js} +7 -5
  3. package/dist/index.js +1 -1
  4. package/package.json +3 -2
  5. package/templates/base/.claude/CLAUDE.md +44 -0
  6. package/templates/base/.claude/agents/daidalos.md +76 -0
  7. package/templates/base/.claude/agents/episteme.md +79 -0
  8. package/templates/base/.claude/agents/librarian.md +132 -0
  9. package/templates/base/.claude/agents/oracle.md +210 -0
  10. package/templates/base/.claude/commands/create-plan.md +159 -0
  11. package/templates/base/.claude/commands/file-beads.md +98 -0
  12. package/templates/base/.claude/commands/review-beads.md +161 -0
  13. package/templates/base/.claude/settings.json +11 -0
  14. package/templates/base/.claude/skills/kuckit/SKILL.md +436 -0
  15. package/templates/base/.claude/skills/kuckit/references/ARCHITECTURE.md +388 -0
  16. package/templates/base/.claude/skills/kuckit/references/CLI-COMMANDS.md +365 -0
  17. package/templates/base/.claude/skills/kuckit/references/MODULE-DEVELOPMENT.md +581 -0
  18. package/templates/base/.claude/skills/kuckit/references/PACKAGES.md +112 -0
  19. package/templates/base/.claude/skills/kuckit/references/PUBLISHING.md +231 -0
  20. package/templates/base/.env.example +13 -0
  21. package/templates/base/.github/workflows/ci.yml +28 -0
  22. package/templates/base/.husky/pre-commit +1 -0
  23. package/templates/base/.prettierignore +5 -0
  24. package/templates/base/.prettierrc +8 -0
  25. package/templates/base/AGENTS.md +351 -0
  26. package/templates/base/apps/server/.env.example +18 -0
  27. package/templates/base/apps/server/AGENTS.md +93 -0
  28. package/templates/base/apps/server/package.json +13 -2
  29. package/templates/base/apps/server/src/app.ts +20 -0
  30. package/templates/base/apps/server/src/auth.ts +10 -0
  31. package/templates/base/apps/server/src/config/modules.ts +22 -0
  32. package/templates/base/apps/server/src/container.ts +81 -0
  33. package/templates/base/apps/server/src/health.ts +27 -0
  34. package/templates/base/apps/server/src/middleware/container.ts +41 -0
  35. package/templates/base/apps/server/src/rpc-router-registry.ts +26 -0
  36. package/templates/base/apps/server/src/rpc.ts +31 -0
  37. package/templates/base/apps/server/src/server.ts +42 -14
  38. package/templates/base/apps/web/.env.example +4 -0
  39. package/templates/base/apps/web/AGENTS.md +127 -0
  40. package/templates/base/apps/web/index.html +1 -1
  41. package/templates/base/apps/web/package.json +15 -2
  42. package/templates/base/apps/web/src/components/KuckitModuleRoute.tsx +82 -0
  43. package/templates/base/apps/web/src/lib/kuckit-router.ts +42 -0
  44. package/templates/base/apps/web/src/main.tsx +26 -14
  45. package/templates/base/apps/web/src/modules.client.ts +4 -3
  46. package/templates/base/apps/web/src/providers/KuckitProvider.tsx +147 -0
  47. package/templates/base/apps/web/src/providers/ServicesProvider.tsx +47 -0
  48. package/templates/base/apps/web/src/routeTree.gen.ts +91 -0
  49. package/templates/base/apps/web/src/routes/$.tsx +14 -0
  50. package/templates/base/apps/web/src/routes/__root.tsx +31 -0
  51. package/templates/base/apps/web/src/routes/index.tsx +46 -0
  52. package/templates/base/apps/web/src/routes/login.tsx +108 -0
  53. package/templates/base/apps/web/src/services/auth-client.ts +12 -0
  54. package/templates/base/apps/web/src/services/index.ts +3 -0
  55. package/templates/base/apps/web/src/services/rpc.ts +29 -0
  56. package/templates/base/apps/web/src/services/types.ts +14 -0
  57. package/templates/base/apps/web/tsconfig.json +5 -1
  58. package/templates/base/apps/web/vite.config.ts +8 -1
  59. package/templates/base/docker-compose.yml +23 -0
  60. package/templates/base/eslint.config.js +18 -0
  61. package/templates/base/package.json +32 -2
  62. package/templates/base/packages/api/AGENTS.md +66 -0
  63. package/templates/base/packages/api/package.json +35 -0
  64. package/templates/base/packages/api/src/context.ts +48 -0
  65. package/templates/base/packages/api/src/index.ts +22 -0
  66. package/templates/base/packages/api/tsconfig.json +8 -0
  67. package/templates/base/packages/auth/AGENTS.md +61 -0
  68. package/templates/base/packages/auth/package.json +27 -0
  69. package/templates/base/packages/auth/src/index.ts +22 -0
  70. package/templates/base/packages/auth/tsconfig.json +8 -0
  71. package/templates/base/packages/db/AGENTS.md +74 -0
  72. package/templates/base/packages/db/drizzle.config.ts +19 -0
  73. package/templates/base/packages/db/package.json +36 -0
  74. package/templates/base/packages/db/src/connection.ts +40 -0
  75. package/templates/base/packages/db/src/index.ts +4 -0
  76. package/templates/base/packages/db/src/migrations/0000_init.sql +54 -0
  77. package/templates/base/packages/db/src/migrations/meta/_journal.json +13 -0
  78. package/templates/base/packages/db/src/schema/auth.ts +51 -0
  79. package/templates/base/packages/db/tsconfig.json +8 -0
  80. package/templates/base/packages/items-module/AGENTS.md +210 -0
  81. package/templates/base/packages/items-module/package.json +32 -0
  82. package/templates/base/packages/items-module/src/adapters/item.drizzle.ts +66 -0
  83. package/templates/base/packages/items-module/src/api/items.router.ts +47 -0
  84. package/templates/base/packages/items-module/src/client-module.ts +39 -0
  85. package/templates/base/packages/items-module/src/domain/item.entity.ts +36 -0
  86. package/templates/base/packages/items-module/src/index.ts +15 -0
  87. package/templates/base/packages/items-module/src/module.ts +53 -0
  88. package/templates/base/packages/items-module/src/ports/item.repository.ts +13 -0
  89. package/templates/base/packages/items-module/src/ui/ItemsPage.tsx +144 -0
  90. package/templates/base/packages/items-module/src/usecases/create-item.ts +25 -0
  91. package/templates/base/packages/items-module/src/usecases/delete-item.ts +18 -0
  92. package/templates/base/packages/items-module/src/usecases/get-item.ts +19 -0
  93. package/templates/base/packages/items-module/src/usecases/list-items.ts +21 -0
  94. package/templates/base/packages/items-module/tsconfig.json +9 -0
  95. package/templates/base/turbo.json +13 -1
  96. package/templates/base/apps/web/src/App.tsx +0 -16
@@ -0,0 +1,93 @@
1
+ # AGENTS.md - Server App
2
+
3
+ > See root [AGENTS.md](../../AGENTS.md) for SDK Module System patterns
4
+
5
+ ## Purpose
6
+
7
+ Express backend hosting oRPC API, Better-Auth authentication, and the Kuckit module system.
8
+
9
+ ## Key Files
10
+
11
+ | File | Purpose |
12
+ | ------------------------ | -------------------------- |
13
+ | `server.ts` | Entry point, bootstrap |
14
+ | `container.ts` | DI container setup |
15
+ | `config/modules.ts` | Module registration |
16
+ | `rpc.ts` | oRPC handler setup |
17
+ | `rpc-router-registry.ts` | Mutable router for modules |
18
+ | `auth.ts` | Better-Auth configuration |
19
+
20
+ ## Module Loading Sequence
21
+
22
+ The server bootstraps in this order:
23
+
24
+ ```
25
+ 1. createKuckitContainer() - Core services (db, logger, cache, etc.)
26
+ 2. loadKuckitModules() with onApiRegistrations callback:
27
+ ├─► register() hooks run (DI bindings)
28
+ ├─► registerApi() hooks run (routers collected)
29
+ ├─► onApiRegistrations() - Wire routers to rootRpcRouter
30
+ └─► onBootstrap() hooks run (startup logic)
31
+ 3. setupRPC() - Create RPCHandler AFTER modules loaded
32
+ 4. Express listens
33
+ ```
34
+
35
+ ## Router Registry Pattern
36
+
37
+ oRPC's `RPCHandler` captures the router at construction time. Modules wire their routers into a **mutable object** before the handler is created:
38
+
39
+ ```typescript
40
+ // rpc-router-registry.ts
41
+ export const rootRpcRouter = { ...appRouter }
42
+
43
+ export const wireModuleRpcRouters = (registrations: ApiRegistration[]) => {
44
+ for (const reg of registrations) {
45
+ if (reg.type === 'rpc-router') {
46
+ rootRpcRouter[reg.name] = reg.router
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ ```typescript
53
+ // server.ts
54
+ await loadKuckitModules({
55
+ container,
56
+ modules: getModuleSpecs(),
57
+ onApiRegistrations: (registrations) => {
58
+ wireModuleRpcRouters(registrations) // Wire BEFORE setupRPC()
59
+ },
60
+ })
61
+
62
+ setupRPC(app) // Now create handler with fully-wired router
63
+ ```
64
+
65
+ ## Per-Request Scoping
66
+
67
+ Each HTTP request gets a scoped container with:
68
+
69
+ - `requestId` - Unique request identifier
70
+ - `requestLogger` - Logger with request context
71
+ - `session` - Current user session (if authenticated)
72
+
73
+ Access scoped services in routers via `context.di.cradle`.
74
+
75
+ ## Adding New Modules
76
+
77
+ 1. Install the module package
78
+ 2. Add to `config/modules.ts`:
79
+
80
+ ```typescript
81
+ import { kuckitModule as myModule } from '@__APP_NAME_KEBAB__/my-module'
82
+
83
+ export const getModuleSpecs = () => [
84
+ { module: itemsModule },
85
+ { module: myModule }, // Add here
86
+ ]
87
+ ```
88
+
89
+ 3. Restart the server
90
+
91
+ ## Environment Variables
92
+
93
+ See `.env.example` in this directory.
@@ -1,5 +1,6 @@
1
1
  {
2
- "name": "__APP_NAME_KEBAB__-server",
2
+ "name": "@__APP_NAME_KEBAB__/server",
3
+ "private": true,
3
4
  "type": "module",
4
5
  "scripts": {
5
6
  "build": "tsdown",
@@ -10,11 +11,21 @@
10
11
  "express": "^5.1.0",
11
12
  "cors": "^2.8.5",
12
13
  "dotenv": "^17.2.2",
13
- "awilix": "^12.0.5"
14
+ "awilix": "^12.0.5",
15
+ "pg": "^8.14.1",
16
+ "@orpc/server": "^1.10.0",
17
+ "@orpc/zod": "^1.10.0",
18
+ "better-auth": "^1.3.28",
19
+ "zod": "^4.1.11",
20
+ "@kuckit/sdk": "^1.0.0",
21
+ "@__APP_NAME_KEBAB__/api": "workspace:*",
22
+ "@__APP_NAME_KEBAB__/auth": "workspace:*",
23
+ "@__APP_NAME_KEBAB__/db": "workspace:*"
14
24
  },
15
25
  "devDependencies": {
16
26
  "@types/express": "^5.0.1",
17
27
  "@types/cors": "^2.8.17",
28
+ "@types/pg": "^8.11.11",
18
29
  "typescript": "^5.8.2",
19
30
  "tsdown": "^0.15.5"
20
31
  }
@@ -0,0 +1,20 @@
1
+ import express, { type Express } from 'express'
2
+ import cors from 'cors'
3
+
4
+ /**
5
+ * Create and configure Express app
6
+ */
7
+ export const createApp = (): Express => {
8
+ const app = express()
9
+
10
+ app.use(
11
+ cors({
12
+ origin: process.env.CORS_ORIGIN || 'http://localhost:3001',
13
+ methods: ['GET', 'POST', 'OPTIONS'],
14
+ allowedHeaders: ['Content-Type', 'Authorization'],
15
+ credentials: true,
16
+ })
17
+ )
18
+
19
+ return app
20
+ }
@@ -0,0 +1,10 @@
1
+ import { auth } from '@__APP_NAME_KEBAB__/auth'
2
+ import { toNodeHandler } from 'better-auth/node'
3
+ import type { Express } from 'express'
4
+
5
+ /**
6
+ * Setup Better-Auth routes
7
+ */
8
+ export const setupAuth = (app: Express) => {
9
+ app.all('/api/auth{/*path}', toNodeHandler(auth))
10
+ }
@@ -0,0 +1,22 @@
1
+ import type { ModuleSpec } from '@kuckit/sdk'
2
+
3
+ // Import your modules here
4
+ // import { kuckitModule as itemsModule } from '@__APP_NAME_KEBAB__/items-module'
5
+
6
+ /**
7
+ * Module specifications for the server application
8
+ *
9
+ * Add modules here to configure the server's functionality.
10
+ * Modules are loaded in order, with dependencies resolved automatically.
11
+ */
12
+ export const getModuleSpecs = (): ModuleSpec[] => {
13
+ const modules: ModuleSpec[] = [
14
+ // Add your modules here:
15
+ // {
16
+ // module: itemsModule,
17
+ // config: { ... },
18
+ // },
19
+ ]
20
+
21
+ return modules
22
+ }
@@ -0,0 +1,81 @@
1
+ import type { AwilixContainer } from 'awilix'
2
+ import {
3
+ createKuckitContainer,
4
+ loadKuckitModules,
5
+ type CoreConfig,
6
+ type CoreCradle,
7
+ } from '@kuckit/sdk'
8
+ import type { Pool } from 'pg'
9
+ import { ensureDatabaseUrl } from '@__APP_NAME_KEBAB__/db/connection'
10
+ import { getModuleSpecs } from './config/modules'
11
+ import { wireModuleRpcRouters } from './rpc-router-registry'
12
+
13
+ /**
14
+ * Server configuration
15
+ */
16
+ export interface ServerConfig extends CoreConfig {
17
+ port: number
18
+ corsOrigin: string
19
+ }
20
+
21
+ /**
22
+ * Server DI container cradle
23
+ */
24
+ export interface ServerCradle extends CoreCradle {
25
+ config: ServerConfig
26
+ dbPool: Pool
27
+ }
28
+
29
+ export type AppContainer = AwilixContainer<ServerCradle>
30
+ export type { ServerConfig as Config, ServerCradle as Cradle }
31
+
32
+ /**
33
+ * Load configuration from environment
34
+ */
35
+ const loadConfig = (): ServerConfig => {
36
+ const databaseUrl = ensureDatabaseUrl()
37
+
38
+ return {
39
+ databaseUrl,
40
+ enableFileLogging: process.env.ENABLE_FILE_LOGGING === 'true',
41
+ logDir: process.env.LOG_DIR || './logs',
42
+ logLevel: (process.env.LOG_LEVEL || 'INFO') as 'DEBUG' | 'INFO' | 'WARN' | 'ERROR',
43
+ env: process.env.NODE_ENV || 'development',
44
+ port: parseInt(process.env.PORT || '3000', 10),
45
+ corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3001',
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Build root container with all modules
51
+ */
52
+ export const buildRootContainer = async (): Promise<AppContainer> => {
53
+ const config = loadConfig()
54
+
55
+ const container = await createKuckitContainer({ config })
56
+
57
+ await loadKuckitModules({
58
+ container,
59
+ env: config.env,
60
+ modules: getModuleSpecs(),
61
+ onApiRegistrations: (registrations) => {
62
+ wireModuleRpcRouters(registrations)
63
+ console.log(`Loaded ${registrations.length} API registrations from modules`)
64
+ },
65
+ onComplete: () => {
66
+ console.log('All modules loaded successfully')
67
+ },
68
+ })
69
+
70
+ return container as AppContainer
71
+ }
72
+
73
+ /**
74
+ * Cleanup container resources
75
+ */
76
+ export const disposeContainer = async (container: AppContainer): Promise<void> => {
77
+ const { dbPool } = container.cradle
78
+ if (dbPool && typeof dbPool.end === 'function') {
79
+ await dbPool.end()
80
+ }
81
+ }
@@ -0,0 +1,27 @@
1
+ import type { Express } from 'express'
2
+ import type { AppContainer } from './container'
3
+
4
+ export const setupHealth = (app: Express, container: AppContainer) => {
5
+ app.get('/health', async (_req, res) => {
6
+ const { dbPool } = container.cradle
7
+
8
+ try {
9
+ const client = await dbPool.connect()
10
+ await client.query('SELECT 1')
11
+ client.release()
12
+
13
+ res.status(200).json({
14
+ status: 'healthy',
15
+ timestamp: new Date().toISOString(),
16
+ checks: { database: 'ok' },
17
+ })
18
+ } catch (error) {
19
+ console.error('[Health] Database check failed:', error)
20
+ res.status(503).json({
21
+ status: 'unhealthy',
22
+ timestamp: new Date().toISOString(),
23
+ checks: { database: 'failed' },
24
+ })
25
+ }
26
+ })
27
+ }
@@ -0,0 +1,41 @@
1
+ import type { Express, Request, Response, NextFunction } from 'express'
2
+ import { asValue } from 'awilix'
3
+ import { buildRootContainer, type AppContainer } from '../container'
4
+
5
+ let rootContainer: AppContainer
6
+
7
+ /**
8
+ * Initialize and setup container middleware
9
+ * Must be awaited before using the container
10
+ */
11
+ export const setupContainerMiddleware = async (app: Express): Promise<void> => {
12
+ rootContainer = await buildRootContainer()
13
+
14
+ app.use((req: Request, res: Response, next: NextFunction) => {
15
+ req.scope = rootContainer.createScope()
16
+
17
+ req.scope.register({
18
+ requestId: asValue(crypto.randomUUID()),
19
+ })
20
+
21
+ res.on('finish', () => {
22
+ req.scope?.dispose()
23
+ })
24
+
25
+ res.on('close', () => {
26
+ req.scope?.dispose()
27
+ })
28
+
29
+ next()
30
+ })
31
+ }
32
+
33
+ /**
34
+ * Get root container (for graceful shutdown)
35
+ */
36
+ export const getRootContainer = (): AppContainer => {
37
+ if (!rootContainer) {
38
+ throw new Error('Container not initialized')
39
+ }
40
+ return rootContainer
41
+ }
@@ -0,0 +1,26 @@
1
+ import type { ApiRegistration } from '@kuckit/sdk'
2
+
3
+ /**
4
+ * Central mutable RPC router object used by RPCHandler.
5
+ *
6
+ * Module routers are wired into this object during the SDK loader's
7
+ * "wire" phase, before RPCHandler is instantiated.
8
+ */
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ export const rootRpcRouter: Record<string, any> = {}
11
+
12
+ /**
13
+ * Wire module RPC routers into the central router object.
14
+ * Called from the SDK loader's onApiRegistrations callback.
15
+ */
16
+ export const wireModuleRpcRouters = (registrations: ApiRegistration[]): void => {
17
+ for (const reg of registrations) {
18
+ if (reg.type !== 'rpc-router') continue
19
+
20
+ if (rootRpcRouter[reg.name]) {
21
+ throw new Error(`Duplicate RPC router name: "${reg.name}"`)
22
+ }
23
+
24
+ rootRpcRouter[reg.name] = reg.router
25
+ }
26
+ }
@@ -0,0 +1,31 @@
1
+ import { RPCHandler } from '@orpc/server/node'
2
+ import { onError } from '@orpc/server'
3
+ import { createContext } from '@__APP_NAME_KEBAB__/api'
4
+ import type { Express } from 'express'
5
+ import { rootRpcRouter } from './rpc-router-registry'
6
+
7
+ /**
8
+ * Setup oRPC handler
9
+ *
10
+ * IMPORTANT: This must be called AFTER setupContainerMiddleware() has completed,
11
+ * which ensures all module routers have been wired into rootRpcRouter.
12
+ */
13
+ export const setupRPC = (app: Express) => {
14
+ const rpcHandler = new RPCHandler(rootRpcRouter, {
15
+ interceptors: [
16
+ onError((error) => {
17
+ console.error('[RPC Error]', error)
18
+ }),
19
+ ],
20
+ })
21
+
22
+ app.use(async (req, res, next) => {
23
+ const result = await rpcHandler.handle(req, res, {
24
+ prefix: '/rpc',
25
+ context: await createContext({ req }),
26
+ })
27
+
28
+ if (result.matched) return
29
+ next()
30
+ })
31
+ }
@@ -1,21 +1,49 @@
1
1
  import 'dotenv/config'
2
- import express from 'express'
3
- import cors from 'cors'
2
+ import { createApp } from './app'
3
+ import { setupContainerMiddleware, getRootContainer } from './middleware/container'
4
+ import { setupAuth } from './auth'
5
+ import { setupRPC } from './rpc'
6
+ import { setupHealth } from './health'
7
+ import { disposeContainer } from './container'
4
8
 
5
- const app = express()
6
- const port = process.env.PORT ?? 3000
9
+ /**
10
+ * Bootstrap and start server
11
+ */
12
+ const bootstrap = async () => {
13
+ const app = createApp()
7
14
 
8
- app.use(cors())
9
- app.use(express.json())
15
+ await setupContainerMiddleware(app)
16
+ const rootContainer = getRootContainer()
10
17
 
11
- // Health check
12
- app.get('/health', (_req, res) => {
13
- res.json({ status: 'ok' })
14
- })
18
+ setupAuth(app)
19
+ setupRPC(app)
20
+ setupHealth(app, rootContainer)
21
+
22
+ const port = process.env.PORT || 3000
23
+ const server = app.listen(port, () => {
24
+ console.log(`Server is running on port ${port}`)
25
+ })
26
+
27
+ const shutdown = async () => {
28
+ console.log('Shutting down gracefully...')
29
+
30
+ server.close(async () => {
31
+ await disposeContainer(rootContainer)
32
+ console.log('Server closed')
33
+ process.exit(0)
34
+ })
35
+
36
+ setTimeout(() => {
37
+ console.error('Forced shutdown')
38
+ process.exit(1)
39
+ }, 10000)
40
+ }
15
41
 
16
- // TODO: Kuckit SDK integration will be added in future version
17
- // See: https://kuckit.dev/docs/getting-started
42
+ process.on('SIGTERM', shutdown)
43
+ process.on('SIGINT', shutdown)
44
+ }
18
45
 
19
- app.listen(port, () => {
20
- console.log(`Server running at http://localhost:${port}`)
46
+ bootstrap().catch((error) => {
47
+ console.error('Failed to start server:', error)
48
+ process.exit(1)
21
49
  })
@@ -0,0 +1,4 @@
1
+ # Web Environment Variables
2
+
3
+ # API URL for the backend server
4
+ VITE_API_URL=http://localhost:3000
@@ -0,0 +1,127 @@
1
+ # AGENTS.md - Web App
2
+
3
+ > See root [AGENTS.md](../../AGENTS.md) for SDK Module System patterns
4
+
5
+ ## Purpose
6
+
7
+ React frontend using TanStack Router, TanStack Query, and Kuckit client modules.
8
+
9
+ ## Key Files
10
+
11
+ | File | Purpose |
12
+ | ---------------------------------- | --------------------------------- |
13
+ | `main.tsx` | App entry point |
14
+ | `modules.client.ts` | Client module registration |
15
+ | `providers/KuckitProvider.tsx` | Kuckit context setup |
16
+ | `providers/ServicesProvider.tsx` | Services context (RPC, auth) |
17
+ | `routes/` | TanStack Router file-based routes |
18
+ | `routes/$.tsx` | Catch-all for module routes |
19
+ | `components/KuckitModuleRoute.tsx` | Renders module-registered routes |
20
+
21
+ ## Adding Routes
22
+
23
+ Create files in `src/routes/`:
24
+
25
+ - `src/routes/about.tsx` → `/about`
26
+ - `src/routes/users/$id.tsx` → `/users/:id`
27
+ - `src/routes/settings/index.tsx` → `/settings`
28
+
29
+ **File-based routes take precedence** over module-registered routes.
30
+
31
+ ## Module Route Integration
32
+
33
+ Modules register routes via `defineKuckitClientModule`. These are rendered via a catch-all pattern:
34
+
35
+ 1. Module registers route in `routes` array
36
+ 2. `RouteRegistry` collects routes during `loadKuckitClientModules()`
37
+ 3. Catch-all route (`$.tsx`) matches any unhandled path
38
+ 4. `KuckitModuleRoute` looks up path in registry and renders the component
39
+
40
+ ```tsx
41
+ // routes/$.tsx - Catches module routes
42
+ import { KuckitModuleRoute } from '@/components/KuckitModuleRoute'
43
+
44
+ export function Route() {
45
+ return <KuckitModuleRoute />
46
+ }
47
+ ```
48
+
49
+ ## Context Providers
50
+
51
+ The app wraps content in Kuckit providers:
52
+
53
+ ```tsx
54
+ <ServicesProvider>
55
+ {' '}
56
+ {/* RPC client, auth */}
57
+ <KuckitProvider>
58
+ {' '}
59
+ {/* Nav, slots, routes registries */}
60
+ <KuckitRpcProvider>
61
+ {' '}
62
+ {/* RPC context for modules */}
63
+ {children}
64
+ </KuckitRpcProvider>
65
+ </KuckitProvider>
66
+ </ServicesProvider>
67
+ ```
68
+
69
+ **Available hooks:**
70
+
71
+ - `useRpc<T>()` - Get typed RPC client for API calls
72
+ - `useNavItems()` - Flat navigation items list
73
+ - `useNavTree()` - Hierarchical navigation tree
74
+ - `useSlot(name)` - Get components for a slot
75
+ - `useHasSlot(name)` - Check if slot has content
76
+
77
+ ## useRpc Hook
78
+
79
+ Module components must use `useRpc()` to access the API:
80
+
81
+ ```tsx
82
+ import { useRpc } from '@kuckit/sdk-react'
83
+ import { useQuery } from '@tanstack/react-query'
84
+
85
+ interface MyRpc {
86
+ items: { list: (input: {}) => Promise<Item[]> }
87
+ }
88
+
89
+ function MyComponent() {
90
+ const rpc = useRpc<MyRpc>()
91
+
92
+ const { data } = useQuery({
93
+ queryKey: ['items'],
94
+ queryFn: () => rpc.items.list({}),
95
+ })
96
+ }
97
+ ```
98
+
99
+ **Important**: Never use `import.meta.env.VITE_SERVER_URL` directly in module components - it's unavailable in external packages. The `useRpc` hook provides the correctly-configured client.
100
+
101
+ ## Using Module UI Components
102
+
103
+ ```tsx
104
+ import { ItemsPage } from '@__APP_NAME_KEBAB__/items-module/ui'
105
+
106
+ // In your route component
107
+ export function Route() {
108
+ return <ItemsPage />
109
+ }
110
+ ```
111
+
112
+ ## Adding Client Modules
113
+
114
+ 1. Import in `modules.client.ts`:
115
+
116
+ ```typescript
117
+ import { kuckitClientModule as myClientModule } from '@__APP_NAME_KEBAB__/my-module/client'
118
+
119
+ export const clientModules = [
120
+ itemsClientModule,
121
+ myClientModule, // Add here
122
+ ]
123
+ ```
124
+
125
+ ## Environment Variables
126
+
127
+ See `.env.example` in this directory.
@@ -6,7 +6,7 @@
6
6
  <title>__APP_NAME__</title>
7
7
  </head>
8
8
  <body>
9
- <div id="root"></div>
9
+ <div id="app"></div>
10
10
  <script type="module" src="/src/main.tsx"></script>
11
11
  </body>
12
12
  </html>
@@ -1,5 +1,7 @@
1
1
  {
2
- "name": "__APP_NAME_KEBAB__-web",
2
+ "name": "@__APP_NAME_KEBAB__/web",
3
+ "version": "0.0.1",
4
+ "private": true,
3
5
  "type": "module",
4
6
  "scripts": {
5
7
  "dev": "vite --port=3001",
@@ -7,11 +9,22 @@
7
9
  "check-types": "tsc --noEmit"
8
10
  },
9
11
  "dependencies": {
12
+ "@kuckit/sdk-react": "^1.0.0",
13
+ "@orpc/client": "^1.10.0",
14
+ "@orpc/tanstack-query": "^1.10.0",
10
15
  "@tanstack/react-query": "^5.85.5",
16
+ "@tanstack/react-router": "^1.114.25",
17
+ "better-auth": "^1.3.28",
11
18
  "react": "^19.1.0",
12
- "react-dom": "^19.1.0"
19
+ "react-dom": "^19.1.0",
20
+ "zod": "^4.1.11",
21
+ "@__APP_NAME_KEBAB__/auth": "workspace:*"
13
22
  },
14
23
  "devDependencies": {
24
+ "@tanstack/react-router-devtools": "^1.114.27",
25
+ "@tanstack/router-plugin": "^1.114.27",
26
+ "@tanstack/react-query-devtools": "^5.85.5",
27
+ "@types/node": "^22.13.13",
15
28
  "@types/react": "~19.1.10",
16
29
  "@types/react-dom": "^19.0.4",
17
30
  "@vitejs/plugin-react": "^4.3.4",