@mandujs/mcp 0.38.12 → 0.39.0-beta.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 (183) hide show
  1. package/README.md +3 -3
  2. package/package.json +3 -5
  3. package/src/activity-adapter.ts +23 -23
  4. package/src/activity-monitor.ts +39 -10
  5. package/src/adapters/index.ts +20 -20
  6. package/src/adapters/monitor-adapter.ts +100 -100
  7. package/src/adapters/tool-adapter.ts +90 -90
  8. package/src/executor/index.ts +22 -22
  9. package/src/executor/tool-executor.ts +148 -148
  10. package/src/hooks/config-watcher.ts +173 -173
  11. package/src/hooks/index.ts +23 -23
  12. package/src/hooks/mcp-hooks.ts +227 -227
  13. package/src/index.ts +5 -5
  14. package/src/logging/index.ts +15 -15
  15. package/src/logging/mcp-transport.ts +134 -134
  16. package/src/new-resources.ts +2 -2
  17. package/src/profiles.ts +25 -54
  18. package/src/prompts.ts +4 -4
  19. package/src/registry/index.ts +13 -13
  20. package/src/registry/mcp-tool-registry.ts +298 -298
  21. package/src/resources/generated-skills/catalog.ts +36 -0
  22. package/src/resources/generated-skills/mandu-agent-workflow/SKILL.md +48 -0
  23. package/src/resources/generated-skills/mandu-contract/SKILL.md +20 -0
  24. package/src/resources/generated-skills/mandu-fs-routes/SKILL.md +19 -0
  25. package/src/resources/generated-skills/mandu-guard/SKILL.md +20 -0
  26. package/src/resources/generated-skills/mandu-hydration/SKILL.md +19 -0
  27. package/src/resources/generated-skills/mandu-testing/SKILL.md +20 -0
  28. package/src/resources/handlers.ts +3 -3
  29. package/src/resources/skills/guides.ts +49 -49
  30. package/src/resources/skills/index.ts +12 -12
  31. package/src/resources/skills/loader.ts +8 -35
  32. package/src/resources/skills/recipes.ts +28 -28
  33. package/src/server.ts +1 -1
  34. package/src/tools/agent.ts +479 -409
  35. package/src/tools/ate-exemplar.ts +92 -92
  36. package/src/tools/ate-flakes.ts +90 -90
  37. package/src/tools/ate-mutate.ts +103 -103
  38. package/src/tools/ate-mutation-report.ts +64 -64
  39. package/src/tools/ate-oracle-pending.ts +49 -49
  40. package/src/tools/ate-oracle-replay.ts +44 -44
  41. package/src/tools/ate-oracle-verdict.ts +70 -70
  42. package/src/tools/ate-prompt.ts +146 -146
  43. package/src/tools/ate-run.ts +1 -1
  44. package/src/tools/ate.ts +38 -38
  45. package/src/tools/brain.ts +6 -6
  46. package/src/tools/composite.ts +19 -61
  47. package/src/tools/contract.ts +11 -9
  48. package/src/tools/deploy-plan.ts +2 -2
  49. package/src/tools/deploy-preview.ts +316 -316
  50. package/src/tools/design.ts +825 -825
  51. package/src/tools/docs.ts +350 -350
  52. package/src/tools/generate.ts +4 -3
  53. package/src/tools/guard.ts +1 -1
  54. package/src/tools/history.ts +1 -1
  55. package/src/tools/hydration.ts +64 -64
  56. package/src/tools/index.ts +0 -118
  57. package/src/tools/kitchen.ts +72 -72
  58. package/src/tools/lint.ts +226 -226
  59. package/src/tools/loop-close.ts +175 -175
  60. package/src/tools/negotiate.ts +263 -263
  61. package/src/tools/resource.ts +1 -1
  62. package/src/tools/run-tests.ts +424 -424
  63. package/src/tools/runtime.ts +1 -1
  64. package/src/tools/seo.ts +1 -1
  65. package/src/tools/slot-validation.ts +19 -19
  66. package/src/tools/spec.ts +201 -201
  67. package/src/tools/transaction.ts +1 -1
  68. package/src/tx-lock.ts +73 -73
  69. package/src/utils/runtime-control.ts +52 -52
  70. package/src/utils/withWarnings.ts +1 -1
  71. package/src/resources/skills/mandu-agent-workflow/SKILL.md +0 -124
  72. package/src/resources/skills/mandu-agent-workflow/metadata.json +0 -7
  73. package/src/resources/skills/mandu-composition/SKILL.md +0 -131
  74. package/src/resources/skills/mandu-composition/metadata.json +0 -13
  75. package/src/resources/skills/mandu-composition/rules/_sections.md +0 -26
  76. package/src/resources/skills/mandu-composition/rules/_template.md +0 -77
  77. package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +0 -146
  78. package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +0 -164
  79. package/src/resources/skills/mandu-composition/rules/comp-island-event.md +0 -161
  80. package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +0 -167
  81. package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +0 -149
  82. package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +0 -148
  83. package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +0 -150
  84. package/src/resources/skills/mandu-deployment/SKILL.md +0 -135
  85. package/src/resources/skills/mandu-deployment/_sections.md +0 -41
  86. package/src/resources/skills/mandu-deployment/_template.md +0 -38
  87. package/src/resources/skills/mandu-deployment/metadata.json +0 -13
  88. package/src/resources/skills/mandu-deployment/rules/db-provider-supabase.md +0 -300
  89. package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +0 -109
  90. package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +0 -115
  91. package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +0 -219
  92. package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +0 -150
  93. package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +0 -223
  94. package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +0 -152
  95. package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +0 -179
  96. package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +0 -140
  97. package/src/resources/skills/mandu-fs-routes/SKILL.md +0 -122
  98. package/src/resources/skills/mandu-fs-routes/metadata.json +0 -12
  99. package/src/resources/skills/mandu-fs-routes/rules/_sections.md +0 -36
  100. package/src/resources/skills/mandu-fs-routes/rules/_template.md +0 -69
  101. package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +0 -65
  102. package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +0 -93
  103. package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +0 -55
  104. package/src/resources/skills/mandu-guard/SKILL.md +0 -162
  105. package/src/resources/skills/mandu-guard/metadata.json +0 -12
  106. package/src/resources/skills/mandu-guard/rules/_sections.md +0 -36
  107. package/src/resources/skills/mandu-guard/rules/_template.md +0 -82
  108. package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +0 -100
  109. package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +0 -76
  110. package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +0 -81
  111. package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +0 -80
  112. package/src/resources/skills/mandu-hydration/SKILL.md +0 -139
  113. package/src/resources/skills/mandu-hydration/metadata.json +0 -12
  114. package/src/resources/skills/mandu-hydration/rules/_sections.md +0 -31
  115. package/src/resources/skills/mandu-hydration/rules/_template.md +0 -72
  116. package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +0 -109
  117. package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +0 -55
  118. package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +0 -160
  119. package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +0 -91
  120. package/src/resources/skills/mandu-performance/SKILL.md +0 -125
  121. package/src/resources/skills/mandu-performance/metadata.json +0 -14
  122. package/src/resources/skills/mandu-performance/rules/_sections.md +0 -31
  123. package/src/resources/skills/mandu-performance/rules/_template.md +0 -64
  124. package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +0 -103
  125. package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +0 -95
  126. package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +0 -124
  127. package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +0 -125
  128. package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +0 -80
  129. package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +0 -145
  130. package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +0 -98
  131. package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +0 -154
  132. package/src/resources/skills/mandu-security/SKILL.md +0 -127
  133. package/src/resources/skills/mandu-security/metadata.json +0 -13
  134. package/src/resources/skills/mandu-security/rules/_sections.md +0 -31
  135. package/src/resources/skills/mandu-security/rules/_template.md +0 -74
  136. package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +0 -127
  137. package/src/resources/skills/mandu-security/rules/sec-env-management.md +0 -133
  138. package/src/resources/skills/mandu-security/rules/sec-input-validate.md +0 -148
  139. package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +0 -146
  140. package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +0 -138
  141. package/src/resources/skills/mandu-slot/SKILL.md +0 -125
  142. package/src/resources/skills/mandu-slot/metadata.json +0 -12
  143. package/src/resources/skills/mandu-slot/rules/_sections.md +0 -36
  144. package/src/resources/skills/mandu-slot/rules/_template.md +0 -63
  145. package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +0 -38
  146. package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +0 -56
  147. package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +0 -59
  148. package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +0 -64
  149. package/src/resources/skills/mandu-styling/SKILL.md +0 -196
  150. package/src/resources/skills/mandu-styling/_sections.md +0 -43
  151. package/src/resources/skills/mandu-styling/_template.md +0 -32
  152. package/src/resources/skills/mandu-styling/metadata.json +0 -15
  153. package/src/resources/skills/mandu-styling/rules/style-component-compound.md +0 -235
  154. package/src/resources/skills/mandu-styling/rules/style-component-slots.md +0 -255
  155. package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +0 -205
  156. package/src/resources/skills/mandu-styling/rules/style-island-animations.md +0 -272
  157. package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +0 -167
  158. package/src/resources/skills/mandu-styling/rules/style-island-variants.md +0 -221
  159. package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +0 -209
  160. package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +0 -192
  161. package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +0 -162
  162. package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +0 -164
  163. package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +0 -170
  164. package/src/resources/skills/mandu-styling/rules/style-tailwind-v4-gotchas.md +0 -179
  165. package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +0 -229
  166. package/src/resources/skills/mandu-testing/SKILL.md +0 -132
  167. package/src/resources/skills/mandu-testing/metadata.json +0 -13
  168. package/src/resources/skills/mandu-testing/rules/_sections.md +0 -26
  169. package/src/resources/skills/mandu-testing/rules/_template.md +0 -65
  170. package/src/resources/skills/mandu-testing/rules/test-component-island.md +0 -195
  171. package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +0 -196
  172. package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +0 -219
  173. package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +0 -192
  174. package/src/resources/skills/mandu-ui/SKILL.md +0 -159
  175. package/src/resources/skills/mandu-ui/_sections.md +0 -23
  176. package/src/resources/skills/mandu-ui/_template.md +0 -32
  177. package/src/resources/skills/mandu-ui/metadata.json +0 -13
  178. package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +0 -232
  179. package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +0 -238
  180. package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +0 -259
  181. package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +0 -258
  182. package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +0 -213
  183. package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +0 -209
