create-lego-one 2.0.12 → 2.0.13
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.
- package/dist/index.cjs +34 -0
- package/dist/index.cjs.map +1 -1
- package/package.json +1 -1
- package/template/.cursor/rules/rules.mdc +639 -0
- package/template/.dockerignore +58 -0
- package/template/.env.example +18 -0
- package/template/.eslintignore +5 -0
- package/template/.eslintrc.js +28 -0
- package/template/.prettierignore +6 -0
- package/template/.prettierrc +11 -0
- package/template/CLAUDE.md +634 -0
- package/template/Dockerfile +67 -0
- package/template/PROMPT.md +457 -0
- package/template/README.md +325 -0
- package/template/docker-compose.yml +48 -0
- package/template/docker-entrypoint.sh +23 -0
- package/template/docs/checkpoints/.template.md +64 -0
- package/template/docs/checkpoints/framework/01-infrastructure-setup.md +132 -0
- package/template/docs/checkpoints/framework/02-pocketbase-setup.md +155 -0
- package/template/docs/checkpoints/framework/03-host-kernel.md +170 -0
- package/template/docs/checkpoints/framework/04-auth-system.md +163 -0
- package/template/docs/checkpoints/framework/phase-05-multitenancy-rbac.md +223 -0
- package/template/docs/checkpoints/framework/phase-06-ui-components.md +260 -0
- package/template/docs/checkpoints/framework/phase-07-communication-system.md +276 -0
- package/template/docs/checkpoints/framework/phase-08-plugin-system.md +91 -0
- package/template/docs/checkpoints/framework/phase-09-dashboard-plugin.md +111 -0
- package/template/docs/checkpoints/framework/phase-10-todo-plugin.md +169 -0
- package/template/docs/checkpoints/framework/phase-11-testing.md +264 -0
- package/template/docs/checkpoints/framework/phase-12-deployment.md +294 -0
- package/template/docs/checkpoints/framework/phase-13-documentation.md +312 -0
- package/template/docs/framework/plans/00-index.md +164 -0
- package/template/docs/framework/plans/01-infrastructure-setup.md +855 -0
- package/template/docs/framework/plans/02-pocketbase-setup.md +1374 -0
- package/template/docs/framework/plans/03-host-kernel.md +1518 -0
- package/template/docs/framework/plans/04-auth-system.md +1466 -0
- package/template/docs/framework/plans/05-multitenancy-rbac.md +1527 -0
- package/template/docs/framework/plans/06-ui-components.md +1478 -0
- package/template/docs/framework/plans/07-communication-system.md +1106 -0
- package/template/docs/framework/plans/08-plugin-system.md +1179 -0
- package/template/docs/framework/plans/09-dashboard-plugin.md +1137 -0
- package/template/docs/framework/plans/10-todo-plugin.md +1343 -0
- package/template/docs/framework/plans/11-testing.md +935 -0
- package/template/docs/framework/plans/12-deployment.md +896 -0
- package/template/docs/framework/prompts/0-boilerplate-modernjs.md +151 -0
- package/template/docs/framework/research/00-modernjs-audit.md +488 -0
- package/template/docs/framework/research/01-system-blueprint.md +721 -0
- package/template/docs/framework/research/02-data-migration-protocol.md +699 -0
- package/template/docs/framework/research/03-host-setup.md +714 -0
- package/template/docs/framework/research/04-plugin-architecture.md +645 -0
- package/template/docs/framework/research/05-slot-injection-pattern.md +671 -0
- package/template/docs/framework/research/06-cli-strategy.md +615 -0
- package/template/docs/framework/research/07-deployment.md +629 -0
- package/template/docs/framework/research/README.md +282 -0
- package/template/docs/framework/setup/00-index.md +210 -0
- package/template/docs/framework/setup/01-framework-structure.md +308 -0
- package/template/docs/framework/setup/02-development-workflow.md +405 -0
- package/template/docs/framework/setup/03-environment-setup.md +215 -0
- package/template/docs/framework/setup/04-kernel-architecture.md +499 -0
- package/template/docs/framework/setup/05-plugin-system.md +620 -0
- package/template/docs/framework/setup/06-communication-patterns.md +451 -0
- package/template/docs/framework/setup/07-plugin-development.md +582 -0
- package/template/docs/framework/setup/08-component-library.md +658 -0
- package/template/docs/framework/setup/09-data-integration.md +609 -0
- package/template/docs/framework/setup/10-auth-rbac.md +497 -0
- package/template/docs/framework/setup/11-hooks-api.md +393 -0
- package/template/docs/framework/setup/12-components-api.md +665 -0
- package/template/docs/framework/setup/13-deployment-guide.md +566 -0
- package/template/docs/framework/setup/README.md +548 -0
- package/template/host/package.json +1 -1
- package/template/nginx.conf +72 -0
- package/template/package.json +1 -1
- package/template/packages/plugins/@lego/plugin-dashboard/package.json +1 -1
- package/template/packages/plugins/@lego/plugin-todo/package.json +1 -1
- package/template/pocketbase/CHANGELOG.md +911 -0
- package/template/pocketbase/LICENSE.md +17 -0
- package/template/scripts/create-plugin.js +221 -0
- package/template/scripts/deploy.sh +56 -0
- package/template/tsconfig.base.json +26 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
# Deployment: Host and Sub-Apps
|
|
2
|
+
|
|
3
|
+
**Project:** Lego-One (Modern.js SaaS OS)
|
|
4
|
+
**Document:** 07 - Deployment Strategy
|
|
5
|
+
**Status:** Research Phase
|
|
6
|
+
|
|
7
|
+
## Executive Summary
|
|
8
|
+
|
|
9
|
+
This document explains how to deploy the Lego-One application to production. **Plugins are bundled into the host** for single-server deployment, while remaining separate during development for independent workflow.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Deployment Architecture
|
|
14
|
+
|
|
15
|
+
### 1.1 Key Principle
|
|
16
|
+
|
|
17
|
+
**Development = Separate servers │ Production = Single server (plugins bundled)**
|
|
18
|
+
|
|
19
|
+
### 1.2 Production Runtime Diagram
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
23
|
+
│ Production Environment │
|
|
24
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
25
|
+
│ │
|
|
26
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
27
|
+
│ │ CDN / Edge Layer │ │
|
|
28
|
+
│ │ (Vercel Edge, CloudFront) │ │
|
|
29
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
30
|
+
│ │ │
|
|
31
|
+
│ ▼ │
|
|
32
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
33
|
+
│ │ Application Server (Single) │ │
|
|
34
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
35
|
+
│ │ │ host/dist/ │ │ │
|
|
36
|
+
│ │ │ ├── index.html │ │ │
|
|
37
|
+
│ │ │ ├── static/js/ │ │ │
|
|
38
|
+
│ │ │ │ ├── main-[hash].js (Host + Kernel) │ │ │
|
|
39
|
+
│ │ │ │ ├── vendor-[hash].js (React, Zustand, etc.) │ │ │
|
|
40
|
+
│ │ │ │ └── plugins/ ← ALL PLUGINS BUNDLED │ │ │
|
|
41
|
+
│ │ │ │ ├── dashboard-[hash].js (Plugin A) │ │ │
|
|
42
|
+
│ │ │ │ ├── loan-calc-[hash].js (Plugin B) │ │ │
|
|
43
|
+
│ │ │ │ └── inventory-[hash].js (Plugin C) │ │ │
|
|
44
|
+
│ │ │ └── static/css/ │ │ │
|
|
45
|
+
│ │ │ └── main-[hash].css │ │ │
|
|
46
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
47
|
+
│ │ │ │ │
|
|
48
|
+
│ │ │ One deployment, one URL │ │
|
|
49
|
+
│ │ ▼ │ │
|
|
50
|
+
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
51
|
+
│ │ │ Browser loads app.yourdomain.com │ │ │
|
|
52
|
+
│ │ │ │ │ │
|
|
53
|
+
│ │ │ User navigates → Garfish loads plugin bundle dynamically │ │ │
|
|
54
|
+
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
|
55
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
56
|
+
│ │ │
|
|
57
|
+
│ │ API Calls │
|
|
58
|
+
│ ▼ │
|
|
59
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
60
|
+
│ │ PocketBase │ │
|
|
61
|
+
│ │ - Docker Container / Managed Service │ │
|
|
62
|
+
│ │ - Port 8090 │ │
|
|
63
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
64
|
+
│ │
|
|
65
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 1.3 Development Runtime Diagram (For Comparison)
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
72
|
+
│ Development Environment │
|
|
73
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
74
|
+
│ │
|
|
75
|
+
│ Host : http://localhost:8080 │
|
|
76
|
+
│ Plugin A : http://localhost:3001 ← Separate dev server │
|
|
77
|
+
│ Plugin B : http://localhost:3002 ← Separate dev server │
|
|
78
|
+
│ Plugin C : http://localhost:3003 ← Separate dev server │
|
|
79
|
+
│ │
|
|
80
|
+
│ WHY? Each developer can work on a plugin independently │
|
|
81
|
+
│ Hot reload works independently for each plugin │
|
|
82
|
+
│ │
|
|
83
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 2: Monorepo vs Polyrepo
|
|
89
|
+
|
|
90
|
+
### 2.1 Comparison Table
|
|
91
|
+
|
|
92
|
+
| Aspect | Monorepo | Polyrepo |
|
|
93
|
+
|--------|----------|----------|
|
|
94
|
+
| **Code Organization** | Single repo with host + plugins | Separate repo per plugin |
|
|
95
|
+
| **Shared Dependencies** | Easy (root package.json) | Difficult (duplicate versions) |
|
|
96
|
+
| **CI/CD** | Single pipeline | Multiple pipelines |
|
|
97
|
+
| **Deployment** | Host + plugins together | Independent plugin deployments |
|
|
98
|
+
| **Team Autonomy** | Coordinated changes | Fully independent |
|
|
99
|
+
| **Git History** | Single timeline | Separate timelines |
|
|
100
|
+
| **Recommended For** | Small teams, tight coupling | Large teams, independent plugins |
|
|
101
|
+
|
|
102
|
+
### 2.2 Our Recommendation: **Monorepo**
|
|
103
|
+
|
|
104
|
+
**Reasons:**
|
|
105
|
+
1. Modern.js + Garfish work best with shared dependencies
|
|
106
|
+
2. Simplified development (`pnpm install` at root)
|
|
107
|
+
3. Atomic commits across host + plugins
|
|
108
|
+
4. Easier onboarding and documentation
|
|
109
|
+
5. pnpm workspaces handle this well
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 3. Monorepo Deployment
|
|
114
|
+
|
|
115
|
+
### 3.1 Repository Structure
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
lego-one/ # Single monorepo
|
|
119
|
+
├── host/ # Kernel application
|
|
120
|
+
├── packages/
|
|
121
|
+
│ └── plugins/
|
|
122
|
+
│ └── @lego/
|
|
123
|
+
│ ├── plugin-dashboard/ # Official plugins
|
|
124
|
+
│ ├── plugin-auth/
|
|
125
|
+
│ └── plugin-billing/
|
|
126
|
+
├── pnpm-workspace.yaml
|
|
127
|
+
├── package.json
|
|
128
|
+
├── turbo.json # Turborepo config (optional)
|
|
129
|
+
└── .github/
|
|
130
|
+
└── workflows/
|
|
131
|
+
└── deploy.yml # CI/CD pipeline
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 3.2 Workspace Configuration
|
|
135
|
+
|
|
136
|
+
**File:** `pnpm-workspace.yaml`
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
packages:
|
|
140
|
+
- 'host'
|
|
141
|
+
- 'packages/plugins/@lego/*'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**File:** `package.json` (root)
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"name": "lego-one",
|
|
149
|
+
"version": "1.0.0",
|
|
150
|
+
"private": true,
|
|
151
|
+
"scripts": {
|
|
152
|
+
"dev": "pnpm --filter './host' dev",
|
|
153
|
+
"build": "pnpm -r --filter './host' --filter './packages/plugins/@lego/*' build",
|
|
154
|
+
"clean": "pnpm -r clean",
|
|
155
|
+
"lint": "pnpm -r lint",
|
|
156
|
+
"typecheck": "pnpm -r typecheck"
|
|
157
|
+
},
|
|
158
|
+
"devDependencies": {
|
|
159
|
+
"@modern-js/app-tools": "^2.0.0",
|
|
160
|
+
"typescript": "^5.5.0"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 4. Build Strategy
|
|
168
|
+
|
|
169
|
+
### 4.1 Production Build Output (Single Server)
|
|
170
|
+
|
|
171
|
+
**IMPORTANT:** In production, ALL plugins are bundled into the host's `dist/` folder. Modern.js handles this automatically when you use dynamic imports.
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
host/dist/
|
|
175
|
+
├── html/
|
|
176
|
+
│ └── index.html # Entry point
|
|
177
|
+
├── static/
|
|
178
|
+
│ ├── js/
|
|
179
|
+
│ │ ├── main-[hash].js # Host bundle
|
|
180
|
+
│ │ ├── vendor-[hash].js # Shared dependencies (React, Zustand, etc.)
|
|
181
|
+
│ │ ├── plugins/ ← PLUGINS BUNDLED HERE
|
|
182
|
+
│ │ │ ├── dashboard-[hash].js
|
|
183
|
+
│ │ │ ├── loan-calc-[hash].js
|
|
184
|
+
│ │ │ └── inventory-[hash].js
|
|
185
|
+
│ │ └── ... # Code-split chunks
|
|
186
|
+
│ └── css/
|
|
187
|
+
│ └── main-[hash].css
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Key Point:** Each plugin is code-split and loaded on-demand when the user navigates to its route. Not all plugins load immediately!
|
|
191
|
+
|
|
192
|
+
### 4.2 Build Configuration
|
|
193
|
+
|
|
194
|
+
**Host:** `host/modern.config.ts`
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
export default defineConfig({
|
|
198
|
+
// Production optimization
|
|
199
|
+
output: {
|
|
200
|
+
distPath: {
|
|
201
|
+
html: './dist/html',
|
|
202
|
+
js: './dist/static/js',
|
|
203
|
+
css: './dist/static/css',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
// Asset prefix for CDN
|
|
208
|
+
source: {
|
|
209
|
+
assetPrefix: process.env.CDN_URL || '',
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Plugin:** `packages/plugins/@lego/plugin-dashboard/modern.config.ts`
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
export default defineConfig({
|
|
218
|
+
deploy: {
|
|
219
|
+
microFrontend: true,
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
output: {
|
|
223
|
+
distPath: {
|
|
224
|
+
html: './dist/html',
|
|
225
|
+
js: './dist/static/js',
|
|
226
|
+
css: './dist/static/css',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 4.3 Shared Dependencies
|
|
233
|
+
|
|
234
|
+
Modern.js + Garfish automatically handle shared dependencies. In production:
|
|
235
|
+
|
|
236
|
+
- **Host bundle** includes: React, ReactDOM, Router, Zustand
|
|
237
|
+
- **Plugin bundles** exclude: React, ReactDOM (marked as external)
|
|
238
|
+
- **Runtime**: Garfish loads shared deps from host, avoids duplicate loading
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 5. Deployment Options
|
|
243
|
+
|
|
244
|
+
### 5.1 Option A: Vercel (Recommended)
|
|
245
|
+
|
|
246
|
+
**Pros:**
|
|
247
|
+
- Zero-config deployment
|
|
248
|
+
- Built-in CI/CD
|
|
249
|
+
- Edge caching
|
|
250
|
+
- Preview deployments
|
|
251
|
+
- **Single deployment for entire app**
|
|
252
|
+
|
|
253
|
+
**Setup:**
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Install Vercel CLI
|
|
257
|
+
pnpm add -g vercel
|
|
258
|
+
|
|
259
|
+
# Deploy the entire app (host + bundled plugins)
|
|
260
|
+
cd host
|
|
261
|
+
vercel --prod
|
|
262
|
+
|
|
263
|
+
# That's it! Plugins are already bundled into host/dist
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**No separate plugin deployments needed!**
|
|
267
|
+
|
|
268
|
+
**Environment Variables:**
|
|
269
|
+
|
|
270
|
+
| Variable | Description | Example |
|
|
271
|
+
|----------|-------------|---------|
|
|
272
|
+
| `VITE_POCKETBASE_URL` | PocketBase API URL | `https://api.example.com` |
|
|
273
|
+
| `VITE_POCKETBASE_ADMIN_EMAIL` | Admin email (for migrations) | `admin@example.com` |
|
|
274
|
+
| `VITE_POCKETBASE_ADMIN_PASSWORD` | Admin password | `***` |
|
|
275
|
+
| `CDN_URL` | CDN prefix for assets | `https://cdn.example.com` |
|
|
276
|
+
|
|
277
|
+
### 5.2 Option B: Railway
|
|
278
|
+
|
|
279
|
+
**Pros:**
|
|
280
|
+
- Docker support
|
|
281
|
+
- Built-in databases
|
|
282
|
+
- Easy PocketBase deployment
|
|
283
|
+
|
|
284
|
+
**Setup:**
|
|
285
|
+
|
|
286
|
+
Create `Dockerfile` for PocketBase:
|
|
287
|
+
|
|
288
|
+
```dockerfile
|
|
289
|
+
# Dockerfile.pocketbase
|
|
290
|
+
FROM alpine:latest
|
|
291
|
+
|
|
292
|
+
RUN apk add --no-cache wget ca-certificates
|
|
293
|
+
|
|
294
|
+
WORKDIR /app
|
|
295
|
+
|
|
296
|
+
# Download PocketBase
|
|
297
|
+
RUN wget https://github.com/pocketbase/pocketbase/releases/download/v0.22.0/pocketbase_0.22.0_linux_amd64.zip
|
|
298
|
+
RUN unzip pocketbase_0.22.0_linux_amd64.zip
|
|
299
|
+
|
|
300
|
+
EXPOSE 8090
|
|
301
|
+
|
|
302
|
+
CMD ["./pocketbase", "serve", "--http", "0.0.0.0:8090"]
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 5.3 Option C: Self-Hosted (Docker Compose)
|
|
306
|
+
|
|
307
|
+
**File:** `docker-compose.yml`
|
|
308
|
+
|
|
309
|
+
```yaml
|
|
310
|
+
version: '3.8'
|
|
311
|
+
|
|
312
|
+
services:
|
|
313
|
+
pocketbase:
|
|
314
|
+
build:
|
|
315
|
+
context: .
|
|
316
|
+
dockerfile: Dockerfile.pocketbase
|
|
317
|
+
ports:
|
|
318
|
+
- "8090:8090"
|
|
319
|
+
volumes:
|
|
320
|
+
- pocketbase_data:/app/pb_data
|
|
321
|
+
restart: unless-stopped
|
|
322
|
+
|
|
323
|
+
# Single app service (plugins already bundled in!)
|
|
324
|
+
app:
|
|
325
|
+
image: node:18-alpine
|
|
326
|
+
working_dir: /app
|
|
327
|
+
volumes:
|
|
328
|
+
- ./host:/app
|
|
329
|
+
- /app/node_modules
|
|
330
|
+
ports:
|
|
331
|
+
- "8080:8080"
|
|
332
|
+
command: sh -c "npm install && npm run build && npm run preview"
|
|
333
|
+
environment:
|
|
334
|
+
- VITE_POCKETBASE_URL=http://pocketbase:8090
|
|
335
|
+
depends_on:
|
|
336
|
+
- pocketbase
|
|
337
|
+
|
|
338
|
+
volumes:
|
|
339
|
+
pocketbase_data:
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Note:** No separate plugin containers needed! They're bundled in the app build.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 6. CI/CD Pipeline
|
|
347
|
+
|
|
348
|
+
### 6.1 GitHub Actions Workflow
|
|
349
|
+
|
|
350
|
+
**File:** `.github/workflows/deploy.yml`
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
name: Deploy
|
|
354
|
+
|
|
355
|
+
on:
|
|
356
|
+
push:
|
|
357
|
+
branches: [main]
|
|
358
|
+
pull_request:
|
|
359
|
+
branches: [main]
|
|
360
|
+
|
|
361
|
+
env:
|
|
362
|
+
NODE_VERSION: '18'
|
|
363
|
+
PNPM_VERSION: '8'
|
|
364
|
+
|
|
365
|
+
jobs:
|
|
366
|
+
# Test job
|
|
367
|
+
test:
|
|
368
|
+
runs-on: ubuntu-latest
|
|
369
|
+
steps:
|
|
370
|
+
- uses: actions/checkout@v4
|
|
371
|
+
|
|
372
|
+
- uses: pnpm/action-setup@v2
|
|
373
|
+
with:
|
|
374
|
+
version: ${{ env.PNPM_VERSION }}
|
|
375
|
+
|
|
376
|
+
- uses: actions/setup-node@v4
|
|
377
|
+
with:
|
|
378
|
+
node-version: ${{ env.NODE_VERSION }}
|
|
379
|
+
cache: 'pnpm'
|
|
380
|
+
|
|
381
|
+
- name: Install dependencies
|
|
382
|
+
run: pnpm install
|
|
383
|
+
|
|
384
|
+
- name: Run tests
|
|
385
|
+
run: pnpm test
|
|
386
|
+
|
|
387
|
+
- name: Type check
|
|
388
|
+
run: pnpm typecheck
|
|
389
|
+
|
|
390
|
+
- name: Lint
|
|
391
|
+
run: pnpm lint
|
|
392
|
+
|
|
393
|
+
# Build job
|
|
394
|
+
build:
|
|
395
|
+
needs: test
|
|
396
|
+
runs-on: ubuntu-latest
|
|
397
|
+
steps:
|
|
398
|
+
- uses: actions/checkout@v4
|
|
399
|
+
|
|
400
|
+
- uses: pnpm/action-setup@v2
|
|
401
|
+
with:
|
|
402
|
+
version: ${{ env.PNPM_VERSION }}
|
|
403
|
+
|
|
404
|
+
- uses: actions/setup-node@v4
|
|
405
|
+
with:
|
|
406
|
+
node-version: ${{ env.NODE_VERSION }}
|
|
407
|
+
cache: 'pnpm'
|
|
408
|
+
|
|
409
|
+
- name: Install dependencies
|
|
410
|
+
run: pnpm install
|
|
411
|
+
|
|
412
|
+
- name: Build application (host + plugins bundled)
|
|
413
|
+
run: pnpm build
|
|
414
|
+
|
|
415
|
+
- name: Upload artifacts
|
|
416
|
+
uses: actions/upload-artifact@v4
|
|
417
|
+
with:
|
|
418
|
+
name: dist
|
|
419
|
+
path: host/dist/
|
|
420
|
+
|
|
421
|
+
# Deploy job - Single deployment only!
|
|
422
|
+
deploy:
|
|
423
|
+
needs: build
|
|
424
|
+
runs-on: ubuntu-latest
|
|
425
|
+
if: github.ref == 'refs/heads/main'
|
|
426
|
+
steps:
|
|
427
|
+
- uses: actions/checkout@v4
|
|
428
|
+
|
|
429
|
+
- name: Download artifacts
|
|
430
|
+
uses: actions/download-artifact@v4
|
|
431
|
+
with:
|
|
432
|
+
name: dist
|
|
433
|
+
path: host/dist/
|
|
434
|
+
|
|
435
|
+
- name: Deploy to Vercel
|
|
436
|
+
working-directory: ./host
|
|
437
|
+
run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Key Change:** Only ONE deployment step, not separate host + plugin deployments!
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 7. Runtime Configuration
|
|
445
|
+
|
|
446
|
+
### 7.1 Host: Dev vs Prod Entry Points
|
|
447
|
+
|
|
448
|
+
**File:** `host/src/modern.runtime.ts`
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
import { defineRuntimeConfig } from '@modern-js/runtime';
|
|
452
|
+
|
|
453
|
+
// Detect environment
|
|
454
|
+
const isDev = import.meta.env.MODE === 'development';
|
|
455
|
+
|
|
456
|
+
export default defineRuntimeConfig({
|
|
457
|
+
masterApp: {
|
|
458
|
+
apps: [
|
|
459
|
+
{
|
|
460
|
+
name: '@lego/plugin-dashboard',
|
|
461
|
+
// Dev: Separate server │ Prod: Bundled via dynamic import
|
|
462
|
+
entry: isDev
|
|
463
|
+
? 'http://localhost:3001'
|
|
464
|
+
: () => import('@lego/plugin-dashboard'),
|
|
465
|
+
activeWhen: '/dashboard',
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: '@lego/plugin-loan-calculator',
|
|
469
|
+
entry: isDev
|
|
470
|
+
? 'http://localhost:3002'
|
|
471
|
+
: () => import('@lego/plugin-loan-calculator'),
|
|
472
|
+
activeWhen: '/apps/loan',
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
name: '@lego/plugin-inventory',
|
|
476
|
+
entry: isDev
|
|
477
|
+
? 'http://localhost:3003'
|
|
478
|
+
: () => import('@lego/plugin-inventory'),
|
|
479
|
+
activeWhen: '/apps/inventory',
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**How it works:**
|
|
487
|
+
- **Development:** Garfish fetches plugin from `http://localhost:3001`
|
|
488
|
+
- **Production:** Modern.js bundles plugin into host, loaded via `import()`
|
|
489
|
+
|
|
490
|
+
### 7.2 Environment-Specific Config
|
|
491
|
+
|
|
492
|
+
**File:** `.env.production`
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
# Host configuration
|
|
496
|
+
VITE_POCKETBASE_URL=https://api.yourdomain.com
|
|
497
|
+
VITE_POCKETBASE_ADMIN_EMAIL=admin@yourdomain.com
|
|
498
|
+
VITE_POCKETBASE_ADMIN_PASSWORD=${PB_ADMIN_PASSWORD}
|
|
499
|
+
|
|
500
|
+
# No plugin URLs needed! They're bundled in production.
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**File:** `.env.development`
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
# Host configuration
|
|
507
|
+
VITE_POCKETBASE_URL=http://localhost:8090
|
|
508
|
+
VITE_POCKETBASE_ADMIN_EMAIL=admin@localhost
|
|
509
|
+
VITE_POCKETBASE_ADMIN_PASSWORD=admin123
|
|
510
|
+
|
|
511
|
+
# Plugin dev servers (for reference)
|
|
512
|
+
VITE_DEV_DASHBOARD_PORT=3001
|
|
513
|
+
VITE_DEV_LOAN_CALC_PORT=3002
|
|
514
|
+
VITE_DEV_INVENTORY_PORT=3003
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## 8. Monitoring and Logging
|
|
520
|
+
|
|
521
|
+
### 8.1 Health Checks
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
// Host: src/api/health.ts
|
|
525
|
+
export async function healthCheck() {
|
|
526
|
+
const checks = {
|
|
527
|
+
host: true,
|
|
528
|
+
pocketbase: false,
|
|
529
|
+
plugins: {},
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// Check PocketBase
|
|
533
|
+
try {
|
|
534
|
+
const pb = new PocketBase(import.meta.env.VITE_POCKETBASE_URL);
|
|
535
|
+
await pb.health.check();
|
|
536
|
+
checks.pocketbase = true;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
console.error('PocketBase health check failed:', error);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Check plugins (if loaded)
|
|
542
|
+
for (const [name, app] of Object.entries(Garfish.apps)) {
|
|
543
|
+
checks.plugins[name] = app.appInfo ? true : false;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return checks;
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### 8.2 Error Tracking
|
|
551
|
+
|
|
552
|
+
Integrate Sentry for both host and plugins:
|
|
553
|
+
|
|
554
|
+
```typescript
|
|
555
|
+
// Host: src/bootstrap.tsx
|
|
556
|
+
import * as Sentry from '@sentry/react';
|
|
557
|
+
|
|
558
|
+
Sentry.init({
|
|
559
|
+
dsn: import.meta.env.VITE_SENTRY_DSN,
|
|
560
|
+
environment: import.meta.env.MODE,
|
|
561
|
+
// Track plugin errors separately
|
|
562
|
+
beforeSend(event, hint) {
|
|
563
|
+
if (event.exception?.values?.[0]?.stacktrace) {
|
|
564
|
+
const stack = event.exception.values[0].stacktrace;
|
|
565
|
+
// Tag plugin errors
|
|
566
|
+
for (const frame of stack.frames || []) {
|
|
567
|
+
if (frame.filename?.includes('@lego/plugin-')) {
|
|
568
|
+
event.tags = { ...event.tags, plugin: frame.filename };
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return event;
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 9. Deployment Checklist
|
|
581
|
+
|
|
582
|
+
### Pre-Deployment
|
|
583
|
+
|
|
584
|
+
- [ ] All tests passing
|
|
585
|
+
- [ ] TypeScript compilation successful
|
|
586
|
+
- [ ] Linting clean
|
|
587
|
+
- [ ] Environment variables configured
|
|
588
|
+
- [ ] PocketBase migrations tested
|
|
589
|
+
- [ ] Build completes successfully (host + plugins bundled)
|
|
590
|
+
|
|
591
|
+
### Post-Deployment
|
|
592
|
+
|
|
593
|
+
- [ ] Application accessible at domain
|
|
594
|
+
- [ ] Navigation loads plugins correctly
|
|
595
|
+
- [ ] PocketBase API accessible
|
|
596
|
+
- [ ] Authentication working
|
|
597
|
+
- [ ] SSL certificates valid
|
|
598
|
+
- [ ] Error monitoring active
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## 10. Next Steps
|
|
603
|
+
|
|
604
|
+
All research documents complete. Proceed to implementation planning phase.
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Research Summary
|
|
609
|
+
|
|
610
|
+
| Document | Status |
|
|
611
|
+
|----------|--------|
|
|
612
|
+
| `00-modernjs-audit.md` | ✅ Complete |
|
|
613
|
+
| `01-system-blueprint.md` | ✅ Complete |
|
|
614
|
+
| `02-data-migration-protocol.md` | ✅ Complete |
|
|
615
|
+
| `03-host-setup.md` | ✅ Complete |
|
|
616
|
+
| `04-plugin-architecture.md` | ✅ Complete |
|
|
617
|
+
| `05-slot-injection-pattern.md` | ✅ Complete |
|
|
618
|
+
| `06-cli-strategy.md` | ✅ Complete |
|
|
619
|
+
| `07-deployment.md` | ✅ Complete |
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## References
|
|
624
|
+
|
|
625
|
+
- [Modern.js Deployment Guide](https://modernjs.dev/guides/deploy)
|
|
626
|
+
- [Vercel Documentation](https://vercel.com/docs)
|
|
627
|
+
- [Railway Documentation](https://docs.railway.app/)
|
|
628
|
+
- [PocketBase Deployment](https://pocketbase.io/docs/go-deployment/)
|
|
629
|
+
- [GitHub Actions](https://docs.github.com/en/actions)
|