# Checkpoint 1.2: Brand Workflow
This checkpoint verifies that you've successfully created the createBrandWorkflow with a step and compensation function.
## Verification Questions
Before proceeding, test your understanding:
1. **Why can't we use `async` or `await` in the workflow function?**
Answer
Workflows are declarative blueprints that define the sequence of steps. They don't execute steps directly - the workflow engine does. Using `async`/`await` would mean executing steps during definition, which breaks the orchestration model. Steps are called synchronously in the workflow function, and the engine handles the async execution.
2. **What is a compensation function and why do we need it?**
Answer
A compensation function is the "undo" logic for a step. If a later step in the workflow fails, Medusa automatically calls compensation functions for all completed steps in reverse order. This provides automatic rollback - for example, if brand creation succeeds but a later S3 upload fails, the compensation function deletes the brand to maintain data consistency.
3. **What does `StepResponse` do?**
Answer
`StepResponse` returns two things: (1) the data to pass to the next step, and (2) the data to pass to the compensation function if rollback is needed. This lets you return different data for success vs. rollback scenarios.
4. **Why do we use `transform()` instead of directly returning workflow input?**
Answer
`transform()` is a utility that extracts and shapes data from step results. It ensures type safety and makes it clear what data is being returned. While you could return step results directly, `transform()` provides better code readability and type inference.
## Implementation Check
Let me verify your implementation. Please share the following:
### 1. Step File
Show me your `src/workflows/create-brand/steps/create-brand.ts` file.
**Key things to check**:
- [ ] Step function is defined with `createStep()`
- [ ] Step name is descriptive (e.g., "create-brand")
- [ ] Input has proper TypeScript type
- [ ] Uses `container.resolve("brand")` to get service
- [ ] Calls `brandService.createBrands()` (note the plural - it's a batch method)
- [ ] Returns `new StepResponse(brand, brand.id)` (brand for next step, id for compensation)
- [ ] Compensation function accepts `brandId` parameter
- [ ] Compensation resolves service and calls `deleteBrands([brandId])`
- [ ] Has null check: `if (!brandId) return`
### 2. Workflow File
Show me your `src/workflows/create-brand/index.ts` file.
**Key things to check**:
- [ ] Uses `createWorkflow()` with unique name
- [ ] Workflow function is NOT async
- [ ] Workflow function does NOT use await
- [ ] Workflow function is NOT an arrow function (uses `function` keyword)
- [ ] Calls `createBrandStep(input)` without await
- [ ] Uses `transform()` to extract brand from step result
- [ ] Returns `new WorkflowResponse(brand)`
### 3. Build Test
Run this command and share any errors:
```bash
npm run build
```
**Expected output**: Build should succeed. TypeScript should not complain about the workflow.
## Common Issues
### "Async function not allowed in workflow"
**Symptom**: TypeScript error or runtime warning about async
**Cause**: Workflow function declared as `async function`
**Fix**:
Remove `async` keyword:
```typescript
// ❌ WRONG
createWorkflow("create-brand", async function (input) {
// ...
})
// ✅ CORRECT
createWorkflow("create-brand", function (input) {
// ...
})
```
### "Cannot use await in workflow"
**Symptom**: Error about await usage
**Cause**: Using `await` when calling steps
**Fix**:
Remove `await` - steps are called synchronously:
```typescript
// ❌ WRONG
const result = await createBrandStep(input)
// ✅ CORRECT
const result = createBrandStep(input)
```
### "Cannot resolve brand"
**Symptom**: Runtime error when executing workflow
**Cause**: Service name doesn't match module registration
**Fix**:
Use exact service name with "ModuleService" suffix:
```typescript
const brandService = container.resolve("brand")
```
## Testing Checklist
Verify each of these steps:
- [ ] Build succeeds without errors
- [ ] No TypeScript warnings about async/await
- [ ] Step file has both step function and compensation
- [ ] Workflow file uses correct syntax (function, no async, no await)
- [ ] Compensation function has null check
- [ ] Service methods use plural names (createBrands, deleteBrands)
- [ ] StepResponse returns both result and compensation data
## Architecture Understanding
At this point, you should understand:
- **Workflows are declarative**: They define the flow, not execute it
- **Steps are composable**: You can reuse steps across workflows
- **Compensation provides safety**: Automatic rollback on failure
- **The engine handles execution**: Steps run async, but you define them sync
**Example of why this matters**:
Imagine this workflow:
1. Create brand
2. Upload logo to S3
3. Send Slack notification
If step 3 fails, the compensation functions for steps 2 and 1 run automatically:
- Delete logo from S3
- Delete brand from database
This ensures your system never ends up in an inconsistent state - all or nothing.
## Next Steps
Once this checkpoint passes:
1. **Brand Module** created
2. **Brand Workflow** created with rollback
3. **Next**: Create the API Route (Part 3 of Lesson 1)
The workflow provides the business logic orchestration. Now we'll expose it via an HTTP API route that validates input and executes the workflow.
**Ready to continue?** Let me know when all checks pass, and we'll move on to creating the API route.