Merge pull request 'feat(site): #integration section - Works with Zeiterfassung.CLOUD' (#1) from feat/integration-zeiterfassung into quality/reference-standard

This commit is contained in:
2026-07-12 08:24:57 +02:00
5 changed files with 144 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# Data provenance — integration section assets
Generated data backing the "Works with Zeiterfassung.CLOUD" landing-page
section. Derived, never typed in — per field:
| Field | Source | Retrieved |
|---|---|---|
| `slug`, `title` | `skills-core/marketplace` index (marketplace.json) — slugs verified to exist in the catalog | 2026-07-11 |
| `esco_uri` | package manifest `ids.esco_uri` of `skills-core/{slug}` (ESCO v1.2.1, © European Union) | 2026-07-11 |
| `onet_code` | package manifest `ids.onet_soc` (O*NET 30.3, USDOL/ETA, CC BY 4.0; industrial-machinery-mechanic: official crosswalk exactMatch; photographer: closeMatch) | 2026-07-11 |
| `kldb_code` | **manually curated** from the official ESCO↔KldB-2010 crosswalk (Bundesagentur für Arbeit); digits 15 of the Tätigkeitsschlüssel | 2026-07-11 |
| `example-response.json` | illustrative fixture for the section's API snippet; field semantics follow the Zeiterfassung.CLOUD HR-API data model v1.2 (Skills & Deployment namespace); person is fictional (Mustermann scheme) | 2026-07-11 |
Note: the ordered example slug `industrial-mechanic` does not exist in the
catalog; the nearest existing slug `industrial-machinery-mechanic`
(ESCO exactMatch to O*NET 49-9041.00) is used instead — flagged in the PR.

View File

@@ -0,0 +1,9 @@
{
"request": "GET /employees/1017/professions",
"response": [
{ "profession": "Industriemechaniker", "slug": "industrial-machinery-mechanic",
"relation_type": "practiced", "is_primary": true, "kldb_code": "24522" },
{ "profession": "Fotograf", "slug": "photographer",
"relation_type": "hobby", "is_primary": false, "source": "self-declared" }
]
}

View File

@@ -0,0 +1,35 @@
{
"_note": "EN/DE strings for the #integration section. The landing page currently ships EN-only ([i18n] LANGS=en-US, no visitor-facing language switcher exists in the template). DE strings are maintained here for the day a switcher lands - see PR notes.",
"en": {
"eyebrow": "Integration",
"headline": "Works with Zeiterfassung.CLOUD",
"subline": "The HR API knows every profession a person has — practiced, trained, or just loved. The agent loads them all.",
"tile1_title": "Many professions, one person",
"tile1_body": "relation_type: practiced · trained · secondary · hobby. The payroll answer stays unambiguous (is_primary, Tätigkeitsschlüssel/KldB); the agent still sees the whole human.",
"tile2_title": "Hobby skills count",
"tile2_body": "Skills attach to the person, not the diploma. Self-assessed abilities flow in with provenance (self · supervisor · imported · skillfactor).",
"tile3_title": "Right person, right slot",
"tile3_body": "skill_requirements per project, team or shift; the matching engine (find_matching_employees) returns who qualifies, with match percentage.",
"example_title": "Mustermann Max",
"example_note": "His agent loads skills-core/industrial-machinery-mechanic as the main profile plus skills-core/photographer as a supplementary package.",
"snippet_caption": "One call — the agent's full package list. Slugs resolve to skills-core/{slug}.",
"mapping_line": "Mapped via ESCO URI · O*NET-SOC · KldB 2010 (Tätigkeitsschlüssel digits 15) — no proprietary IDs.",
"cta": "Explore the HR data model →"
},
"de": {
"eyebrow": "Integration",
"headline": "Funktioniert mit Zeiterfassung.CLOUD",
"subline": "Die HR-API kennt jeden Beruf eines Menschen — ausgeübt, gelernt oder einfach geliebt. Der Agent lädt sie alle.",
"tile1_title": "Viele Berufe, ein Mensch",
"tile1_body": "relation_type: practiced · trained · secondary · hobby. Die lohnrelevante Antwort bleibt eindeutig (is_primary, Tätigkeitsschlüssel/KldB); der Agent sieht trotzdem den ganzen Menschen.",
"tile2_title": "Hobby-Fähigkeiten zählen",
"tile2_body": "Skills hängen an der Person, nicht am Abschluss. Selbst eingeschätzte Fähigkeiten fließen mit Herkunftskennzeichnung ein (self · supervisor · imported · skillfactor).",
"tile3_title": "Richtige Person, richtige Stelle",
"tile3_body": "skill_requirements je Projekt, Team oder Schicht; die Matching-Engine (find_matching_employees) liefert, wer qualifiziert ist — mit Übereinstimmungsgrad.",
"example_title": "Mustermann Max",
"example_note": "Sein Agent lädt skills-core/industrial-machinery-mechanic als Hauptprofil plus skills-core/photographer als Ergänzungspaket.",
"snippet_caption": "Ein Aufruf — die vollständige Paketliste des Agenten. Slugs verweisen auf skills-core/{slug}.",
"mapping_line": "Zugeordnet über ESCO-URI · O*NET-SOC · KldB 2010 (Tätigkeitsschlüssel Stellen 15) — keine proprietären IDs.",
"cta": "HR-Datenmodell erkunden →"
}
}

View File

@@ -0,0 +1,20 @@
[
{
"slug": "industrial-machinery-mechanic",
"title": "industrial machinery mechanic",
"esco_uri": "http://data.europa.eu/esco/occupation/269c47e7-9017-4aa6-bce8-49e89a696a64",
"onet_code": "49-9041.00",
"kldb_code": "24522",
"source_repo": "skills-core/industrial-machinery-mechanic",
"fetched_at": "2026-07-11"
},
{
"slug": "photographer",
"title": "photographer",
"esco_uri": "http://data.europa.eu/esco/occupation/66542dd6-05a6-4d9e-97ff-3f4858c31ff9",
"onet_code": "51-9151.00",
"kldb_code": "23412",
"source_repo": "skills-core/photographer",
"fetched_at": "2026-07-11"
}
]

View File

@@ -89,6 +89,21 @@
.sf-footnote { padding: 34px 0 60px; font-size: 12.5px; color: #8a8a99; text-align: center; }
/* Integration (Zeiterfassung.CLOUD) */
.sf-int-grid { display: grid; grid-template-columns: .9fr 1.1fr; gap: 26px; margin-top: 36px; align-items: start; }
.sf-int-person { background: #fff; border: 1px solid #ececee; border-radius: 16px; padding: 24px 26px; }
.sf-int-name { font-size: 19px; font-weight: 700; color: #25253d; margin-bottom: 10px; }
.sf-int-role { font-size: 14px; color: #515164; padding: 6px 0; border-bottom: 1px solid #f4f4f5; }
.sf-int-role code { background: #fff0f3; color: #b30d32; border-radius: 6px; padding: 1px 7px; font-size: 12.5px; }
.sf-int-loads { margin: 14px 0 10px; font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #8a8a99; }
.sf-int-chips { display: flex; flex-direction: column; gap: 8px; }
.sf-int-chip { display: block; text-decoration: none; font: 500 13px/1.5 ui-monospace, Consolas, monospace; color: #25253d !important; background: #f4f4f5; border: 1px solid #ececee; border-radius: 10px; padding: 9px 13px; }
.sf-int-chip small { color: #8a8a99; font-family: "DM Sans", sans-serif; margin-left: 6px; }
.sf-int-chip:hover { border-color: #ff355e; }
.sf-int-chip-main { background: #fff0f3; border-color: #ffd6de; }
.sf-int-chip-main small { color: #b30d32; }
@media (max-width: 1000px) { .sf-int-grid { grid-template-columns: 1fr; } }
/* Live-Status-Panel */
.sf-live-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.sf-live-card { background: #fff; border: 1px solid #ffd6de; border-radius: 12px; padding: 14px 16px; display: block; }
@@ -390,6 +405,55 @@ a.sf-live-card:hover { border-color: #ff355e; box-shadow: 0 8px 24px rgba(255,53
</div>
</section>
<!-- Integration: Zeiterfassung.CLOUD HR API -->
<section class="sf-section" id="integration" style="padding-top: 8px;">
<div class="sf-wrap">
<div class="sf-center">
<span class="sf-eyebrow">Integration</span>
<h2 class="sf-h2">Works with Zeiterfassung.CLOUD</h2>
<p class="sf-sub">The HR API knows every profession a person has — practiced, trained, or just loved.
The agent loads them all.</p>
</div>
<div class="sf-features" style="grid-template-columns: repeat(3, 1fr);">
<div class="sf-feat"><div class="sf-ico">👥</div><h3>Many professions, one person</h3>
<p><code>relation_type: practiced · trained · secondary · hobby</code>. The payroll answer stays
unambiguous (<code>is_primary</code>, Tätigkeitsschlüssel/KldB); the agent still sees the whole human.</p></div>
<div class="sf-feat"><div class="sf-ico">🧩</div><h3>Hobby skills count</h3>
<p>Skills attach to the person, not the diploma. Self-assessed abilities flow in with provenance
(<code>self · supervisor · imported · skillfactor</code>) — hidden abilities get a structured data
source, not just observation.</p></div>
<div class="sf-feat"><div class="sf-ico">🎯</div><h3>Right person, right slot</h3>
<p><code>skill_requirements</code> per project, team or shift; the matching engine
(<code>find_matching_employees</code>) returns who qualifies, with match percentage.</p></div>
</div>
<div class="sf-int-grid">
<div class="sf-int-person">
<div class="sf-int-name">Mustermann Max</div>
<div class="sf-int-role">Industriemechaniker · <code>practiced</code> · primary · KldB 24522</div>
<div class="sf-int-role">Fotograf · <code>hobby</code> · self-declared</div>
<div class="sf-int-loads">agent loads ↓</div>
<div class="sf-int-chips">
<a class="sf-int-chip sf-int-chip-main" href="{{AppSubUrl}}/skills-core/industrial-machinery-mechanic">skills-core/industrial-machinery-mechanic <small>main profile</small></a>
<a class="sf-int-chip" href="{{AppSubUrl}}/skills-core/photographer">skills-core/photographer <small>supplementary</small></a>
</div>
</div>
<div class="sf-code-card" style="position:static;">
<div class="sf-code-label">GET /employees/1017/professions</div>
<pre>[
{ "profession": "Industriemechaniker", "slug": "industrial-machinery-mechanic",
"relation_type": <b>"practiced"</b>, "is_primary": true, "kldb_code": "24522" },
{ "profession": "Fotograf", "slug": "photographer",
"relation_type": <b>"hobby"</b>, "is_primary": false, "source": "self-declared" }
]</pre>
<div style="margin-top:12px;font-size:12.5px;color:#8a8a99;">One call — the agent&#39;s full package
list. Slugs resolve to <i>skills-core/{slug}</i>.</div>
</div>
</div>
<p class="sf-center" style="margin-top:22px;font-size:13.5px;color:#8a8a99;">Mapped via ESCO URI · O*NET-SOC · KldB 2010 (Tätigkeitsschlüssel digits 15) — no proprietary IDs.</p>
<p class="sf-center" style="margin-top:10px;"><a class="sf-tlink" href="TODO:/hr_api_data_model_explorer.html?de=1&amp;vendor=skillfactor">Explore the HR data model&nbsp;→</a></p>
</div>
</section>
<!-- Layer model -->
<section class="sf-section">
<div class="sf-wrap">