diff --git a/.github/workflows/api-dev.yaml b/.github/workflows/api-dev.yaml deleted file mode 100644 index 57b52ad49a..0000000000 --- a/.github/workflows/api-dev.yaml +++ /dev/null @@ -1,94 +0,0 @@ -# Legacy Azure deploy — will be removed after DFX server migration cutover. -# New deploy pipeline: dfx-api-dev.yaml (Docker + SSH to dfxdev). -name: API DEV CI/CD - -on: - push: - branches: [develop] - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: deploy-dev - cancel-in-progress: true - -env: - AZURE_WEBAPP_NAME: app-dfx-api-dev - AZURE_WEBAPP_PACKAGE_PATH: '.' - NODE_VERSION: '20.x' - DEV_API_URL: https://dev.api.dfx.swiss - -jobs: - build-and-deploy: - name: Build, test and deploy to DEV - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v5 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Install packages - uses: nick-fields/retry@v4 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_on: error - command: npm ci - - - name: Run linter - run: npm run lint - - - name: Format check - run: npm run format:check - - - name: Build code - run: npm run build - - - name: Run tests - run: npm run test - - - name: Security audit - run: npm audit --audit-level=high - continue-on-error: true - - - name: Write version file - run: echo "${{ github.sha }}" > dist/version.txt - - - name: Deploy to Azure App Service (DEV) - uses: azure/webapps-deploy@v3 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - publish-profile: ${{ secrets.DEV_PUBLISH_PROFILE }} - package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} - - - name: Verify DEV deployment - timeout-minutes: 15 - run: | - EXPECTED=${{ github.sha }} - echo "Expected commit: $EXPECTED" - - for i in {1..30}; do - if RESPONSE=$(curl -sf ${{ env.DEV_API_URL }}/version 2>&1); then - ACTUAL=$(echo "$RESPONSE" | jq -r '.commit') - echo "Attempt $i: DEV running $ACTUAL" - - if [ "$EXPECTED" == "$ACTUAL" ]; then - echo "DEV is running the latest develop commit" - exit 0 - fi - else - echo "Attempt $i: DEV API not reachable" - fi - - sleep 30 - done - - echo "::error::DEV is not running the latest develop commit after 15 minutes" - exit 1 diff --git a/src/subdomains/supporting/realunit/__tests__/realunit.service.spec.ts b/src/subdomains/supporting/realunit/__tests__/realunit.service.spec.ts index 592a1fb9b6..6c88ab96e0 100644 --- a/src/subdomains/supporting/realunit/__tests__/realunit.service.spec.ts +++ b/src/subdomains/supporting/realunit/__tests__/realunit.service.spec.ts @@ -577,7 +577,7 @@ describe('RealUnitService', () => { expect(status.userData!.kycData.lastName).toBe('Mustermann'); }); - it('returns state=KYC_REQUIRED when no step exists and no KYC data is present', () => { + it('returns state=NEW_REGISTRATION with no userData when no step exists and no KYC data is present (first-time user gets an empty form)', () => { const userData = { firstname: null, surname: null, @@ -586,7 +586,7 @@ describe('RealUnitService', () => { const status = service.getRegistrationInfo(userData, walletAddress); - expect(status.state).toBe(RealUnitRegistrationState.KYC_REQUIRED); + expect(status.state).toBe(RealUnitRegistrationState.NEW_REGISTRATION); expect(status.isRegistered).toBe(false); expect(status.userData).toBeUndefined(); }); diff --git a/src/subdomains/supporting/realunit/controllers/realunit.controller.ts b/src/subdomains/supporting/realunit/controllers/realunit.controller.ts index ea66d6c19b..b4c3e4b663 100644 --- a/src/subdomains/supporting/realunit/controllers/realunit.controller.ts +++ b/src/subdomains/supporting/realunit/controllers/realunit.controller.ts @@ -612,7 +612,7 @@ export class RealUnitController { @ApiOperation({ summary: 'Get RealUnit registration info for the connected wallet', description: - 'Returns the action the client should take to RealUnit-register the connected wallet (`state`), the registration data to pre-fill or display (`userData`), and a legacy `isRegistered` flag. Drives the registration UX: client routes on `state` (AlreadyRegistered / AddWallet / NewRegistration / KycRequired) without inferring it locally.', + 'Returns the action the client should take to RealUnit-register the connected wallet (`state`), the registration data to pre-fill or display (`userData`), and a legacy `isRegistered` flag. Drives the registration UX: client routes on `state` (AlreadyRegistered / AddWallet / NewRegistration) without inferring it locally.', }) @ApiOkResponse({ type: RealUnitRegistrationInfoDto }) async getRegistrationInfo(@GetJwt() jwt: JwtPayload): Promise { diff --git a/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts b/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts index 4e4d5e5522..daf717f1ca 100644 --- a/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts +++ b/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts @@ -240,7 +240,6 @@ export enum RealUnitRegistrationState { ALREADY_REGISTERED = 'AlreadyRegistered', ADD_WALLET = 'AddWallet', NEW_REGISTRATION = 'NewRegistration', - KYC_REQUIRED = 'KycRequired', } export class RealUnitRegistrationInfoDto { @@ -254,7 +253,7 @@ export class RealUnitRegistrationInfoDto { @ApiProperty({ enum: RealUnitRegistrationState, description: - 'Action the client should take for this wallet. `AlreadyRegistered`: no UX needed. `AddWallet`: render a one-tap Add-Wallet flow that submits to POST /register/wallet using the prior signed payload (`userData` is set). `NewRegistration`: render the full registration form pre-filled with `userData`. `KycRequired`: user must complete DFX KYC first (`userData` not set; edge case).', + 'Action the client should take for this wallet. `AlreadyRegistered`: no UX needed. `AddWallet`: render a one-tap Add-Wallet flow that submits to POST /register/wallet using the prior signed payload (`userData` is set). `NewRegistration`: render the full registration form — pre-filled with `userData` when present, otherwise empty for the client to collect every field manually.', }) state: RealUnitRegistrationState; diff --git a/src/subdomains/supporting/realunit/realunit.service.ts b/src/subdomains/supporting/realunit/realunit.service.ts index aa42630a50..13029bc276 100644 --- a/src/subdomains/supporting/realunit/realunit.service.ts +++ b/src/subdomains/supporting/realunit/realunit.service.ts @@ -670,11 +670,10 @@ export class RealUnitService { getRegistrationInfo(userData: UserData, walletAddress: string): RealUnitRegistrationInfoDto { const { step, isForCurrentWallet } = this.findRegistrationStep(userData, walletAddress); - // Dispatch to one of four states so the client can route to the right UX without inferring + // Dispatch to one of three states so the client can route to the right UX without inferring // it locally. Order matters: a registration step for the current wallet (ALREADY_REGISTERED) // wins over any other signal; a step for a different wallet drives the one-tap Add-Wallet - // flow (ADD_WALLET); otherwise we pre-fill the full form from existing KYC data when - // available (NEW_REGISTRATION), falling back to KYC_REQUIRED when no usable data exists. + // flow (ADD_WALLET); otherwise this wallet still needs a fresh registration (NEW_REGISTRATION). if (step) { const stepUserData = this.toUserDataDto(step); const state = isForCurrentWallet @@ -687,21 +686,16 @@ export class RealUnitService { }; } - // No step exists. Pre-fill from DFX KYC data (firstname/surname guarded by - // toUserDataDtoFromUserData) and fall through to KYC_REQUIRED when that returns undefined. - const prefill = this.toUserDataDtoFromUserData(userData); - if (prefill) { - return { - isRegistered: false, - state: RealUnitRegistrationState.NEW_REGISTRATION, - userData: prefill, - }; - } - + // No step exists: this wallet needs a fresh RealUnit registration. Pre-fill the form from + // existing DFX KYC data when we have verified personal data (firstname/surname present); + // otherwise return NEW_REGISTRATION without `userData` so the client renders an empty form and + // collects every field manually. `completeRegistration` accepts and persists manually-entered + // data for first-time users — email registration (KYC Level 10) is the only prerequisite — so + // this branch must not dead-end onboarding by withholding the registration step. return { isRegistered: false, - state: RealUnitRegistrationState.KYC_REQUIRED, - userData: undefined, + state: RealUnitRegistrationState.NEW_REGISTRATION, + userData: this.toUserDataDtoFromUserData(userData), }; }