@@ -1,300 +0,0 @@
1
- ---
2
- title: Use Supabase as Postgres provider
3
- impact: MEDIUM
4
- impactDescription: Managed Postgres + optional Realtime / Storage / Auth — Mandu consumes it as a connection string, not a deploy target
5
- tags: database, postgres, supabase, baas
6
- ---
7
-
8
- ## Use Supabase as Postgres provider
9
-
10
- > **Supabase 는 Mandu 의 배포 타겟이 아닙니다.** Mandu 앱은 Render / Fly / Railway /
11
- > Vercel / Docker 등으로 배포하고, Supabase 는 **Postgres 제공자 + 선택적
12
- > BaaS 기능** (Realtime, Storage, Auth, Edge Functions) 으로만 사용합니다.
13
- > Mandu 의 `@mandujs/core/db` 가 `Bun.SQL` wrapper 이기 때문에 Supabase 의
14
- > pooler URL 을 그대로 꽂으면 별도 SDK 없이 바로 동작합니다.
15
-
16
- ## 1. 가장 단순한 경로 — DB-only (권장)
17
-
18
- Supabase 를 Postgres 로만 쓰는 경우. Mandu 의 네이티브 DB 레이어가 그대로 커버합니다.
19
-
20
- ### 1.1 Connection string 획득
21
-
22
- Supabase Dashboard → Settings → Database → **Connection pooling**
23
- - `Transaction` 모드 URL 복사 (포트 `6543`)
24
- - 형식: `postgres://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres`
25
-
26
- ### 1.2 `.env` 에 저장
27
-
28
- ```bash
29
- DATABASE_URL=postgres://postgres.xxxx:your-password@aws-0-us-east-1.pooler.supabase.com:6543/postgres
30
- ```
31
-
32
- ### 1.3 Mandu DB 핸들 생성
33
-
34
- ```typescript
35
- // lib/db.ts
36
- import { createDb } from "@mandujs/core/db";
37
-
38
- export const db = createDb({
39
- url: process.env.DATABASE_URL!,
40
- });
41
- ```
42
-
43
- ### 1.4 Filling 에서 쿼리
44
-
45
- ```typescript
46
- // app/users/[id]/route.ts
47
- import { defineFilling, notFound } from "@mandujs/core/filling";
48
- import { db } from "@/lib/db";
49
-
50
- export const filling = defineFilling({
51
- async loader({ params }) {
52
- const user = await db.one<{ id: string; email: string; name: string }>`
53
- SELECT id, email, name FROM users WHERE id = ${params.id}
54
- `;
55
- if (!user) throw notFound();
56
- return { user };
57
- },
58
- });
59
- ```
60
-
61
- 트랜잭션:
62
-
63
- ```typescript
64
- await db.transaction(async (tx) => {
65
- const user = await tx.one<{ id: string }>`
66
- INSERT INTO users (email, name) VALUES (${email}, ${name}) RETURNING id
67
- `;
68
- await tx`INSERT INTO profiles (user_id, bio) VALUES (${user!.id}, ${bio})`;
69
- });
70
- ```
71
-
72
- **필요한 Supabase-specific 의존성**: 없음. `@mandujs/core/db` 만 사용. Supabase 가 바뀌어도 connection string 교체뿐.
73
-
74
- ## 2. 마이그레이션
75
-
76
- Mandu 의 기본 마이그레이션 러너를 사용하거나 (`@mandujs/core/db/migrations`), Supabase CLI 를 병행할 수 있습니다.
77
-
78
- ### Mandu 마이그레이션 (권장)
79
-
80
- ```sql
81
- -- migrations/001_users.sql
82
- CREATE TABLE users (
83
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
84
- email TEXT UNIQUE NOT NULL,
85
- name TEXT,
86
- created_at TIMESTAMPTZ DEFAULT NOW()
87
- );
88
- ```
89
-
90
- ```bash
91
- bun run mandu db migrate
92
- ```
93
-
94
- ### Supabase CLI 병행
95
-
96
- RLS (Row Level Security) / policies 등 Supabase-native 기능이 필요한 경우:
97
-
98
- ```bash
99
- npm install -g supabase
100
- supabase login
101
- supabase init
102
- supabase migration new create_users_table
103
- # edit supabase/migrations/<timestamp>_create_users_table.sql
104
- supabase db push
105
- ```
106
-
107
- `ALTER TABLE users ENABLE ROW LEVEL SECURITY;` 등은 plain SQL 이므로 Mandu 마이그레이션에도 그대로 작성 가능. Supabase CLI 는 RLS policy 편집 UX 와 타입 생성 (`supabase gen types typescript`) 때문에 편리합니다.
108
-
109
- ## 3. Supabase SDK 를 함께 쓰고 싶다면 (BaaS 기능)
110
-
111
- DB 는 `@mandujs/core/db` 로, Supabase-specific 기능 (Realtime / Storage / Edge Functions) 만 SDK 로 사용하는 하이브리드가 깔끔합니다.
112
-
113
- ### 3.1 클라이언트 설정
114
-
115
- ```bash
116
- bun add @supabase/supabase-js
117
- ```
118
-
119
- ```typescript
120
- // lib/supabase.ts
121
- import { createClient } from "@supabase/supabase-js";
122
-
123
- const supabaseUrl = process.env.SUPABASE_URL!;
124
- const supabaseAnonKey = process.env.SUPABASE_ANON_KEY!;
125
-
126
- export const supabase = createClient(supabaseUrl, supabaseAnonKey);
127
-
128
- // 서버 사이드 (Service Role) — filling 안에서만 사용
129
- export function createServerSupabase() {
130
- return createClient(supabaseUrl, process.env.SUPABASE_SERVICE_ROLE_KEY!, {
131
- auth: { autoRefreshToken: false, persistSession: false },
132
- });
133
- }
134
- ```
135
-
136
- ### 3.2 Realtime (Island)
137
-
138
- Mandu 의 client island 에서 Realtime 구독:
139
-
140
- ```tsx
141
- // app/messages/MessagesIsland.client.tsx
142
- import { wrapComponent } from "@mandujs/core/client";
143
- import { useEffect, useState } from "react";
144
- import { supabase } from "@/lib/supabase";
145
-
146
- function Messages() {
147
- const [messages, setMessages] = useState<Array<{ id: string; content: string }>>([]);
148
-
149
- useEffect(() => {
150
- supabase.from("messages").select("*").then(({ data }) => {
151
- setMessages(data ?? []);
152
- });
153
-
154
- const channel = supabase
155
- .channel("messages")
156
- .on(
157
- "postgres_changes",
158
- { event: "INSERT", schema: "public", table: "messages" },
159
- (payload) => {
160
- setMessages((prev) => [...prev, payload.new as { id: string; content: string }]);
161
- },
162
- )
163
- .subscribe();
164
-
165
- return () => {
166
- supabase.removeChannel(channel);
167
- };
168
- }, []);
169
-
170
- return (
171
- <ul>
172
- {messages.map((m) => <li key={m.id}>{m.content}</li>)}
173
- </ul>
174
- );
175
- }
176
-
177
- export default wrapComponent(Messages);
178
- ```
179
-
180
- ### 3.3 Storage
181
-
182
- ```typescript
183
- // filling 내에서
184
- const serverSupabase = createServerSupabase();
185
-
186
- const { data, error } = await serverSupabase.storage
187
- .from("avatars")
188
- .upload(`${userId}/avatar.png`, file);
189
-
190
- const { data: { publicUrl } } = serverSupabase.storage
191
- .from("avatars")
192
- .getPublicUrl(`${userId}/avatar.png`);
193
- ```
194
-
195
- ### 3.4 Edge Functions
196
-
197
- Supabase 의 Deno 런타임에서 도는 서버리스 함수. Mandu 앱 바깥에서 별도 배포되고, Mandu 는 HTTP 로 호출만:
198
-
199
- ```typescript
200
- const res = await fetch(`${process.env.SUPABASE_URL}/functions/v1/hello`, {
201
- method: "POST",
202
- headers: {
203
- "Authorization": `Bearer ${process.env.SUPABASE_ANON_KEY}`,
204
- "Content-Type": "application/json",
205
- },
206
- body: JSON.stringify({ name: "mandu" }),
207
- });
208
- ```
209
-
210
- ## 4. Supabase Auth 와 Mandu auth — 선택 문제
211
-
212
- 두 가지가 겹치는 영역이라 **둘 중 하나만** 씁니다:
213
-
214
- | Mandu 의 `@mandujs/core/auth` (native) | Supabase Auth |
215
- |---|---|
216
- | Bun.password (argon2id) | Bcrypt + custom hashing |
217
- | `@mandujs/core/middleware/session` SQLite session store | JWT + cookie |
218
- | CSRF (`@mandujs/core/middleware/csrf`) | — |
219
- | Mandu 프로젝트 자체 사용자 테이블 | Supabase `auth.users` 테이블 |
220
-
221
- **추천**: Mandu 앱이 Supabase 의 다른 기능 (Realtime / Storage) 을 안 쓰면 **Mandu native auth** 가 의존성 적고 예측 가능. Supabase 의 social providers (GitHub / Google OAuth UI) 가 필요하면 Supabase Auth 를 쓰고 Mandu auth 는 bypass.
222
-
223
- 병행 사용 (Supabase Auth 만 이용하면서 Mandu filling 안에서 token 검증):
224
-
225
- ```typescript
226
- // middleware/supabase-auth.ts
227
- import { createServerSupabase } from "@/lib/supabase";
228
-
229
- export async function supabaseAuthMiddleware(ctx) {
230
- const header = ctx.headers.get("authorization");
231
- if (!header?.startsWith("Bearer ")) return ctx.unauthorized("Missing token");
232
-
233
- const token = header.slice(7);
234
- const supabase = createServerSupabase();
235
- const { data: { user }, error } = await supabase.auth.getUser(token);
236
- if (error || !user) return ctx.unauthorized("Invalid token");
237
-
238
- ctx.set("user", user);
239
- }
240
- ```
241
-
242
- ## 5. 환경 변수
243
-
244
- ```bash
245
- # .env
246
- # DB connection (최소 요구사항)
247
- DATABASE_URL=postgres://postgres.xxx:password@aws-0-us-east-1.pooler.supabase.com:6543/postgres
248
-
249
- # Supabase SDK 사용 시 추가
250
- SUPABASE_URL=https://xxx.supabase.co
251
- SUPABASE_ANON_KEY=eyJ...
252
- SUPABASE_SERVICE_ROLE_KEY=eyJ... # 서버 전용, 클라이언트에 노출 금지
253
- ```
254
-
255
- ## 6. 배포 플랫폼과 조합
256
-
257
- Supabase 는 DB layer 이므로 **Mandu 앱 자체는 다른 곳** 에 배포합니다. `DATABASE_URL` 만 환경 변수로 주입:
258
-
259
- ### Render (`mandu deploy --target=render` 가 자동 생성)
260
-
261
- ```yaml
262
- # render.yaml
263
- services:
264
- - type: web
265
- name: mandu-app
266
- runtime: node
267
- buildCommand: |
268
- curl -fsSL https://bun.sh/install | bash
269
- export PATH="$HOME/.bun/bin:$PATH"
270
- bun install --frozen-lockfile
271
- bun run build
272
- startCommand: bun run start
273
- envVars:
274
- - key: DATABASE_URL
275
- sync: false # Render 대시보드에서 Supabase pooler URL 설정
276
- - key: SUPABASE_URL
277
- sync: false # SDK 쓸 때만
278
- - key: SUPABASE_ANON_KEY
279
- sync: false
280
- ```
281
-
282
- ### Fly / Railway
283
-
284
- ```bash
285
- fly secrets set DATABASE_URL="postgres://..." SUPABASE_URL="..." SUPABASE_ANON_KEY="..."
286
- railway variables set DATABASE_URL="postgres://..." SUPABASE_URL="..." SUPABASE_ANON_KEY="..."
287
- ```
288
-
289
- ## 7. 주의사항
290
-
291
- - **Transaction mode pooler (6543) 를 사용**하세요. Session mode (5432) 는 커넥션 고정이 필요한 경우에만.
292
- - **Service Role key 는 서버 전용**. Client island 에서 절대 import 하지 마세요 — Mandu 의 island 번들에 포함되면 공개됩니다.
293
- - **RLS 를 켜지 않은 테이블** 은 anon key 로 전체 읽기가 가능해집니다. 항상 `ENABLE ROW LEVEL SECURITY` 적용하고 policy 를 명시.
294
- - **Realtime 구독은 client bundle 비용**이 큽니다 (`@supabase/supabase-js` ~60 KB). 페이지 단위로 island 분리하세요.
295
-
296
- ## Reference
297
-
298
- - [Supabase Docs](https://supabase.com/docs)
299
- - `@mandujs/core/db` — Bun.SQL wrapper, provider-agnostic. `packages/core/src/db/index.ts`
300
- - Deploy adapters — `packages/cli/src/commands/deploy/adapters/{render,fly,railway,vercel,netlify,docker,docker-compose,cf-pages}.ts`
@@ -1,109 +0,0 @@
1
- ---
2
- title: Bun Production Build
3
- impact: CRITICAL
4
- impactDescription: Build failure blocks deployment
5
- tags: deployment, build, bun, bundler
6
- ---
7
-
8
- ## Bun Production Build
9
-
10
- **Impact: CRITICAL (Build failure blocks deployment)**
11
-
12
- Bun 번들러를 사용하여 프로덕션 최적화된 빌드를 생성하세요.
13
-
14
- **bunfig.toml 설정:**
15
-
16
- ```toml
17
- [build]
18
- target = "bun"
19
- minify = true
20
- sourcemap = "external"
21
-
22
- [build.define]
23
- "process.env.NODE_ENV" = "'production'"
24
- ```
25
-
26
- **빌드 스크립트:**
27
-
28
- ```typescript
29
- // scripts/build.ts
30
- import { $ } from "bun";
31
-
32
- // 클린 빌드
33
- await $`rm -rf dist`;
34
-
35
- // 서버 빌드
36
- await Bun.build({
37
- entrypoints: ["./src/server.ts"],
38
- outdir: "./dist",
39
- target: "bun",
40
- minify: true,
41
- sourcemap: "external",
42
- define: {
43
- "process.env.NODE_ENV": JSON.stringify("production"),
44
- },
45
- });
46
-
47
- // 클라이언트 빌드 (Islands)
48
- await Bun.build({
49
- entrypoints: ["./app/**/client.tsx"],
50
- outdir: "./dist/public",
51
- target: "browser",
52
- minify: true,
53
- splitting: true,
54
- sourcemap: "external",
55
- });
56
-
57
- console.log("✅ Build complete");
58
- ```
59
-
60
- ## package.json 스크립트
61
-
62
- ```json
63
- {
64
- "scripts": {
65
- "build": "bun run scripts/build.ts",
66
- "start": "NODE_ENV=production bun run dist/server.js",
67
- "preview": "bun run build && bun run start"
68
- }
69
- }
70
- ```
71
-
72
- ## 빌드 최적화 옵션
73
-
74
- ```typescript
75
- await Bun.build({
76
- entrypoints: ["./src/index.ts"],
77
- outdir: "./dist",
78
-
79
- // 필수 최적화
80
- minify: true, // 코드 압축
81
- splitting: true, // 코드 분할
82
-
83
- // 선택적 최적화
84
- treeshaking: true, // 미사용 코드 제거 (기본값)
85
-
86
- // 외부 패키지 처리
87
- external: ["better-sqlite3"], // 네이티브 모듈 제외
88
-
89
- // 환경 변수 주입
90
- define: {
91
- "process.env.API_URL": JSON.stringify(process.env.API_URL),
92
- },
93
- });
94
- ```
95
-
96
- ## 빌드 검증
97
-
98
- ```bash
99
- # 빌드 크기 확인
100
- du -sh dist/
101
-
102
- # 번들 분석
103
- bun build --analyze ./src/server.ts
104
-
105
- # 빌드 테스트
106
- bun run dist/server.js
107
- ```
108
-
109
- Reference: [Bun Bundler](https://bun.sh/docs/bundler)
@@ -1,115 +0,0 @@
1
- ---
2
- title: Build Output Configuration
3
- impact: HIGH
4
- impactDescription: Affects bundle size and load performance
5
- tags: deployment, build, output, optimization
6
- ---
7
-
8
- ## Build Output Configuration
9
-
10
- **Impact: HIGH (Affects bundle size and load performance)**
11
-
12
- 빌드 출력을 최적화하여 번들 크기를 줄이고 로딩 성능을 개선하세요.
13
-
14
- **디렉토리 구조:**
15
-
16
- ```
17
- dist/
18
- ├── server.js # 서버 엔트리포인트
19
- ├── public/
20
- │ ├── islands/ # Island 컴포넌트 청크
21
- │ │ ├── counter-abc123.js
22
- │ │ └── form-def456.js
23
- │ ├── shared/ # 공유 청크
24
- │ │ └── react-vendor-xyz789.js
25
- │ └── assets/ # 정적 자산
26
- │ ├── styles.css
27
- │ └── images/
28
- └── server.js.map # 소스맵 (프로덕션 디버깅용)
29
- ```
30
-
31
- **청크 분할 설정:**
32
-
33
- ```typescript
34
- // scripts/build.ts
35
- await Bun.build({
36
- entrypoints: ["./app/**/client.tsx"],
37
- outdir: "./dist/public/islands",
38
- target: "browser",
39
- splitting: true, // 공유 코드 자동 분리
40
- minify: true,
41
- naming: {
42
- chunk: "[name]-[hash].js",
43
- entry: "[name]-[hash].js",
44
- asset: "[name]-[hash][ext]",
45
- },
46
- });
47
- ```
48
-
49
- ## 정적 자산 처리
50
-
51
- ```typescript
52
- // 정적 파일 복사
53
- import { $ } from "bun";
54
-
55
- // public 폴더 복사
56
- await $`cp -r public/* dist/public/`;
57
-
58
- // CSS 최적화 (optional)
59
- await $`bunx lightningcss --minify public/styles.css -o dist/public/styles.css`;
60
- ```
61
-
62
- ## Gzip/Brotli 압축
63
-
64
- ```typescript
65
- // 프로덕션 서버에서 압축
66
- import { gzipSync } from "bun";
67
-
68
- // 또는 빌드 시 사전 압축
69
- import { $ } from "bun";
70
-
71
- const files = await Array.fromAsync(
72
- new Bun.Glob("dist/public/**/*.{js,css}").scan()
73
- );
74
-
75
- for (const file of files) {
76
- const content = await Bun.file(file).arrayBuffer();
77
- await Bun.write(`${file}.gz`, gzipSync(new Uint8Array(content)));
78
- }
79
- ```
80
-
81
- ## 빌드 매니페스트
82
-
83
- ```typescript
84
- // 빌드 후 매니페스트 생성
85
- const manifest = {
86
- version: process.env.BUILD_VERSION || Date.now().toString(),
87
- files: {},
88
- };
89
-
90
- const files = await Array.fromAsync(
91
- new Bun.Glob("dist/public/**/*").scan()
92
- );
93
-
94
- for (const file of files) {
95
- const hash = Bun.hash(await Bun.file(file).arrayBuffer());
96
- manifest.files[file] = hash.toString(16);
97
- }
98
-
99
- await Bun.write("dist/manifest.json", JSON.stringify(manifest, null, 2));
100
- ```
101
-
102
- ## 번들 크기 모니터링
103
-
104
- ```bash
105
- # 번들 크기 리포트
106
- bun run scripts/bundle-size.ts
107
-
108
- # CI에서 크기 제한 체크
109
- if [ $(du -sb dist/public | cut -f1) -gt 1048576 ]; then
110
- echo "Bundle size exceeds 1MB limit"
111
- exit 1
112
- fi
113
- ```
114
-
115
- Reference: [Bun Build Naming](https://bun.sh/docs/bundler#naming)