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,231 @@
1
+ # Publishing Kuckit Packages
2
+
3
+ ## Preferred Method: Git Tags + CI/CD
4
+
5
+ The recommended way to publish kuckit packages is via Git tags, which trigger GitHub Actions to handle the npm publish.
6
+
7
+ ---
8
+
9
+ ## SDK Packages (Changeset Workflow)
10
+
11
+ SDK packages use **Changesets** for version management. This is a **multi-step process** that must be followed exactly.
12
+
13
+ ### Complete Release Flow
14
+
15
+ ```bash
16
+ # 1. Create a changeset (describes what changed)
17
+ bunx changeset
18
+
19
+ # 2. Consume changesets and bump versions
20
+ bun run version-packages
21
+
22
+ # NOTE: version-packages requires GITHUB_TOKEN for changelog generation.
23
+ # If you don't have GITHUB_TOKEN set, use gh CLI:
24
+ export GITHUB_TOKEN=$(gh auth token)
25
+
26
+ # 3. Commit the version bumps and changelog updates
27
+ git add packages/*/package.json packages/*/CHANGELOG.md .changeset/
28
+ git commit -m "chore(release): bump SDK packages to X.Y.Z"
29
+ git push
30
+
31
+ # 4. Create and push a tag to trigger publish
32
+ git tag sdk-v1.0.X
33
+ git push origin sdk-v1.0.X
34
+ ```
35
+
36
+ ### What Each Step Does
37
+
38
+ | Step | Command | What It Does |
39
+ | ---------------- | -------------------------- | ----------------------------------------------------------------------------- |
40
+ | Create changeset | `bunx changeset` | Creates a `.changeset/*.md` file describing the change |
41
+ | Version packages | `bun run version-packages` | Consumes changeset files, bumps `package.json` versions, generates CHANGELOGs |
42
+ | Push tag | `git tag sdk-v*` | Triggers CI workflow which runs `changeset publish` |
43
+
44
+ ### Fixed Package Groups
45
+
46
+ The SDK packages are configured as a **fixed** group in `.changeset/config.json`. This means they always share the same version number:
47
+
48
+ - `@kuckit/domain`
49
+ - `@kuckit/application`
50
+ - `@kuckit/infrastructure`
51
+ - `@kuckit/api`
52
+ - `@kuckit/contracts`
53
+ - `@kuckit/auth`
54
+ - `@kuckit/db`
55
+ - `@kuckit/sdk`
56
+ - `@kuckit/sdk-react`
57
+ - `@kuckit/users-module`
58
+
59
+ When you bump one, they all bump together.
60
+
61
+ ---
62
+
63
+ ## Common Pitfalls
64
+
65
+ ### Pushing a tag without running `version-packages`
66
+
67
+ **Symptom:** CI workflow runs successfully but outputs "No unpublished projects to publish". Packages stay at their old version on npm.
68
+
69
+ **Cause:** A changeset file exists (`.changeset/*.md`) but `bun run version-packages` was never run. The tag triggers `changeset publish`, which only publishes packages whose `package.json` version is higher than what's on npm.
70
+
71
+ **Fix:**
72
+
73
+ ```bash
74
+ # Run the version step you missed
75
+ bun run version-packages
76
+
77
+ # Commit the version bumps
78
+ git add packages/*/package.json packages/*/CHANGELOG.md .changeset/
79
+ git commit -m "chore(release): bump SDK packages to X.Y.Z"
80
+ git push
81
+
82
+ # Delete the old tag and create a new one
83
+ git tag -d sdk-vX.Y.Z
84
+ git push origin :refs/tags/sdk-vX.Y.Z
85
+ git tag sdk-vX.Y.Z
86
+ git push origin sdk-vX.Y.Z
87
+ ```
88
+
89
+ ### Forgetting to create a changeset
90
+
91
+ **Symptom:** `bun run version-packages` does nothing.
92
+
93
+ **Cause:** No changeset files exist in `.changeset/`.
94
+
95
+ **Fix:** Run `bunx changeset` first to create a changeset describing your changes.
96
+
97
+ ### Version already published
98
+
99
+ **Symptom:** npm publish fails with "You cannot publish over previously published versions"
100
+
101
+ **Cause:** The version in `package.json` already exists on npm.
102
+
103
+ **Fix:** Create a new changeset and run `version-packages` again to bump to a new version.
104
+
105
+ ### Missing GITHUB_TOKEN for version-packages
106
+
107
+ **Symptom:** `bun run version-packages` fails or hangs without clear explanation.
108
+
109
+ **Cause:** The `version-packages` command requires `GITHUB_TOKEN` to be set for changelog generation (fetching PR/commit info from GitHub).
110
+
111
+ **Fix:** Set the token using the `gh` CLI:
112
+
113
+ ```bash
114
+ export GITHUB_TOKEN=$(gh auth token)
115
+ bun run version-packages
116
+ ```
117
+
118
+ ---
119
+
120
+ ## CLI & Create-App Packages (Direct Publish)
121
+
122
+ For `@kuckit/cli` and `create-kuckit-app`, these are published directly (not via changesets):
123
+
124
+ ### Workflow
125
+
126
+ 1. **Bump version** in the package's `package.json` (e.g., `packages/kuckit-cli/package.json`)
127
+
128
+ 2. **Commit and push:**
129
+
130
+ ```bash
131
+ git commit -am "chore(cli): release @kuckit/cli v0.2.0"
132
+ git push
133
+ ```
134
+
135
+ 3. **Create and push a tag:**
136
+
137
+ ```bash
138
+ git tag cli-v0.2.0
139
+ git push origin cli-v0.2.0
140
+ ```
141
+
142
+ 4. **GitHub Actions handles the rest** - builds and publishes to npm
143
+
144
+ ---
145
+
146
+ ## Tag Patterns
147
+
148
+ | Tag Pattern | Publishes | Method |
149
+ | --------------- | ------------------------------------------ | ------------------ |
150
+ | `sdk-v*` | All SDK packages (fixed group) | Changesets |
151
+ | `cli-v*` | Only `@kuckit/cli` | Direct npm publish |
152
+ | `create-app-v*` | Only `create-kuckit-app` | Direct npm publish |
153
+ | `v*` | Both `@kuckit/cli` and `create-kuckit-app` | Direct npm publish |
154
+
155
+ ---
156
+
157
+ ## Commands Reference
158
+
159
+ | Command | Description |
160
+ | -------------------------- | --------------------------------------------------------------- |
161
+ | `bunx changeset` | Create a new changeset file describing your changes |
162
+ | `bun run version-packages` | Consume changesets, bump versions, generate CHANGELOGs |
163
+ | `bunx changeset status` | Check what changesets exist and which packages will be affected |
164
+ | `bunx changeset publish` | Publish packages (run by CI, not locally) |
165
+
166
+ ---
167
+
168
+ ## Pre-publish Check (Optional)
169
+
170
+ Before tagging, you can verify the package builds correctly:
171
+
172
+ ```bash
173
+ cd packages/kuckit-cli
174
+ bun run prepublishOnly
175
+ ```
176
+
177
+ This runs:
178
+
179
+ 1. `tsdown` build
180
+ 2. Workspace protocol check (ensures no `workspace:` or `catalog:` protocols leak into published package)
181
+
182
+ ---
183
+
184
+ ## CI/CD Workflow
185
+
186
+ The publish workflow is located at `.github/workflows/publish.yml`.
187
+
188
+ **What it does:**
189
+
190
+ 1. Triggers on tag push matching the patterns above
191
+ 2. Runs `bun install --frozen-lockfile`
192
+ 3. Builds the package(s)
193
+ 4. Resolves workspace protocols (converts `workspace:*` and `catalog:` to real versions)
194
+ 5. Publishes to npm
195
+
196
+ **Required secret:** `NPM_TOKEN` must be configured in GitHub repository secrets.
197
+
198
+ ---
199
+
200
+ ## Key Files
201
+
202
+ | File | Purpose |
203
+ | ----------------------------------------- | ------------------------------------------------- |
204
+ | `.changeset/config.json` | Changeset configuration with fixed package groups |
205
+ | `scripts/resolve-workspace-protocols.cjs` | Resolves workspace:\*/catalog: before publish |
206
+ | `.github/workflows/publish.yml` | CI workflow that handles publishing |
207
+
208
+ ---
209
+
210
+ ## Why Git Tags over Local Publish?
211
+
212
+ While the repo has Changesets configured, **local publishing doesn't work well** because:
213
+
214
+ - npm requires 2FA for publishing
215
+ - Local tokens don't have 2FA bypass permissions
216
+ - The CI/CD workflow has a granular access token (`NPM_TOKEN` secret) with proper permissions
217
+
218
+ **Use Changesets for:** Version management and changelog generation. Rely on Git tags for actual publishing.
219
+
220
+ ---
221
+
222
+ ## Troubleshooting
223
+
224
+ | Issue | Solution |
225
+ | ------------------------------------------------------- | ---------------------------------------------------------------- |
226
+ | "No unpublished projects to publish" | Run `bun run version-packages` first, then push a new tag |
227
+ | "You cannot publish over previously published versions" | Bump the version in package.json first |
228
+ | "Two-factor authentication required" | Use Git tags + CI/CD instead of local publish |
229
+ | Build fails in CI | Check `bun run prepublishOnly` locally first |
230
+ | Changeset file exists but versions didn't bump | Run `bun run version-packages` to consume the changeset |
231
+ | `version-packages` fails or hangs | Set `GITHUB_TOKEN` first: `export GITHUB_TOKEN=$(gh auth token)` |
@@ -0,0 +1,13 @@
1
+ # Database
2
+ DATABASE_URL=postgresql://postgres:password@localhost:5432/__APP_NAME_KEBAB__
3
+
4
+ # Auth
5
+ BETTER_AUTH_SECRET=your-secret-key-change-in-production
6
+ BETTER_AUTH_URL=http://localhost:3000
7
+
8
+ # Server
9
+ PORT=3000
10
+ NODE_ENV=development
11
+
12
+ # Web
13
+ VITE_API_URL=http://localhost:3000
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ quality:
11
+ name: Code Quality
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Bun
19
+ uses: oven-sh/setup-bun@v2
20
+
21
+ - name: Install dependencies
22
+ run: bun install --frozen-lockfile
23
+
24
+ - name: Lint
25
+ run: bun run lint
26
+
27
+ - name: Type check
28
+ run: bun run check-types
@@ -0,0 +1 @@
1
+ bun run lint-staged
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ dist
3
+ .turbo
4
+ bun.lockb
5
+ *.log
@@ -0,0 +1,8 @@
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true,
4
+ "tabWidth": 2,
5
+ "useTabs": true,
6
+ "trailingComma": "es5",
7
+ "printWidth": 100
8
+ }
@@ -0,0 +1,351 @@
1
+ # AGENTS.md - **APP_NAME**
2
+
3
+ ## Quick Start
4
+
5
+ ```bash
6
+ bun install # Install dependencies
7
+ docker compose up -d # Start PostgreSQL
8
+ bun run db:migrate # Run database migrations
9
+ bun run dev # Start dev servers (web + server)
10
+ ```
11
+
12
+ ## Project Structure
13
+
14
+ ```
15
+ __APP_NAME_KEBAB__/
16
+ ├── apps/
17
+ │ ├── server/ # Express + oRPC backend (port 3000)
18
+ │ └── web/ # React + TanStack Router frontend (port 3001)
19
+ ├── packages/
20
+ │ ├── api/ # Shared API context and types
21
+ │ ├── auth/ # Better-Auth configuration
22
+ │ ├── db/ # Drizzle ORM, migrations, schema
23
+ │ └── items-module/ # Example Kuckit module (reference implementation)
24
+ ├── .env.example # Environment template
25
+ ├── docker-compose.yml # PostgreSQL container
26
+ └── turbo.json # Turborepo configuration
27
+ ```
28
+
29
+ ## Module Development
30
+
31
+ Kuckit uses a **module-based architecture** where each module contains its own Clean Architecture layers internally.
32
+
33
+ ### Module Structure
34
+
35
+ ```
36
+ packages/your-module/
37
+ ├── src/
38
+ │ ├── domain/ # Entities with Zod schemas
39
+ │ ├── ports/ # Repository interfaces
40
+ │ ├── adapters/ # Drizzle implementations
41
+ │ ├── usecases/ # Business logic
42
+ │ ├── api/ # oRPC routers
43
+ │ ├── ui/ # React components (optional)
44
+ │ ├── module.ts # Server module definition
45
+ │ └── client-module.ts # Client module definition
46
+ ```
47
+
48
+ ### Creating a New Module
49
+
50
+ 1. Copy `packages/items-module` as a template
51
+ 2. Rename and update `package.json`
52
+ 3. Implement your domain entities in `domain/`
53
+ 4. Define repository interfaces in `ports/`
54
+ 5. Implement adapters in `adapters/`
55
+ 6. Create use cases in `usecases/`
56
+ 7. Expose API in `api/` via oRPC router
57
+ 8. Register module in `apps/server/src/config/modules.ts`
58
+ 9. Add client module to `apps/web/src/modules.client.ts`
59
+
60
+ ### Dependency Rules
61
+
62
+ ```
63
+ domain → No dependencies (pure Zod schemas)
64
+
65
+ ports → Depends on domain only
66
+
67
+ usecases → Depends on ports and domain
68
+
69
+ adapters → Implements ports, depends on domain
70
+
71
+ api → Wires everything together
72
+ ```
73
+
74
+ ## SDK Module System
75
+
76
+ > **SDK Documentation**: For comprehensive module patterns, see [@kuckit/sdk](https://github.com/draphonix/kuckit)
77
+
78
+ ### Module Lifecycle
79
+
80
+ Modules are loaded in a specific sequence:
81
+
82
+ ```
83
+ 1. createKuckitContainer()
84
+ └─► Core services registered (logger, db, cache, eventBus)
85
+
86
+ 2. loadKuckitModules({ modules: [...] })
87
+ ├─► Phase 1: register() - DI bindings for all modules
88
+ ├─► Phase 2: registerApi() - API registrations collected
89
+ ├─► Phase 3: onApiRegistrations callback (wire routers HERE)
90
+ ├─► Phase 4: onBootstrap() - Startup logic
91
+ └─► Phase 5: onComplete callback
92
+
93
+ 3. Application runs...
94
+
95
+ 4. disposeContainer()
96
+ └─► For each module: onShutdown()
97
+ ```
98
+
99
+ ### Core Services (CoreCradle)
100
+
101
+ After container creation, these services are available via DI:
102
+
103
+ | Token | Type | Lifetime | Description |
104
+ | ------------------ | ------------------ | --------- | --------------------------- |
105
+ | `config` | `CoreConfig` | Singleton | Application configuration |
106
+ | `db` | Drizzle | Singleton | Database query builder |
107
+ | `dbPool` | `Pool` | Singleton | PostgreSQL connection pool |
108
+ | `logger` | `Logger` | Singleton | Structured logging |
109
+ | `eventBus` | `EventBus` | Singleton | Pub/sub event system |
110
+ | `clock` | `Clock` | Singleton | Time abstraction (testable) |
111
+ | `cacheStore` | `CacheStore` | Singleton | Key-value cache |
112
+ | `rateLimiterStore` | `RateLimiterStore` | Singleton | Rate limiting |
113
+ | `auth` | Better-Auth | Singleton | Authentication utilities |
114
+ | `requestId` | `string` | Scoped | Per-request unique ID |
115
+ | `requestLogger` | `Logger` | Scoped | Logger with request context |
116
+
117
+ ### Server Module Definition
118
+
119
+ ```typescript
120
+ import { defineKuckitModule, asClass, asFunction } from '@kuckit/sdk'
121
+
122
+ export const kuckitModule = defineKuckitModule({
123
+ id: 'myapp.billing',
124
+ displayName: 'Billing',
125
+ version: '1.0.0',
126
+ capabilities: ['nav.item', 'api.public'],
127
+
128
+ register(ctx) {
129
+ // Phase 1: Register DI bindings
130
+ ctx.container.register({
131
+ invoiceRepository: asClass(InvoiceRepository).scoped(),
132
+ createInvoice: asFunction(makeCreateInvoiceUseCase).scoped(),
133
+ })
134
+ },
135
+
136
+ registerApi(ctx) {
137
+ // Phase 2: Register API routes
138
+ ctx.addApiRegistration({
139
+ type: 'rpc-router',
140
+ name: 'invoices',
141
+ router: invoicesRouter,
142
+ })
143
+ },
144
+
145
+ onBootstrap(ctx) {
146
+ // Phase 4: Startup logic (cache warming, logging, etc.)
147
+ ctx.container.resolve('logger').info('Billing module started')
148
+ },
149
+
150
+ onShutdown(ctx) {
151
+ // Cleanup on shutdown
152
+ ctx.container.resolve('logger').info('Billing module stopped')
153
+ },
154
+ })
155
+ ```
156
+
157
+ ### Client Module Definition
158
+
159
+ ```typescript
160
+ import { defineKuckitClientModule } from '@kuckit/sdk-react'
161
+
162
+ export const kuckitClientModule = defineKuckitClientModule({
163
+ id: 'myapp.billing',
164
+ displayName: 'Billing',
165
+ capabilities: ['nav.item', 'dashboard.widget'],
166
+
167
+ routes: [
168
+ {
169
+ id: 'billing-invoices',
170
+ path: '/billing/invoices',
171
+ component: InvoicesPage,
172
+ },
173
+ ],
174
+
175
+ navItems: [
176
+ {
177
+ id: 'billing-nav',
178
+ label: 'Billing',
179
+ href: '/billing/invoices',
180
+ icon: CreditCard,
181
+ order: 50,
182
+ },
183
+ ],
184
+
185
+ slots: {
186
+ 'dashboard.widgets': {
187
+ component: BillingWidget,
188
+ order: 10,
189
+ },
190
+ },
191
+ })
192
+ ```
193
+
194
+ ### Module Capabilities
195
+
196
+ Modules can declare capabilities for discovery:
197
+
198
+ - `nav.item` - Provides navigation items
199
+ - `settings.page` - Has settings page
200
+ - `dashboard.widget` - Provides dashboard widgets
201
+ - `api.webhook` - Exposes webhooks
202
+ - `api.public` - Has public API endpoints
203
+ - `slot.provider` - Provides slot components
204
+
205
+ ### useRpc with TanStack Query
206
+
207
+ Module components use the `useRpc` hook to access the API:
208
+
209
+ ```typescript
210
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
211
+ import { useRpc } from '@kuckit/sdk-react'
212
+
213
+ interface ItemsRpc {
214
+ items: {
215
+ list: (input: Record<string, never>) => Promise<Item[]>
216
+ create: (input: { name: string }) => Promise<Item>
217
+ }
218
+ }
219
+
220
+ function ItemsPage() {
221
+ const rpc = useRpc<ItemsRpc>()
222
+ const queryClient = useQueryClient()
223
+
224
+ const { data: items = [], isLoading } = useQuery({
225
+ queryKey: ['items'],
226
+ queryFn: () => rpc.items.list({}),
227
+ })
228
+
229
+ const createMutation = useMutation({
230
+ mutationFn: (data: { name: string }) => rpc.items.create(data),
231
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['items'] }),
232
+ })
233
+
234
+ // ... component render
235
+ }
236
+ ```
237
+
238
+ ### oRPC Router Wiring (Important)
239
+
240
+ oRPC's `RPCHandler` captures the router object at construction time. Module routers must be wired **before** the handler is created:
241
+
242
+ 1. Modules register routers via `registerApi()` hook
243
+ 2. Server wires routers in `onApiRegistrations` into a **mutable router object**
244
+ 3. `RPCHandler` is created **after** modules are loaded
245
+
246
+ ```typescript
247
+ // apps/server/src/rpc-router-registry.ts
248
+ export const rootRpcRouter = { ...appRouter }
249
+
250
+ export const wireModuleRpcRouters = (registrations: ApiRegistration[]) => {
251
+ for (const reg of registrations) {
252
+ if (reg.type === 'rpc-router') {
253
+ rootRpcRouter[reg.name] = reg.router
254
+ }
255
+ }
256
+ }
257
+ ```
258
+
259
+ ### Typing DI in Routers
260
+
261
+ Use a module-local interface to type `context.di.cradle`:
262
+
263
+ ```typescript
264
+ // In your module's router file
265
+ interface BillingCradle {
266
+ createInvoice: (input: CreateInvoiceInput) => Promise<Invoice>
267
+ }
268
+
269
+ export const invoicesRouter = {
270
+ create: protectedProcedure.input(createInvoiceSchema).handler(async ({ input, context }) => {
271
+ const { createInvoice } = context.di.cradle as BillingCradle
272
+ return createInvoice(input)
273
+ }),
274
+ }
275
+ ```
276
+
277
+ ## Common Tasks
278
+
279
+ ### Add a new API endpoint
280
+
281
+ 1. Define input/output schemas in `domain/`
282
+ 2. Create use case in `usecases/`
283
+ 3. Add to router in `api/`
284
+
285
+ ### Add a new database table
286
+
287
+ 1. Define schema in your module's `adapters/` or `packages/db/src/schema/`
288
+ 2. Run `bun run db:generate`
289
+ 3. Run `bun run db:migrate`
290
+
291
+ ### Add authentication to an endpoint
292
+
293
+ ```typescript
294
+ import { protectedProcedure } from '@__APP_NAME_KEBAB__/api'
295
+
296
+ export const myRouter = {
297
+ protectedRoute: protectedProcedure.input(mySchema).handler(async ({ input, context }) => {
298
+ const { user } = context // Authenticated user
299
+ // ...
300
+ }),
301
+ }
302
+ ```
303
+
304
+ ## Scripts
305
+
306
+ | Command | Description |
307
+ | ---------------------- | -------------------------------------- |
308
+ | `bun run dev` | Start all dev servers |
309
+ | `bun run build` | Build all packages |
310
+ | `bun run check-types` | Type check all packages |
311
+ | `bun run lint` | Run ESLint on all packages |
312
+ | `bun run lint:fix` | Fix ESLint issues automatically |
313
+ | `bun run format` | Format code with Prettier |
314
+ | `bun run format:check` | Check formatting without changes |
315
+ | `bun run db:generate` | Generate migration from schema changes |
316
+ | `bun run db:migrate` | Apply pending migrations |
317
+ | `bun run db:studio` | Open Drizzle Studio |
318
+
319
+ ## Code Quality
320
+
321
+ This project includes pre-configured code quality tools:
322
+
323
+ - **ESLint** - TypeScript linting with recommended rules
324
+ - **Prettier** - Code formatting
325
+ - **Husky** - Git hooks for pre-commit checks
326
+ - **lint-staged** - Run linters on staged files only
327
+
328
+ Pre-commit hooks automatically run `lint-staged` which:
329
+
330
+ 1. Runs ESLint on staged `.ts/.tsx/.js/.jsx` files
331
+ 2. Runs Prettier on all staged files
332
+
333
+ To bypass hooks (not recommended): `git commit --no-verify`
334
+
335
+ ## Environment Variables
336
+
337
+ See `.env.example` for required variables:
338
+
339
+ - `DATABASE_URL` - PostgreSQL connection string
340
+ - `BETTER_AUTH_SECRET` - Auth session secret
341
+ - `BETTER_AUTH_URL` - Auth callback URL
342
+ - `PORT` - Server port (default: 3000)
343
+ - `VITE_API_URL` - API URL for frontend
344
+
345
+ ## Related Documentation
346
+
347
+ - [Kuckit SDK](https://github.com/draphonix/kuckit)
348
+ - [oRPC](https://orpc.dev)
349
+ - [Better-Auth](https://better-auth.com)
350
+ - [Drizzle ORM](https://orm.drizzle.team)
351
+ - [TanStack Router](https://tanstack.com/router)
@@ -0,0 +1,18 @@
1
+ # Server Environment Variables
2
+
3
+ # Database connection
4
+ DATABASE_URL=postgresql://postgres:password@localhost:5432/__APP_NAME_KEBAB__
5
+
6
+ # Authentication
7
+ BETTER_AUTH_SECRET=your-secret-key-change-in-production
8
+ BETTER_AUTH_URL=http://localhost:3000
9
+
10
+ # Server configuration
11
+ PORT=3000
12
+ NODE_ENV=development
13
+ CORS_ORIGIN=http://localhost:3001
14
+
15
+ # Logging (optional)
16
+ LOG_LEVEL=INFO
17
+ ENABLE_FILE_LOGGING=false
18
+ LOG_DIR=./logs