{"id":76572,"date":"2026-10-29T14:58:01","date_gmt":"2026-10-29T13:58:01","guid":{"rendered":"https:\/\/lumi-systems.io\/?p=76572"},"modified":"2026-10-29T15:59:55","modified_gmt":"2026-10-29T14:59:55","slug":"pm-suite-management-cockpit-gitlab-ce","status":"publish","type":"post","link":"https:\/\/lumi-systems.io\/en\/pm-suite-management-cockpit-gitlab-ce\/","title":{"rendered":"From GitLab Issues to a Management Cockpit: Our PM-Suite"},"content":{"rendered":"<style id=\"lumi-article-css\">.lumi-article{--ink:#0f172a;--muted:#64748b;--line:rgba(15,23,42,0.1);--blue:#1a56db;--cyan:#06b6d4;--soft:#f8fafc;}.lumi-article p,.lumi-article ul,.lumi-article ol{font-size:17.5px;line-height:1.65;}.lumi-article p{margin:0 0 1.15em;text-wrap:pretty;}.lumi-article h2{margin:2.2em 0 0.8em;letter-spacing:-0.015em;}.lumi-article h3{margin:1.6em 0 0.5em;letter-spacing:-0.01em;}.lumi-article li{margin:0.35em 0;}.lumi-article li::marker{color:var(--blue);}.lumi-article a{text-underline-offset:2px;}.lumi-article .lumi-takeaways{background:linear-gradient(135deg,#eff6ff 0%,#f8fafc 65%);border:1px solid #bfdbfe;border-radius:18px;padding:22px 26px;margin:0 0 2.2em;max-width:100%;}.lumi-article .lumi-takeaways ul{margin:0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 28px;}.lumi-article .lumi-takeaways li{position:relative;padding-left:28px;margin:0.35em 0;font-size:16.5px;line-height:1.5;}.lumi-article .lumi-takeaways li::before{content:\"\u2713\";position:absolute;left:0;top:0.02em;color:#15803d;font-weight:800;}.lumi-article .lumi-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin:1.7em 0 2.1em;}.lumi-article .lumi-stat{background:var(--soft);border:1px solid var(--line);border-radius:16px;padding:18px 20px;}.lumi-article .lumi-stat-label{display:block;font-size:11px;font-weight:700;letter-spacing:0.14em;text-transform:uppercase;color:var(--blue);margin-bottom:8px;}.lumi-article .lumi-stat strong{display:block;font-size:32px;line-height:1.05;letter-spacing:-0.025em;color:var(--ink);}.lumi-article .lumi-stat span:last-child{display:block;margin-top:6px;font-size:14px;line-height:1.45;color:var(--muted);}.lumi-article .lumi-callout{border-radius:16px;padding:20px 24px;margin:1.8em 0;border:1px solid transparent;}.lumi-article .lumi-callout p:last-child{margin-bottom:0;}.lumi-article .lumi-callout-title{font-size:12px;font-weight:800;letter-spacing:0.13em;text-transform:uppercase;margin-bottom:0.55em;}.lumi-article .is-info{background:#eff6ff;border-color:#bfdbfe;}.lumi-article .is-info .lumi-callout-title{color:#1d4ed8;}.lumi-article .is-warning{background:#fff7ed;border-color:#fed7aa;}.lumi-article .is-warning .lumi-callout-title{color:#b45309;}.lumi-article .is-success{background:#f0fdf4;border-color:#bbf7d0;}.lumi-article .is-success .lumi-callout-title{color:#15803d;}.lumi-article .is-muted{background:var(--soft);border-color:var(--line);}.lumi-article .is-muted .lumi-callout-title{color:var(--muted);}.lumi-article .lumi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:14px;margin:1.7em 0 2em;}.lumi-article .lumi-grid-2{grid-template-columns:repeat(2,minmax(0,1fr));}.lumi-article .lumi-grid-3{grid-template-columns:repeat(3,minmax(0,1fr));}.lumi-article .lumi-card{background:#ffffff;border:1px solid var(--line);border-radius:16px;padding:20px 22px;box-shadow:0 1px 2px rgba(15,23,42,0.04);}.lumi-article .lumi-card h3{margin:0.1em 0 0.45em;font-size:19px;line-height:1.25;}.lumi-article .lumi-card p{margin-bottom:0.55em;font-size:16px;line-height:1.55;}.lumi-article .lumi-card p:last-child{margin-bottom:0;}.lumi-article .lumi-card-num{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;background:var(--blue);color:#fff;font-size:14px;font-weight:700;margin-bottom:10px;}.lumi-article .lumi-kicker{display:block;font-size:11px;font-weight:700;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-bottom:4px;}.lumi-article .lumi-panel{border-radius:16px;padding:20px 24px;margin:1.7em 0;background:var(--soft);border:1px solid var(--line);}.lumi-article .lumi-panel h3{margin-top:0;font-size:18px;}.lumi-article .lumi-panel ul{margin-bottom:0;}.lumi-article .lumi-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:1.7em 0 2em;}.lumi-article .lumi-step{background:var(--soft);border:1px solid var(--line);border-top:3px solid var(--blue);border-radius:12px;padding:15px 17px;}.lumi-article .lumi-step .lumi-step-num{display:block;font-size:11px;font-weight:700;letter-spacing:0.12em;text-transform:uppercase;color:var(--blue);margin-bottom:6px;}.lumi-article .lumi-step strong{display:block;font-size:16px;line-height:1.3;margin-bottom:4px;}.lumi-article .lumi-step p{margin:0;font-size:14.5px;line-height:1.5;color:var(--muted);}.lumi-article .lumi-table-scroll{max-width:100%;margin:1.6em 0 2em;}.lumi-article table{width:100%;border-collapse:collapse;font-size:15.5px;line-height:1.5;}.lumi-article thead th{text-align:left;vertical-align:bottom;padding:0 20px 10px 0;font-size:12px;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--muted);border-bottom:2px solid var(--ink);white-space:nowrap;}.lumi-article tbody td{text-align:left;vertical-align:top;padding:12px 20px 12px 0;border-bottom:1px solid var(--line);}.lumi-article tbody td:first-child{width:24%;font-weight:600;color:var(--ink);}.lumi-article tbody tr:nth-child(even) td{background:rgba(15,23,42,0.025);}.lumi-article tbody tr:hover td{background:rgba(26,86,219,0.05);}.lumi-article figcaption{text-align:left;font-size:14px;color:var(--muted);}@media (max-width:900px){.lumi-article .lumi-takeaways ul,.lumi-article .lumi-grid-2,.lumi-article .lumi-steps{grid-template-columns:1fr;}.lumi-article .lumi-grid{grid-template-columns:1fr;}.lumi-article table{font-size:14px;}.lumi-article thead th,.lumi-article tbody td{padding-right:14px;}.lumi-article tbody td:first-child{width:auto;}}.lumi-article h2[id],.lumi-article h3[id]{scroll-margin-top:100px;}.lumi-article .lumi-toc{background:#ffffff;border:1px solid var(--line);border-radius:16px;padding:18px 24px;margin:0 0 2.2em;}.lumi-article .lumi-toc-title{margin:0 0 0.7em;font-size:12px;font-weight:800;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);}.lumi-article .lumi-toc-title span{color:#94a3b8;font-weight:600;}.lumi-article .lumi-toc ol{margin:0;padding-left:1.2em;columns:2;column-gap:40px;font-size:15.5px;line-height:1.45;}.lumi-article .lumi-toc li{margin:0.28em 0;break-inside:avoid;}.lumi-article .lumi-toc a{color:var(--ink);text-decoration:none;}.lumi-article .lumi-toc a:hover{color:var(--blue);text-decoration:underline;}.lumi-article figure a{display:block;cursor:zoom-in;}.lumi-article figure a img{display:block;width:100%;height:auto;}@media (max-width:900px){.lumi-article .lumi-toc ol{columns:1;}}.lumi-article .lumi-cta{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:18px;background:linear-gradient(135deg,#0f172a 0%,#1e3a8a 100%);color:#f8fafc;border-radius:18px;padding:26px 30px;margin:2.4em 0 0;}.lumi-article .lumi-cta h2{color:#ffffff;margin:0 0 0.35em;font-size:24px;letter-spacing:-0.01em;}.lumi-article .lumi-cta p{color:#cbd5e1;margin:0;font-size:16px;line-height:1.5;max-width:760px;}.lumi-article .lumi-cta .lumi-cta-eyebrow{font-size:11px;font-weight:700;letter-spacing:0.14em;text-transform:uppercase;color:#93c5fd;margin-bottom:6px;}.lumi-article .lumi-cta .lumi-cta-link{display:inline-block;background:#ffffff;color:#0f172a;font-weight:700;font-size:16px;padding:12px 22px;border-radius:10px;text-decoration:none;white-space:nowrap;}.lumi-article .lumi-cta .lumi-cta-link:hover{background:#e2e8f0;color:#0f172a;}@media (max-width:900px){.lumi-article .lumi-cta{flex-direction:column;align-items:flex-start;padding:22px 22px;}.lumi-article .lumi-cta h2{font-size:21px;}}.lumi-article details.lumi-toc>summary{cursor:pointer;list-style:none;margin:0;}.lumi-article details.lumi-toc>summary::-webkit-details-marker{display:none;}.lumi-article details.lumi-toc>summary::after{content:\"\u25be\";float:right;color:#94a3b8;font-size:14px;}.lumi-article details.lumi-toc[open]>summary{margin-bottom:0.7em;}.lumi-article details.lumi-toc:not([open]){padding-bottom:18px;}.lumi-article .lumi-cta .lumi-cta-title{color:#ffffff;margin:0 0 0.35em;font-size:24px;line-height:1.25;letter-spacing:-0.01em;}@media (max-width:900px){.lumi-article .lumi-cta .lumi-cta-title{font-size:21px;}}.lumi-article figure.lumi-figure-mobile{max-width:430px;margin-left:auto;margin-right:auto;}.lumi-article figure.lumi-figure-mobile a,.lumi-article figure.lumi-figure-mobile img{width:100%;height:auto;}.lumi-article figure.lumi-figure-mobile figcaption{max-width:430px;font-size:13px;}@media (max-width:480px){.lumi-article figure.lumi-figure-mobile{max-width:100%;}}<\/style>\n<div class=\"lumi-article\">\n<p>GitLab CE tracks work well: issues, boards, milestones, time tracking. What it lacks is a management layer across projects. Epics, iterations and roadmap reports are Premium and Ultimate features per the GitLab documentation (checked October 2026); we stay on self-managed CE (see <a href=\"https:\/\/lumi-systems.io\/gitlab-ce-vs-premium-self-managed\/\">GitLab CE vs. Premium<\/a>).<\/p>\n<p>The questions were always the same: what is at risk, what ships when, who is overloaded? Answering them meant rebuilding the picture in a spreadsheet that was outdated before it was finished.<\/p>\n<p>So we built the PM-Suite for the IT team at SPL Tele: a read-only portfolio, roadmap and controlling view on top of our GitLab instance. At the time of writing it covered about 50 projects and some 330 issues.<\/p>\n<div class=\"lumi-stats\">\n<div class=\"lumi-stat\"><span class=\"lumi-stat-label\">Deployment<\/span><strong>1 container<\/strong><span>server-rendered Node.js 24, no npm packages<\/span><\/div>\n<div class=\"lumi-stat\"><span class=\"lumi-stat-label\">Metrics<\/span><strong>27<\/strong><span>documented formulas across five areas<\/span><\/div>\n<div class=\"lumi-stat\"><span class=\"lumi-stat-label\">Own planning data<\/span><strong>0<\/strong><span>read-only; GitLab stays the source of truth<\/span><\/div>\n<\/div>\n<details class=\"lumi-toc\" aria-label=\"In this article\">\n<summary class=\"lumi-toc-title\">In this article <span>&middot; 7 min read<\/span><\/summary>\n<ol>\n<li><a href=\"#what-it-is-in-architecture-terms\">What it is, in architecture terms<\/a><\/li>\n<li><a href=\"#one-question-per-page\">One question per page<\/a><\/li>\n<li><a href=\"#cockpit-30-seconds-to-the-first-answer\">Cockpit: 30 seconds to the first answer<\/a><\/li>\n<li><a href=\"#portfolio-a-traffic-light-with-a-reason\">Portfolio: a traffic light with a reason<\/a><\/li>\n<li><a href=\"#roadmap-sprints-as-bands-issues-as-bars\">Roadmap: sprints as bands, issues as bars<\/a><\/li>\n<li><a href=\"#sprints-burnup-and-an-honest-forecast\">Sprints: burnup and an honest forecast<\/a><\/li>\n<li><a href=\"#capacity-the-heatmap-the-team-actually-looks-at\">Capacity: the heatmap the team actually looks at<\/a><\/li>\n<li><a href=\"#steuerung-are-we-keeping-our-commitments\">Steuerung: are we keeping our commitments?<\/a><\/li>\n<li><a href=\"#vorgaenge-the-list-behind-every-number\">Vorg\u00e4nge: the list behind every number<\/a><\/li>\n<li><a href=\"#hilfe-a-definition-for-every-number\">Hilfe: a definition for every number<\/a><\/li>\n<li><a href=\"#project-pages-dark-mode-mobile\">Project pages, dark mode, mobile<\/a><\/li>\n<li><a href=\"#how-it-differs-from-our-sprint-planning-tool\">How it differs from our sprint planning tool<\/a><\/li>\n<li><a href=\"#what-it-does-not-do\">What it does not do<\/a><\/li>\n<\/ol>\n<\/details>\n<h2 id=\"key-takeaways\">Key takeaways<\/h2>\n<div class=\"lumi-takeaways\">\n<ul>\n<li>GitLab CE tracks work per project but has no portfolio, roadmap or management view. Premium adds epics, iterations and roadmap reports; a read-only layer closes the gap for teams on CE.<\/li>\n<li>The PM-Suite is one container, server-rendered, no database, no npm packages, no own planning data. It reads GitLab and writes nothing.<\/li>\n<li>One question per page beats one page with every chart.<\/li>\n<li>The value is not the traffic light but the documented definition behind it and the trace back to a GitLab issue.<\/li>\n<li>The limits are part of the product: read-only, German, internal, only as good as the data in GitLab.<\/li>\n<\/ul>\n<\/div>\n<h2 id=\"what-it-is-in-architecture-terms\">What it is, in architecture terms<\/h2>\n<p>One container, Node.js 24, no npm packages, no database. The suite renders server-side HTML and reads GitLab through REST and GraphQL: REST for projects, issues, estimates and links, GraphQL for board column and card order.<\/p>\n<div class=\"lumi-grid lumi-grid-2\">\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Principle<\/span><\/p>\n<h3>No own planning data<\/h3>\n<p>Sprints are issues in a dedicated project, work packages link to them, capacity comes from a report written every five minutes by a CI job. The suite aggregates.<\/p>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Principle<\/span><\/p>\n<h3>Read-only by design<\/h3>\n<p>Read-scope token, no forms, no write API. The only &ldquo;write&rdquo; is the refresh button discarding the app&rsquo;s own cache.<\/p>\n<\/article>\n<\/div>\n<p>There is no login: the service runs inside our network and shows only what the IT team already sees in GitLab. Missing data renders as a dash, never as zero.<\/p>\n<h2 id=\"one-question-per-page\">One question per page<\/h2>\n<p>The navigation follows the questions, not GitLab&#39;s object model. The German page names match the screenshots.<\/p>\n<div class=\"lumi-grid lumi-grid-3\">\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Cockpit<\/span><\/p>\n<h3>What needs attention now?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Portfolio<\/span><\/p>\n<h3>What is at risk?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Roadmap<\/span><\/p>\n<h3>What comes when?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Sprints<\/span><\/p>\n<h3>How is the sprint going?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Kapazit\u00e4t<\/span><\/p>\n<h3>Who has room?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Steuerung<\/span><\/p>\n<h3>Do we keep commitments?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Vorg\u00e4nge<\/span><\/p>\n<h3>What is to do?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Hilfe<\/span><\/p>\n<h3>How is this calculated?<\/h3>\n<\/article>\n<article class=\"lumi-card\"><span class=\"lumi-kicker\">Project detail<\/span><\/p>\n<h3>How does this project stand?<\/h3>\n<\/article>\n<\/div>\n<h2 id=\"cockpit-30-seconds-to-the-first-answer\">Cockpit: 30 seconds to the first answer<\/h2>\n<p>The cockpit opens with five role entries (CEO, CDO, Head of IT, project manager, project supervisor), each linked to its target page. Six KPI tiles follow: projects, open issues, overdue issues, team utilization, quarter progress, data quality.<\/p>\n<p>The portfolio traffic light is four vertical columns (red, amber, green, grey); a click opens the filtered project list. A table names the riskiest projects and states the reason. Below: the running sprint, upcoming due issues, notices by severity, last movement, data sources and status.<\/p>\n<p>Every page shows the time of the last fetch and a refresh button that discards the 60-second cache and never writes to GitLab. If a source fails, the page keeps the last state and names the missing source.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit.jpg\" alt=\"Cockpit page with role shortcuts and six KPI tiles\" class=\"wp-image-76559\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-01-cockpit-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">The cockpit: role entries and six KPI tiles.<\/figcaption><\/figure>\n<h2 id=\"portfolio-a-traffic-light-with-a-reason\">Portfolio: a traffic light with a reason<\/h2>\n<p>The traffic light is a rule: +3 per overdue open issue (max +9), +2 if more than half of the open issues lack an estimate, +1 if more than half lack an assignee, +2 or +1 for inactivity over 30 or 14 days, +2 if a due date is within seven days while progress is below 50 percent. Zero to two points is green, three to five amber, six or more red, grey without issues.<\/p>\n<p>Filters cover area, status, traffic light, search and sorting, with card and table views. Filters live in the URL, so a view is shareable and works without JavaScript. Code and help share one rule.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio.jpg\" alt=\"Portfolio page with traffic-light rule, filters and KPI tiles\" class=\"wp-image-76560\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-02-portfolio-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Portfolio: the traffic-light rule, filters and the KPI tiles for the current selection.<\/figcaption><\/figure>\n<h2 id=\"roadmap-sprints-as-bands-issues-as-bars\">Roadmap: sprints as bands, issues as bars<\/h2>\n<p>CE has no group roadmap and no epics, so the roadmap uses two objects that exist: sprints as bands across the top and issues with a start and due date as bars. One row per project: the bar spans earliest start to latest due date, the fill shows progress by closed estimate hours, the number at its end counts open issues; due dates are markers, max eight per row. Overdue bars are red and hatched.<\/p>\n<p>Project and group milestones exist in CE; the roadmap uses project milestones because that is where the due dates sit. They form a table below the chart with due date, status and open versus total issues. No dependency arrows, no rescheduling; whether a date holds is a question for the Steuerung page.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap.jpg\" alt=\"Roadmap Gantt chart with sprint bands and project bars\" class=\"wp-image-76561\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-03-roadmap-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Roadmap: sprint bands, project bars, due-date markers and overdue work.<\/figcaption><\/figure>\n<h2 id=\"sprints-burnup-and-an-honest-forecast\">Sprints: burnup and an honest forecast<\/h2>\n<p>The sprint page lists all sprints with period, capacity, planned hours, utilization and progress; selecting one opens progress by count and estimate hours, remaining hours and a per-person table. The burnup plots cumulative closed estimate hours per working day against scope and an ideal line. The forecast is simple: closed hours plus current pace times remaining working days; at the time of writing it was well below scope. Velocity compares scope and closed hours per sprint, with a dashed average over completed sprints only.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints.jpg\" alt=\"Sprint page with burnup chart, scope, ideal line and forecast\" class=\"wp-image-76562\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-04-sprints-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Sprints: burnup with scope, ideal line, today marker and forecast.<\/figcaption><\/figure>\n<h2 id=\"capacity-the-heatmap-the-team-actually-looks-at\">Capacity: the heatmap the team actually looks at<\/h2>\n<p>Rows are people, columns are sprints. Each cell shows planned hours against capacity as a percentage, the number in the cell and color as a second channel: up to 80 percent green, 80 to 100 yellow, above 100 red, grey without data. Capacity comes from FTE, working days, a daily hours model, holidays and planned absences. The page separates the free buffer (positive remainders, the part that can be redistributed) from the net remainder (including negative values). Overloaded people are listed with sprint and gap; the suite reassigns nothing.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet.jpg\" alt=\"Capacity heatmap of utilization per person and sprint\" class=\"wp-image-76563\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-05-kapazitaet-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Capacity heatmap: planned hours against capacity per person and sprint.<\/figcaption><\/figure>\n<h2 id=\"steuerung-are-we-keeping-our-commitments\">Steuerung: are we keeping our commitments?<\/h2>\n<p>The page for uncomfortable questions: lead time median and average, on-time delivery, work in progress, overdue issues, age of open issues, velocity, created versus closed issues per week over 12 weeks, the ten longest-overdue issues, the risk register with reasons, and data quality. Data quality names the share of open issues without estimate, assignee or due date and links into the matching GitLab filter, so the page ends in a work list. Where CE has no filter, it says so.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung.jpg\" alt=\"Steuerung page with top overdue issues and risk register\" class=\"wp-image-76564\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-06-steuerung-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Steuerung: top overdue issues and the risk register with reasons.<\/figcaption><\/figure>\n<h2 id=\"vorgaenge-the-list-behind-every-number\">Vorg\u00e4nge: the list behind every number<\/h2>\n<p>Every number leads back to an issue list. Filters cover search, project, status, person, label type, priority and overdue state. The header shows count and sum of estimates; the table carries reference, title, project, person, status, priority, estimate, due date, sprint and labels, 50 rows per page. Read-only: work happens in GitLab.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge.jpg\" alt=\"Vorg\u00e4nge page with filter panel and issue table\" class=\"wp-image-76565\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-07-vorgaenge-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Vorg\u00e4nge: filters, result count and the issue table.<\/figcaption><\/figure>\n<h2 id=\"hilfe-a-definition-for-every-number\">Hilfe: a definition for every number<\/h2>\n<p>Twenty-seven metrics in five groups with formula, unit and a good\/bad reading. Thresholds are tables, not prose. Definitions come from one module in the code and the help page reads the same source, so a formula cannot drift from its explanation; every KPI tile links to its anchor.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe.jpg\" alt=\"Hilfe page with metric definitions and formulas\" class=\"wp-image-76566\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-08-hilfe-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">Hilfe: every metric with formula, unit and thresholds.<\/figcaption><\/figure>\n<h2 id=\"project-pages-dark-mode-mobile\">Project pages, dark mode, mobile<\/h2>\n<p>Each project has a detail page: traffic light with risk points and reasons, key figures (open, overdue, progress, open estimate, booked time, last activity), the description, weekly created and closed issues, issue list, and people with open issues and open estimate hours. No profiles, no performance ranking.<\/p>\n<p>Light and dark mode follow the system setting and can be switched. The UI is server-rendered and works without JavaScript, charts are server-generated SVG with a table alternative; at 1440 and 390 pixels there is no horizontal overflow.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark.jpg\" alt=\"Cockpit page in dark mode\" class=\"wp-image-76567\" width=\"1600\" height=\"1000\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark.jpg 1600w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-300x188.jpg 300w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-1024x640.jpg 1024w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-768x480.jpg 768w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-1536x960.jpg 1536w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-18x12.jpg 18w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-09-dark-730x456.jpg 730w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/a><figcaption class=\"wp-element-caption\">The cockpit in dark mode.<\/figcaption><\/figure>\n<figure class=\"wp-block-image size-large lumi-figure-mobile\"><a href=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-10-mobile.jpg\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-10-mobile.jpg\" alt=\"Portfolio page on a mobile screen, 390 pixels wide\" class=\"wp-image-76568\" width=\"390\" height=\"844\" loading=\"lazy\" srcset=\"https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-10-mobile.jpg 390w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-10-mobile-139x300.jpg 139w, https:\/\/lumi-systems.io\/wp-content\/uploads\/2026\/10\/pmsuite-10-mobile-6x12.jpg 6w\" sizes=\"auto, (max-width: 390px) 100vw, 390px\" \/><\/a><figcaption class=\"wp-element-caption\">The portfolio on a 390 px phone screen.<\/figcaption><\/figure>\n<h2 id=\"how-it-differs-from-our-sprint-planning-tool\">How it differs from our sprint planning tool<\/h2>\n<p>We built a sprint planning view for GitLab CE first, described in <a href=\"https:\/\/lumi-systems.io\/sprint-planning-tool-for-gitlab-ce\/\">We built our own sprint planning view<\/a>. Both read GitLab and answer different questions: the sprint planning view is operational (who works on what, planned and booked hours, overload), the PM-Suite is the management layer (portfolio, roadmap, delivery metrics, capacity across sprints). We did not merge them; a planner needs different granularity than a CEO. What they share is that GitLab stays the only place where planning data is written.<\/p>\n<h2 id=\"what-it-does-not-do\">What it does not do<\/h2>\n<div class=\"lumi-panel is-warning\">\n<ul>\n<li><strong>Read-only:<\/strong> changes happen in GitLab, the suite shows the effect at the next refresh.<\/li>\n<li><strong>Metrics are only as good as the data:<\/strong> labels, estimates, due dates and assignments are the input; gaps show as gaps, not as zero.<\/li>\n<li><strong>No planning tool:<\/strong> no backlog ordering, no new issues, no time booking.<\/li>\n<li><strong>No roadmap dependencies:<\/strong> CE has no epic links, and we did not want a second relationship model.<\/li>\n<li><strong>German UI, internal deployment:<\/strong> choices, not gaps.<\/li>\n<li><strong>Capacity needs a report that needs an export;<\/strong> without it there is no invented utilization.<\/li>\n<\/ul>\n<\/div>\n<p>The same principle is behind <a href=\"https:\/\/lumi-systems.io\/alem-application-lifecycle-engineering-model\/\">ALEM<\/a>, our lifecycle and engineering model: the source of truth stays where the work happens.<\/p>\n<aside class=\"lumi-cta\">\n<div>\n<p class=\"lumi-cta-eyebrow\">Lumi-Systems.io<\/p>\n<h2 class=\"lumi-cta-title\">Need a management view for your GitLab projects?<\/h2>\n<p>We build read-only portfolio, roadmap and delivery cockpits on top of GitLab CE: defined metrics, one source of truth, no BI project.<\/p>\n<\/div>\n<p><a class=\"lumi-cta-link\" href=\"https:\/\/contact.lumi-systems.io\/\">Talk to us<\/a><br \/>\n<\/aside>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>GitLab CE has no portfolio, roadmap or management view. We built a read-only management cockpit on top of it: server-rendered, no database, no separate login.<\/p>","protected":false},"author":2,"featured_media":76590,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[343,413],"tags":[408,417,412,419,418],"class_list":["post-76572","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-lumi-systems-io","category-project-management","tag-gitlab-ce","tag-portfolio-management","tag-project-management","tag-reporting","tag-roadmap"],"_links":{"self":[{"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/posts\/76572","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/comments?post=76572"}],"version-history":[{"count":13,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/posts\/76572\/revisions"}],"predecessor-version":[{"id":76619,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/posts\/76572\/revisions\/76619"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/media\/76590"}],"wp:attachment":[{"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/media?parent=76572"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/categories?post=76572"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lumi-systems.io\/en\/wp-json\/wp\/v2\/tags?post=76572"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}