--- 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 owner: the-custodian topic_slug: vergabe-teilnahme created: "2026-09-11" updated: "2026-09-12" 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. ## 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: "Native tenant/user/password setup is verified. Await admitted application placement, tenant welcome/sign-in connection and demonstrated restore." 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: todo 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.