KPD closed beta Sign inRequest access
← Back to the guide

KPD Studio · User guide

Hello World: a guided tour of KPD

Build one small, complete data pipeline from an empty screen, step by step, and use every part of KPD on the way.

This tutorial is for your first hour with KPD. You build one simple pipeline from start to finish, and on the way you use every part of the tool: projects, the domain map, clusters and compute pools, schemas, connectors, topics, Flink, governance, access, data quality, dead letter topics, exports, notes and decisions. When you finish, you will have a design that validates cleanly, a picture of it, a design document and Terraform.

Every step says exactly what to click and what to type, and there are pictures throughout. Nothing here connects to Kafka or Confluent Cloud: KPD only designs, so you can't break anything.

What you will build

Hello Coffee Co runs coffee shops. Every order goes into a PostgreSQL database called shopdb. The Sales team wants two things from it, as orders happen:

So the pipeline is:

  1. A CDC connector watches two tables in the shop database, orders and customers, and writes every change to two raw topics.
  2. A Flink statement joins each order to its customer and writes a tidy canonical order topic.
  3. Two more Flink statements read the canonical topic and each write a data product topic.
  4. Every topic has an Avro schema; data quality rules check the canonical orders; failures go to dead letter topics.
The finished Hello World pipeline, as KPD exports it at the end of the tutorial.
The finished Hello World pipeline, as KPD exports it at the end of the tutorial.

Contents

Tip: tick each numbered step as you finish it. Printing tip: choose Background graphics in your browser's print options to keep the coloured notes and tables.

1. Create the project

A new project from the Data Product (DPCF) template, with three clusters and two compute pools.

A project is a folder that holds everything for one piece of work: its pipelines, schemas, clusters, accounts, tags and rules. You start every design by creating one.

Open the New project dialog

  1. Open KPD. You see whichever project you had open last (here, the Inclined Labs sample), or the welcome screen if this is your first time.
  2. Click the File menu at the top left.
KPD as it opens. The File menu is top left.
KPD as it opens. The File menu is top left.
  1. Choose New project…
File → New project…
File → New project…

Name it and pick the template

  1. Project name: type Hello World Coffee. This is the only required field.
  2. Client: type Hello Coffee Co. It appears on the design document and the Terraform README.
  3. Click the Data Product (DPCF) card. The template gives you classification tags, a DataProduct catalogue metadata definition, the DPCF topic naming rule, two suggested compute pools, and a first pipeline laid out as Ingestion → Process → Surface.
  4. Organisation code: type hwc. Every topic name will start with it: the hint shows the pattern hwc.<env>.<raw|ent|sys>.<entity>.<function>.v<n>.
Name, client, the Data Product (DPCF) template and the organisation code hwc.
Name, client, the Data Product (DPCF) template and the organisation code hwc.
Reading a DPCF topic namehwc.prod.raw.order.shopdb.v1 means: organisation hwc, environment prod, layer raw (as captured; ent is the cleaned enterprise layer and sys is for system topics such as dead letters), entity order, function shopdb (where it came from), version 1. KPD checks every topic name against this rule as you type. See Topic naming standards.

Add three clusters and check the pools

Lower down the dialog you can describe your Kafka clusters and Flink compute pools now, so pipelines can use them straight away. Part 3 looks at them in more detail.

  1. Under Kafka clusters, click Add cluster three times to get three rows.
  2. Fill them in like this:
    EnvironmentCluster nameTypeCloudRegion
    devhwc-devStandardAWSeu-west-2
    testhwc-testStandardAWSeu-west-2
    prodhwc-prodStandardAWSeu-west-2
  3. Under Flink compute pools the template has already suggested two pools, one per processing stage: hwc-raw-to-cdm (raw to canonical) and hwc-cdm-to-surface (canonical to data products). Leave them at 10 max CFU. Once a cluster has a region, the pools take it.
Three Standard clusters on AWS in London (eu-west-2), and the two suggested compute pools.
Three Standard clusters on AWS in London (eu-west-2), and the two suggested compute pools.
  1. Click Create project.
Everything filled in. Create project is bottom right.
Everything filled in. Create project is bottom right.

A quick look around

KPD creates the project folder and opens its first pipeline, data-product.kpd, with the three layer boxes already drawn and a Start your pipeline card in the middle.

The new project. Left: the explorer. Middle: the canvas. Bottom: the properties panel. Right: the palettes.
The new project. Left: the explorer. Middle: the canvas. Bottom: the properties panel. Right: the palettes.

Press Ctrl/⌘+S to save. Next: 2. Draw the domain map.

2. Draw the domain map

A Sales domain with a Store orders sub-domain, their owners and contacts, and the pipeline linked to them.

The domain map records which part of the business owns the data, and who to talk to. Pipelines link to it, and their data products then take their domain, sub-domain, owner and contact from it automatically (you will see this in Part 5). We use one domain, Sales, with one sub-domain, Store orders.

Open the domain map

  1. In the explorer, click Domain map (just under the project name).
Domain map in the explorer.
Domain map in the explorer.
  1. A Domain map tab opens with a Draw your domains card. Click Add a domain.
The empty domain map. Its palette (right) has only Domain, Sub-domain, Group box and Note.
The empty domain map. Its palette (right) has only Domain, Sub-domain, Group box and Note.
  1. In the list that appears, choose Domain.
Choose Domain.
Choose Domain.

Describe the Sales domain

A domain appears on the map, selected, with its settings in the properties panel. Fill in:

FieldType
NameSales
CodeSAL
DescriptionEverything about selling coffee: orders in our shops and on the app, payments and loyalty.
OwnerSales Data Team
ContactsClick to add a contact, then name Priya Shah, role Domain owner, contact priya.shah@hello-coffee.example
The Sales domain with its owner and contact. The fields scroll: Name and Code are above the description.
The Sales domain with its owner and contact. The fields scroll: Name and Code are above the description.

Add the Store orders sub-domain

  1. With Sales selected, a + appears on its right-hand edge. Click it.
The + beside the domain is quick add.
The + beside the domain is quick add.
  1. KPD offers only what can connect there: Sub-domain. Choose it. The sub-domain appears to the right, already wired to Sales.
