vergabe-teilnahme/workplans/VERGABE-WP-0019-invited-company-pilot.md
tegwick 5cdcbd2186
All checks were successful
Application acceptance / application-tests (push) Successful in 13s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Record that the company database restore rehearsal passed.
Assistant: grok
Assistant-Session: 01a0d25d-d358-7e13-b84a-d007fbb7e34f
2026-09-25 02:06:02 +02:00

309 lines
16 KiB
Markdown

---
id: VERGABE-WP-0019
type: workplan
title: "Admit the first invited company pilot with protected access and recoverable data"
domain: communication
repo: vergabe-teilnahme
status: active
flavor: implementation
owner: the-custodian
topic_slug: vergabe-teilnahme
created: "2026-09-11"
updated: "2026-09-25"
related: [VERGABE-WP-0018, RAPPS-WP-0014, HFACT-WP-0001, CUST-WP-0071]
state_hub_workstream_id: "85b5f304-d497-5570-bebf-3a3669ef6a7d"
---
# Invited company pilot
## Confirm the bounded customer milestone
```task
id: VERGABE-WP-0019-T01
status: done
priority: high
assignee: the-custodian
state_hub_task_id: "5785d35a-6501-57a3-aedf-3885db269e83"
```
User decision on 2026-09-11: start with an invited pilot, one company and several
users, manually onboarded. Pricing is a later improvement and is not an entry
gate. Use the existing single-company product: each admitted company has an
isolated deployment, database and data volumes. All active company members can
collaborate on the company's tenders; the existing v1 domain approval roles
remain descriptive. Django staff/superuser administration remains restricted.
External partners remain data objects. No public registration or shared-app
multitenancy is introduced.
Product readiness proceeds alongside the governed factory runtime. It does not
wait for the fourteen-day factory value study. VERGABE-WP-0018-T03 retains the
separate claim that the factory can produce and deliver the customer release;
HFACT-WP-0001-T05 still needs a natural governed worker trace.
## Require invited access across the UI and uploaded documents
```task
id: VERGABE-WP-0019-T02
status: done
priority: high
assignee: the-custodian
state_hub_task_id: "11e67327-aae4-5c83-99eb-86a8c82dd0be"
```
Use Django's default-deny login middleware with explicit health/login exemptions,
German login and password-change forms, CSRF-protected POST logout, and full-page
reauthentication for expired HTMX sessions. Protect uploaded files in production
and development, serve private attachments only within MEDIA_ROOT, and keep
operational issue state outside that downloadable root. Do not cache company
responses. Inactive users lose existing session access; ordinary members do not
gain Django administration privileges.
The 12 access regressions initially produced 9 failures, including actual
anonymous tender read/create. After the fix all 94 application tests pass
locally and in the existing container target; Vite assets build, 139 static
files collect, and migration drift is absent. New/changed access modules pass
Ruff. Source acceptance is not native customer admission.
## Publish and prove the isolated deployment and recovery contract
```task
id: VERGABE-WP-0019-T03
status: progress
priority: high
assignee: the-custodian
depends_on: [VERGABE-WP-0019-T02, RAPPS-WP-0014-T02, RAPPS-WP-0014-T03]
state_hub_task_id: "9065d5cb-2c65-561e-a237-e39da4f3b0fd"
```
RAPPS-WP-0014 owns exact image/chart/host/namespace/database/Secret binding,
persistent media plus distinct issue-facade state, isolated restore rehearsal,
and rollback. The customer app owns live CI and immutable release evidence.
The user now selects a fresh `demo-company` demo tenant with `demo-user1`, etc.
Use `tenant:trial:demo-company` under NetKingdom ADR-0013 and two ordinary demo
accounts initially. Native tenant creation and memberships use the existing
User Engine operator portal; this does not implement Django SSO. The user selected
`https://vergabe-teilnahme.coulomb.social/demo-company` (one product host,
company path). The concrete
prepared binding lives at `railiance-apps/docs/vergabe-demo-company-binding.md`.
No password or personal user list belongs in public work records.
The historical vergabe_db is not disposable and must not be overwritten.
The user subsequently accepts a 60m application CPU request for one tenant with
very few users as a prototype of HelixForge app delivery and Railiance/NetKingdom
onboarding. RAPPS-WP-0014 owns the explicit pilot override; this is an accepted
low-allocation experiment, not measured production sizing. CUST-WP-0071 is
registered for later metrics-based sizing and a final weekly allocation-review
setup. That follow-up does not block this deployment. CPU limits, memory,
protected access and company/data isolation remain governed by the pilot packet.
On 2026-09-11 the checked Railiance cluster contains neither the historical
vergabe-teilnahme namespace nor any Deployment whose name/image contains
vergabe/teilnahme. Treat the old runbook as historical intent, not a live return.
Native placement and existing data inventory remain required before cutover.
2026-09-12 deployment evidence: the operator added A records for
vergabe-teilnahme.coulomb.social and users.coulomb.social. Authoritative IONOS
and recursive readback both return 92.205.62.239. Both cert-manager certificates
are Ready. The portal now uses https://users.coulomb.social/login; its legacy
nip.io address redirects to the canonical hostname. The exact new callback is
registered alongside the rollback callback; scopes, public client type and PKCE
remain unchanged. Canonical authorization succeeds; unapproved callback and
missing PKCE fail. This supersedes earlier DNS and portal-hostname blockers.
Helm release vergabe-teilnahme revision 1 is deployed in vergabe-demo-company,
chart 0.2.1, pinned product digest cebe8ca6218cc89f903e8a69e06ac50d3812526d4119cf4da485cc173f674b68.
Deployment UID 2152014d-a020-4c5e-a3b0-9575e9f21c44 is Ready 1/1. Its init
migration completed before the web process; both phases share the same 60m CPU /
256Mi memory request. Node requests now total 3965m of 4000m; the 35m remainder
matches the accepted prototype allocation. No unrelated resource requests changed.
RPF-WP-0039 delivered fresh vergabe_demo_company database/role on apps-pg and
runtime Secret vergabe-demo-company/vergabe-demo-env. The app's own connection
confirms that exact database/role. The role is non-superuser, cannot create roles
or databases, has a 20-connection ceiling and 15-second timeouts, and cannot
CONNECT to historical vergabe_db, coulomb_social_db or apps_meta. Both dedicated
PVCs are Bound: 5Gi media and 1Gi issue state. Historical data was not selected
or overwritten; no credentials are recorded here.
Thirteen live Chromium/HTTP checks pass: page and assets, secure tenant-scoped
CSRF cookie, anonymous login gate and media refusal, private operational path
refusal, neighboring/root path refusal, canonical slash, HTTPS redirect and
missing-CSRF POST denial. Migration/app initialization also proves consumer
connectivity. The empty product has zero accounts, including zero staff accounts.
The current login is still the interim Django login, not NetKingdom SSO. Native
recipient login, company welcome and account mapping remain VERGABE-WP-0019-T06.
2026-09-25: RAPPS-WP-0014-T03 restored `vergabe_demo_company` into a scratch
database in 2 seconds, 39 tables and 212 rows, checksum matched, scratch
dropped. The app pod was recreated and health returned 200. The backup artifact
is a workstation age file, not the Nextcloud upload. Media and issue-facade
claims are empty local-path volumes. Evidence:
`railiance-apps/docs/evidence/2026-09-25-vergabe-demo-company-restore.md`.
No second-user acceptance is claimed.
## Accept onboarding, collaboration, recovery and support with pilot users
```task
id: VERGABE-WP-0019-T04
status: wait
priority: high
assignee: the-custodian
depends_on: [VERGABE-WP-0019-T03]
blocking_reason: "Database restore and app restart are proved. Await two ordinary users collaborating on a tender, task, and document."
state_hub_task_id: "db807f96-f5b8-528d-bc33-75a33fbbf1e4"
```
Product acceptance: Bernd Worsch and the named company contact. Verify two
separate ordinary-user accounts (`demo-user1` and `demo-user2` initially) can sign
in, change passwords, create a tender
and lot, collaborate on tasks, upload/download a document, record a v1 domain
approval and submission, and report feedback. Verify anonymous access and a
revoked user fail, health remains available, and pod replacement preserves all
three data stores. Restore a backup into an isolated destination and repeat the
workflow without touching the live database. Record operator/support contact,
incident route, backup cadence/retention and demonstrated recovery time. Use
manual account creation/reset/deactivation through the admitted operator path;
never seed development accounts or put credentials in logs/workplans/chat.
A successful invited pilot does not claim shared multitenancy, paid subscriptions,
HA or autonomous production release. Pricing is outside this milestone and will
need a later explicit product decision.
## Support the selected product host and tenant path
```task
id: VERGABE-WP-0019-T05
status: done
priority: high
assignee: the-custodian
state_hub_task_id: "d00acb0b-6514-5ab5-9894-7fadb917feb7"
```
Implement fixed APP_BASE_PATH, prefix-aware Django URLs/assets/media, scoped and
uniquely named cookies, and prefixed login/logout/password-change/HTMX redirects.
Replace root URL literals in templates and breadcrumbs with named reversing.
The edge strips only the admitted company prefix; the application remains an
isolated per-company instance. Four prefix regressions and seven local Chromium
checks pass, alongside the existing 94 root-path tests. Vite builds correctly.
See docs/tenant-path-deployment.md. T03 retains CI publication, exact live pin,
DNS/TLS/namespace/database binding and recovery; source acceptance is not deployment.
On 2026-09-11 at 19:03:18 UTC, native operator creation succeeded. Authority
readback confirms tenant:trial:demo-company active, version 1; the chosen first
administrator exists in User Engine with invited status. A subsequent Create
login failed in identity-provisioner at LLDAP service authentication (HTTP 401).
Its existing credential was reloaded without rotation; the connection still
fails. NetKingdom tracks that owner-credential reconciliation before identity
provisioning retries. No passwords or private addresses enter this record.
2026-09-12 native follow-through: the credential repair is verified, the operator
reports successful user password setup, and live read-only User Engine evidence
shows three memberships with one linked directory identity. This supersedes the
preceding service-login failure. It does not create a Django account or session.
## Connect identity setup to the company's welcome and sign-in page
```task
id: VERGABE-WP-0019-T06
status: progress
priority: high
assignee: the-custodian
state_hub_task_id: "455b33f9-163a-5389-86a3-04000c32d176"
```
The operator successfully sets a user's directory password, but the provider ends
on a generic Password set page. The user requests a welcome page for the tenant
on the application. Target the selected
https://vergabe-teilnahme.coulomb.social/demo-company/ entry point.
Finish RAPPS-WP-0014-T02's real application route/data/placement, then preserve
company and intended recipient through the invitation/password-setup handoff
using exact allowed HTTPS return locations. Show a tenant-specific welcome page
and a clear sign-in action. Connect application authentication to the existing
NetKingdom identity contract, with issuer, signature, audience, expiry and exact
tenant validation, and a stable subject-to-local-account mapping. Keep ordinary
users non-staff and reject wrong-tenant identities. No password copying or
operator-session impersonation is an acceptable bridge.
The administrator may create another user's setup link while signed in as
platform-root. Completing that link must not turn the operator's existing portal
or shared SSO session into the recipient's application session. Handle the
explicit fresh-user sign-in/account-switch boundary; USER-WP-0025-T03 retains
complete provider sign-out coordination. Preserve the single-company database,
media and issue-state isolation and the accepted 60m allocation.
Verify a fresh invited user follows setup → company welcome → authenticated
application, sees the correct company, and can enter the pilot workflow. Verify
invalid/expired setup returns, unapproved external return URLs, wrong-tenant
identities and operator-session confusion fail safely. Keep setup tokens,
credentials and personal addresses out of work records. The earlier manual
Django login gate remains an interim product capability, not SSO proof.
2026-09-12 continuation: implemented company welcome, OIDC code+PKCE/nonce
verification, explicit account confirmation and stable issuer/subject mapping.
New accounts are ordinary users with unusable local passwords; signed directory
membership, exact tenant and bounded session expiry are required. Added callback,
wrong-tenant/platform, signature, replay, CSRF, local deactivation and prefix tests.
Source/deployment contract: docs/netkingdom-sign-in.md. The current live issuer
predates tenant_source and drops prompt=login before Authelia, so enabling the
product depends on KEY-WP-0033 and NK-WP-0037's exact registration/provider rollout.
The password-setup company return is grant-bound in NK-WP-0037. Native recipient
login/MFA, product publication and live acceptance remain open; no completed SSO
or pilot acceptance is claimed from source tests.
2026-09-12 release readiness: source 8be2810 is published as
sha256:2cb393608a82be2851adfc27f2bf4d8ef5d709f1b0038be5d0999e38c68b039e
(Forgejo run 51). All 125 local app tests, build and migration checks pass.
Acceptance run 49 completed tests but failed at image export; the independent
publication gate passed, and acceptance run 52 plus smoke run 53 pass on
cf50cc5 with identical application source (only generated brief changed).
The exact release packet, rollback and server-dry-run manifests are in
railiance-apps/docs/vergabe-demo-company-sso-rollout.md. Runtime remains on the
interim gate pending the documented attended KeyCape upgrade and native user/MFA
acceptance. KEY-WP-0033 and NK-WP-0037 remain live receiving records.
2026-09-12 attended rollout executed after explicit operator approval. KeyCape
and password setup are Ready on the prepared digests; exact public client
registration was CAS-applied (config resourceVersion 60123977) with unrelated
config bytes/Secret data preserved. Existing portal and product client both
pass fresh-login forwarding, wrong-callback and missing-PKCE checks (6 checks).
Vergabe Helm revision 2 is Ready; identity migration completed, both PVCs remain,
and requests remain 60m CPU/256Mi memory. Eleven live product checks pass:
company welcome, anonymous gate, no-store, secure scoped CSRF, POST/CSRF-only
login start, native issuer redirect, private company/media protection and
invalid callback/confirmation rejection. Initial readback showed zero accounts,
identity mappings and staff accounts. Native invited-user sign-in/MFA and
confirmation are now requested from the operator; no user credential was used
by the agent. Recovery and two-user acceptance remain their existing tasks.
Evidence: railiance-apps/docs/evidence/2026-09-12-demo-company-sso-live.md.
### Rejected-login recovery follow-up — 2026-09-12
Operator reports a dead-end error after trying a non-customer identity. Recent
issuer evidence shows token exchange failure; the exact browser cause is not
yet confirmed. Rejected callbacks and unusable confirmation now redirect to the
central account recovery page without code, state or claimed identity. Existing
tenant, principal, signature, CSRF and account-admission boundaries remain.
Validation: 126 application tests passed using an isolated in-memory database.
KEY-WP-0034 owns provider recovery/sign-out; USER-WP-0026 owns account visibility.
Publication and attended live recovery verification are in progress.
2026-09-24 23:46 UTC the founder completed one Vergabe sign-in on the freshness
image. The issuer issued a token for `vergabe-demo-company` after one failed
code exchange. That closes the native-login wait owned by KEY-WP-0033. This
task still owns the rest of the pilot: a second user, the setup-to-welcome
handoff, and entry into the company workflow. Receipt:
`key-cape/docs/evidence/2026-09-24-fresh-login-and-account-switch.md`.
### Live recovery rollout — 2026-09-12
Recovery is deployed in KeyCape 4d8b8fe, User Engine e54b6ee and Vergabe c067993
(Helm revision 3). All three are Ready. Six provider checks, eleven product
checks and six fresh anonymous Chromium checks pass, including actual provider
logout POST and return to the portal without test overrides. Real-user identity
switching is still awaiting operator evidence; no authenticated/MFA acceptance
is inferred. Detailed receipt: railiance-apps/docs/evidence/2026-09-12-account-recovery-live.md.