Modules Example
Demonstrates modular project organization with users, products, and analytics modules.
Overview
The modules example shows:
- Modular code organization
- Separate concerns by domain
- Shared workflows across modules
- Client generation
- Testing generated clients
Structure
examples/modules/
├── users/
│ └── procedures.ts # User management
├── products/
│ ├── procedures.ts # Product CRUD
│ └── types.ts # Shared types
├── analytics/
│ └── procedures.ts # Analytics tracking
├── workflows/
│ └── user-onboarding.ts # Cross-module workflow
├── scripts/
│ └── generate-client.ts # Client generation script
├── generated/
│ └── client.ts # Generated client
├── package.json
└── tsconfig.jsonUsers Module
User management procedures:
typescript
// examples/modules/users/procedures.ts
import { z } from "zod";
import type { Procedure } from "@c4c/core";
const userSchema = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string().email(),
createdAt: z.string().datetime(),
});
export const createUser: Procedure = {
contract: {
name: "users.create",
description: "Create a new user",
input: z.object({
name: z.string(),
email: z.string().email(),
}),
output: userSchema,
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["users", "write"],
},
},
handler: async (input) => {
return {
id: crypto.randomUUID(),
...input,
createdAt: new Date().toISOString(),
};
},
};
export const getUser: Procedure = {
contract: {
name: "users.get",
description: "Get user by ID",
input: z.object({ id: z.string().uuid() }),
output: userSchema,
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["users", "read"],
},
},
handler: async (input) => {
return {
id: input.id,
name: "John Doe",
email: "john@example.com",
createdAt: new Date().toISOString(),
};
},
};
export const listUsers: Procedure = {
contract: {
name: "users.list",
description: "List all users",
input: z.object({
limit: z.number().min(1).max(100).default(10),
offset: z.number().min(0).default(0),
}),
output: z.object({
users: z.array(userSchema),
total: z.number(),
}),
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["users", "read"],
},
},
handler: async (input) => {
return {
users: [
{
id: crypto.randomUUID(),
name: "Alice",
email: "alice@example.com",
createdAt: new Date().toISOString(),
},
],
total: 1,
};
},
};Products Module
Product management procedures:
typescript
// examples/modules/products/procedures.ts
import { z } from "zod";
import type { Procedure } from "@c4c/core";
const productSchema = z.object({
id: z.string().uuid(),
name: z.string(),
description: z.string(),
price: z.number().positive(),
createdAt: z.string().datetime(),
});
export const createProduct: Procedure = {
contract: {
name: "products.create",
description: "Create a new product",
input: z.object({
name: z.string(),
description: z.string(),
price: z.number().positive(),
}),
output: productSchema,
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["products", "write"],
},
},
handler: async (input) => {
return {
id: crypto.randomUUID(),
...input,
createdAt: new Date().toISOString(),
};
},
};
export const listProducts: Procedure = {
contract: {
name: "products.list",
description: "List all products",
input: z.object({
limit: z.number().min(1).max(100).default(10),
}),
output: z.object({
products: z.array(productSchema),
}),
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["products", "read"],
},
},
handler: async (input) => {
return {
products: [
{
id: crypto.randomUUID(),
name: "Widget",
description: "A useful widget",
price: 9.99,
createdAt: new Date().toISOString(),
},
],
};
},
};Analytics Module
Analytics tracking:
typescript
// examples/modules/analytics/procedures.ts
import { z } from "zod";
import type { Procedure } from "@c4c/core";
export const trackEvent: Procedure = {
contract: {
name: "analytics.track",
description: "Track an analytics event",
input: z.object({
userId: z.string().uuid(),
event: z.string(),
properties: z.record(z.any()).optional(),
}),
output: z.object({
tracked: z.boolean(),
eventId: z.string().uuid(),
}),
metadata: {
exposure: "external",
roles: ["api-endpoint", "sdk-client"],
tags: ["analytics", "write"],
},
},
handler: async (input) => {
console.log(`Tracking event: ${input.event} for user ${input.userId}`);
return {
tracked: true,
eventId: crypto.randomUUID(),
};
},
};Cross-Module Workflow
Workflow using multiple modules:
typescript
// examples/modules/workflows/user-onboarding.ts
import { workflow, step, parallel } from "@c4c/workflow";
import { z } from "zod";
export default workflow("user-onboarding")
.name("User Onboarding Workflow")
.version("1.0.0")
.step(step({
id: "create-user",
input: z.object({ name: z.string(), email: z.string() }),
output: z.object({ id: z.string() }),
execute: ({ engine, inputData }) =>
engine.run("users.create", inputData),
}))
.step(parallel({
id: "parallel-setup",
branches: [
step({
id: "track-signup",
execute: ({ engine, context }) => {
const user = context.get("create-user");
return engine.run("analytics.track", {
userId: user.id,
event: "user_signed_up",
});
},
}),
step({
id: "create-sample-product",
execute: ({ engine }) =>
engine.run("products.create", {
name: "Sample Product",
description: "Welcome product",
price: 0,
}),
}),
],
waitForAll: true,
}))
.commit();Running the Example
Install Dependencies
bash
cd examples/modules
pnpm installStart Dev Server
bash
pnpm devExecute Procedures
bash
# User operations
pnpm c4c exec users.create --input '{"name":"Alice","email":"alice@example.com"}'
pnpm c4c exec users.list --input '{"limit":10}'
# Product operations
pnpm c4c exec products.create --input '{"name":"Widget","description":"A widget","price":9.99}'
pnpm c4c exec products.list
# Analytics
pnpm c4c exec analytics.track --input '{"userId":"123","event":"page_view"}'Execute Workflow
bash
pnpm c4c exec user-onboarding --input '{"name":"Alice","email":"alice@example.com"}'Generate Client
bash
pnpm generate:clientThis creates generated/client.ts with type-safe procedures.
Test Generated Client
bash
pnpm test:clientUsing the Generated Client
typescript
import { createClient } from "./generated/client";
const client = createClient({
baseUrl: "http://localhost:3000"
});
// User operations
const user = await client.usersCreate({
name: "Alice",
email: "alice@example.com"
});
const users = await client.usersList({
limit: 10,
offset: 0
});
// Product operations
const product = await client.productsCreate({
name: "Widget",
description: "A useful widget",
price: 9.99
});
// Analytics
await client.analyticsTrack({
userId: user.id,
event: "product_created",
properties: { productId: product.id }
});Package.json Scripts
json
{
"scripts": {
"dev": "c4c dev",
"serve": "c4c serve",
"generate:client": "c4c generate client --out ./generated/client.ts",
"generate:openapi": "c4c generate openapi --out ./openapi.json",
"test:client": "tsx scripts/test-client.ts"
}
}Key Takeaways
- Modular Organization - Separate concerns by domain
- Cross-Module Workflows - Workflows can use any procedure
- Type-Safe Clients - Generated clients are fully typed
- Flexible Structure - Organize code your way
- Zero Config - Framework discovers everything automatically
Next Steps
- Integrations Example - External API integration
- Cross-Integration Example - Multi-app integration
- Triggers Example - Webhook and event handling