Quick add suggests Sub-domain.
Quick add suggests Sub-domain.
  1. Fill in the sub-domain:
    FieldType
    NameStore orders
    CodeSAL-ORD
    DescriptionOrders placed in our coffee shops and on the app, and the customers who place them.
    OwnerStore Orders Team
    ContactsTom Reed, Product owner, store-orders@hello-coffee.example
Store orders, linked to Sales. Its References list shows the domain it belongs to.
Store orders, linked to Sales. Its References list shows the domain it belongs to.
The finished domain map: Sales and its sub-domain Store orders.
The finished domain map: Sales and its sub-domain Store orders.
  1. Click the data-product.kpd tab above the canvas to go back to the pipeline.
  2. Click an empty part of the canvas so nothing is selected. The properties panel shows the pipeline's General tab.
  3. Domain: choose Sales (SAL). Sub-domain: choose Store orders.
  4. Anchor statement: one sentence saying why the pipeline exists, in the DPCF form <domain> needs to <answer a question / take action> so that <business outcome>. Type:
    Sales needs to see every store order as it happens so that customers can see their order history and store managers can spot big orders straight away.
The pipeline linked to Sales / Store orders, with its anchor statement. It leads the design document in Part 8.
The pipeline linked to Sales / Store orders, with its anchor statement. It leads the design document in Part 8.

Save with Ctrl/⌘+S. Next: 3. Set up dev, test and prod.

3. Set up dev, test and prod

Describe the three clusters and the two Flink compute pools, and put the pipeline on production.

A normal setup has three environments: dev to build and try things, test to check a release, and prod for real use. You created a cluster for each in Part 1; now you describe them, look at the compute pools, and say which cluster the pipeline runs on.

KPD never needs your credentialsClusters hold names, types, regions and ids, never keys or passwords. Terraform gets every secret from variables your CI supplies.

Describe each cluster

  1. In the explorer, open Environments → Clusters. The three clusters are listed with their type.
Environments → Clusters in the explorer.
Environments → Clusters in the explorer.
  1. Click hwc-prod. The Edit cluster dialog opens.
  2. Look at the fields: Bootstrap server, Environment ID (env-…) and Cluster ID (lkc-…) come from Confluent Cloud once the cluster exists. Leave them empty for this tutorial: KPD reminds you about them (as information, not errors) and Terraform marks them as TODOs.
  3. Description: type Production: where the store-orders pipeline runs. Ids to add once the cluster exists. and click Save.
Edit cluster. The ids are what Terraform needs to find a real cluster; leave them empty for now.
Edit cluster. The ids are what Terraform needs to find a real cluster; leave them empty for now.
  1. Do the same for hwc-dev (Development: for building and trying things out. Ids to add once the cluster exists.) and hwc-test (Test: for testing a release before production.).
More clusters laterRight-click Clusters and choose New Kafka cluster… to add one at any time.
Right-click Clusters → New Kafka cluster…
Right-click Clusters → New Kafka cluster…

Check the compute pools

Flink statements run in a compute pool, measured in CFUs (Confluent Flink Units). Each statement needs at least one, so a 10 CFU pool holds up to ten statements. Using one pool per stage keeps a busy stage from starving the other.

  1. Under Stream configuration → Flink compute pools, click hwc-raw-to-cdm.
  2. Check Max CFUs is 10. Leave Existing pool ID empty (fill it only if the pool already exists, and Terraform will use it instead of creating one).
  3. Description: Process stage: the statement that joins raw orders and customers into the canonical order. Click Save.
  4. Click hwc-cdm-to-surface and give it the description Surface stage: the two data product statements.
Edit compute pool: name, cloud, region, max CFUs and a description.
Edit compute pool: name, cloud, region, max CFUs and a description.

Put the pipeline on production

  1. Click an empty part of the canvas so the pipeline's settings show.
  2. Kafka cluster: choose hwc-prod (prod). The cluster's name now appears large in the corner of the canvas, so you always know where a pipeline runs.
The pipeline runs on hwc-prod. That is why every topic name in this tutorial starts hwc.prod.
The pipeline runs on hwc-prod. That is why every topic name in this tutorial starts hwc.prod.

Save. Next: 4. Build the pipeline.

4. Build the pipeline

Avro schemas, a PostgreSQL CDC source, two raw topics, a Flink join to a canonical topic, and two data products.

This is the longest part: you build the whole pipeline. In order:

  1. rename the pipeline;
  2. create five Avro schemas;
  3. add the CDC source and its two raw topics;
  4. add the Flink join and the canonical topic;
  5. add the two data product statements and their topics.

4.1 Rename the pipeline

  1. In the explorer, right-click data-product.kpd under Pipelines and choose Rename…
Right-click the pipeline → Rename…
Right-click the pipeline → Rename…
  1. Type store-orders and click Rename. The file becomes store-orders.kpd.
The new name.
The new name.

4.2 Create the five Avro schemas

