Build reusable authenticated forms and results API in player portal
Build in PRK.PlayerPortal (deployed Razor Pages portal), not legacy PRK.Portal. Users authenticate with existing OAuth/OIDC and receive shared form links. No email delivery, anonymous applications, client changes or embedded LLM integration. Provide read-only authorized structured results API for external LLM tooling. Scope: reusable field definitions/validation, immutable published form versions, admin create/edit/preview/publish/close, account-linked submissions, response review/filter/export and API. Preserve historical question meaning; enforce authorization and duplicate-submission policy server-side. Management and results access now include developer alongside administrator/management in local source (user-approved scope extension); one submission per stable OAuth issuer+subject per form. No model-generated SQL or public response data. Acceptance: publication/submission/versioning and field validation work; unauthorized access and repeat/concurrent submissions rejected; API paginates and returns definitions plus typed answers without exposing account secrets. Prepare this feature for the existing CI/CD pipeline: automatically apply the portal-only additive schema before serving requests, safely handle repeated/concurrent startup, package migrations in the published portal, wire an optional role-scoped read API secret for Ithaca production, and retain the existing CI flow while keeping SQL schema/lifecycle tests available locally. Preserve existing site tables and never seed production test data. Schema deployment documented without modifying existing site tables. Relevant build/regression tests pass; validation limitations explicit. Implemented and pushed on feature/player-portal-forms. Commits f8766c6c4 (feature: Add reusable authenticated player portal forms) and 643401486 (ci: Validate portal forms before production deployment) include only the 37 intended session files; local .env, certificates, test forms and data remain uncommitted. Reusable short/long text, choice, number, date and consent fields; stable keys and immutable definition snapshots; typed answer/choice tables. Admin draft editor/reordering/preview/publish/close and authenticated shared-link response flow; one issuer+subject hash per form enforced by unique database constraint. Form revision concurrency serializes submissions against publish/close. Admin search/review and bounded JSON page export. Read-only API supports admin cookies or dedicated Forms__ReadApiToken; paginated lists/results, version definitions and literal search. Initial version excludes CSV, notes/shortlisting, conditional logic, attachments, automatic retention/deletion and LLM execution. Verified: portal build zero warnings/errors; 40 focused PlayerPortal tests pass, none skipped, including actual Kestrel/Razor create/publish/submit/review/export and CSRF/encoding tests, API authorization/token scope/pagination tests, plus three real MSSQL tests for duplicate races, close/submission rollback, publication conflicts and typed round-trip. SQL migration applied to isolated PortalFormsLocal and PortalFormsTests databases on existing local Docker MSSQL; existing IthacaDb untouched. HTTP home 200 and anonymous forms API 401. No real-browser authenticated session exercised. Local Docker container prk-portal-forms serves https://localhost:5200 (self-signed development certificate), management /Admin/Forms. Local-only compose at .dev-data/portal-forms/compose.yml, restart with docker compose -f .dev-data/portal-forms/compose.yml up -d. User-provided .env is passed directly to Docker without reading/printing; PORTAL_OIDC_CLIENT_ID/PORTAL_OIDC_SECRET mapped to app OIDC configuration. Fixed local DB configuration overrides .env. User subsequently exercised the authenticated admin UI; fixed the empty validation error notice and made list actions separate spaced buttons. A published local client-beta-test form exists; user has edited it to version 2. Full real-browser OAuth/submission acceptance has not been independently recorded, so leave the final live workflow criterion open. CI/CD preparation implemented and committed: portal-only SQL scripts are now embedded under PRK.PlayerPortal/Data/Migrations rather than requiring manual SQL installation. PortalSchemaMigrator applies them in one transaction under sp_getapplock before listening; hash history rejects modified applied scripts, and schema validation rejects incompatible columns, primary/unique keys and foreign keys during adoption. --migrate-site-db mode initializes schema without game data/OAuth/listener. No production seed data. Request parser now supports the advertised multi-choice selection count (2600 values, bounded 6 MiB body); HTTP regression exercises >1024 selections. User explicitly chose direct-to-production rollout, with no staging requirement. The added portal-forms-check.yml workflow, its helper script and the Ithaca deployment gate were removed at the user's request after remote parsing rejected secrets under workflow_call. Existing CI/deployment behavior is retained; the only production workflow diff forwards the optional site DB/API token secrets. The additional OIDC client-ID deployment guard was also removed. Ergo workflow and secrets file are restored to their original content. Test harness uses disposable MSSQL, publishes the self-contained Release portal and runs migration-only mode twice, including empty SITE_DB fallback. Ithaca-specific Kamal configuration passes optional SITE_DB and Forms__ReadApiToken aliases only to the portal role, sourced from PORTAL_SITE_DB/FORMS_READ_API_TOKEN. Ergo receives neither new secret; its config-only clear-map normalization preserves existing metrics/port settings. Shared portal code remains in the common image; no runtime environment feature restriction was requested. Empty DB falls back to existing AOEMU_DB_URL; empty token disables bearer access, malformed nonempty token fails startup. Existing production OIDC configuration is retained without adding a deployment guard. Existing Ithaca OIDC settings unchanged. README documents production-only rollout, permissions, secrets, smoke checks and additive rollback behavior. Updated Kamal config assertions and actionlint pass; application code/tests unchanged by this scope refinement. Verified CI reproduction: clean source copy without .env/game data, node:22-bookworm with official .NET 8 SDK/native build tools; exact test-portal-forms.sh succeeds with 48 tests passed/0 skipped, warning-free portal Release build, self-contained publish with CSS and two migration-only artifact executions. Existing broader unit-project compile warnings remain outside portal warnings-as-errors. Actionlint passes with exclusions for existing Forgejo absolute action URLs/custom runner labels. Actual Kamal 2.12 config objects validate both destination merges, secret alias isolation, port and metrics preservation using synthetic values. Static feature review was partial (generated binary build artifacts, since removed); two verified findings were addressed with regression tests. No post-fix review approval is claimed. Local Docker rebuilt/restarted successfully: home 200, anonymous forms API 401, both portal schema migrations recorded, existing test forms/versions preserved. Production untouched. Remote Forgejo workflow/reusable expansion, deployment image as a whole, remote SQL permissions and staging/production OAuth callbacks are not executed/verified. Required operator setup: retain existing production OIDC credentials, optionally configure PORTAL_SITE_DB and FORMS_READ_API_TOKEN, verify target database backup/DDL permissions, then use the existing Ithaca deployment process and smoke-test the forms/API workflow. No staging credentials or staging-first promotion required. User authorized PR preparation and explicitly selected develop as base. Opened PR #2680, feature: Add reusable player portal forms and results API — https://git.project-rk.com/prk/engines/pulls/2680 . Head feature/player-portal-forms, base develop; branch pushed with upstream, working tree clean, no history rewriting. One unrelated newer develop client-UI commit was not imported into the branch; PR reports no conflicts. Final complete 37-file patch inspected and whitespace/config/workflow checks pass; prior 48-test clean-container validation remains the relevant execution evidence. No additional full test rerun or remote CI success is claimed merely from opening the PR. Follow-up commit 71b69d056 (ci: Remove dedicated portal forms validation workflow) is pushed to the existing PR; its body now reflects the removed gate and the observed remote parse failure. Workflow lint (Forgejo-specific exclusions), Kamal synthetic configuration assertions, dangling-reference checks and git diff --check pass. No application/test code changed, so the prior 48-test execution remains the relevant automated evidence; no remote rerun success is claimed. Working tree clean. Production deployment subsequently performed by user. Incident investigation on Ithaca: deployed portal cff8ba87cd8514cd0b8d94f5c3a03ca5a5439115 restart-loops before migrations/listening because Forms__ReadApiToken is configured with length 20; Program.cs rejects nonempty tokens outside 32–512 characters. Confirmed via container logs and length-only inspection, without exposing token. Other engines are running. SITE_DB empty uses AOEMU_DB_URL fallback. User authorized recovery without full redeploy. Recreated only the current portal container from its inspected image/config/host/network settings with Forms__ReadApiToken empty, disabling bearer results access. Original failed container retained under a timestamped recovery name and inspection backed up root-only on host. No game engines restarted. Both embedded migrations applied successfully; portal listening in Production, local and external ithaca.project-rk.com:5051 home HTTP 200, anonymous /api/forms HTTP 401; replacement running with zero restarts. Deployment secret remains invalid and must be cleared or replaced with a 32–512-character random token before next deploy to prevent recurrence. Follow-up public HTTPS check found proxy-level 404 despite healthy direct backend. Edge proxy at 5.161.243.214 correctly targets 10.222.0.2:5051; fresh backend connections returned 200 while its existing pooled connections returned 404 after portal outage/recovery. Restarted only prk-web-proxy-reverse-proxy-1 to clear connections. Verified public https://portal.project-rk.com/ 200, /api/status 200, /api/forms 401, /Admin/Forms 302 to expected OIDC provider with correct https://portal.project-rk.com/signin-oidc callback. No game engine restart. Developer access extension implemented locally: shared CanManageForms role predicate used by FormsManage, FormsResults and navigation; README updated. HTTP regression covers all three staff roles creating/editing/publishing/closing forms, reviewing/exporting responses and seeing navigation; API regression covers developer/admin/management access, player/bug_hunter rejection and read-only bearer scope. Focused portal tests via local SDK container: 37 passed, 11 SQL integration cases skipped (PORTAL_FORMS_TEST_DB not configured), zero failures; Razor portal compiled. Initial local build lacked make; retry used installed Ninja in isolated native build directory. git diff --check passes. Developer permission change committed as 7c3e7434d (fix: Allow developers to manage portal forms) on dedicated branch fix/allow-developers-to-manage-forms based on latest origin/main, pushed with upstream. Opened PR #2687 targeting main: https://git.project-rk.com/prk/engines/pulls/2687 . Complete branch comparison contains only five intended files and one commit, with no inherited earlier feature-branch commits; working tree clean. Rebuilt/reran focused portal suite on the final branch: 37 passed, 11 SQL cases skipped, zero failures; git diff --check passes. No production rollout; user plans next deployment with replacement API key. Follow-up response-display fix pushed to the same PR #2687 as commit 036f0dd2a: trim trailing decimal zeros without losing meaningful fractional digits; hide internal field keys from review labels; preserve original values and keys in JSON exports. Extended real Razor HTTP regression for 25.00000000 → 25, 1.23000000 → 1.23, 0.00000001 preservation, clean labels and unchanged export. Focused portal suite rebuilt and rerun: 37 passed, 11 SQL cases skipped, zero failures; whitespace checks pass. PR description updated; no deployment. Authenticated OAuth/forms acceptance remains open.
Checklist
5 of 6 complete- Implement versioned schema, validation and authenticated/concurrency-safe submission lifecycle.
- Implement authorized paginated read-only results API and deployment/API documentation.
- Verify relevant automated tests and builds; record remaining validation limits.
- Implement portal form management, respondent flow and response review.
- Verify real OAuth login and authenticated local workflow after test client allows https://localhost:5200/signin-oidc.
- Verify published schema initialization and production-only portal secret wiring while retaining existing CI workflows.
- Area
- Project Rubi-Ka
- Project
- engines
- Kind
- Feature
- Task ID
tsk_4b4v73utex- Updated