# Checkpoint 2.1: Module Links This checkpoint verifies that you've successfully defined a module link between Brand and Product modules and synced it to the database. ## Verification Questions Before proceeding, test your understanding: 1. **Why do we use module links instead of directly importing from another module?**
Answer Module links maintain module isolation - modules don't depend on each other's code. The Brand Module doesn't import Product entities, and Product Module doesn't import Brand entities. This prevents circular dependencies and allows modules to be developed, tested, and deployed independently. Links are managed by Medusa's linking layer, not by direct module-to-module references.
2. **What does `isList: true` mean in a link definition?**
Answer `isList: true` means "one brand can have many products". Without it (or with `isList: false`), the relationship would be one-to-one. In our case, we want one brand (e.g., "Nike") to link to multiple products (shoes, shirts, etc.), so we use `isList: true`.
3. **What is the purpose of `BrandModule.linkable.brand`?**
Answer `linkable` is a configuration object exported from each module that declares which entities can be linked to. `BrandModule.linkable.brand` tells Medusa "the Brand entity in the Brand Module can be used in links".
4. **Why do we put links in `src/links` directory and not inside a module?**
Answer Links are separate from modules to emphasize module independence. A link is a relationship managed by Medusa's linking layer, not by either module. Keeping links in a separate directory makes it clear that they're infrastructure concerns, not business logic. It also makes it easier to see all relationships in your application at a glance.
## Implementation Check Let me verify your implementation. Please share the following: ### 1. Brand Module Linkable Configuration Show me your `src/modules/brand/index.ts` file. **Key things to check**: - [ ] Exports module with `Module()` - [ ] Module has `service` property pointing to BrandService - [ ] Uses `Modules.BRAND` constant for module name (or string "brand") ### 2. Brand Module Constants Show me if you created `src/modules/brand/types/index.ts` for module constants. **Key things to check**: - [ ] Exports `MODULE_NAME = "brand"` - [ ] Exports `Modules.BRAND` constant (if using Modules enum) **Note**: You can also define the constant directly in index.ts or use a string literal. ### 3. Link Definition File Show me your `src/links/brand-product.ts` file. **Key things to check**: - [ ] Imports `defineLink` from "@medusajs/framework/utils" - [ ] Imports `Modules` from "@medusajs/framework/utils" (for ProductModule reference) - [ ] Imports `BrandModule` from "../modules/brand" - [ ] Calls `defineLink()` with two arguments - [ ] First argument configures product side: ```typescript { linkable: ProductModule.linkable.product, isList: true, } ``` - [ ] Second argument is `BrandModule.linkable.brand` - [ ] File has default export: `export default defineLink(...)` ### 4. Database Sync Run the database sync command: ```bash npx medusa db:sync-links ``` **Expected output**: Should show that link was created successfully without errors. You should see output mentioning the brand-product relationship. ### 5. Build Test Run build to ensure no TypeScript errors: ```bash npm run build ``` **Expected output**: Build should succeed without errors related to links or modules. ## Common Issues ### "Link sync failed" or "Cannot resolve module" **Symptom**: `db:sync-links` command fails **Cause**: Module not registered in medusa-config.ts, or server not recognizing the module **Fix**: 1. Verify brand module is in `medusa-config.ts` modules array 2. Restart dev server: `npm run dev` 3. Try sync again: `npx medusa db:sync-links` ## Testing Checklist Verify each of these steps: - [ ] Link file created in `src/links/` directory - [ ] `db:sync-links` command succeeds - [ ] Build succeeds without TypeScript errors - [ ] Dev server starts without link-related errors ## Architecture Understanding At this point, you should understand: **Module Isolation**: ``` ┌─────────────┐ ┌──────────────┐ │ Brand │ │ Product │ │ Module │ │ Module │ │ │ │ │ │ - No direct imports between modules │ │ - Each module is independent │ └─────────────┘ └──────────────┘ │ │ └────────┬────────────────┘ │ ┌──────▼────────┐ │ Link Layer │ │ (Medusa) │ │ │ │ Manages │ │ relationships│ └───────────────┘ ``` **Why module links matter**: - **Flexibility**: Modules can be added/removed without breaking others - **Testability**: Test Brand Module without needing Product Module - **Scalability**: Modules can be extracted into separate packages - **Versioning**: Modules can evolve independently ## Next Steps Once this checkpoint passes: 1. **Module Link** defined between Brand and Product 2. **Database** synced with link relationship 3. **Next**: Consume Workflow Hooks (Part 2 of Lesson 2) The link is now defined at the infrastructure level. Next, we'll make it functional by consuming the `productsCreated` workflow hook to automatically link brands to products when products are created. **Ready to continue?** Let me know when all checks pass, and we'll move on to workflow hooks.