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-consoleand approve proposals/service texts, and update partner contract status. - Partner user: can access
partner-consoleand 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
SENTin the drawer.
Expected results¶
- A new contract exists with status
SENT. - Contract is visible to the partner in
partner-consoleContracts 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
SENTcontract 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
SIGNEDand 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
ACTIVEcontract back toSIGNED. - 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
DRAFTcontract). - C5.3 (C5_addTerm): Call API to add a term:
POST /api/partner/admin/partners/:partnerId/contracts/:contractId/terms/:annexTypeannexTypeinservices|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/:contractIdin 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
translateandenhanceare 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
FAILEDif 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
FAILEDstate, click Run AI actions again and confirm it returns toPROCESSING_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=ACTIVEis 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
PENDINGproposal 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
PENDINGproposal 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
ACTIVEand 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