Skip to main content

Team

The team/ directory covers who owns the data product. It maps to two schemas from the library's team module: TeamMember, for the people accountable for the product, and Team, for the group they form.

Team members

The people side lives in team/member.k. Each is a TeamMember, and the schema validates dateIn and dateOut against an ISO-8601 date pattern (YYYY-MM-DD) in its own check block, so a malformed date is rejected at compile time rather than silently accepted as an arbitrary string:

import enkinex_odps.team

JohnDoe = team.TeamMember {
username = "john.doe@retailcorp.com"
name = "John Doe"
description = "Data Product Owner"
role = "owner"
dateIn = "2023-01-15"
}

JaneSmith = team.TeamMember {
username = "jane.smith@retailcorp.com"
name = "Jane Smith"
description = "Data Steward"
role = "data steward"
dateIn = "2023-02-01"
}

Both members set only dateIn. The optional dateOut and replacedByUsername stay unset, since neither person has left the team in the source document — the schema allows those fields without forcing them on every entry.

The team

team/team.k assembles the two members into a Team. Because Team extends the library's discoverable base, it carries tags and customProperties of its own — this is the only place in the document where a composite, rather than a port, is tagged:

import enkinex_odps.team

import .member as team_member

DataTeam = team.Team {
name = "Data Team"
description = "The Data Team is responsible for the data product."
tags = ["data", "team"]
customProperties = [
{property = "dataTeam", value = "true"}
]
members = [
team_member.JohnDoe
team_member.JaneSmith
]
}

The second import is the interesting one. team/team.k and team/member.k sit in the same directory, but that is not enough to put JohnDoe in scope: a KCL import resolves a single file, so a file that wants values from a sibling file must import it — import .member as team_member — and reach them through the alias. The same leading-dot rule as the root file applies, one directory level down.

Keeping the members in their own file means a person is declared once and can be referenced from more than one team, while the grouping — the team's name, description, and tags — stays with the product that defines it.

Composing the root product.k

Now we extend the root file from the previous section. One new local import appears, and the team field joins the ones we already had:

import enkinex_odps.odps

import .metadata.description as product_description
import .team.team as product_team

odps.DataProduct {
name = "Customer Data Product"
id = "fbe8d147-28db-4f1d-bedf-a3fe9f458427"
domain = "seller"
status = "draft"
tenant = "RetailCorp"
tags = ["customer"]
description = product_description.ProductDescription
team = product_team.DataTeam
productCreatedTs = "2023-01-15T10:30:00Z"
}

The root never mentions JohnDoe or JaneSmith. It names one value, DataTeam, and that value knows how it was built — which is exactly the property that makes a team reusable across products.