Every topic carries messages of a known shape, described by a schema. KPD has a visual editor for Avro, so you never need to write the JSON by hand. You need five: one for each raw table, one for the canonical order, and one for each data product. Their file names follow the topic names with -value on the end (the Schema Registry subject for a topic's values).

  1. In the explorer, scroll down to Shared schemas, right-click it and choose New schema…
Right-click Shared schemas → New schema…
Right-click Shared schemas → New schema…
  1. The New schema dialog opens with an example record. Keep Folder as Shared schemas (top level) and Format as Avro (.avsc).
A new schema starts as an example with two fields. You replace them.
A new schema starts as an example with two fields. You replace them.
  1. File name: hwc.prod.raw.order.shopdb.v1-value
  2. Record name: Order. Namespace: com.hellocoffee.raw
  3. Change the two example fields and use Add field until you have these five. Type each name, then pick its type from the list (timestamp-millis is in the list too):
    FieldType
    order_idlong
    customer_idlong
    store_idstring
    total_penceint
    ordered_attimestamp-millis
The raw Order record. The arrows reorder fields; the bin deletes one.
The raw Order record. The arrows reorder fields; the bin deletes one.

Two handy extras while you are here. Open Example message to see a sample record that matches the schema. Click Source to see the Avro JSON KPD writes for you. The blue Valid Avro bar means the schema is checked against the Avro specification as you type.

An illustrative example message, with a Copy button.
An illustrative example message, with a Copy button.
The Source view: the same schema as Avro JSON. You can edit either view.
The Source view: the same schema as Avro JSON. You can edit either view.
  1. Click Create schema.
  2. Repeat for the other four schemas:
    File nameRecord / namespaceFields
    hwc.prod.raw.customer.shopdb.v1-valueCustomer / com.hellocoffee.rawcustomer_id long, name string, email string (tick nullable)
    hwc.prod.ent.order.cdm.v1-valueStoreOrder / com.hellocoffee.cdmorderId long, customerId long, customerName string, customerEmail string (nullable), storeId string, totalPence int, orderedAt timestamp-millis
    hwc.prod.ent.order.history.v1-valueOrderHistory / com.hellocoffee.productorderId long, customerId long, customerName string, storeId string, totalPence int, orderedAt timestamp-millis
    hwc.prod.ent.order.big-orders.v1-valueBigOrder / com.hellocoffee.productorderId long, storeId string, totalPence int, orderedAt timestamp-millis
The canonical StoreOrder: business-friendly names, and the customer’s name and email joined in. nullable is ticked on customerEmail because not every customer gives one.
The canonical StoreOrder: business-friendly names, and the customer’s name and email joined in. nullable is ticked on customerEmail because not every customer gives one.
Why the names changeRaw topics keep the database's own column names (order_id), exactly as captured. The canonical layer uses the business's names (orderId) once, so every data product built on it agrees. That is the DPCF raw → canonical → product pattern.
All five schemas under Shared schemas.
All five schemas under Shared schemas.

4.3 Add the CDC source

CDC (change data capture) reads the database's own change log, so every insert and update is captured once, in order, without querying the tables.

  1. Make sure the store-orders.kpd tab is showing. On the Start your pipeline card, click Add a source. (Start from a system would draw the shop database itself first, which is a good way into a workshop; here we go straight to the connector.)
  2. Type postgres and choose Postgres CDC (its full name is PostgreSQL CDC Source V2).
Type to search; choose Postgres CDC.
Type to search; choose Postgres CDC.
  1. The connector appears on the canvas. If it isn't inside the green Ingestion box, drag it there: sources belong in the ingestion layer.
  2. On its General tab: Name hwc-shopdb-cdc; Description Captures every new and changed row in the shop database's orders and customers tables, one raw topic per table. (Leave Service account for Part 6.)
The connector in the Ingestion box, with its General tab. Each tab across the panel is one group of connector settings.
The connector in the Ingestion box, with its General tab. Each tab across the panel is one group of connector settings.
  1. Connector tab: database.hostname shopdb.hello-coffee.example, database.port 5432, database.dbname shopdb, database.sslmode require. (No password: that is a secret, supplied when deploying.)
Where the database is. Reset returns a field to its default.
Where the database is. Reset returns a field to its default.
  1. Capture tab: table.include.list public.orders,public.customers; snapshot.mode initial (copy the existing rows first, then stream changes); slot.name hwc_shopdb_slot; publication.name hwc_shopdb_pub; publication.autocreate.mode filtered (the publication covers just these two tables).
Which tables to capture, and how.
Which tables to capture, and how.
  1. Data format tab: output.data.format AVRO, output.key.format STRING, topic.prefix hwc.prod.raw.shopdb.
Avro values, string keys.
Avro values, string keys.
How a CDC connector names its topicsA CDC connector writes one topic per table and names each one itself: topic.prefix, then the schema and table. With our prefix, public.orders would land in hwc.prod.raw.shopdb.public.orders. KPD works these names out and checks the topics you wire against them. Our DPCF standard wants names like hwc.prod.raw.order.shopdb.v1 instead, so the next step adds a transform that renames them. (Without it, KPD would offer to Add topics with the connector's own names. See CDC sources and their topics.)
  1. Advanced tab: in SMT chain, type RegexRouter and press Enter. RegexRouter is the single message transform that renames each topic to our DPCF name.
The SMT chain records that a RegexRouter renames the topics. The red 1 on Problems says the connector captures two tables but has no topics yet; 4.4 adds them.
The SMT chain records that a RegexRouter renames the topics. The red 1 on Problems says the connector captures two tables but has no topics yet; 4.4 adds them.

Because a transform renames the topics, KPD can't predict the names any more, so it checks only that there is one topic per captured table. (The transform's own settings, the pattern and the replacement, are added to the Terraform by hand.)

Hover the ⓘ iconsEvery setting has a short explanation from the connector's documentation. The Docs link top right opens Confluent's page for the connector.

4.4 Add the two raw topics

  1. With the connector selected, click the + on its right-hand edge (its Records output).
The + on the connector’s output.
The + on the connector’s output.
  1. Choose Topic. A topic appears, already connected.
Quick add only offers what can connect: a Topic, or a Dead Letter topic.
Quick add only offers what can connect: a Topic, or a Dead Letter topic.
  1. On the topic's General tab: Name hwc.prod.raw.order.shopdb.v1; Description Every order row from shopdb (public.orders), as captured. Raw: never published.
  2. Partitions & durability tab: Partitions 3; Partition key order_id (a design note: which field keeps one order's changes in order).
Three partitions, keyed by order. (The red 1 on Problems goes away when the schema is set.)
Three partitions, keyed by order. (The red 1 on Problems goes away when the schema is set.)
  1. Schema tab: Key format String; Value schema file hwc.prod.raw.order.shopdb.v1-value.avsc.
The topic’s value schema is the file you made in 4.2.
The topic’s value schema is the file you made in 4.2.
  1. Select the connector again, click its + again and add a second Topic: name hwc.prod.raw.customer.shopdb.v1, description Every customer row from shopdb (public.customers), as captured. Raw: never published., 3 partitions, partition key customer_id, key format String, value schema hwc.prod.raw.customer.shopdb.v1-value.avsc.
One connector, two raw topics, both in the Ingestion box.
One connector, two raw topics, both in the Ingestion box.
One connector, two topicsOne wire per captured table shows where the data really goes, and the connector's warning about tables without a topic has gone. The Terraform will create both topics before the connector starts, with the partitions and schemas you set here, so the connector never has to create them itself (it would make them with 1 partition). To let the connector create a topic instead, set the topic's Managed by to Connector; see Who creates the topics.

4.5 Join orders to customers in Flink

  1. Select the order raw topic and click its +. Choose Flink SQL. The statement is placed in the purple Process box.
After a topic, quick add suggests things that read topics. Choose Flink SQL.
After a topic, quick add suggests things that read topics. Choose Flink SQL.
  1. On the statement's General tab: Name orders_raw_to_cdm; Description Joins each raw order with its customer to make the canonical store order: business field names, the customer's name and email added.; Compute pool hwc-raw-to-cdm.
The statement runs in the raw-to-canonical pool. The hint under the pool shows how many of its 10 CFUs are used.
The statement runs in the raw-to-canonical pool. The hint under the pool shows how many of its 10 CFUs are used.
  1. Now wire the customer topic in as the join. A Flink statement has a Main input on its left and a Join input on its bottom edge. Drag from the customer topic's right-hand dot (its output) to the dot on the bottom of the statement. A line follows the mouse while you drag.
Dragging from the customer topic’s output to the statement’s Join input.
Dragging from the customer topic’s output to the statement’s Join input.
Connected. Hovering a statement labels its ports: Main input, Join input, Output, Errors and UDFs / models.
Connected. Hovering a statement labels its ports: Main input, Join input, Output, Errors and UDFs / models.
  1. SQL tab: Statement kind INSERT INTO. Keep the SQL in a file of its own, so it can be reviewed like any other code: under SQL file choose + New SQL file…. The dialog suggests the name orders_raw_to_cdm in a new store-orders folder; keep both, replace the starter text with this, and click Create SQL file:
    -- Each order, with the customer who placed it.
    INSERT INTO `hwc.prod.ent.order.cdm.v1`
    SELECT
      o.order_id    AS orderId,
      o.customer_id AS customerId,
      c.name        AS customerName,
      c.email       AS customerEmail,
      o.store_id    AS storeId,
      o.total_pence AS totalPence,
      o.ordered_at  AS orderedAt
    FROM `hwc.prod.raw.order.shopdb.v1` AS o
    JOIN `hwc.prod.raw.customer.shopdb.v1` AS c
      ON o.customer_id = c.customer_id;
    The SQL tab now shows the file, Read-only so it isn’t changed by accident. To change it later, untick Read-only and edit it there, or open it from Stream configuration → SQL in the explorer.
The join, in its own file, sql/store-orders/orders_raw_to_cdm.sql. In Confluent Cloud Flink every topic is a table, so the SQL uses the topic names in back-quotes.
The join, in its own file, sql/store-orders/orders_raw_to_cdm.sql. In Confluent Cloud Flink every topic is a table, so the SQL uses the topic names in back-quotes.
KPD doesn't run your SQLIt stores it, shows it in the design document, and puts it in Terraform exactly as written. Check it in Confluent Cloud's SQL workspace before you rely on it.

4.6 Add the canonical topic

  1. Select orders_raw_to_cdm, click the + on its Output and choose Topic.
  2. Name hwc.prod.ent.order.cdm.v1; Description Canonical store orders: every order with its customer, in business field names. The single source for the data products.; 3 partitions, partition key orderId; key format String; value schema hwc.prod.ent.order.cdm.v1-value.avsc.

4.7 Add the two data products

Each data product is a Flink statement that reads the canonical topic and writes its own topic, in the blue Surface box.

  1. Select the canonical topic, click its + and choose Flink SQL. Name it order_history_product, description Data product DP-001: every order with who placed it, for the app's order history., compute pool hwc-cdm-to-surface. On SQL, choose + New SQL file… as before, keep the suggested name, and create it with:
    -- DP-001: each customer's orders, without their email.
    INSERT INTO `hwc.prod.ent.order.history.v1`
    SELECT orderId, customerId, customerName, storeId, totalPence, orderedAt
    FROM `hwc.prod.ent.order.cdm.v1`;
  2. Select order_history_product, click the + on its Output, choose Topic: name hwc.prod.ent.order.history.v1, description DP-001 Customer order history: every store order with the customer who placed it., 3 partitions keyed by orderId, key String, value schema hwc.prod.ent.order.history.v1-value.avsc.
  3. Select the canonical topic again and add a second Flink SQL: big_orders_product, description Data product DP-002: orders of £20 or more, for store managers., pool hwc-cdm-to-surface, and a + New SQL file… with:
    -- DP-002: orders of £20 (2000 pence) or more.
    INSERT INTO `hwc.prod.ent.order.big-orders.v1`
    SELECT orderId, storeId, totalPence, orderedAt
    FROM `hwc.prod.ent.order.cdm.v1`
    WHERE totalPence >= 2000;
  4. Give it an output Topic: hwc.prod.ent.order.big-orders.v1, description DP-002 Big orders: orders of £20 or more, as they happen., 3 partitions keyed by orderId, key String, value schema hwc.prod.ent.order.big-orders.v1-value.avsc.
The Big orders statement: a simple filter on the canonical topic, in its own SQL file.
The Big orders statement: a simple filter on the canonical topic, in its own SQL file.
The whole pipeline: source and raw topics in Ingestion, the join and canonical topic in Process, two data products in Surface. The status bar says No problems.
The whole pipeline: source and raw topics in Ingestion, the join and canonical topic in Process, two data products in Surface. The status bar says No problems.
Tidy as you goDrag assets to line them up; Snap to grid keeps them neat. If a line runs through an asset, move one of them a little. Shift+1 fits the whole pipeline on screen.

Save. Next: 5. Governance: tags and the catalogue.

5. Governance: tags and the catalogue

Classification tags on every topic, and catalogue metadata on the two data products.

Tags say how sensitive data is; they become Stream Catalog tags in Confluent Cloud, so people can search for them and policies can act on them. Business metadata describes a data product in the catalogue: what it is, who owns it, how good it is. The DPCF template created both for you.

The tags you have

  1. In the explorer, open Stream governance → Tags. There are four classification tiers (Public, Internal, Confidential, Restricted), two overlays for special data (PII personal data, PCI card data) and DataProduct for published products.
The template’s tags, and the DataProduct business metadata with 13 attributes.
The template’s tags, and the DataProduct business metadata with 13 attributes.
  1. Click PII to see what a tag holds: a name, a colour and a description. Click Cancel: there is nothing to change.
A tag’s colour is the dot it shows on the canvas.
A tag’s colour is the dot it shows on the canvas.

Tag every topic

  1. Click the topic hwc.prod.raw.customer.shopdb.v1 and open its Governance tab.
  2. In Add a tag… choose Restricted, then open it again and choose PII. Each becomes a chip; click a chip's × to remove it.
Raw customer data: Restricted, and PII because it has names and emails.
Raw customer data: Restricted, and PII because it has names and emails.
  1. Tag the other topics the same way:
    TopicTagsWhy
    hwc.prod.raw.order.shopdb.v1RestrictedRaw data is never published.
    hwc.prod.raw.customer.shopdb.v1Restricted, PIIRaw, with personal data.
    hwc.prod.ent.order.cdm.v1Confidential, PIICleaned, but still has names and emails.
    hwc.prod.ent.order.history.v1Confidential, PII, DataProductA product, with customer names.
    hwc.prod.ent.order.big-orders.v1Internal, DataProductA product with no personal data.

Catalogue the two data products

  1. Click hwc.prod.ent.order.history.v1 and open Governance.
  2. In Add business metadata… choose DataProduct. Its attributes appear (a red * marks the required ones).
  3. Fill in:
    AttributeCustomer order historyBig orders
    ProductNameCustomer order historyBig orders
    DescriptionEvery store order with the customer who placed it, for the order history screen in the app.Orders of £20 or more, as they happen, so store managers can thank big customers and plan stock.
    ProductIdDP-001DP-002
    StewardPriya ShahPriya Shah
    CustodianData Platform TeamData Platform Team
    ClassificationConfidential, PIIInternal
    TierBronzeBronze
    LifecycleStateCandidateCandidate
    ContractSummarySchema hwc.prod.ent.order.history.v1-value. Each order within a minute of being placed.Schema hwc.prod.ent.order.big-orders.v1-value. Each big order within a minute of being placed.
The DataProduct metadata on the order history topic.
The DataProduct metadata on the order history topic.
  1. Notice Domain, SubDomain, Owner and Contact: you don't type them. They show from domain map, because the pipeline is linked to Sales / Store orders (Part 2). Change the domain map and every product follows.
Inherited from the domain map: Sales, Store orders, Store Orders Team.
Inherited from the domain map: Sales, Store orders, Store Orders Team.
  1. Do the same on hwc.prod.ent.order.big-orders.v1 with the Big orders column.

Back on the canvas, the coloured dots under each topic are its tags, so you can see the classification at a glance.

Tag dots under the topics.
Tag dots under the topics.

Save. Next: 6. Service accounts and role bindings.

6. Service accounts and role bindings

One account for the connector and one for Flink, each with just the access it needs.

In Confluent Cloud, connectors and Flink statements run as a service account, and the account's role bindings say what it may read and write. Least privilege means each account gets only what its job needs. KPD records the bindings you choose and writes them into Terraform; it never adds any by itself.

An account for the connector

  1. In the explorer, right-click Environments → Service accounts and choose New service account…
Right-click Service accounts → New service account…
Right-click Service accounts → New service account…
  1. Service account name sa-hwc-cdc; Description Runs the shop database CDC connector. Writes the raw topics and their schemas only.
  2. Under Clusters, tick hwc-prod.
  3. Click Add binding twice and fill the rows:
    RoleScopeClusterResourcePrefix
    DeveloperWriteTopichwc-prodhwc.prod.raw.ticked
    DeveloperWriteSchema subjecthwc-prodhwc.prod.raw.ticked
    Prefix means "every topic (or subject) whose name starts with this", so the connector can write any raw topic and its schema, and nothing else.
  4. Leave Create an API key unticked: connectors and Flink run as the account and need no key. Click Create service account.
The connector’s account: write access to raw topics and their schemas.
The connector’s account: write access to raw topics and their schemas.
  1. Create a second account: sa-hwc-flink, description Runs the three Flink statements. Reads raw and canonical topics, writes canonical and product topics., cluster hwc-prod, and these bindings:
    RoleScopeResourcePrefixWhy
    FlinkDeveloperEnvironment (of the cluster)(the cluster's environment)Run statements in the environment's pools.
    DeveloperReadTopichwc.prod.tickedRead raw and canonical topics.
    DeveloperWriteTopichwc.prod.ent.tickedWrite canonical and product topics.
    DeveloperReadSchema subjecthwc.prod.tickedRead their schemas.
    DeveloperWriteSchema subjecthwc.prod.ent.tickedRegister product schemas.
The Flink account. What do the roles allow? explains each role.
The Flink account. What do the roles allow? explains each role.

Say which asset runs as which account

  1. Click the connector hwc-shopdb-cdc. On General, set Service account to sa-hwc-cdc.
  2. Click each of the three Flink statements and set Service account to sa-hwc-flink. The hint under it lists the roles the account has.
orders_raw_to_cdm runs as sa-hwc-flink.
orders_raw_to_cdm runs as sa-hwc-flink.
Both accounts in the explorer, with their number of bindings.
Both accounts in the explorer, with their number of bindings.
Missed something?You don't have to get access perfect now. In Part 8, Terraform's permission advice compares what each asset reads and writes with its bindings, and offers what is missing for you to tick.

Save. Next: 7. Data quality and dead letter topics.

7. Data quality and dead letter topics

Two contract rules on the canonical topic, three dead letter topics, and a clean Validate.

Data contract rules check each message as it is written to a topic. A message that fails can be sent to a dead letter topic (DLQ) instead of stopping the pipeline. Flink statements have their own Errors output for records they can't process. By the end of this part every failure has somewhere to go, and the project validates.

Two rules for the canonical orders

  1. In the explorer, right-click Contract rules and choose New contract rule…
Right-click Contract rules → New contract rule…
Right-click Contract rules → New contract rule…
  1. Leave Start from as a blank rule (the list has ready-made templates to try another time). Fill in:
    • Rule name orderTotalPositive; Rule type Condition (CEL): it checks each whole message and fails when the expression is false.
    • Description An order must have a positive total. Failures go to the canonical order DLQ for the store team to check.
    • Runs On write (producer) · WRITE; On failure Send to dead letter topic · DLQ.
    • CEL expression message.totalPence > 0
  2. Click Create rule.
A CEL condition that sends failures to a dead letter topic.
A CEL condition that sends failures to a dead letter topic.
  1. Create a second rule the same way: customerNamePresent, Condition (CEL), description Every order must name its customer (the join found them). Failures go to the canonical order DLQ., WRITE, DLQ, expression size(message.customerName) > 0.
  2. Click the canonical topic hwc.prod.ent.order.cdm.v1, open Data contract, and in Add a rule… choose orderTotalPositive, then customerNamePresent. They run in the order listed.
The canonical topic’s Data contract tab, ready to add rules from the project’s library.
The canonical topic’s Data contract tab, ready to add rules from the project’s library.

Send rejected orders to a dead letter topic

  1. Once the topic has a rule that sends failures to a DLQ, it grows a Rejected output on its bottom edge (and a Contract · 2 badge). The orange ! is KPD reminding you the rejects have nowhere to go yet. Click the red + under the topic.
The Rejected output’s +.
The Rejected output’s +.
  1. Choose Dead Letter.
Only a Dead Letter topic can take rejected records.
Only a Dead Letter topic can take rejected records.
  1. On the dead letter topic's General tab: Name hwc.prod.ent.order.cdm.v1.dlq (the canonical topic's name plus .dlq); Description Canonical orders that broke a data quality rule, for the store team to check and fix at source. Holds customer details, so tagged like the canonical topic.; Replay strategy manual (someone fixes and resends them by hand).
  2. Governance tab: tag it Confidential and PII. A DLQ holds the same data as its source, so it needs the same protection.
The canonical DLQ, under the canonical topic. The red dashed line is labelled <i>contract rejects</i>.
The canonical DLQ, under the canonical topic. The red dashed line is labelled contract rejects.
  1. Click orders_raw_to_cdm. Its Errors output is the red + on its bottom edge. Click it and choose Dead Letter.
  2. Name it hwc.prod.sys.order.to-cdm.v1.dlq (sys, because it is a system topic), description Records orders_raw_to_cdm could not process (for example a value that would not convert), for the data team to inspect., replay manual, tags Confidential and PII.
Two dead letter topics in the Process box: Flink errors (left) and contract rejects (right).
Two dead letter topics in the Process box: Flink errors (left) and contract rejects (right).
  1. Now the two data product statements. Click order_history_product and click the red + on its Errors output.
The Errors + on order_history_product.
The Errors + on order_history_product.
  1. Choose Dead Letter: hwc.prod.sys.order.to-product.v1.dlq, description Records the two data product statements could not process, for the data team to inspect., replay manual, tags Confidential and PII.
The product DLQ. Its References list both statements once the second is wired.
The product DLQ. Its References list both statements once the second is wired.
  1. One DLQ can serve both product statements. Drag from the Errors dot under big_orders_product to the input dot on top of the new dead letter topic.
  2. Tidy up: drag the new DLQ into the bottom of the blue Surface box, under big_orders_product. If the line from order_history_product runs through big_orders_product, drag order_history_product a little to the right so its line drops straight down beside it.
Every failure has a home: Flink errors and contract rejects in Process, product errors in Surface.
Every failure has a home: Flink errors and contract rejects in Process, product errors in Surface.

Validate the project

  1. Click Validate in the toolbar.
The toolbar’s Validate.
The toolbar’s Validate.
  1. KPD checks the whole project. You should see Project validates: No errors or warnings, and Terraform will generate.
Project validates. The blue messages are information, not problems.
Project validates. The blue messages are information, not problems.

The messages are worth reading. Most say the clusters have no bootstrap server or ids yet: expected, because they don't exist yet. Two say how many CFUs each pool will use. The last ones are permission advice: the connector needs to create its topics (DeveloperManage), and Flink needs to write to the two sys dead letter topics, which its hwc.prod.ent. binding doesn't cover. You will accept that advice in Part 8.

Save. Next: 8. Export the picture, design document and Terraform.

8. Export the picture, design document and Terraform

A PNG of the pipeline, the detailed design (LLD) document, and Terraform with permission advice.

Everything you take out of KPD is on the Export menu. Each export is downloaded by your browser and also saved in the project's exports/ folder, so it stays with the design.

A picture of the pipeline (PNG)

  1. Choose Export → Export PNG (or Ctrl/⌘+Shift+E, or the green Export PNG button top right). Include legend in PNG is ticked by default.
Export → Export PNG
Export → Export PNG
  1. Your browser downloads store-orders.png: the pipeline at twice screen resolution, captioned with its cluster, with a legend that explains only the colours and lines it uses. The background is transparent, so it sits well on a slide or in a document.
The exported PNG (shown here on white).
The exported PNG (shown here on white).

The detailed design document (LLD)

  1. Choose Export → Export to Detailed Design Template.
Export → Export to Detailed Design Template
Export → Export to Detailed Design Template
  1. KPD writes the whole project as a low-level design in Markdown, hello-world-coffee-detailed-design.md, with the diagrams as PNG files beside it in exports/. Open it in any Markdown editor, or import it into Google Docs or Word (see Detailed design document).
The start of the document: title, version history and a contents list that follows a typical client LLD.
The start of the document: title, version history and a contents list that follows a typical client LLD.

Everything KPD knows is written for you: the topic catalogue, schema field tables, the Flink SQL, role bindings, tags and metadata. Anything it can't know is marked ✏️ Author with a starting point to replace with your own words. Look at section 6: the data product definitions came from the catalogue metadata you entered in Part 5, and the owner and contact from the domain map.

Section 6.1, Customer order history: owner, steward, custodian and contact are already filled in.
Section 6.1, Customer order history: owner, steward, custodian and contact are already filled in.
Section 7.3 lists every dead letter topic with what feeds it and its replay strategy.
Section 7.3 lists every dead letter topic with what feeds it and its replay strategy.
Export it again at the endSection 13 (decisions, assumptions, dependencies and actions) is empty until you add them in Part 9. Export once more after Part 9 to fill it.

Terraform

  1. Choose Export → Terraform…
Export → Terraform…
Export → Terraform…
  1. The Terraform page has three sections. 1. Checks: one pipeline included, no validation errors. 2. Permission advice: what the running assets seem to need that their bindings don't cover. 3. Output: the TODOs and the files.
The Terraform page. Note the line at the top: no keys or secrets are ever written.
The Terraform page. Note the line at the top: no keys or secrets are ever written.
  1. Tick both suggestions: sa-hwc-flink needs DeveloperWrite on each of the two sys dead letter topics. Click Add 2 ticked bindings to service accounts. (The connector's account needs nothing more: Terraform creates the raw topics before the connector starts, so the connector only writes to them, which Part 6 already allows.)
Nothing is added unless you tick it.
Nothing is added unless you tick it.
  1. The section now says Every running asset's service account has bindings that cover what it reads and writes.
Access covered.
Access covered.
  1. Under 3. Output, click any file to preview it. pipeline-store-orders.tf has the topics (with prevent_destroy, so a topic's data can't be deleted by accident), schemas with their contract rules, tags, metadata, the connector and the Flink statements.
Previewing pipeline-store-orders.tf.
Previewing pipeline-store-orders.tf.
  1. The three TODOs: two say the hwc-prod cluster has no Environment ID or Cluster ID. That's right: fill them in on the cluster (Part 3) once the cluster exists, and they disappear. The third asks for the connector's database.user: the connector needs it, but a design doesn't hold it, so it is a Terraform variable you set for each environment.
  2. Click Download .zip to take the Terraform away, or Write to exports/terraform/ to keep it with the project.
Download .zip or Write to exports/terraform/.
Download .zip or Write to exports/terraform/.

Back in the explorer, sa-hwc-flink now has seven bindings: the five you added in Part 6 and the two from the advice. Click it to see them; you can change or remove them like any other.

The added bindings are ordinary bindings on the account.
The added bindings are ordinary bindings on the account.
A starting point, not a deploymentThe Terraform is for your team to review, check in and run from CI (terraform init, terraform plan). KPD never connects to Confluent Cloud. See Terraform.

Next: 9. Notes, decisions, actions, groups and shading.

9. Notes, decisions, actions, groups and shading

Record why the design is the way it is, and make the diagram easy to read.

A design is more than its assets. This part records why it is the way it is (decisions), what it takes on trust (assumptions), what must be in place first (dependencies), what is still to do (actions), and makes the diagram read well with groups and shading. None of it changes validation or Terraform; all of it appears in the exports.

Why record decisions, assumptions and dependencies?

A diagram shows what the design is. It doesn't show why it is that way, what it takes on trust, or what has to happen first. Those live in people's heads and in meeting notes, and they get lost: the person who chose CDC moves on, someone asks "why didn't we just poll the table?", and the team spends an afternoon working it out again. KPD keeps them on the canvas, beside the assets they are about, numbered so a document or a ticket can point at them.

Record a…WhenWhy it helpsIn this tutorial
Design decision (D1, D2…)You chose between real options: CDC or polling, one topic or two, which key to partition by, Avro or JSON.Says what was chosen and why, so it isn't argued again, a reviewer can check the reasoning, and a newcomer understands the design. If the reason stops being true, you know which decision to revisit.D1: log-based CDC rather than polling.
Assumption (A1, A2…)The design relies on something you believe but haven't confirmed: a field is never empty, totals are in pence, volumes stay small.Assumptions are risks. Writing them down makes them visible, names who should confirm them, and lets a review ask "has A1 been checked?" before go-live. When one turns out wrong, you can see exactly which assets it touches.A1: totals are whole pence, so totalPence is an int.
Dependency / pre-requisite (DEP1…)Something outside your pipeline has to be in place first, usually provided by another team: a database setting, network access, an account, a schema from upstream.These are what delay go-lives. Listing them early lets a project plan include them and the team that owns them hear about them in good time.DEP1: logical replication and a publication on shopdb.
Next action (ACN1…)Someone has to do something: confirm an assumption, arrange a dependency, chase an answer.Turns open questions into a to-do list with a date and a name, so nothing is forgotten between workshops.ACN1 arranges DEP1; ACN2 confirms the big-order threshold.

They work together: an assumption or a dependency usually leads to an action, and once the action is done, the assumption may become a decision. Linking each note to its asset (below) means the technical export quotes it under that asset, and the detailed design document lists them all in its section 13 with dates and authors, ready for a design review.

Good habitsWrite them as you design, not afterwards: a reason is easy to record at the moment you choose and hard to reconstruct a month later. Keep one point per note. Say who should confirm an assumption or provide a dependency. Before go-live, read down the Decisions tab and ask of every assumption: has this been checked?

Say who you are

KPD stamps each decision, assumption, dependency and action with the date and an author. There is no login, so set your name once.

  1. Click an empty part of the canvas and open the pipeline's Actions tab (the same box is on Decisions).
  2. In Documented by, type your name (we used Alex Morgan). Your browser remembers it.
Documented by, top right of the Actions tab.
Documented by, top right of the Actions tab.

A design decision

  1. Right-click an empty part of the canvas, inside the Ingestion box under the connector, and choose Add design decision here. (Or press D with the mouse over the canvas.)
The canvas right-click menu: group box, note, decision, assumption and dependency.
The canvas right-click menu: group box, note, decision, assumption and dependency.
  1. A blue note appears, numbered D1, ready for typing. Type Use log-based CDC (Debezium) rather than polling shopdb: every insert and update arrives once, in order, with no extra load on the shop database. and press Esc (or click away) to finish.
Writing D1. If the text doesn’t fit, select the note and drag its corner handle to resize it.
Writing D1. If the text doesn’t fit, select the note and drag its corner handle to resize it.
Edit laterDouble-click any note to change its text. Its number never changes and is never reused, so a document can cite D1 safely.

An assumption, a dependency and a plain note

Add three more the same way (right-click the canvas, or press the key):

KindKeyWhereText
Assumption A1 (orange)ATop of the Process boxOrder totals are whole pence, never fractions, so totalPence is an int. Sales to confirm with the till supplier.
Dependency DEP1 (slate)PUnder the Ingestion boxshopdb needs logical replication on (wal_level = logical) and a user allowed to create the hwc_shopdb_pub publication. The shop database team provides this.
Plain note (yellow)NTop of the Surface boxOrder history leaves out customer emails: the app only shows names.
  1. Every note has a connector dot on its right edge, and every asset has a small grey Notes dot at its top-left corner (both outlined below). Drag from the note's dot to the asset's dot.
From D1’s dot (right edge) to the connector’s Notes dot (top-left corner).
From D1’s dot (right edge) to the connector’s Notes dot (top-left corner).
A dotted grey line now joins them, and follows when either moves.
A dotted grey line now joins them, and follows when either moves.
  1. Link DEP1 to the connector too, A1 to the canonical topic hwc.prod.ent.order.cdm.v1, and the plain note to order_history_product.
All four notes, each linked to the asset it is about.
All four notes, each linked to the asset it is about.

The decision log and next actions

  1. Click an empty part of the canvas and open the pipeline's Decisions tab. It lists every decision, assumption and dependency with its date, author and the assets it applies to. Click a row to jump to the note on the canvas. Dates and authors can be corrected here.
The decision log: D1, A1 and DEP1.
The decision log: D1, A1 and DEP1.
  1. Open Actions and click + Next action.
The Actions tab before any actions.
The Actions tab before any actions.
  1. Type Ask the shop database team to turn on logical replication on shopdb and create the hwc_shopdb_pub publication (see DEP1). It becomes ACN1.
  2. Add a second: Confirm the £20 big-order threshold with the Sales team before the first release. (ACN2).
Two next actions, stamped with today’s date and your name. Actions live on this tab, not on the canvas.
Two next actions, stamped with today’s date and your name. Actions live on this tab, not on the canvas.

Groups

The three layer boxes are groups: labelled backgrounds for parts of a solution. The DPCF template drew them for you.

The toolbar’s Group button.
The toolbar’s Group button.
The Surface group selected: its name, colour, description, and the assets inside it.
The Surface group selected: its name, colour, description, and the assets inside it.

Shading by data product

Shading gives assets a pale background to show what belongs together. Here, one shade per data product.

  1. Click order_history_product. In the properties panel's header, click the pale blue swatch, Sky.
The shade swatches in the panel header. The first (crossed out) means no shade.
The shade swatches in the panel header. The first (crossed out) means no shade.
  1. Shade the topic hwc.prod.ent.order.history.v1 Sky too, and give big_orders_product and hwc.prod.ent.order.big-orders.v1 the pale orange, Peach.
  2. You can also right-click an asset (or several selected together): the menu starts with the same swatches.
The right-click menu’s Shade row.
The right-click menu’s Shade row.
  1. Say what the shades mean: click an empty part of the canvas, open Shading key, and type Customer order history (DP-001) beside Sky and Big orders (DP-002) beside Peach. Press Tab or Enter after each to save it.
The shading key: the meaning applies to the whole project; <i>Assets here</i> counts this pipeline.
The shading key: the meaning applies to the whole project; Assets here counts this pipeline.

Finished

Save, fit the pipeline to the screen (Shift+1), and click Validate once more.

The finished Hello World pipeline in KPD.
The finished Hello World pipeline in KPD.
Still validates, and no permission advice is left.
Still validates, and no permission advice is left.

Export the PNG again: decisions, assumptions, dependencies and notes are in the picture, and the shading key is under the legend. Export the design document again too, and its section 13 now lists D1, A1, DEP1, ACN1 and ACN2.

The final PNG, with notes and the shading key.
The final PNG, with notes and the shading key.

Next: 10. Share it: export and import.

10. Share it: export and import

Export the whole project as a zip, import one, and download our finished copy.

A project moves between people and machines as one zip: project file, pipelines, schemas, SQL files and exports together, so nothing is left behind.

Export your project

  1. Click Export project in the toolbar (or Export → Export project (.zip)). KPD offers to save anything unsaved first.
  2. Your browser downloads hello-world-coffee-<date>.zip. Send it to a colleague, or keep it as a backup.
Export project, top right.
Export project, top right.

Import a project

  1. Choose File → Import project (.zip)…
File → Import project (.zip)…
File → Import project (.zip)…
  1. Pick the zip. KPD checks it (it must contain a project file, and nothing unsafe), creates the project and opens it.
  2. If a project with the same name already exists, the new one gets -1 (then -2…) on the end, so nothing is ever overwritten. Below, importing our sample beside the one we built gave Hello World Coffee-1.
Imported and opened, with everything from the tutorial: notes, shading, groups and all.
Imported and opened, with everything from the tutorial: notes, shading, groups and all.

Where next

You have used every part of KPD on one small pipeline. Some ideas for your own designs:

When you find something confusing or broken, please tell us with Help → Send feedback. That is what the beta is for.

Download the finished sample

If you get stuck, or want to compare your work with ours, download the finished Hello World Coffee project. It is exactly what you build in this tutorial, and it validates with no errors or warnings.

Download hello-world-coffee.zip (11 KB: the project file, the pipeline, its five Avro schemas and three SQL files)

To open it in KPD:

  1. Download the file above and keep it as a .zip. Don't unzip it: KPD reads the zip itself. (Some browsers unzip downloads automatically; if yours did, zip the hello-world-coffee folder up again.)
  2. In KPD choose File → Import project (.zip)…
  3. Pick hello-world-coffee.zip. KPD uploads it, checks it, creates the project and opens it. You see a message such as Imported project "Hello World Coffee".
  4. If you already have a project called Hello World Coffee (for example the one you built), the import is named Hello World Coffee-1, so nothing of yours is overwritten.
  5. Open store-orders.kpd under Pipelines in the explorer and press Validate to see it pass.

Part 10 shows these steps with pictures: Share it: export and import.

Download the finished sample

If you get stuck, or want to compare your work with ours, download the finished Hello World Coffee project. It is exactly what you build in this tutorial, and it validates with no errors or warnings.

Download hello-world-coffee.zip (11 KB: the project file, the pipeline, its five Avro schemas and three SQL files)

To open it in KPD:

  1. Download the file above and keep it as a .zip. Don't unzip it: KPD reads the zip itself. (Some browsers unzip downloads automatically; if yours did, zip the hello-world-coffee folder up again.)
  2. In KPD choose File → Import project (.zip)…
  3. Pick hello-world-coffee.zip. KPD uploads it, checks it, creates the project and opens it. You see a message such as Imported project "Hello World Coffee".
  4. If you already have a project called Hello World Coffee (for example the one you built), the import is named Hello World Coffee-1, so nothing of yours is overwritten.
  5. Open store-orders.kpd under Pipelines in the explorer and press Validate to see it pass.

Part 10 shows these steps with pictures: Share it: export and import.