feat: establish Corp v1 Board portal
Build and publish Corp v1 Board portal / build (push) Successful in 34s

This commit is contained in:
2026-08-14 09:18:27 +00:00
parent 261d8c0b49
commit 38d3e17260
10 changed files with 98 additions and 32 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
name: Build and publish Corp v1 steering documentation name: Build and publish Corp v1 Board portal
on: on:
push: push:
+3 -3
View File
@@ -1,9 +1,9 @@
# Corp v1 Steering Committee # Corp v1 Board Portal
Authoritative documentation for Corp v1 project governance, teams, and members. Authoritative documentation for Corp v1 project governance, teams, and members.
- Repository: https://gitea.lego-cloud.eu/corp-v1/sterring-commitee - Repository: https://gitea.lego-cloud.eu/corp-v1/portal
- Published site: https://pages.apps.lego-cloud.eu/corp-v1/sterring-commitee/ - Published site: https://pages.apps.lego-cloud.eu/corp-v1/portal/
## Development ## Development
+28
View File
@@ -0,0 +1,28 @@
---
title: "Board Members"
description: "Identify the only members authorized to start or close Corp v1 projects and approve changes to the Corp v1 main governance skill."
slug: /
sidebar_position: 1
---
# Board Members
The Corp v1 Board has exactly three members:
| Discord member | Account | Board authority |
|---|---|---|
| `<@1518725627845283888>` | RootAtSkic (`root_at_skic`) | Start/close projects; approve `corp-v1--main` changes |
| `<@476287310627864587>` | Panther Skeleton (`pantherskeleton`) | Start/close projects; approve `corp-v1--main` changes |
| `<@773109855497093191>` | MartynasP (`w4rl0ck_21`) | Start/close projects; approve `corp-v1--main` changes |
Only these Board members may approve a project kickoff or project closure. Approval must be explicit and attributable to one of the Discord IDs above.
Only these Board members may approve changes to `corp-v1--main`. Other members and agents may identify gaps and prepare proposals, but they must not publish governance changes as approved.
## Channel-skill change flow
1. Propose a change to a central project-channel reference skill (`corp-v1-channel-*`) to the Board.
2. Obtain explicit Board approval before publishing the central reference change.
3. Ask each affected project channel to review and synchronize its project-adopted channel skill (`corp-v1-channel-*--<code>`).
4. Preserve project-specific decisions during synchronization and return conflicts to the Board instead of overwriting them.
5. Verify the central commit, every project adoption commit, runtime skill copy, and attached synchronization job before recording completion.
+15 -6
View File
@@ -1,22 +1,31 @@
--- ---
title: Project Lifecycle title: "Project Lifecycle"
description: "Apply the Board-controlled lifecycle for starting, operating, synchronizing, and closing Corp v1 projects."
slug: /project-lifecycle/ slug: /project-lifecycle/
sidebar_position: 1 sidebar_position: 1
--- ---
# Project Lifecycle # Project Lifecycle
## Board authority
Only the three people listed in [Board Members](/board/) may approve a project kickoff, project closure, or a change to the global `corp-v1--main` governance skill. Approval must be explicit and attributable to a listed Discord ID. Agents and other members may prepare proposals and evidence but cannot approve these actions.
## 1. Proposed ## 1. Proposed
Capture the problem, intended outcome, sponsor, initial lead, constraints, dependencies, and rough effort. Capture the problem, intended outcome, sponsor, initial lead, constraints, dependencies, rough effort, and complete provisioning proposal. No project resources may be provisioned yet.
## 2. Approved ## 2. Approved
Record the steering decision, committed scope, success measures, team, budget or capacity boundary, risks, and target dates. Obtain explicit Board approval. Record the approving Board member, decision evidence, committed scope, success measures, team, budget or capacity boundary, risks, and target dates before provisioning.
## 3. Active ## 3. Active
Maintain current status, decisions, risks, milestones, and material scope changes. Maintain current status, decisions, risks, milestones, and material scope changes. Project teams retain authority within their approved project boundaries; Board approval is still required for kickoff/closure and changes to `corp-v1--main`.
### Project-channel skill changes
A proposed change to a central project-channel reference skill (`corp-v1-channel-*`) must be presented to the Board before publication. After explicit Board approval and central publication, ask every affected project channel to review and synchronize its project-adopted channel skill (`corp-v1-channel-*--<code>`). Synchronization must preserve project-specific decisions, report conflicts for Board review, update runtime copies, and verify attached channel jobs.
## 4. Paused ## 4. Paused
@@ -24,8 +33,8 @@ State the reason, preservation requirements, restart conditions, accountable own
## 5. Shutting down ## 5. Shutting down
Stop new commitments, inventory deliverables and dependencies, transfer or archive ownership, revoke project-specific access, and communicate impact. Obtain explicit Board approval for the closure scope. Stop new commitments, inventory deliverables and dependencies, transfer or archive ownership, revoke project-specific access, and communicate impact.
## 6. Closed ## 6. Closed
Record the shutdown decision, final outcome against success measures, retained artifacts, unresolved obligations, lessons learned, and closure date. Record the approving Board member and closure decision, final outcome against success measures, retained artifacts, unresolved obligations, lessons learned, and closure date.
+6 -4
View File
@@ -1,13 +1,14 @@
--- ---
id: index id: index
slug: /overview/ slug: /overview/
title: Corp v1 Steering Committee title: "Corp v1 Board"
description: "Understand the authoritative Corp v1 governance workspace and its Board-controlled decisions."
sidebar_position: 1 sidebar_position: 1
--- ---
# Corp v1 Steering Committee # Corp v1 Board
This repository is the authoritative governance workspace for starting, steering, and shutting down Corp v1 projects. This repository is the authoritative governance workspace for starting, governing, and closing Corp v1 projects.
## Registries ## Registries
@@ -16,7 +17,8 @@ This repository is the authoritative governance workspace for starting, steering
| [Projects](/projects/) | Portfolio status, ownership, lifecycle, and outcomes | | [Projects](/projects/) | Portfolio status, ownership, lifecycle, and outcomes |
| [Teams](/teams/) | Team mandates, responsibilities, and project assignments | | [Teams](/teams/) | Team mandates, responsibilities, and project assignments |
| [Members](/members/) | Member identity, roles, and team membership | | [Members](/members/) | Member identity, roles, and team membership |
| [Board](/board/) | The only members authorized to approve project kickoff, project closure, and `corp-v1--main` changes |
## Operating principle ## Operating principle
Every project has a named sponsor, accountable lead, team, explicit status, kickoff decision, and—when closed—a shutdown record with retained artifacts and lessons learned. Every project has a named sponsor, accountable lead, team, explicit status, Board-approved kickoff decision, and—when closed—a Board-approved closure record with retained artifacts and lessons learned.
+12 -9
View File
@@ -5,16 +5,16 @@ import type * as Preset from '@docusaurus/preset-classic';
const docsCommon = { const docsCommon = {
showLastUpdateAuthor: true, showLastUpdateAuthor: true,
showLastUpdateTime: true, showLastUpdateTime: true,
editUrl: 'https://gitea.lego-cloud.eu/corp-v1/sterring-commitee/_edit/main/', editUrl: 'https://gitea.lego-cloud.eu/corp-v1/portal/_edit/main/',
}; };
const config: Config = { const config: Config = {
title: 'Corp v1 Steering Committee', title: 'Corp v1 Board',
tagline: 'Project governance, teams, and membership registry', tagline: 'Project governance, Board, teams, and membership registry',
url: 'https://pages.apps.lego-cloud.eu', url: 'https://pages.apps.lego-cloud.eu',
baseUrl: '/corp-v1/sterring-commitee/', baseUrl: '/corp-v1/portal/',
organizationName: 'corp-v1', organizationName: 'corp-v1',
projectName: 'sterring-commitee', projectName: 'portal',
trailingSlash: true, trailingSlash: true,
onBrokenLinks: 'throw', onBrokenLinks: 'throw',
markdown: {hooks: {onBrokenMarkdownLinks: 'throw'}}, markdown: {hooks: {onBrokenMarkdownLinks: 'throw'}},
@@ -37,6 +37,7 @@ const config: Config = {
['@docusaurus/plugin-content-docs', {...docsCommon, id: 'projects', path: 'docs/projects', routeBasePath: 'projects', sidebarPath: './sidebars/projects.ts'}], ['@docusaurus/plugin-content-docs', {...docsCommon, id: 'projects', path: 'docs/projects', routeBasePath: 'projects', sidebarPath: './sidebars/projects.ts'}],
['@docusaurus/plugin-content-docs', {...docsCommon, id: 'teams', path: 'docs/teams', routeBasePath: 'teams', sidebarPath: './sidebars/teams.ts'}], ['@docusaurus/plugin-content-docs', {...docsCommon, id: 'teams', path: 'docs/teams', routeBasePath: 'teams', sidebarPath: './sidebars/teams.ts'}],
['@docusaurus/plugin-content-docs', {...docsCommon, id: 'members', path: 'docs/members', routeBasePath: 'members', sidebarPath: './sidebars/members.ts'}], ['@docusaurus/plugin-content-docs', {...docsCommon, id: 'members', path: 'docs/members', routeBasePath: 'members', sidebarPath: './sidebars/members.ts'}],
['@docusaurus/plugin-content-docs', {...docsCommon, id: 'board', path: 'docs/board', routeBasePath: 'board', sidebarPath: './sidebars/board.ts'}],
['@docusaurus/plugin-content-docs', {...docsCommon, id: 'governance', path: 'docs/governance', routeBasePath: 'governance', sidebarPath: './sidebars/governance.ts'}], ['@docusaurus/plugin-content-docs', {...docsCommon, id: 'governance', path: 'docs/governance', routeBasePath: 'governance', sidebarPath: './sidebars/governance.ts'}],
], ],
themes: [[ themes: [[
@@ -46,7 +47,7 @@ const config: Config = {
indexDocs: true, indexDocs: true,
indexBlog: false, indexBlog: false,
indexPages: true, indexPages: true,
docsRouteBasePath: ['/', 'projects', 'teams', 'members', 'governance'], docsRouteBasePath: ['/', 'projects', 'teams', 'members', 'board', 'governance'],
language: ['en'], language: ['en'],
highlightSearchTermsOnTargetPage: true, highlightSearchTermsOnTargetPage: true,
explicitSearchResultPath: true, explicitSearchResultPath: true,
@@ -57,13 +58,14 @@ const config: Config = {
themeConfig: { themeConfig: {
colorMode: {defaultMode: 'dark', disableSwitch: false, respectPrefersColorScheme: true}, colorMode: {defaultMode: 'dark', disableSwitch: false, respectPrefersColorScheme: true},
navbar: { navbar: {
title: 'CORP V1 / STEERING', title: 'CORP V1 / BOARD',
items: [ items: [
{type: 'docSidebar', sidebarId: 'projectsSidebar', docsPluginId: 'projects', label: 'Projects', position: 'left'}, {type: 'docSidebar', sidebarId: 'projectsSidebar', docsPluginId: 'projects', label: 'Projects', position: 'left'},
{type: 'docSidebar', sidebarId: 'teamsSidebar', docsPluginId: 'teams', label: 'Teams', position: 'left'}, {type: 'docSidebar', sidebarId: 'teamsSidebar', docsPluginId: 'teams', label: 'Teams', position: 'left'},
{type: 'docSidebar', sidebarId: 'membersSidebar', docsPluginId: 'members', label: 'Members', position: 'left'}, {type: 'docSidebar', sidebarId: 'membersSidebar', docsPluginId: 'members', label: 'Members', position: 'left'},
{type: 'docSidebar', sidebarId: 'boardSidebar', docsPluginId: 'board', label: 'Board', position: 'left'},
{type: 'docSidebar', sidebarId: 'governanceSidebar', docsPluginId: 'governance', label: 'Governance', position: 'left'}, {type: 'docSidebar', sidebarId: 'governanceSidebar', docsPluginId: 'governance', label: 'Governance', position: 'left'},
{href: 'https://gitea.lego-cloud.eu/corp-v1/sterring-commitee', label: 'Gitea ↗', position: 'right'}, {href: 'https://gitea.lego-cloud.eu/corp-v1/portal', label: 'Gitea ↗', position: 'right'},
], ],
}, },
footer: { footer: {
@@ -72,11 +74,12 @@ const config: Config = {
{label: 'Projects', to: '/projects/'}, {label: 'Projects', to: '/projects/'},
{label: 'Teams', to: '/teams/'}, {label: 'Teams', to: '/teams/'},
{label: 'Members', to: '/members/'}, {label: 'Members', to: '/members/'},
{label: 'Board', to: '/board/'},
]}, {title: 'Governance', items: [ ]}, {title: 'Governance', items: [
{label: 'Project lifecycle', to: '/governance/project-lifecycle/'}, {label: 'Project lifecycle', to: '/governance/project-lifecycle/'},
{label: 'Decision log', to: '/governance/decisions/'}, {label: 'Decision log', to: '/governance/decisions/'},
]}], ]}],
copyright: `© ${new Date().getFullYear()} Corp v1 Steering Committee`, copyright: `© ${new Date().getFullYear()} Corp v1 Board`,
}, },
prism: {theme: prismThemes.github, darkTheme: prismThemes.oneDark}, prism: {theme: prismThemes.github, darkTheme: prismThemes.oneDark},
} satisfies Preset.ThemeConfig, } satisfies Preset.ThemeConfig,
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "corp-v1-sterring-commitee", "name": "corp-v1-portal",
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
+19 -3
View File
@@ -15,12 +15,28 @@ assert.match(globalCss, /\[data-theme=['"]light['"]\]/, 'global CSS needs an exp
assert.match(homepageCss, /:global\(\[data-theme=['"]light['"]\]\)/, 'homepage needs a light palette'); assert.match(homepageCss, /:global\(\[data-theme=['"]light['"]\]\)/, 'homepage needs a light palette');
assert.doesNotMatch(globalCss, /html,\s*body\s*\{\s*background:\s*#08101b/, 'document background must not be hard-coded dark'); assert.doesNotMatch(globalCss, /html,\s*body\s*\{\s*background:\s*#08101b/, 'document background must not be hard-coded dark');
for (const section of ['projects', 'teams', 'members', 'governance']) { for (const section of ['projects', 'teams', 'members', 'board', 'governance']) {
assert.match(config, new RegExp(`id:\\s*'${section}'`), `${section} docs plugin is missing`); assert.match(config, new RegExp(`id:\\s*'${section}'`), `${section} docs plugin is missing`);
assert.match(config, new RegExp(`sidebarId:\\s*'${section}Sidebar'`), `${section} navbar item does not target its dedicated sidebar`); assert.match(config, new RegExp(`sidebarId:\\s*'${section}Sidebar'`), `${section} navbar item does not target its dedicated sidebar`);
assert.ok(existsSync(join(root, `sidebars/${section}.ts`)), `${section} sidebar file is missing`); assert.ok(existsSync(join(root, `sidebars/${section}.ts`)), `${section} sidebar file is missing`);
} }
assert.match(config, /baseUrl:\s*'\/corp-v1\/portal\/'/, 'Pages base URL must follow the renamed repository');
assert.match(config, /projectName:\s*'portal'/, 'Docusaurus project name must be portal');
assert.doesNotMatch(config, /sterring-commitee/, 'legacy repository name must not remain in Docusaurus config');
const board = read('docs/board/index.md');
for (const memberId of ['1518725627845283888', '476287310627864587', '773109855497093191']) {
assert.ok(board.includes(memberId), `board page is missing Discord member ${memberId}`);
}
assert.match(board, /Only these Board members may approve a project kickoff or project closure/i);
assert.match(board, /Only these Board members may approve changes to `corp-v1--main`/i);
const lifecycle = read('docs/governance/project-lifecycle.md');
assert.match(lifecycle, /Board approval/i, 'project lifecycle must require Board approval');
assert.match(lifecycle, /central project-channel reference skill/i, 'lifecycle must govern central channel-reference skill changes');
assert.match(lifecycle, /project-adopted channel skill/i, 'lifecycle must require project skill synchronization');
for (const section of ['projects', 'teams', 'members']) { for (const section of ['projects', 'teams', 'members']) {
const sidebar = read(`sidebars/${section}.ts`); const sidebar = read(`sidebars/${section}.ts`);
assert.match(sidebar, /label:\s*'Registry'/, `${section} sidebar registry label must be concise`); assert.match(sidebar, /label:\s*'Registry'/, `${section} sidebar registry label must be concise`);
@@ -30,7 +46,7 @@ for (const section of ['projects', 'teams', 'members']) {
assert.ok(packageJson.dependencies?.['@easyops-cn/docusaurus-search-local'], 'local search dependency is missing'); assert.ok(packageJson.dependencies?.['@easyops-cn/docusaurus-search-local'], 'local search dependency is missing');
assert.match(config, /@easyops-cn\/docusaurus-search-local/, 'local search theme is not configured'); assert.match(config, /@easyops-cn\/docusaurus-search-local/, 'local search theme is not configured');
assert.match(config, /indexPages:\s*true/, 'custom pages must be indexed'); assert.match(config, /indexPages:\s*true/, 'custom pages must be indexed');
for (const route of ['/', 'projects', 'teams', 'members', 'governance']) { for (const route of ['/', 'projects', 'teams', 'members', 'board', 'governance']) {
assert.ok(config.includes(`'${route}'`), `search does not include route base ${route}`); assert.ok(config.includes(`'${route}'`), `search does not include route base ${route}`);
} }
@@ -38,7 +54,7 @@ if (existsSync(join(root, 'build'))) {
const filename = readdirSync(join(root, 'build')).find((name) => /^search-index(?:-[a-f0-9]+)?\.json$/.test(name)); const filename = readdirSync(join(root, 'build')).find((name) => /^search-index(?:-[a-f0-9]+)?\.json$/.test(name));
assert.ok(filename, 'production search index is missing'); assert.ok(filename, 'production search index is missing');
const search = readFileSync(join(root, 'build', filename), 'utf8').toLowerCase(); const search = readFileSync(join(root, 'build', filename), 'utf8').toLowerCase();
for (const term of ['projects registry', 'teams registry', 'members registry', 'project lifecycle', 'corp v1 steering committee']) { for (const term of ['projects registry', 'teams registry', 'members registry', 'board members', 'project lifecycle', 'corp v1 board']) {
assert.ok(search.includes(term), `search index is missing: ${term}`); assert.ok(search.includes(term), `search index is missing: ${term}`);
} }
} }
+7
View File
@@ -0,0 +1,7 @@
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
const sidebars: SidebarsConfig = {
boardSidebar: [{type: 'doc', id: 'index', label: 'Members'}],
};
export default sidebars;
+6 -5
View File
@@ -31,6 +31,7 @@ const groups: PortalGroup[] = [
links: [ links: [
{label: 'Teams registry', to: '/teams/', description: 'Find teams and their responsibilities'}, {label: 'Teams registry', to: '/teams/', description: 'Find teams and their responsibilities'},
{label: 'Members registry', to: '/members/', description: 'Review governance roles and assignments'}, {label: 'Members registry', to: '/members/', description: 'Review governance roles and assignments'},
{label: 'Board members', to: '/board/', description: 'See who can start or close projects'},
], ],
}, },
{ {
@@ -38,8 +39,8 @@ const groups: PortalGroup[] = [
title: 'Governance', title: 'Governance',
description: 'Follow the decisions that authorize projects and preserve accountability as direction changes.', description: 'Follow the decisions that authorize projects and preserve accountability as direction changes.',
links: [ links: [
{label: 'Decision log', to: '/governance/decisions/', description: 'Read authoritative steering decisions'}, {label: 'Decision log', to: '/governance/decisions/', description: 'Read authoritative Board decisions'},
{label: 'Steering overview', to: '/overview/', description: 'Learn how this committee operates'}, {label: 'Board overview', to: '/overview/', description: 'Learn how Corp v1 governance operates'},
], ],
}, },
]; ];
@@ -74,8 +75,8 @@ function PortalCard({group}: {group: PortalGroup}): React.JSX.Element {
export default function Home(): React.JSX.Element { export default function Home(): React.JSX.Element {
return ( return (
<Layout <Layout
title="Corp v1 Steering Committee" title="Corp v1 Board"
description="Authoritative project, team, member, and steering decision registry for Corp v1."> description="Authoritative project, team, Board member, and governance decision registry for Corp v1.">
<main className={styles.page}> <main className={styles.page}>
<section className={styles.hero}> <section className={styles.hero}>
<div className={styles.gridTexture} aria-hidden="true" /> <div className={styles.gridTexture} aria-hidden="true" />
@@ -91,7 +92,7 @@ export default function Home(): React.JSX.Element {
</div> </div>
</div> </div>
<div className={styles.heroRail} aria-label="Registry areas"> <div className={styles.heroRail} aria-label="Registry areas">
<span>PROJECTS</span><span>TEAMS</span><span>MEMBERS</span><span>DECISIONS</span> <span>PROJECTS</span><span>TEAMS</span><span>BOARD</span><span>DECISIONS</span>
</div> </div>
</section> </section>