Skip to content

Manual Testing: Partner Contracts + Partner Service Editing (Local Docker)

This guide defines manual test workflows (with multiple use cases each) for: - Workflow A: Partner-level contract creation end-to-end (starts in admin-console, finishes in partner-console). - Workflow B: Partner service editing end-to-end, including: - ServiceTexts workflow for description and short_description (translate/enhance/etc + approval steps). - ServiceProposals workflow where admin approval is required (restricted edits + activation requests).

Each use case contains: - A Mermaid diagram with stable Node IDs - A step-by-step procedure where each step maps to a Node ID


Environment + URLs (Local Docker)

  • Admin Console: https://admin-console-dev.portugalodyssey.pt
  • Partner Console: https://partner-console-dev.portugalodyssey.pt
  • API Gateway: https://api-dev.portugalodyssey.pt

API routing note: - Consoles call partner endpoints under .../api/partner/*. - API Gateway rewrites /api/partner/*/api/partners/* (partner-service uses /api/partners/* internally).


Roles / Accounts required

  • Admin user: can access admin-console and approve proposals/service texts, and update partner contract status.
  • Partner user: can access partner-console and upload a signed contract PDF; can create service text revisions and request approval.

Test data prerequisites (minimum)

  • P0: At least one Partner exists and is visible in admin-console → Partners.
  • P1: That Partner can log in to partner-console (has a Keycloak/tenant association already).
  • P2: The Partner has at least one Service (for Workflow B).

If P2 is missing, create a service in partner-console: - Partner Console → Services → Create Service


Workflow A: Partner Contract Creation (Admin → Partner → Admin)

Contract status machine (reference)

Backend status transitions are enforced: - DRAFT → SENT → SIGNED → ACTIVE - From ACTIVE: SUSPENDED / TERMINATED / EXPIRED - From SUSPENDED: ACTIVE / TERMINATED / EXPIRED - Terminal: TERMINATED, EXPIRED


UC-C1: Create Draft Contract and Send to Partner (DRAFT → SENT)

Diagram

sequenceDiagram
  participant AdminUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  AdminUI->>ApiGateway: C1_openPartnerDrawer
  ApiGateway->>PartnerService: C1_listPartnerContracts(GET_/api/partner/admin/partners/:partnerId/contracts_via_gateway)
  PartnerService->>Postgres: C1_readContracts
  Postgres-->>PartnerService: C1_contractList
  PartnerService-->>ApiGateway: C1_200_contractList
  ApiGateway-->>AdminUI: C1_renderContracts

  AdminUI->>ApiGateway: C1_createDraftClick
  ApiGateway->>PartnerService: C1_createDraft(POST_/api/partner/admin/partners/:partnerId/contracts)
  PartnerService->>Postgres: C1_insertDraft(status=DRAFT)
  Postgres-->>PartnerService: C1_draftRow
  PartnerService-->>ApiGateway: C1_201_draft
  ApiGateway-->>AdminUI: C1_renderDraft

  AdminUI->>ApiGateway: C1_sendClick
  ApiGateway->>PartnerService: C1_patchStatus(PATCH_/api/partner/admin/partners/:partnerId/contracts/:contractId)
  PartnerService->>PartnerService: C1_validateTransition(DRAFT_to_SENT)
  PartnerService->>Postgres: C1_updateStatus(status=SENT)
  Postgres-->>PartnerService: C1_sentRow
  PartnerService-->>ApiGateway: C1_200_sent
  ApiGateway-->>AdminUI: C1_renderSent

Steps (each step maps to the diagram)

  • C1.1 (C1_openPartnerDrawer): Admin Console → Partners → Open a partner (opens the right-side drawer).
  • C1.2 (C1_createDraftClick): In drawer → Contracts → Click Create draft.
  • C1.3 (C1_sendClick): In the draft contract row (status DRAFT) → Click Send.
  • C1.4 (C1_renderSent): Confirm contract now shows status SENT in the drawer.

Expected results

  • A new contract exists with status SENT.
  • Contract is visible to the partner in partner-console Contracts page.

UC-C2: Partner Uploads Signed Contract PDF (SENT → SIGNED)

Diagram

sequenceDiagram
  participant PartnerUI
  participant ApiGateway
  participant FileService
  participant PartnerService
  participant Postgres

  PartnerUI->>ApiGateway: C2_openContractsPage
  ApiGateway->>PartnerService: C2_listContracts(GET_/api/partner/:partnerId/contracts)
  PartnerService->>Postgres: C2_readContracts
  Postgres-->>PartnerService: C2_contractList
  PartnerService-->>ApiGateway: C2_200_contractList
  ApiGateway-->>PartnerUI: C2_renderContracts

  PartnerUI->>ApiGateway: C2_uploadPdf(POST_/api/file/files/upload)
  ApiGateway->>FileService: C2_storeFile
  FileService-->>ApiGateway: C2_fileKey
  ApiGateway-->>PartnerUI: C2_uploadOk

  PartnerUI->>ApiGateway: C2_signContract(POST_/api/partner/:partnerId/contracts/:contractId/sign)
  ApiGateway->>PartnerService: C2_signWithFileKey
  PartnerService->>PartnerService: C2_validateSignAllowed(SENT_or_DRAFT)
  PartnerService->>Postgres: C2_updateSigned(status=SIGNED,partner_signed_at,signed_document_file_key)
  Postgres-->>PartnerService: C2_signedRow
  PartnerService-->>ApiGateway: C2_200_signed
  ApiGateway-->>PartnerUI: C2_renderSigned

Steps

  • C2.1 (C2_openContractsPage): Partner Console → Contracts → confirm the contract appears with status SENT.
  • C2.2 (C2_uploadPdf): In the SENT contract card → upload a PDF via the upload dropzone.
  • C2.3 (C2_signContract): Wait for upload/sign to complete (UI refreshes contract list).
  • C2.4 (C2_renderSigned): Confirm contract now shows status SIGNED and shows the uploaded signed document.

Expected results

  • Contract is updated to SIGNED.
  • Signed document can be opened/downloaded via File Service.

UC-C3: Admin Activates Signed Contract (SIGNED → ACTIVE)

Diagram

sequenceDiagram
  participant AdminUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  AdminUI->>ApiGateway: C3_openPartnerDrawer
  ApiGateway->>PartnerService: C3_listPartnerContracts(GET_/api/partner/admin/partners/:partnerId/contracts)
  PartnerService->>Postgres: C3_readContracts
  Postgres-->>PartnerService: C3_contractList
  PartnerService-->>ApiGateway: C3_200_contractList
  ApiGateway-->>AdminUI: C3_renderContracts

  AdminUI->>ApiGateway: C3_activateClick
  ApiGateway->>PartnerService: C3_patchStatus(PATCH_/api/partner/admin/partners/:partnerId/contracts/:contractId,status=ACTIVE)
  PartnerService->>PartnerService: C3_validateTransition(SIGNED_to_ACTIVE)
  PartnerService->>Postgres: C3_updateStatus(status=ACTIVE)
  Postgres-->>PartnerService: C3_activeRow
  PartnerService-->>ApiGateway: C3_200_active
  ApiGateway-->>AdminUI: C3_renderActive

Steps

  • C3.1 (C3_openPartnerDrawer): Admin Console → Partners → Open the same partner drawer.
  • C3.2 (C3_activateClick): Find the contract with status SIGNED → Click Activate.
  • C3.3 (C3_renderActive): Confirm status becomes ACTIVE.

UC-C4: Invalid Status Transition Guardrail (ACTIVE → SIGNED should fail)

This validates backend transition enforcement.

Diagram

sequenceDiagram
  participant Tester
  participant ApiGateway
  participant PartnerService

  Tester->>ApiGateway: C4_patchInvalid(PATCH_/api/partner/admin/partners/:partnerId/contracts/:contractId,status=SIGNED)
  ApiGateway->>PartnerService: C4_forwardPatch
  PartnerService->>PartnerService: C4_validateTransition(ACTIVE_to_SIGNED)
  PartnerService-->>ApiGateway: C4_400_invalidTransition
  ApiGateway-->>Tester: C4_400_invalidTransition

Steps

  • C4.1 (C4_patchInvalid): Use Postman/curl against API Gateway to PATCH an ACTIVE contract back to SIGNED.
  • Endpoint (gateway): PATCH /api/partner/admin/partners/:partnerId/contracts/:contractId
  • Body: { "status": "SIGNED" }
  • C4.2 (C4_400_invalidTransition): Confirm the request fails with 400 and an “Invalid status transition” error.

UC-C5: Annex Terms CRUD (Services/Commercial/Cancellation)

Diagram

flowchart TD
  C5_start[Start] --> C5_openDrawer[OpenPartnerDrawer]
  C5_openDrawer --> C5_createDraft[CreateDraftContract]
  C5_createDraft --> C5_addTerm[AddAnnexTerm]
  C5_addTerm --> C5_updateTerm[UpdateAnnexTerm]
  C5_updateTerm --> C5_removeTerm[RemoveAnnexTerm]
  C5_removeTerm --> C5_verifyAnnex[VerifyAnnexJson]
  C5_verifyAnnex --> C5_end[End]

Steps

  • C5.1 (C5_openDrawer): Admin Console → Partners → open partner drawer.
  • C5.2 (C5_createDraft): Create a draft contract (or reuse an existing DRAFT contract).
  • C5.3 (C5_addTerm): Call API to add a term:
  • POST /api/partner/admin/partners/:partnerId/contracts/:contractId/terms/:annexType
  • annexType in services|commercial|cancellation
  • Body example: { "title": "TermTitle", "text": "Term body" }
  • C5.4 (C5_updateTerm): Call API to update that term:
  • PATCH /api/partner/admin/partners/:partnerId/contracts/:contractId/terms/:annexType/:termId
  • C5.5 (C5_removeTerm): Call API to remove that term:
  • DELETE /api/partner/admin/partners/:partnerId/contracts/:contractId/terms/:annexType/:termId
  • C5.6 (C5_verifyAnnexJson): Re-open drawer and confirm annex JSON reflects the CRUD actions.
  • If the UI doesn’t display annex JSON, validate via GET /api/partner/admin/partners/:partnerId/contracts/:contractId in Postman.

Workflow B: Edit Partner Service End-to-End

This workflow has two distinct paths: - B1 ServiceTexts: translation/enhancement pipeline for fields like description and short_description. - B2 ServiceProposals: admin approval workflow for restricted edits and activation.


B1: ServiceTexts workflow (description + short_description)

ServiceTexts status machine (reference)

DRAFT → AWAITING_ADMIN_ACTIONS → PROCESSING_AI → AWAITING_ADMIN_REVIEW → AWAITING_PARTNER_APPROVAL → AWAITING_ADMIN_APPROVAL → PUBLISHED

Failure: - PROCESSING_AI → FAILED (retry possible via admin “Run AI actions”).


UC-T1: Partner drafts a description revision and requests approval

Diagram

sequenceDiagram
  participant PartnerUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  PartnerUI->>ApiGateway: T1_openEditService
  ApiGateway->>PartnerService: T1_listFields(GET_/api/partner/:partnerId/services/:serviceId/text-fields)
  PartnerService->>Postgres: T1_readFields
  Postgres-->>PartnerService: T1_fieldList
  PartnerService-->>ApiGateway: T1_200_fieldList
  ApiGateway-->>PartnerUI: T1_renderFields

  PartnerUI->>ApiGateway: T1_saveDraft
  ApiGateway->>PartnerService: T1_createOrPatchRevision(POST_or_PATCH_revision)
  PartnerService->>Postgres: T1_insertNewRevision(status=DRAFT)
  Postgres-->>PartnerService: T1_revisionId
  PartnerService-->>ApiGateway: T1_201_or_200_revision
  ApiGateway-->>PartnerUI: T1_toastSaved

  PartnerUI->>ApiGateway: T1_requestApproval
  ApiGateway->>PartnerService: T1_requestApproval(POST_/api/partner/.../text-fields/revisions/:revisionId/request-approval)
  PartnerService->>Postgres: T1_updateStatus(AWAITING_ADMIN_ACTIONS)
  PartnerService-->>ApiGateway: T1_200_requested
  ApiGateway-->>PartnerUI: T1_toastRequested

Steps

  • T1.1 (T1_openEditService): Partner Console → Services → Edit a service → open Content tab.
  • T1.2 (T1_listFields): Select field key description.
  • T1.3 (T1_saveDraft): Fill Original text and requested actions (ensure translate and enhance are enabled for later UCs) → Click Save draft.
  • T1.4 (T1_requestApproval): Click Request publication.
  • T1.5 (T1_toastRequested): Confirm status shows Waiting for admin actions (or equivalent) and a success toast appears.

UC-T2: Admin runs AI actions and ingests AI results (PROCESSING_AI)

Diagram

sequenceDiagram
  participant AdminUI
  participant ApiGateway
  participant PartnerService
  participant AiService
  participant Postgres

  AdminUI->>ApiGateway: T2_openQueue
  ApiGateway->>PartnerService: T2_listQueue(GET_/api/partner/admin/service-texts/queue)
  PartnerService->>Postgres: T2_readQueue
  Postgres-->>PartnerService: T2_queue
  PartnerService-->>ApiGateway: T2_200_queue
  ApiGateway-->>AdminUI: T2_renderQueue

  AdminUI->>ApiGateway: T2_triggerAi
  ApiGateway->>PartnerService: T2_triggerAi(POST_/api/partner/admin/service-texts/revisions/:revisionId/trigger-ai)
  PartnerService->>Postgres: T2_updateStatus(PROCESSING_AI)
  PartnerService-->>AiService: T2_asyncJobRequested

  AiService->>ApiGateway: T2_submitResults(POST_/api/partner/internal/service-texts/revisions/:revisionId/results)
  ApiGateway->>PartnerService: T2_forwardResults
  PartnerService->>Postgres: T2_storeVariantsAndStatus(AWAITING_ADMIN_REVIEW_or_FAILED)
  PartnerService-->>ApiGateway: T2_200_resultsAccepted
  ApiGateway-->>AdminUI: T2_refresh

Steps

  • T2.1 (T2_openQueue): Admin Console → Service Text Review.
  • T2.2 (T2_triggerAi): Select the pending revision created in UC-T1 → Click Run AI actions.
  • T2.3 (T2_submitResults): Wait for AI processing to complete.
  • If AI service isn’t running, simulate results via Postman:
    • POST /api/partner/internal/service-texts/revisions/:revisionId/results
    • Body example:
    • { "status": "OK", "variants": [{"locale":"en","enhanced_text":"...","final_text":"..."}] }
  • T2.4 (T2_refresh): Confirm revision moves to Waiting for admin review (or FAILED if error).

UC-T3: Dual approval to publish (Admin → Partner → Admin)

Diagram

flowchart TD
  T3_start[Start] --> T3_adminEdit[AdminEditsFinalText]
  T3_adminEdit --> T3_requestPartner[AdminRequestsPartnerApproval]
  T3_requestPartner --> T3_partnerApprove[PartnerApproves]
  T3_partnerApprove --> T3_adminApprove[AdminFinalApprove]
  T3_adminApprove --> T3_published[Published]

Steps

  • T3.1 (T3_adminEdit): Admin Console → Service Text Review → open the revision → edit per-locale final text → Save.
  • T3.2 (T3_requestPartner): Click Request partner approval.
  • T3.3 (T3_partnerApprove): Partner Console → Services → Edit Service → Content tab → select the same field → Click Approve.
  • T3.4 (T3_adminApprove): Admin Console → Service Text Review → open revision → Click Approve.
  • T3.5 (T3_published): Confirm status becomes PUBLISHED and the service’s published text reflects the new value.

UC-T4: AI failure + retry

Diagram

sequenceDiagram
  participant AdminUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  AdminUI->>ApiGateway: T4_triggerAi
  ApiGateway->>PartnerService: T4_triggerAi(POST_trigger-ai)
  PartnerService->>Postgres: T4_setProcessing
  Postgres-->>PartnerService: T4_ok

  AdminUI->>ApiGateway: T4_submitFailed(Postman_optional)
  ApiGateway->>PartnerService: T4_ingestFailed(internal_results_status=FAILED)
  PartnerService->>Postgres: T4_setFailed
  PartnerService-->>ApiGateway: T4_200_failed

  AdminUI->>ApiGateway: T4_retryTriggerAi
  ApiGateway->>PartnerService: T4_triggerAi_again

Steps

  • T4.1 (T4_triggerAi): Admin Console → open revision → click Run AI actions.
  • T4.2 (T4_submitFailed): If needed, simulate failure via internal results endpoint with { "status": "FAILED", "error": "..." }.
  • T4.3 (T4_retryTriggerAi): In FAILED state, click Run AI actions again and confirm it returns to PROCESSING_AI.

B2: ServiceProposals workflow (restricted edits + activation)

Important behavior: - Partner can edit some fields directly. - For restricted fields or certain transitions, backend may: - Create a proposal, then return 403 Forbidden indicating approval is required.


UC-P1: Partner triggers proposal via restricted edit (403 + proposal created)

Diagram

sequenceDiagram
  participant PartnerUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  PartnerUI->>ApiGateway: P1_submitServiceUpdate(PATCH_/api/partner/:partnerId/services/:serviceId)
  ApiGateway->>PartnerService: P1_forwardPatch
  PartnerService->>PartnerService: P1_splitFields(update_vs_propose)
  PartnerService->>Postgres: P1_insertProposal(status=PENDING)
  PartnerService-->>ApiGateway: P1_403_proposalCreated
  ApiGateway-->>PartnerUI: P1_showForbidden

Steps

  • P1.1 (P1_submitServiceUpdate): Partner Console → Services → Edit service → General tab → change a field that requires approval (team-specific; often status=ACTIVE is reliable).
  • P1.2 (P1_showForbidden): Click Save; confirm UI reports that admin approval is required.
  • P1.3 (P1_insertProposal): Go to the new Proposals tab/section (after UI wiring) and confirm a PENDING proposal exists.

UC-P2: Admin approves a proposal → changes applied

Diagram

sequenceDiagram
  participant AdminUI
  participant ApiGateway
  participant PartnerService
  participant Postgres

  AdminUI->>ApiGateway: P2_openPartnerServices
  ApiGateway->>PartnerService: P2_listServices(GET_/api/partner/:partnerId/services)
  PartnerService-->>ApiGateway: P2_200_services
  ApiGateway-->>AdminUI: P2_renderServices

  AdminUI->>ApiGateway: P2_listProposals(GET_/api/partner/:partnerId/services/:serviceId/proposals?status=PENDING)
  ApiGateway->>PartnerService: P2_forwardList
  PartnerService->>Postgres: P2_readProposals
  PartnerService-->>ApiGateway: P2_200_proposals
  ApiGateway-->>AdminUI: P2_renderProposals

  AdminUI->>ApiGateway: P2_approve(POST_/api/partner/:partnerId/services/:serviceId/proposals/:proposalId/approve)
  ApiGateway->>PartnerService: P2_forwardApprove
  PartnerService->>Postgres: P2_applyProposal_and_updateStatus(APPROVED)
  PartnerService-->>ApiGateway: P2_200_approved
  ApiGateway-->>AdminUI: P2_removeFromList

Steps

  • P2.1 (P2_openPartnerServices): Admin Console → Partners → open partner drawer → Services section.
  • P2.2 (P2_listProposals): Expand a service entry and confirm pending proposals show.
  • P2.3 (P2_approve): Click Approve.
  • P2.4 (P2_applyProposal_and_updateStatus): Verify the service reflects the change (refresh partner-console service view).

UC-P3: Admin rejects a proposal → changes not applied

Diagram

flowchart TD
  P3_start[Start] --> P3_findPending[FindPendingProposal]
  P3_findPending --> P3_reject[RejectProposal]
  P3_reject --> P3_verifyNotApplied[VerifyChangeNotApplied]
  P3_verifyNotApplied --> P3_end[End]

Steps

  • P3.1 (P3_findPending): Ensure a PENDING proposal exists (use UC-P1).
  • P3.2 (P3_reject): Admin Console → reject the proposal.
  • P3.3 (P3_verifyNotApplied): Confirm the underlying service does not reflect the proposed change.

UC-P4: Partner requests activation (status=ACTIVE) → proposal → admin approves activation

Diagram

sequenceDiagram
  participant PartnerUI
  participant ApiGateway
  participant PartnerService
  participant AdminUI

  PartnerUI->>ApiGateway: P4_requestActive(PATCH_service_status_ACTIVE)
  ApiGateway->>PartnerService: P4_forwardPatch
  PartnerService-->>ApiGateway: P4_403_activationProposalCreated
  ApiGateway-->>PartnerUI: P4_showRequiresApproval

  AdminUI->>ApiGateway: P4_adminApproveProposal(POST_approve)
  ApiGateway->>PartnerService: P4_forwardApprove
  PartnerService-->>AdminUI: P4_200_approved

Steps

  • P4.1 (P4_requestActive): Partner Console → Edit service → attempt to set status to ACTIVE and save.
  • P4.2 (P4_showRequiresApproval): Confirm UI indicates approval is required.
  • P4.3 (P4_adminApproveProposal): Admin Console → approve the proposal.
  • P4.4: Partner Console → refresh service and confirm status becomes ACTIVE.

Automated tests to implement (coverage map)

Integration tests (Jest) — /tests/integration

  • Contracts
  • UC-C1/2/3/4: tests/integration/src/services/partner-service/partner-contracts.test.ts
  • ServiceTexts
  • UC-T1/2/3/4: tests/integration/src/services/partner-service/service-texts.test.ts
  • ServiceProposals
  • UC-P1/2/3/4: tests/integration/src/services/partner-service/service-proposals.test.ts

Unit tests (Jest) — services/partner-service

  • Contract transition matrix
  • ServiceTexts request/approve status transitions
  • Proposal creation logic for restricted fields