Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Take-Home Technical Assessment — Graduate / Junior Engineer

Time budget: ~2 hours. We respect your time — please don't spend significantly longer. An incomplete solution with clear reasoning beats a polished one that took a whole weekend.

Background

Our platform is built on Restate, a framework for building resilient, durable services. We work in the manufacturing domain, where a common task is integrating ERP systems with shop-floor systems using the ISA-95 standard as a common language.

In this exercise you'll extend Restate's hello-world example into a small integration pipeline: receive a production order from an (imaginary) ERP, transform it into a simplified ISA-95 structure, and write the result to a file.

You may use any language with a Restate SDK (TypeScript, Python, Java, Kotlin, Go, Rust...) — use whichever you're most comfortable with.

⚠️ There are no provided restate binaries for Windows: We recommend using NPM/Node in this case

Part 0 — Setup (~15 min)

Follow the Restate Quickstart for your chosen language:

  1. Install the Restate Server & CLI.
  2. Create the Greeter template project (e.g. npx -y @restatedev/create-app@latest for TypeScript — the quickstart shows equivalents for other languages).
  3. Run the service, register it with the Restate server, and confirm the Greeter responds:
curl localhost:8080/restate/call/Greeter/greet --json '{"name": "Sarah"}'

Keep the Greeter in your project — it's a handy reference for handler syntax.

Part 1 — Order Ingestion Service (~30 min)

Add a new Restate service OrderIngestion with a handler submitOrder that:

  1. Accepts an ERP production order (JSON payload below).
  2. Validates it: required fields present, quantity > 0, plannedEnd after plannedStart. Reject invalid orders with a meaningful error.
  3. Calls the Isa95Mapper service (Part 2) to transform and persist the order.
  4. Returns a confirmation containing the order number and the path of the file that was written.

📝 Check the Restate Docs for your chosen SDK on how to call another service

Sample ERP payload

This payload (and four more, including one deliberately invalid order for testing your validation) is provided in the sample-orders/ folder.

{
  "orderNumber": "PO-2026-004512",
  "erpSystem": "SAP-PP",
  "material": {
    "materialNumber": "FG-8842",
    "description": "Stainless Steel Valve Assembly DN50",
    "uom": "EA"
  },
  "quantity": 250,
  "plannedStart": "2026-08-03T06:00:00Z",
  "plannedEnd": "2026-08-05T18:00:00Z",
  "priority": 2,
  "plant": "DE01",
  "routing": [
    { "operation": "0010", "workCenter": "CNC-LATHE-3", "description": "Turn valve body", "setupMinutes": 45, "runMinutesPerUnit": 4.5 },
    { "operation": "0020", "workCenter": "ASSY-LINE-1", "description": "Assemble valve", "setupMinutes": 20, "runMinutesPerUnit": 6.0 },
    { "operation": "0030", "workCenter": "QA-BENCH-2", "description": "Pressure test", "setupMinutes": 10, "runMinutesPerUnit": 2.0 }
  ],
  "components": [
    { "materialNumber": "RM-1001", "description": "Steel bar stock 60mm", "quantityPer": 1.2, "uom": "KG" },
    { "materialNumber": "PM-2205", "description": "Seal kit DN50", "quantityPer": 1.0, "uom": "EA" }
  ]
}

Part 2 — ISA-95 Mapper Service (~45 min)

Add a second service Isa95Mapper with a handler mapAndStore that:

  1. Transforms the ERP order into the simplified ISA-95 Operations Request structure below.
  2. Writes it as pretty-printed JSON to ./output/<orderNumber>.json.
  3. Returns the file path.

Target structure (simplified ISA-95 / B2MML-inspired)

This is the complete expected output for the sample payload above — your output/PO-2026-004512.json should match it exactly:

{
  "operationsRequest": {
    "id": "PO-2026-004512",
    "operationsType": "Production",
    "startTime": "2026-08-03T06:00:00Z",
    "endTime": "2026-08-05T18:00:00Z",
    "priority": 2,
    "hierarchyScope": { "id": "DE01", "equipmentLevel": "Site" },
    "segmentRequirements": [
      {
        "id": "PO-2026-004512-0010",
        "description": "Turn valve body",
        "equipmentRequirement": { "id": "CNC-LATHE-3" },
        "duration": 1170,
        "materialRequirements": [
          {
            "id": "RM-1001",
            "materialUse": "Consumed",
            "quantity": { "value": 300, "unitOfMeasure": "KG" }
          },
          {
            "id": "PM-2205",
            "materialUse": "Consumed",
            "quantity": { "value": 250, "unitOfMeasure": "EA" }
          }
        ]
      },
      {
        "id": "PO-2026-004512-0020",
        "description": "Assemble valve",
        "equipmentRequirement": { "id": "ASSY-LINE-1" },
        "duration": 1520,
        "materialRequirements": []
      },
      {
        "id": "PO-2026-004512-0030",
        "description": "Pressure test",
        "equipmentRequirement": { "id": "QA-BENCH-2" },
        "duration": 510,
        "materialRequirements": [
          {
            "id": "FG-8842",
            "materialUse": "Produced",
            "quantity": { "value": 250, "unitOfMeasure": "EA" }
          }
        ]
      }
    ]
  }
}

mapping diagram A visual reference of the full mapping (source model, target model, and numbered mapping rules) is provided in mapping-diagram.png (editable source: mapping-diagram.drawio).

Mapping rules:

  • One segmentRequirement per routing operation; id = <orderNumber>-<operation>.
  • duration = setup time + (run time per unit × order quantity), given in minutes.
  • Attach each component as a materialRequirement on the first segment only, with quantity.value = quantityPer × order quantity and materialUse: "Consumed".
  • The produced material goes on the last segment as a materialRequirement with materialUse: "Produced" and the full order quantity.

Restate hint: side effects like file writes should be wrapped appropriately so they behave correctly under Restate's durable execution model. Look at ctx.run (or your SDK's equivalent) and be ready to explain why it matters.

Stretch goal (optional) — Virtual Objects

Only if you have time left within the 2 hours — this is genuinely optional and also a discussion topic in the follow-up interview.

Each order's routing references work centers (e.g. CNC-LATHE-3). Using a Restate Virtual Object keyed by work center ID, implement (or sketch in your README) a WorkCenter object that:

  • Tracks the total scheduled minutes booked against that work center.
  • Exposes a handler to query its current load.
  • Is updated by the pipeline whenever an order is processed.

Consider: what does keying by work center ID give you when two orders touching the same work center arrive concurrently?

Submission

  • A git repository (zip or link) containing your code, the generated output/ sample file for the payload above, and a README with: how to run it, your Part 3 answers, any assumptions or shortcuts, and what you'd do next with more time.
  • Please include your commit history — we like seeing how you work incrementally.

What we look for

  • It works: the sample payload flows through and produces a correct ISA-95 file.
  • Restate understanding: sensible use of services, service-to-service calls, and durable side effects. We don't expect you to fully understand the internals of Restate, but knowledge of the basics will help.
  • Code quality: clear naming, small functions, sensible validation and error handling. No over-engineering.
  • Communication: a README that explains your thinking.

We do not expect: tests beyond one or two happy-path checks, deployment setup, exhaustive ISA-95 coverage, or a UI.

Questions or blockers? Email us — asking a good question counts in your favour.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors