From f569ee69a650561507412826ae32a24c819099d2 Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Sun, 1 Mar 2026 14:43:58 +0100 Subject: [PATCH 1/8] feat: enrich products with creator info Add endpoint that fetches user info from the user service to show who created a product. --- packages/product-service/src/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/product-service/src/index.ts b/packages/product-service/src/index.ts index be15f21..27fa01b 100644 --- a/packages/product-service/src/index.ts +++ b/packages/product-service/src/index.ts @@ -4,6 +4,8 @@ import { insert, findById, findAll } from "@playground/database"; const app = express(); app.use(express.json()); +const USER_SERVICE = "http://user-service:3001"; + app.get("/products", (_req, res) => { res.json(findAll("products")); }); @@ -22,6 +24,17 @@ app.post("/products", (req, res) => { res.status(201).json(product); }); +app.get("/products/:id/creator", async (req, res) => { + const product = findById("products", req.params.id); + if (!product) { + res.status(404).json({ error: "Product not found" }); + return; + } + const response = await fetch(`${USER_SERVICE}/users/${product.createdBy}`); + const creator = await response.json(); + res.json({ product, creator }); +}); + app.listen(3002, () => { console.log("product-service listening on :3002"); }); From bcfa1dbf1eb86e5a73c032fdb3c25c35051e7e8a Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 08:12:45 +0100 Subject: [PATCH 2/8] test new version --- .github/workflows/erode.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index e044e59..1dea560 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -25,11 +25,11 @@ jobs: owner: ${{ github.repository_owner }} - name: Run Erode Analysis - uses: erode-app/erode@main + uses: erode-app/erode@feat/deterministic-model-patching with: model-repo: ${{ github.repository }} model-path: likec4 - model-ref: main + model-ref: https://github.com/erode-app/playground-models-only ai-provider: gemini gemini-api-key: ${{ secrets.GEMINI_API_KEY }} github-token: ${{ steps.app-token.outputs.token }} \ No newline at end of file From cb3fff3604b4456dcbc1bdb60e7f5e80c9e33915 Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 08:15:36 +0100 Subject: [PATCH 3/8] auto update prs --- .github/workflows/erode.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index 1dea560..3ed09e7 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -1,19 +1,20 @@ -name: Architecture Drift Detection +name: Architecture Drift Check on: pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: erode-${{ github.event.pull_request.number }} - cancel-in-progress: true - -permissions: - packages: read + issue_comment: + types: [created] jobs: erode: - name: Detect Architecture Drift + if: >- + (github.event_name == 'pull_request' && + github.actor != 'dependabot[bot]' && + !github.event.pull_request.draft) + || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '/erode update-model')) runs-on: ubuntu-latest steps: - name: Generate GitHub App Token @@ -30,6 +31,7 @@ jobs: model-repo: ${{ github.repository }} model-path: likec4 model-ref: https://github.com/erode-app/playground-models-only + open-pr: ${{ github.event_name == 'issue_comment' && 'true' || 'auto' }} ai-provider: gemini gemini-api-key: ${{ secrets.GEMINI_API_KEY }} - github-token: ${{ steps.app-token.outputs.token }} \ No newline at end of file + github-token: ${{ steps.app-token.outputs.token }} From 14c059af738e969bfe27145d9b13e24a7ec59ad7 Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 08:18:44 +0100 Subject: [PATCH 4/8] wrong ref and repo --- .github/workflows/erode.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index 3ed09e7..a599ce2 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -28,9 +28,9 @@ jobs: - name: Run Erode Analysis uses: erode-app/erode@feat/deterministic-model-patching with: - model-repo: ${{ github.repository }} + model-repo: https://github.com/erode-app/playground-models-only model-path: likec4 - model-ref: https://github.com/erode-app/playground-models-only + model-ref: main open-pr: ${{ github.event_name == 'issue_comment' && 'true' || 'auto' }} ai-provider: gemini gemini-api-key: ${{ secrets.GEMINI_API_KEY }} From ba32a0626a5bd91d10daeb11ba810e4c8f1cb69d Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 08:20:47 +0100 Subject: [PATCH 5/8] use correct repo name --- .github/workflows/erode.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index a599ce2..3314c1f 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -28,7 +28,7 @@ jobs: - name: Run Erode Analysis uses: erode-app/erode@feat/deterministic-model-patching with: - model-repo: https://github.com/erode-app/playground-models-only + model-repo: erode-app/playground-models-only model-path: likec4 model-ref: main open-pr: ${{ github.event_name == 'issue_comment' && 'true' || 'auto' }} From 899da20ca83a0cd3fa83683c4ad2fae512839414 Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 08:31:31 +0100 Subject: [PATCH 6/8] use openai --- .github/workflows/erode.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index 3314c1f..ada52f1 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -32,6 +32,6 @@ jobs: model-path: likec4 model-ref: main open-pr: ${{ github.event_name == 'issue_comment' && 'true' || 'auto' }} - ai-provider: gemini - gemini-api-key: ${{ secrets.GEMINI_API_KEY }} + ai-provider: openai + openai-api-key: ${{ secrets.OPENAI_API_KEY }} github-token: ${{ steps.app-token.outputs.token }} From 33f83ea75200c122f56cd28279ec5d28fc7db1cb Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Mon, 2 Mar 2026 13:26:04 +0100 Subject: [PATCH 7/8] add order-service that calls product-service New order-service (port 3005) with GET/POST /orders endpoints. POST /orders validates the product exists by calling product-service. API gateway updated with proxy routes to order-service. Co-Authored-By: Claude Opus 4.6 --- packages/api-gateway/src/index.ts | 20 +++++++++++++ packages/order-service/package.json | 18 ++++++++++++ packages/order-service/src/index.ts | 42 ++++++++++++++++++++++++++++ packages/order-service/tsconfig.json | 11 ++++++++ tsconfig.json | 3 +- 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/order-service/package.json create mode 100644 packages/order-service/src/index.ts create mode 100644 packages/order-service/tsconfig.json diff --git a/packages/api-gateway/src/index.ts b/packages/api-gateway/src/index.ts index 5a264f6..8ad2886 100644 --- a/packages/api-gateway/src/index.ts +++ b/packages/api-gateway/src/index.ts @@ -5,6 +5,7 @@ app.use(express.json()); const USER_SERVICE = "http://user-service:3001"; const PRODUCT_SERVICE = "http://product-service:3002"; +const ORDER_SERVICE = "http://order-service:3005"; app.get("/users", async (_req, res) => { const response = await fetch(`${USER_SERVICE}/users`); @@ -44,6 +45,25 @@ app.post("/products", async (req, res) => { res.status(response.status).json(await response.json()); }); +app.get("/orders", async (_req, res) => { + const response = await fetch(`${ORDER_SERVICE}/orders`); + res.json(await response.json()); +}); + +app.get("/orders/:id", async (req, res) => { + const response = await fetch(`${ORDER_SERVICE}/orders/${req.params.id}`); + res.status(response.status).json(await response.json()); +}); + +app.post("/orders", async (req, res) => { + const response = await fetch(`${ORDER_SERVICE}/orders`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(req.body), + }); + res.status(response.status).json(await response.json()); +}); + app.listen(3000, () => { console.log("api-gateway listening on :3000"); }); diff --git a/packages/order-service/package.json b/packages/order-service/package.json new file mode 100644 index 0000000..d14fa2a --- /dev/null +++ b/packages/order-service/package.json @@ -0,0 +1,18 @@ +{ + "name": "@playground/order-service", + "version": "1.0.0", + "private": true, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc --build", + "start": "node dist/index.js" + }, + "dependencies": { + "@playground/database": "*", + "express": "^4.21.0" + }, + "devDependencies": { + "@types/express": "^5.0.0" + } +} diff --git a/packages/order-service/src/index.ts b/packages/order-service/src/index.ts new file mode 100644 index 0000000..0c15850 --- /dev/null +++ b/packages/order-service/src/index.ts @@ -0,0 +1,42 @@ +import express from "express"; +import { insert, findById, findAll } from "@playground/database"; + +const app = express(); +app.use(express.json()); + +const PRODUCT_SERVICE = "http://product-service:3002"; + +app.get("/orders", (_req, res) => { + res.json(findAll("orders")); +}); + +app.get("/orders/:id", (req, res) => { + const order = findById("orders", req.params.id); + if (!order) { + res.status(404).json({ error: "Order not found" }); + return; + } + res.json(order); +}); + +app.post("/orders", async (req, res) => { + const { productId, userId } = req.body; + + const productResponse = await fetch(`${PRODUCT_SERVICE}/products/${productId}`); + if (!productResponse.ok) { + res.status(400).json({ error: "Invalid product" }); + return; + } + + const order = insert("orders", { + id: crypto.randomUUID(), + productId, + userId, + status: "created", + }); + res.status(201).json(order); +}); + +app.listen(3005, () => { + console.log("order-service listening on :3005"); +}); diff --git a/packages/order-service/tsconfig.json b/packages/order-service/tsconfig.json new file mode 100644 index 0000000..98ab749 --- /dev/null +++ b/packages/order-service/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src"], + "references": [ + { "path": "../database" } + ] +} diff --git a/tsconfig.json b/tsconfig.json index a272970..517fbdf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ { "path": "packages/user-service" }, { "path": "packages/product-service" }, { "path": "packages/api-gateway" }, - { "path": "packages/frontend" } + { "path": "packages/frontend" }, + { "path": "packages/order-service" } ] } From 9cbf8620c830edf02ae28485d1f73fdc96131a00 Mon Sep 17 00:00:00 2001 From: Anders Hassis Date: Tue, 3 Mar 2026 14:04:18 +0100 Subject: [PATCH 8/8] ci: use main of erode --- .github/workflows/erode.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/erode.yml b/.github/workflows/erode.yml index ada52f1..ceabac0 100644 --- a/.github/workflows/erode.yml +++ b/.github/workflows/erode.yml @@ -26,7 +26,7 @@ jobs: owner: ${{ github.repository_owner }} - name: Run Erode Analysis - uses: erode-app/erode@feat/deterministic-model-patching + uses: erode-app/erode@main with: model-repo: erode-app/playground-models-only model-path: likec4