Skip to content

Commit b7fee7a

Browse files
committed
docs: align README, DEVELOPMENT, k8s, and skill docs with current repo
- README: fix per-function ports (8081/8082), add knative-job-example (8083) and python-example (8084), drop stale k8s/Makefile instructions in favor of make skaffold-dev, switch package references from @constructive-io/knative-job-fn to fn-runtime/fn-app, expand project structure - DEVELOPMENT: bump Node prerequisite to >= 22, add new functions to port maps and build-artifacts table, replace manual skaffold/ job-service edit steps with a pointer to docs/skills/adding-functions (those edits are now generated by pnpm generate) - AGENTS: each function declares its own port in handler.json; 8080 is the job service - k8s/README: rewrite around the actual overlays (local-simple, local, ci, dev, staging); make skaffold-dev is the primary local path - k8s/ARCHITECTURE: retitle for casablanca, fix interweb/k8s paths and namespace claims, add a local-simple overlay section, mark the local variants in "future improvements" as in place - docs/skills/adding-functions: add actorId to documented job context
1 parent 9fb9705 commit b7fee7a

6 files changed

Lines changed: 168 additions & 233 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pnpm build # Recompile
129129

130130
## Key Details
131131

132-
- Functions run on `PORT=8080` (Knative default)
132+
- Each function declares its port in `handler.json` (`simple-email` 8081, `send-email-link` 8082, `knative-job-example` 8083, `python-example` 8084); the job service uses 8080
133133
- Email functions support dry-run via `SIMPLE_EMAIL_DRY_RUN` / `SEND_EMAIL_LINK_DRY_RUN`
134134
- `loadFunctionApp()` in job/service resolves modules by name (e.g. `@constructive-io/simple-email-fn`)
135135
- GraphQL clients require `GRAPHQL_URL` env var and `X-Database-Id` header

DEVELOPMENT.md

