@crossdelta/platform-sdk 0.7.20 β 0.7.22
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/README.md +165 -417
- package/bin/templates/workspace/package.json.hbs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,12 +15,11 @@
|
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
18
|
-
<
|
|
18
|
+
<em>Includes optional AI-assisted service generation (OpenAI / Anthropic).</em>
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
22
|
<a href="https://www.npmjs.com/package/@crossdelta/platform-sdk"><img src="https://img.shields.io/npm/v/@crossdelta/platform-sdk.svg?style=flat-square" alt="npm version" /></a>
|
|
23
|
-
|
|
24
23
|
<img src="https://img.shields.io/badge/bun-%E2%9A%A1-f9f1e1?style=flat-square" alt="Bun" />
|
|
25
24
|
<img src="https://img.shields.io/badge/pulumi-ready-blueviolet?style=flat-square" alt="Pulumi" />
|
|
26
25
|
<img src="https://img.shields.io/badge/DigitalOcean-App_Platform_|_DOKS-0080FF?style=flat-square" alt="DigitalOcean" />
|
|
@@ -30,29 +29,24 @@
|
|
|
30
29
|
<em><code>pf</code> enforces conventions that keep application code and cloud infrastructure in lockstep β from local development to production.</em>
|
|
31
30
|
</p>
|
|
32
31
|
|
|
33
|
-
<br />
|
|
34
|
-
|
|
35
32
|
---
|
|
36
33
|
|
|
37
34
|
## Installation
|
|
38
35
|
|
|
39
36
|
```bash
|
|
40
|
-
# Pick your package manager
|
|
41
37
|
bun add -g @crossdelta/platform-sdk
|
|
42
|
-
npm install -g @crossdelta/platform-sdk
|
|
43
|
-
pnpm add -g @crossdelta/platform-sdk
|
|
38
|
+
# or: npm install -g @crossdelta/platform-sdk
|
|
44
39
|
```
|
|
45
40
|
|
|
46
41
|
<details>
|
|
47
|
-
<summary>Alternative: Auto-installer or
|
|
42
|
+
<summary>Alternative: Auto-installer or run without installing</summary>
|
|
48
43
|
|
|
49
44
|
```bash
|
|
50
|
-
# Auto-installer (
|
|
45
|
+
# Auto-installer (installs CLI globally, prompts to install Bun if missing)
|
|
51
46
|
curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash
|
|
52
47
|
|
|
53
|
-
# Or run directly without
|
|
48
|
+
# Or run directly without installing
|
|
54
49
|
bunx @crossdelta/platform-sdk new workspace my-platform
|
|
55
|
-
npx @crossdelta/platform-sdk new workspace my-platform
|
|
56
50
|
```
|
|
57
51
|
|
|
58
52
|
</details>
|
|
@@ -62,277 +56,83 @@ npx @crossdelta/platform-sdk new workspace my-platform
|
|
|
62
56
|
## Quick Start
|
|
63
57
|
|
|
64
58
|
```bash
|
|
65
|
-
|
|
66
|
-
pf new workspace my-platform -y
|
|
67
|
-
cd my-platform
|
|
68
|
-
|
|
69
|
-
# Generate microservice with AI
|
|
70
|
-
pf setup --ai # Configure AI provider (first time only)
|
|
71
|
-
pf new hono-micro services/orders --ai -d "Handle order creation and payment"
|
|
72
|
-
|
|
73
|
-
# Start development
|
|
59
|
+
pf new workspace my-platform -y && cd my-platform
|
|
74
60
|
pf dev
|
|
75
61
|
```
|
|
76
62
|
|
|
77
|
-
**What you get
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
- β Auto-generated `.env.local` with service ports
|
|
83
|
-
- β AI-generated service code
|
|
84
|
-
|
|
85
|
-
All wired automatically. Local + production infra in lockstep.
|
|
86
|
-
|
|
87
|
-
### β‘ One CLI for everything
|
|
88
|
-
|
|
89
|
-
`pf` runs your workspace scripts from anywhere:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
pf test # β turbo run test
|
|
93
|
-
pf build # β turbo run build
|
|
94
|
-
pf pulumi up # β runs in infra/ directory
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Why:** Keeps commands consistent across the team and works from any subdirectory.
|
|
98
|
-
|
|
99
|
-
> **π Note:** You can be productive with `pf` in minutes using the commands above. The sections below are reference documentationβexplore them when you need specific details.
|
|
100
|
-
|
|
101
|
-
<br />
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## π― Why This Exists
|
|
106
|
-
|
|
107
|
-
**`pf` solves these platform engineering problems:**
|
|
108
|
-
|
|
109
|
-
- **Infrastructure drift** β Infra configs live in separate repos, diverge from code
|
|
110
|
-
- **Manual wiring** β Ports, env vars, service discovery configured by hand
|
|
111
|
-
- **Slow onboarding** β New devs spend days setting up local environment
|
|
112
|
-
|
|
113
|
-
**`pf` is lockstep infra + code:** Services auto-generate `infra/services/*.ts`, ports/env derived automatically, event handlers type-safe and auto-discovered.
|
|
114
|
-
|
|
115
|
-
<br />
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## π§© What This SDK Is / Is Not
|
|
120
|
-
|
|
121
|
-
### β
`pf` is:
|
|
122
|
-
|
|
123
|
-
- **Opinionated platform toolkit** for event-driven microservices
|
|
124
|
-
- **[Turborepo](https://turbo.build/repo) scaffolder** with [Pulumi](https://www.pulumi.com) IaC and [NATS](https://nats.io) messaging built-in
|
|
125
|
-
- **AI-assisted code generator** that creates service boilerplate from descriptions
|
|
126
|
-
- **Unified dev workflow** β one command to run all services (`pf dev`)
|
|
127
|
-
- **[DigitalOcean](https://www.digitalocean.com)-first** deployment target (App Platform + DOKS)
|
|
128
|
-
|
|
129
|
-
### β `pf` is not:
|
|
130
|
-
|
|
131
|
-
- **Generic microservice generator** β makes architectural choices for you
|
|
132
|
-
- **Multi-cloud** (not yet) β DigitalOcean first, extensible provider architecture
|
|
133
|
-
- **Runtime manager** β scaffolds code, you deploy with Pulumi
|
|
134
|
-
- **Kubernetes replacement** β generates K8s configs via Pulumi
|
|
135
|
-
|
|
136
|
-
**Note:** `pf` runs nothing implicitlyβno hidden daemons, no automatic deployments or provisioning. You maintain explicit control over when code runs and infrastructure is deployed.
|
|
137
|
-
|
|
138
|
-
### π₯ Why `pf` vs other tools?
|
|
139
|
-
|
|
140
|
-
- **π Lockstep infra + code** β `infra/services/*.ts` auto-generated from service metadata, ports/env derived automatically
|
|
141
|
-
- **β‘ Event-driven by default** β [NATS](https://nats.io) + JetStream built-in with auto-discovered handlers (`*.event.ts`) and Zod-validated payloads
|
|
142
|
-
- **π€ Automation through conventions** β New service = infra config + env vars + port assignment happens automatically
|
|
63
|
+
**What you get:**
|
|
64
|
+
- Turborepo monorepo with Biome linting
|
|
65
|
+
- NATS + JetStream for event-driven messaging
|
|
66
|
+
- Pulumi infrastructure (`infra/services/*.ts`)
|
|
67
|
+
- Auto-generated `.env.local` with service ports
|
|
143
68
|
|
|
144
|
-
|
|
69
|
+
> **Lockstep by design:**
|
|
70
|
+
> In `pf`, application code and infrastructure are generated from the same source of truth.
|
|
71
|
+
> Service metadata defines ports, env vars, event wiring, and Pulumi configs β
|
|
72
|
+
> eliminating drift between local development, CI, and production.
|
|
145
73
|
|
|
146
74
|
---
|
|
147
75
|
|
|
148
|
-
##
|
|
76
|
+
## π§ How You Work With pf (Happy Paths)
|
|
149
77
|
|
|
150
|
-
|
|
78
|
+
### Start a new platform
|
|
151
79
|
|
|
80
|
+
```bash
|
|
81
|
+
pf new workspace my-platform --github-owner my-org --pulumi-stack dev -y
|
|
82
|
+
cd my-platform
|
|
83
|
+
pf dev
|
|
152
84
|
```
|
|
153
|
-
my-platform/
|
|
154
|
-
βββ services/ # Microservices (generate with pf new hono-micro)
|
|
155
|
-
β βββ nats/ # NATS message broker (auto-scaffolded)
|
|
156
|
-
β βββ <service>/ # Your services go here
|
|
157
|
-
β βββ src/
|
|
158
|
-
β βββ events/ # Event handlers (*.event.ts)
|
|
159
|
-
β βββ use-cases/ # Business logic (*.use-case.ts)
|
|
160
|
-
β βββ types/ # Zod schemas & types
|
|
161
|
-
β βββ index.ts # Service entrypoint
|
|
162
|
-
βββ apps/ # Frontend apps (optional)
|
|
163
|
-
βββ packages/
|
|
164
|
-
β βββ contracts/ # Event contracts (Schema Registry)
|
|
165
|
-
β βββ src/
|
|
166
|
-
β βββ events/ # Event schemas (single source of truth)
|
|
167
|
-
βββ infra/ # Pulumi Infrastructure-as-Code
|
|
168
|
-
β βββ index.ts # Main Pulumi program
|
|
169
|
-
β βββ services/ # Per-service K8s configs (auto-generated)
|
|
170
|
-
βββ .github/
|
|
171
|
-
β βββ workflows/ # CI/CD pipelines
|
|
172
|
-
βββ turbo.json # Turborepo task orchestration
|
|
173
|
-
βββ .env.local # Auto-generated from infra configs
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Key Conventions
|
|
177
|
-
|
|
178
|
-
| Location | Purpose |
|
|
179
|
-
|----------|---------|
|
|
180
|
-
| `services/*/src/events/*.event.ts` | Event handlers (auto-discovered) |
|
|
181
|
-
| `services/*/src/use-cases/*.use-case.ts` | Business logic (pure functions) |
|
|
182
|
-
| `services/*/src/types/*.ts` | Service-local Zod schemas |
|
|
183
|
-
| `packages/contracts/src/events/*.ts` | Event contracts (Schema Registry) |
|
|
184
|
-
| `infra/services/*.ts` | Pulumi configs per service |
|
|
185
|
-
|
|
186
|
-
### Key Rules
|
|
187
|
-
|
|
188
|
-
- **Never duplicate schemas** β Contracts in `packages/contracts` are the single source of truth
|
|
189
|
-
- **Event handlers stay thin** β Delegate to use-cases, no business logic in handlers
|
|
190
|
-
- **Infrastructure is explicit** β Ports, env vars derived from `infra/services/*.ts`
|
|
191
|
-
|
|
192
|
-
### Event-Driven Mental Model
|
|
193
|
-
|
|
194
|
-
Services communicate via **CloudEvents** over **NATS JetStream** using the **Schema Registry** as single source of truth:
|
|
195
|
-
|
|
196
|
-
**1. Define contract (Schema Registry):**
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
// packages/contracts/src/events/orders-created.ts
|
|
200
|
-
import { createContract } from '@crossdelta/cloudevents'
|
|
201
|
-
import { z } from 'zod'
|
|
202
85
|
|
|
203
|
-
|
|
204
|
-
type: 'orders.created',
|
|
205
|
-
schema: z.object({
|
|
206
|
-
orderId: z.string(),
|
|
207
|
-
customerId: z.string(),
|
|
208
|
-
total: z.number(),
|
|
209
|
-
}),
|
|
210
|
-
})
|
|
86
|
+
This scaffolds a complete Turborepo monorepo with NATS, Pulumi infrastructure, GitHub Actions workflows, and auto-generated environment variables.
|
|
211
87
|
|
|
212
|
-
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**2. Service A publishes an event:**
|
|
88
|
+
### Add a new microservice
|
|
216
89
|
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
import { publish } from '@crossdelta/cloudevents'
|
|
220
|
-
import { OrdersCreatedContract } from '@my-platform/contracts'
|
|
221
|
-
|
|
222
|
-
await publish(OrdersCreatedContract, {
|
|
223
|
-
orderId: '123',
|
|
224
|
-
customerId: 'cust-456',
|
|
225
|
-
total: 99.99
|
|
226
|
-
})
|
|
90
|
+
```bash
|
|
91
|
+
pf new hono-micro services/orders
|
|
227
92
|
```
|
|
228
93
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
// services/notifications/src/events/orders-created.event.ts
|
|
233
|
-
import { handleEvent } from '@crossdelta/cloudevents'
|
|
234
|
-
import { OrdersCreatedContract, type OrdersCreatedData } from '@my-platform/contracts'
|
|
235
|
-
import { sendOrderNotification } from '../use-cases/send-order-notification.use-case'
|
|
94
|
+
Or use AI generation:
|
|
236
95
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
})
|
|
96
|
+
```bash
|
|
97
|
+
pf new hono-micro services/orders --ai -d "Handle order creation and publish order events"
|
|
240
98
|
```
|
|
241
99
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
<br />
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
## π§ Design Principles
|
|
249
|
-
|
|
250
|
-
These principles guide every decision in `pf`:
|
|
100
|
+
Both generate the service structure, Pulumi config in `infra/services/`, and wire everything automatically.
|
|
251
101
|
|
|
252
|
-
|
|
253
|
-
- **π¦ Monorepo-centric** β One repo to rule them all. Turborepo for caching and parallel builds
|
|
254
|
-
- **ποΈ Infrastructure-as-Code by default** β No ClickOps. Every service has Pulumi config
|
|
255
|
-
- **π Event-driven communication baked in** β NATS + JetStream are first-class citizens, not afterthoughts
|
|
256
|
-
- **π DigitalOcean-first, cloud-agnostic later** β Start simple with DO, expand to AWS/GCP when needed
|
|
257
|
-
- **π€ AI-augmented development** β Use AI to generate complete services, not just snippets
|
|
258
|
-
- **π Convention over configuration** β Strong opinions enable automation
|
|
102
|
+
### Generate with AI (optional)
|
|
259
103
|
|
|
260
|
-
|
|
104
|
+
Configure your AI provider once:
|
|
261
105
|
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## π₯ Who Is This For?
|
|
265
|
-
|
|
266
|
-
`pf` is designed for **small to mid-sized teams building event-driven systems** who want strong conventions, infra parity, and fast onboarding β without maintaining their own internal platform.
|
|
267
|
-
|
|
268
|
-
<br />
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## π Deep Dive & Reference
|
|
273
|
-
|
|
274
|
-
The sections below cover architectural details, workflows, and advanced usage.
|
|
275
|
-
**You don't need to read them to get started** β they're here when you need them.
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## π Workflows
|
|
280
|
-
|
|
281
|
-
### Generate microservices
|
|
282
|
-
|
|
283
|
-
**Manual scaffolding:**
|
|
284
|
-
```bash
|
|
285
|
-
pf new hono-micro services/orders
|
|
286
|
-
pf new nest-micro services/api-gateway
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
**AI-powered generation:**
|
|
290
106
|
```bash
|
|
291
|
-
|
|
292
|
-
pf setup --ai
|
|
293
|
-
|
|
294
|
-
# Generate service with AI
|
|
295
|
-
pf new hono-micro services/payments --ai \
|
|
296
|
-
-d "Handle Stripe webhooks and send payment confirmations"
|
|
107
|
+
pf setup --ai # OpenAI or Anthropic
|
|
297
108
|
```
|
|
298
109
|
|
|
299
|
-
|
|
300
|
-
- β
Complete service with event handlers & use cases
|
|
301
|
-
- β
Pulumi infrastructure configuration
|
|
302
|
-
- β
Test files with validation logic
|
|
303
|
-
- β
Complete README documentation
|
|
304
|
-
|
|
305
|
-
> **Note:** AI-generated code is a starting point. Always review and test before deploying to production. `pf` never deploys or provisions infrastructure automatically β deployment always happens explicitly via Pulumi.
|
|
306
|
-
|
|
307
|
-
### Start local development
|
|
110
|
+
Then use `--ai` with any service generator:
|
|
308
111
|
|
|
309
112
|
```bash
|
|
310
|
-
|
|
311
|
-
pf dev
|
|
113
|
+
pf new hono-micro services/notifications --ai -d "Send emails on order events"
|
|
312
114
|
```
|
|
313
115
|
|
|
314
|
-
|
|
315
|
-
- π Auto-generate `.env.local` from infrastructure config
|
|
316
|
-
- π Start NATS + all services in watch mode (via Turbo)
|
|
317
|
-
- π Auto-assign unique ports per service
|
|
318
|
-
- π¦ Monitor for file changes and hot-reload
|
|
116
|
+
AI generates: service code, event handlers, use cases, tests, and documentation.
|
|
319
117
|
|
|
320
|
-
|
|
118
|
+
AI is a productivity layer β all generated code follows the same conventions and can be written manually without loss of functionality.
|
|
321
119
|
|
|
322
|
-
|
|
323
|
-
# Run all tests across the monorepo
|
|
324
|
-
pf test
|
|
120
|
+
### Daily commands
|
|
325
121
|
|
|
326
|
-
|
|
327
|
-
|
|
122
|
+
| Command | What it does |
|
|
123
|
+
|---------|--------------|
|
|
124
|
+
| `pf dev` | Start NATS + all services in watch mode |
|
|
125
|
+
| `pf test` | Run tests across the monorepo |
|
|
126
|
+
| `pf lint` | Lint and format with Biome |
|
|
127
|
+
| `pf build` | Build all packages and services |
|
|
128
|
+
| `pf pulumi up` | Deploy infrastructure (runs in `infra/`) |
|
|
328
129
|
|
|
329
|
-
|
|
330
|
-
pf build
|
|
331
|
-
```
|
|
130
|
+
`pf` proxies to Turborepo from any subdirectory.
|
|
332
131
|
|
|
333
|
-
###
|
|
132
|
+
### Configuration (advanced)
|
|
334
133
|
|
|
335
|
-
|
|
134
|
+
<details>
|
|
135
|
+
<summary>Workspace configuration via <code>package.json</code></summary>
|
|
336
136
|
|
|
337
137
|
```json
|
|
338
138
|
{
|
|
@@ -343,238 +143,186 @@ Configure workspace behavior via the `pf` field in your root `package.json`:
|
|
|
343
143
|
"deploy": { "cwd": "infra", "command": "pulumi up --yes" }
|
|
344
144
|
},
|
|
345
145
|
"paths": {
|
|
346
|
-
"services": {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
"apps": {
|
|
351
|
-
"path": "apps",
|
|
352
|
-
"watch": true
|
|
353
|
-
},
|
|
354
|
-
"packages": {
|
|
355
|
-
"path": "packages",
|
|
356
|
-
"watch": true,
|
|
357
|
-
"ignorePatterns": ["packages/some-internal-package"]
|
|
358
|
-
},
|
|
359
|
-
"contracts": {
|
|
360
|
-
"path": "packages/contracts"
|
|
361
|
-
}
|
|
146
|
+
"services": { "path": "services", "watch": true },
|
|
147
|
+
"apps": { "path": "apps", "watch": true },
|
|
148
|
+
"packages": { "path": "packages", "watch": true },
|
|
149
|
+
"contracts": { "path": "packages/contracts" }
|
|
362
150
|
}
|
|
363
151
|
}
|
|
364
152
|
}
|
|
365
153
|
```
|
|
366
154
|
|
|
367
|
-
|
|
368
|
-
- `
|
|
369
|
-
- `paths.<type>.
|
|
370
|
-
- `paths.<type>.watch`: Whether to watch this directory in dev mode (default: `false`)
|
|
371
|
-
- `paths.<type>.ignorePatterns`: Glob patterns to ignore within this path (optional)
|
|
155
|
+
- `commands`: Custom shortcuts with working directory overrides
|
|
156
|
+
- `paths.<type>.watch`: Enable file watching in dev mode
|
|
157
|
+
- `paths.<type>.ignorePatterns`: Glob patterns to exclude
|
|
372
158
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
---
|
|
376
|
-
|
|
377
|
-
## π Typical Workflows
|
|
378
|
-
|
|
379
|
-
Here's how developers actually use `pf` in real-world scenarios:
|
|
159
|
+
</details>
|
|
380
160
|
|
|
381
161
|
<details>
|
|
382
|
-
<summary
|
|
383
|
-
|
|
384
|
-
<br />
|
|
162
|
+
<summary>Infrastructure configuration via <code>infra/services/*.ts</code></summary>
|
|
385
163
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
```bash
|
|
389
|
-
# Step 1: Scaffold the workspace
|
|
390
|
-
bunx @crossdelta/platform-sdk new workspace my-platform \
|
|
391
|
-
--github-owner my-platform \
|
|
392
|
-
--pulumi-stack dev \
|
|
393
|
-
-y
|
|
394
|
-
|
|
395
|
-
cd my-platform
|
|
396
|
-
|
|
397
|
-
# Step 2: Configure infrastructure (optional)
|
|
398
|
-
# Edit infra/config.ts to customize:
|
|
399
|
-
# - DigitalOcean region (defaults to nyc3)
|
|
400
|
-
# - Kubernetes cluster size
|
|
401
|
-
# - Database instance sizes
|
|
164
|
+
```ts
|
|
165
|
+
import { ports, type K8sServiceConfig } from '@crossdelta/infrastructure'
|
|
402
166
|
|
|
403
|
-
|
|
404
|
-
|
|
167
|
+
export const config: K8sServiceConfig = {
|
|
168
|
+
name: 'orders',
|
|
169
|
+
ports: ports().http(4001).build(),
|
|
170
|
+
replicas: 1,
|
|
171
|
+
healthCheck: { httpPath: '/health' },
|
|
172
|
+
resources: {
|
|
173
|
+
requests: { cpu: '50m', memory: '64Mi' },
|
|
174
|
+
limits: { cpu: '150m', memory: '128Mi' },
|
|
175
|
+
},
|
|
176
|
+
}
|
|
405
177
|
```
|
|
406
178
|
|
|
407
|
-
|
|
408
|
-
- β
Turborepo monorepo with Biome linting/formatting
|
|
409
|
-
- β
NATS service running in Docker
|
|
410
|
-
- β
Pulumi infrastructure setup for DigitalOcean
|
|
411
|
-
- β
GitHub Actions workflows for CI/CD
|
|
412
|
-
- β
`.env.local` auto-generated with all service ports
|
|
179
|
+
See [@crossdelta/infrastructure](https://www.npmjs.com/package/@crossdelta/infrastructure) for full options.
|
|
413
180
|
|
|
414
181
|
</details>
|
|
415
182
|
|
|
416
183
|
---
|
|
417
184
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
```bash
|
|
421
|
-
# Generate with AI (optional: use --ai flag)
|
|
422
|
-
pf new hono-micro services/payments --ai \
|
|
423
|
-
-d "Stripe payment processing: handle webhooks, publish events"
|
|
185
|
+
## π― Why This Exists
|
|
424
186
|
|
|
425
|
-
|
|
426
|
-
# Start the service
|
|
427
|
-
pf dev
|
|
428
|
-
```
|
|
187
|
+
`pf` solves platform engineering problems:
|
|
429
188
|
|
|
430
|
-
**
|
|
189
|
+
- **Infrastructure drift** β Infra configs diverge from code in separate repos
|
|
190
|
+
- **Manual wiring** β Ports, env vars, service discovery configured by hand
|
|
191
|
+
- **Slow onboarding** β New devs spend days setting up local environments
|
|
431
192
|
|
|
432
|
-
|
|
193
|
+
**Solution:** Services auto-generate `infra/services/*.ts`, ports/env derived automatically, event handlers type-safe and auto-discovered.
|
|
433
194
|
|
|
434
|
-
|
|
195
|
+
In short: docker-compose starts services β `pf` prevents systems from drifting apart over time.
|
|
435
196
|
|
|
436
|
-
|
|
197
|
+
---
|
|
437
198
|
|
|
438
|
-
|
|
439
|
-
services/nats/
|
|
440
|
-
βββ nats.conf # Local dev config (JetStream enabled)
|
|
441
|
-
βββ nats.prod.conf # Production config (auth + persistence)
|
|
442
|
-
βββ scripts/start-dev.sh # Docker startup script
|
|
443
|
-
βββ README.md # Full NATS documentation
|
|
444
|
-
```
|
|
199
|
+
## π§© What pf Is / Is Not
|
|
445
200
|
|
|
446
|
-
|
|
447
|
-
-
|
|
448
|
-
-
|
|
449
|
-
-
|
|
450
|
-
-
|
|
201
|
+
**β
pf is:**
|
|
202
|
+
- Opinionated platform toolkit for event-driven microservices
|
|
203
|
+
- Turborepo scaffolder with Pulumi IaC and NATS messaging built-in
|
|
204
|
+
- AI-assisted code generator from natural language descriptions
|
|
205
|
+
- Unified dev workflow β one command to run everything
|
|
206
|
+
- DigitalOcean-first deployment target
|
|
451
207
|
|
|
452
|
-
|
|
208
|
+
**β pf is not:**
|
|
209
|
+
- Generic microservice generator β makes architectural choices for you
|
|
210
|
+
- Multi-cloud (not yet) β DigitalOcean first, extensible architecture
|
|
211
|
+
- Runtime manager β scaffolds code, you deploy with Pulumi
|
|
453
212
|
|
|
454
|
-
|
|
213
|
+
**Note:** `pf` runs nothing implicitly. No hidden daemons, no automatic deployments. You control when code runs and infrastructure deploys.
|
|
455
214
|
|
|
456
215
|
---
|
|
457
216
|
|
|
458
|
-
##
|
|
459
|
-
|
|
460
|
-
<details>
|
|
461
|
-
<summary><strong>π View Full Command Reference</strong></summary>
|
|
462
|
-
|
|
463
|
-
<br />
|
|
217
|
+
## ποΈ Architecture
|
|
464
218
|
|
|
465
|
-
|
|
219
|
+
```
|
|
220
|
+
my-platform/
|
|
221
|
+
βββ services/ # Microservices
|
|
222
|
+
β βββ nats/ # NATS message broker (auto-scaffolded)
|
|
223
|
+
β βββ <service>/
|
|
224
|
+
β βββ src/
|
|
225
|
+
β βββ events/ # Event handlers (*.event.ts)
|
|
226
|
+
β βββ use-cases/ # Business logic (*.use-case.ts)
|
|
227
|
+
β βββ types/ # Zod schemas
|
|
228
|
+
β βββ index.ts
|
|
229
|
+
βββ packages/
|
|
230
|
+
β βββ contracts/ # Event contracts (Schema Registry)
|
|
231
|
+
βββ infra/ # Pulumi Infrastructure-as-Code
|
|
232
|
+
β βββ services/ # Per-service K8s configs
|
|
233
|
+
βββ .env.local # Auto-generated from infra
|
|
234
|
+
```
|
|
466
235
|
|
|
467
|
-
|
|
468
|
-
|---------|-------------|
|
|
469
|
-
| `pf new` | Interactive creation wizard |
|
|
470
|
-
| `pf new workspace <name>` | Scaffold a complete platform monorepo |
|
|
471
|
-
| `pf setup --ai` | Configure AI provider (OpenAI or Anthropic) |
|
|
236
|
+
### Conventions
|
|
472
237
|
|
|
473
|
-
|
|
238
|
+
| Location | Purpose |
|
|
239
|
+
|----------|---------|
|
|
240
|
+
| `services/*/src/events/*.event.ts` | Event handlers (auto-discovered) |
|
|
241
|
+
| `services/*/src/use-cases/*.use-case.ts` | Business logic (pure functions) |
|
|
242
|
+
| `packages/contracts/src/events/*.ts` | Event contracts (single source of truth) |
|
|
243
|
+
| `infra/services/*.ts` | Pulumi configs per service |
|
|
474
244
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
| `pf new hono-micro <path> --ai` | Generate service with AI (requires `pf setup --ai`) |
|
|
245
|
+
> **Schema Registry pattern:**
|
|
246
|
+
> All event contracts live in `packages/contracts` as the single source of truth.
|
|
247
|
+
> Services import contracts instead of redefining schemas, ensuring
|
|
248
|
+
> type safety, compatibility, and explicit ownership across service boundaries.
|
|
480
249
|
|
|
481
|
-
### Event
|
|
250
|
+
### Event-Driven Pattern
|
|
482
251
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
| `pf event:http <name>` | Send via HTTP Pub/Sub endpoint |
|
|
252
|
+
**1. Define contract:**
|
|
253
|
+
```typescript
|
|
254
|
+
// packages/contracts/src/events/orders-created.ts
|
|
255
|
+
import { createContract } from '@crossdelta/cloudevents'
|
|
256
|
+
import { z } from 'zod'
|
|
489
257
|
|
|
490
|
-
|
|
258
|
+
export const OrdersCreatedContract = createContract({
|
|
259
|
+
type: 'orders.created',
|
|
260
|
+
schema: z.object({ orderId: z.string(), total: z.number() }),
|
|
261
|
+
})
|
|
262
|
+
```
|
|
491
263
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
264
|
+
**2. Publish (Service A):**
|
|
265
|
+
```typescript
|
|
266
|
+
// services/orders/src/use-cases/create-order.use-case.ts
|
|
267
|
+
await publish(OrdersCreatedContract, { orderId: '123', total: 99.99 })
|
|
268
|
+
```
|
|
496
269
|
|
|
497
|
-
|
|
270
|
+
**3. Handle (Service B, auto-discovered):**
|
|
271
|
+
```typescript
|
|
272
|
+
// services/notifications/src/events/orders-created.event.ts
|
|
273
|
+
export default handleEvent(OrdersCreatedContract, async (data) => {
|
|
274
|
+
await sendOrderNotification(data)
|
|
275
|
+
})
|
|
276
|
+
```
|
|
498
277
|
|
|
499
|
-
|
|
278
|
+
No manual subscriptions. Convention over configuration.
|
|
500
279
|
|
|
501
280
|
---
|
|
502
281
|
|
|
503
|
-
##
|
|
504
|
-
|
|
505
|
-
Define infrastructure in `infra/services/*.ts` using [`@crossdelta/infrastructure`](https://www.npmjs.com/package/@crossdelta/infrastructure):
|
|
282
|
+
## β‘ NATS Message Broker
|
|
506
283
|
|
|
507
|
-
|
|
508
|
-
import { ports } from '@crossdelta/infrastructure'
|
|
509
|
-
import type { K8sServiceConfig } from '@crossdelta/infrastructure'
|
|
284
|
+
Every workspace includes pre-configured NATS with JetStream:
|
|
510
285
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
replicas: 1,
|
|
515
|
-
healthCheck: { httpPath: '/health' },
|
|
516
|
-
resources: {
|
|
517
|
-
requests: { cpu: '50m', memory: '64Mi' },
|
|
518
|
-
limits: { cpu: '150m', memory: '128Mi' },
|
|
519
|
-
},
|
|
520
|
-
env: {
|
|
521
|
-
DATABASE_URL: databaseUrl,
|
|
522
|
-
NATS_URL: natsUrl,
|
|
523
|
-
},
|
|
524
|
-
}
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
**π See the [Infrastructure Package Docs](https://www.npmjs.com/package/@crossdelta/infrastructure) for advanced configuration options.**
|
|
286
|
+
- Auto-started with `pf dev`
|
|
287
|
+
- Ports: `4222` (client), `8222` (monitoring)
|
|
288
|
+
- Health check: `curl http://localhost:8222/healthz`
|
|
528
289
|
|
|
529
|
-
|
|
290
|
+
See `services/nats/README.md` for details.
|
|
530
291
|
|
|
531
292
|
---
|
|
532
293
|
|
|
533
|
-
##
|
|
534
|
-
|
|
535
|
-
### Local Deployment
|
|
294
|
+
## Deployment
|
|
536
295
|
|
|
537
296
|
```bash
|
|
538
|
-
pulumi login
|
|
539
|
-
pulumi up --stack dev
|
|
297
|
+
pulumi login && pulumi up --stack dev
|
|
540
298
|
```
|
|
541
299
|
|
|
542
|
-
###
|
|
543
|
-
|
|
544
|
-
Every workspace includes pre-configured GitHub Actions workflows in `.github/workflows/`:
|
|
300
|
+
### GitHub Actions (pre-configured)
|
|
545
301
|
|
|
546
302
|
| Workflow | Trigger | Purpose |
|
|
547
303
|
|----------|---------|---------|
|
|
548
|
-
|
|
|
549
|
-
|
|
|
550
|
-
|
|
|
551
|
-
|
|
552
|
-
### Required GitHub Secrets
|
|
553
|
-
|
|
554
|
-
Configure these secrets in your repository settings (`Settings` β `Secrets and variables` β `Actions`):
|
|
304
|
+
| `lint-and-tests.yml` | PR to `main` | Lint + test |
|
|
305
|
+
| `build-and-deploy.yml` | Push to `main` | Build, push to GHCR, deploy |
|
|
306
|
+
| `publish-packages.yml` | Changes in `packages/` | Publish to npm |
|
|
555
307
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
| `PULUMI_ACCESS_TOKEN` | Pulumi Cloud access token | All deployments |
|
|
559
|
-
| `DIGITALOCEAN_TOKEN` | DigitalOcean API token | Infrastructure provisioning |
|
|
560
|
-
| `NPM_TOKEN` | npm registry token | Package publishing (optional) |
|
|
561
|
-
| `GHCR_TOKEN` | GitHub Container Registry PAT | Docker image publishing |
|
|
308
|
+
<details>
|
|
309
|
+
<summary>Required secrets</summary>
|
|
562
310
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
311
|
+
| Secret | Description |
|
|
312
|
+
|--------|-------------|
|
|
313
|
+
| `PULUMI_ACCESS_TOKEN` | [Pulumi Cloud token](https://app.pulumi.com/account/tokens) |
|
|
314
|
+
| `DIGITALOCEAN_TOKEN` | [DO API token](https://cloud.digitalocean.com/account/api/tokens) |
|
|
315
|
+
| `GHCR_TOKEN` | GitHub Container Registry PAT |
|
|
567
316
|
|
|
568
|
-
|
|
317
|
+
</details>
|
|
569
318
|
|
|
570
319
|
---
|
|
571
320
|
|
|
572
321
|
## π Requirements
|
|
573
322
|
|
|
574
|
-
- **
|
|
575
|
-
- **[Pulumi CLI](https://www.pulumi.com/docs/install/)**
|
|
576
|
-
- **[Docker](https://www.docker.com/)**
|
|
577
|
-
|
|
323
|
+
- **Bun** (recommended) or Node.js β₯ 21
|
|
324
|
+
- **[Pulumi CLI](https://www.pulumi.com/docs/install/)** for deployment
|
|
325
|
+
- **[Docker](https://www.docker.com/)** for local NATS
|
|
578
326
|
|
|
579
327
|
---
|
|
580
328
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "pf dev",
|
|
6
|
-
"generate-env": "cd infra && generate-env",
|
|
6
|
+
"generate-env": "cd infra && bun run generate-env",
|
|
7
7
|
"build": "dotenv -e .env.local -- turbo run build",
|
|
8
8
|
"preview": "dotenv -e .env.local -- turbo run preview",
|
|
9
9
|
"lint": "turbo run lint",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/platform-sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.22",
|
|
4
4
|
"description": "Your AI-powered platform engineer. Scaffold complete Turborepo workspaces, generate microservice boilerplate with natural language, and deploy to the cloud β all from one CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|