Lines changed: 18 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Local development setup for running functions against real infrastructure (Postg
44

55
## Prerequisites
66

7-
- Node.js >= 18.17.0
7+
- Node.js >= 22.0.0
88
- pnpm >= 10
99
- Docker Desktop
1010

@@ -60,7 +60,8 @@ After this you should have built artifacts in:
6060
|---------|--------|
6161
| `generated/send-email-link/dist/` | Send-email-link function server |
6262
| `generated/simple-email/dist/` | Simple-email function server |
63-
| `generated/example/dist/` | Example function server |
63+
| `generated/example/dist/` | knative-job-example function server |
64+
| `generated/python-example/dist/` | Python example function server |
6465
| `job/service/dist/` | Knative job service (worker + scheduler) |
6566
| `packages/fn-runtime/dist/` | Function runtime library |
6667
| `packages/fn-app/dist/` | Function app framework |
@@ -113,6 +114,8 @@ This runs `scripts/dev.ts` which spawns local Node processes with env vars point
113114
| **job-service** | 8080 | `job/service/dist/run.js` |
114115
| **simple-email** | 8081 | `generated/simple-email/dist/index.js` |
115116
| **send-email-link** | 8082 | `generated/send-email-link/dist/index.js` |
117+
| **knative-job-example** | 8083 | `generated/example/dist/index.js` |
118+
| **python-example** | 8084 | `generated/python-example/...` (python entrypoint) |
116119

117120
To start a single function:
118121

@@ -175,6 +178,8 @@ make dev-down # Stop Docker infrastructure
175178
| Job Service | 8080 |
176179
| simple-email | 8081 |
177180
| send-email-link | 8082 |
181+
| knative-job-example | 8083 |
182+
| python-example | 8084 |
178183

179184
## Architecture
180185

@@ -280,6 +285,8 @@ Changes to runtime packages (`packages/fn-runtime`, `packages/fn-app`) or `packa
280285
|---------|------------|
281286
| simple-email | 8081 |
282287
| send-email-link | 8082 |
288+
| knative-job-example | 8083 |
289+
| python-example | 8084 |
283290
| Job Service | 8080 |
284291
| PostgreSQL | 5432 |
285292
| Constructive Server | 3002 |
@@ -295,61 +302,15 @@ Changes to runtime packages (`packages/fn-runtime`, `packages/fn-app`) or `packa
295302

296303
## Adding a New Function
297304

298-
1. **Create the function source:**
299-
300-
```bash
301-
mkdir functions/my-function
302-
```
303-
304-
Add `functions/my-function/handler.json`:
305-
```json
306-
{
307-
"name": "my-function",
308-
"version": "1.0.0",
309-
"type": "node-graphql",
310-
"description": "What this function does",
311-
"dependencies": {}
312-
}
313-
```
314-
315-
Add `functions/my-function/handler.ts` with your function logic.
316-
317-
2. **Generate the workspace package:**
318-
319-
```bash
320-
pnpm generate
321-
pnpm install
322-
```
323-
324-
This creates `generated/my-function/` with the full package, Dockerfile, and k8s manifests (including `k8s/local-deployment.yaml`).
325-
326-
3. **Register in Skaffold** — edit `skaffold.yaml`, add to the `local-simple` profile:
327-
328-
```yaml
329-
rawYaml:
330-
- generated/simple-email/k8s/local-deployment.yaml
331-
- generated/send-email-link/k8s/local-deployment.yaml
332-
- generated/my-function/k8s/local-deployment.yaml # <- add this
333-
```
334-
335-
And add a port-forward entry:
336-
```yaml
337-
portForward:
338-
- resourceType: service
339-
resourceName: my-function
340-
namespace: constructive-functions
341-
port: 80
342-
localPort: 8083 # pick an unused port
343-
```
344-
345-
4. **Register in job-service** — edit `k8s/overlays/local-simple/job-service.yaml`, add to `JOBS_SUPPORTED` and `INTERNAL_GATEWAY_DEVELOPMENT_MAP`.
346-
347-
5. **Test:**
348-
349-
```bash
350-
make skaffold-dev # deploy
351-
pnpm test:e2e # run e2e tests
352-
```
305+
The canonical, end-to-end workflow lives in [docs/skills/adding-functions.md](./docs/skills/adding-functions.md). Quick summary:
306+
307+
1. Create `functions/<name>/handler.json` and `functions/<name>/handler.ts`.
308+
2. Register the function with the job service in `job/service/src/types.ts` (`FunctionName` union) and `job/service/src/index.ts` (`functionRegistry` entry).
309+
3. Run `pnpm generate && pnpm install && pnpm build`.
310+
311+
`pnpm generate` automatically updates `skaffold.yaml` (per-function profile + port-forwards), `k8s/overlays/local-simple/job-service.yaml` (`JOBS_SUPPORTED` and `INTERNAL_GATEWAY_DEVELOPMENT_MAP`), and `generated/functions-manifest.json`. No manual edits to those files are needed.
312+
313+
Then test with `make skaffold-dev` and `pnpm test:e2e`. See the skill doc for the unit-test, e2e-test, and CI checklist.
353314

354315
## E2E Tests
355316

README.md

Lines changed: 60 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,109 @@
11
# constructive-functions
22

3-
Functions playground for Constructive — isolated workspace for building, testing, and deploying Knative-style HTTP functions.
3+
Functions playground for Constructive — a workspace for building, testing, and deploying serverless HTTP functions backed by a Postgres-backed job queue.
4+
5+
Functions are authored in `functions/<name>/` (a `handler.ts` plus a `handler.json` manifest), generated into runnable workspace packages by `pnpm generate`, and dispatched by the job service in `job/service/`. Templates live in `templates/` (`node-graphql` and `python` are supported today).
46

57
## Quick Start
68

79
```bash
8-
# Install dependencies
9-
pnpm install
10-
11-
# Build all functions
12-
pnpm build
10+
pnpm generate # generate workspace packages from handler.json manifests
11+
pnpm install # install dependencies (including generated packages)
12+
pnpm build # build all packages and functions
1313

14-
# Build Docker images locally
15-
make docker-build
16-
17-
# Build individual function images
18-
make docker-build-simple-email
14+
make docker-build # build all function Docker images
15+
make docker-build-simple-email # build a single function image
1916
make docker-build-send-email-link
2017
```
2118

2219
## Functions
2320

24-
### `@constructive-io/simple-email-fn`
21+
| Function | Port | Type | Image |
22+
|----------|------|------|-------|
23+
| `simple-email` | 8081 | node-graphql | `ghcr.io/constructive-io/constructive-functions/simple-email:latest` |
24+
| `send-email-link` | 8082 | node-graphql | `ghcr.io/constructive-io/constructive-functions/send-email-link:latest` |
25+
| `knative-job-example` | 8083 | node-graphql | `ghcr.io/constructive-io/constructive-functions/knative-job-example:latest` |
26+
| `python-example` | 8084 | python | `ghcr.io/constructive-io/constructive-functions/python-example:latest` |
2527

26-
Simple email function that sends emails directly from job payload.
28+
Port `8080` is reserved for the job service.
2729

28-
- **Port**: `8080`
29-
- **Docker image**: `ghcr.io/constructive-io/constructive-functions/simple-email:latest`
30-
- **Environment**:
31-
- `SIMPLE_EMAIL_DRY_RUN` — If `true`, logs email payload without sending
32-
- `MAILGUN_API_KEY`, `MAILGUN_KEY` — Mailgun credentials
33-
- `MAILGUN_DOMAIN`, `MAILGUN_FROM`, `MAILGUN_REPLY` — Mailgun email config
30+
### `simple-email`
3431

35-
### `@constructive-io/send-email-link-fn`
32+
Sends emails directly from a job payload.
3633

37-
Email link function for invite, password reset, and verification emails.
34+
- `SIMPLE_EMAIL_DRY_RUN` — if `true`, logs the payload instead of sending
35+
- `MAILGUN_API_KEY`, `MAILGUN_KEY`, `MAILGUN_DOMAIN`, `MAILGUN_FROM`, `MAILGUN_REPLY` — Mailgun config
3836

39-
- **Port**: `8080`
40-
- **Docker image**: `ghcr.io/constructive-io/constructive-functions/send-email-link:latest`
41-
- **Environment**:
42-
- `SEND_EMAIL_LINK_DRY_RUN` — If `true`, logs email payload without sending
43-
- `DEFAULT_DATABASE_ID` — Default database UUID
44-
- `GRAPHQL_URL` — GraphQL API endpoint
45-
- `META_GRAPHQL_URL` — Meta GraphQL API endpoint (optional)
46-
- `GRAPHQL_AUTH_TOKEN` — Optional Bearer token for GraphQL requests
47-
- `LOCAL_APP_PORT` — Local port for dashboard links (e.g., `3000`)
48-
- `MAILGUN_*` — Same Mailgun config as `simple-email`
37+
### `send-email-link`
4938

50-
## Development
39+
Sends invite, password reset, and verification emails (rendered via MJML).
5140

52-
This repo includes full Kubernetes manifests for deploying functions to any cluster.
41+
- `SEND_EMAIL_LINK_DRY_RUN` — if `true`, logs the payload instead of sending
42+
- `DEFAULT_DATABASE_ID` — default database UUID
43+
- `GRAPHQL_URL`, `META_GRAPHQL_URL` — GraphQL API endpoints
44+
- `GRAPHQL_AUTH_TOKEN` — optional Bearer token for GraphQL requests
45+
- `LOCAL_APP_PORT` — local port for dashboard links (e.g. `3000`)
46+
- `MAILGUN_*` — same Mailgun config as `simple-email`
5347

54-
### Local Kubernetes (kind/minikube)
48+
### `knative-job-example` / `python-example`
5549

56-
```bash
57-
cd k8s
50+
Reference implementations for the `node-graphql` and `python` templates.
5851

59-
# Install Knative Serving + Kourier only (no CNPG)
60-
make operators-knative-only
52+
## Development
6153

62-
# Apply local overlay (single Postgres, single MinIO, functions)
63-
make kustomize-local
54+
The full local-dev guide lives in [DEVELOPMENT.md](./DEVELOPMENT.md). Two paths:
6455

65-
# Port-forward to local services
66-
make proxy-server # GraphQL API -> localhost:8080
67-
make proxy-explorer # GraphQL explorer UI -> localhost:8081
68-
make proxy-web # Dashboard UI -> localhost:3000
69-
```
56+
- **Docker Compose + local Node** (fastest iteration) — `make dev` for infrastructure, `make dev-fn` to run functions as local Node processes.
57+
- **Skaffold on local k8s** (production-like, with hot reload) — `make skaffold-dev` deploys the full stack to the `constructive-functions` namespace and watches handler files.
7058

71-
See `k8s/DEVELOPMENT_LOCAL.md` for detailed local setup.
59+
For the Knative variant of the k8s setup, see `k8s/DEVELOPMENT_LOCAL.md`.
7260

7361
### CI/CD
7462

75-
The `CI Test K8s` workflow (`.github/workflows/test-k8s-deployment.yaml`) runs on every PR/push to `main` that touches `k8s/**`. It:
76-
77-
1. Spins up a `kind` cluster
78-
2. Installs Knative via `make operators-knative-only`
79-
3. Applies the `k8s/overlays/ci` overlay
80-
4. Waits for workloads to be ready
63+
The `CI Test K8s` workflow (`.github/workflows/test-k8s-deployment.yaml`) runs on PRs and pushes to `main` that touch `k8s/`, `tests/e2e/`, or `functions/`. It spins up a `kind` cluster, applies the `k8s/overlays/ci` overlay, and runs the per-function e2e tests.
8164

8265
## Project Structure
8366

8467
```
8568
.
86-
├── functions/
87-
│ ├── send-email-link/
88-
│ │ ├── src/
89-
│ │ ├── package.json
90-
│ │ ├── Dockerfile
91-
│ │ └── tsconfig.json
92-
│ └── simple-email/
93-
│ └── (same structure)
69+
├── functions/ # User-authored handler.ts + handler.json (git tracked)
70+
├── templates/ # Template definitions (node-graphql, python, shared, k8s)
71+
├── generated/ # Generated workspace packages (gitignored)
72+
├── packages/
73+
│ ├── fn-runtime/ # createFunctionServer, GraphQL clients, FunctionContext
74+
│ └── fn-app/ # Express app factory with job callbacks
75+
├── job/
76+
│ ├── service/ # Orchestrator (loads functions + worker + scheduler)
77+
│ ├── server/ # Callback receiver
78+
│ └── worker/ # Job dispatcher
9479
├── k8s/
95-
│ ├── base/
96-
│ ├── overlays/
97-
│ ├── scripts/
98-
│ └── Makefile
99-
├── types/
100-
│ └── (custom type definitions for external packages)
80+
│ ├── base/ # Shared manifests
81+
│ └── overlays/ # local-simple, local, ci, dev, staging
82+
├── tests/ # integration + e2e suites
83+
├── scripts/ # generate.ts, dev.ts, docker-build.ts
84+
├── skaffold.yaml
10185
├── package.json
102-
├── pnpm-workspace.yaml
10386
└── Makefile
10487
```
10588

10689
## Notes
10790

108-
- Functions use `@constructive-io/knative-job-fn` for the Express/Knative HTTP wrapper
109-
- Email providers use `@constructive-io/postmaster` (Mailgun) and `@launchql/mjml` (styled-email templates via MJML)
110-
- No `docker-compose` — this repo is Kubernetes-focused for functions deployment
111-
- Root workspace manages shared linting/formatting configs; each function has its own build config
91+
- Functions use `@constructive-io/fn-runtime` (runtime + GraphQL clients) and `@constructive-io/fn-app` (Express wrapper).
92+
- Email providers are wired through `@constructive-io/postmaster` (Mailgun) and `@launchql/mjml` / `@launchql/styled-email` for templating.
93+
- Both Node (`node-graphql`) and Python (`python`) templates are supported — pick via the `type` field in `handler.json`.
94+
- The `generated/` directory is entirely gitignored; rerun `pnpm generate` after changing any `handler.json`.
95+
- Root workspace manages shared linting/formatting; each generated function ships its own build config and Dockerfile.
11296

11397
## Pushing Images
11498

115-
To push to GitHub Container Registry:
99+
Images are tagged with the GHCR prefix automatically:
116100

117101
```bash
118102
docker push ghcr.io/constructive-io/constructive-functions/simple-email:latest
119103
docker push ghcr.io/constructive-io/constructive-functions/send-email-link:latest
104+
docker push ghcr.io/constructive-io/constructive-functions/knative-job-example:latest
105+
docker push ghcr.io/constructive-io/constructive-functions/python-example:latest
120106
```
121107

122-
Images are built with the correct registry prefix via the Makefile:
123-
- `make docker-build` — Builds all functions with `ghcr.io/constructive-io/constructive-functions/<name>:latest`
124-
- `make docker-build-simple-email` — Builds `ghcr.io/constructive-io/constructive-functions/simple-email:latest`
125-
- `make docker-build-send-email-link` — Builds `ghcr.io/constructive-io/constructive-functions/send-email-link:latest`
108+
- `make docker-build` — builds all function images
109+
- `make docker-build-<name>` — builds a single function image

docs/skills/adding-functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const handler: FunctionHandler<MyPayload> = async (params, context) => {
5959
// context provides: { client, meta, job, log, env }
6060
// client — GraphQL client for the database's API
6161
// meta — GraphQL client for metadata API
62-
// job — { jobId, workerId, databaseId }
62+
// job — { jobId, workerId, databaseId, actorId }
6363
// log — structured logger (info, error, warn, debug)
6464
// env — process.env
6565

0 commit comments

Comments
 (0)