From 28774f419c569f0b4b84290682163180ddc24272 Mon Sep 17 00:00:00 2001 From: Ida Dittrich Date: Mon, 1 Dec 2025 17:03:39 +0100 Subject: [PATCH] extended PEK routes and included swisstopo connector --- config.ini | 9 +- docs/code-documentation/date-time-handling.md | 365 ++++ docs/code-documentation/security-api.md | 1 + .../chat-playground-page-requirements.md | 786 ++++++++ .../chat-playground-workflow-journeys.md | 542 ++++++ .../connection-page-customer-journeys.md | 293 +++ .../connection-page-requirements.md | 491 +++++ .../dynamic-forms-and-pagination.md | 689 +++++++ .../file-page-customer-journeys.md | 335 ++++ .../file-page-requirements.md | 574 ++++++ .../prompt-page-customer-journeys.md | 349 ++++ .../prompt-page-requirements.md | 549 ++++++ .../user-page-customer-journeys.md | 516 +++++ .../user-page-requirements.md | 843 +++++++++ .../voice-service-customer-journeys.md | 474 +++++ .../voice-service-page-requirements.md | 1081 +++++++++++ .../workflow-page-customer-journeys.md | 768 ++++++++ .../workflow-page-requirements.md | 555 ++++++ .../workflow-routes-frontend.md | 1677 ----------------- .../07-environment.md | 1 + .../14-stac-api-integration.md | 491 +++++ .../README.md | 2 + .../20251127-113948-147_m_1_0_0/message.json | 19 - .../message_text.txt | 1 - .../20251127-113957-841_m_1_1_0/message.json | 19 - .../message_text.txt | 6 - .../20251127-113958-980_m_1_1_0/message.json | 19 - .../message_text.txt | 3 - .../20251127-114024-001_m_1_1_1/message.json | 19 - .../message_text.txt | 4 - .../document_001_metadata.json | 12 - .../document_001_test_document_memo.docx | Bin 36938 -> 0 bytes .../document_002_metadata.json | 12 - .../document_002_structured_content.json | 106 -- .../20251127-114110-763_m_1_1_2/message.json | 19 - .../message_text.txt | 4 - .../document_001_memo_analysis_report.txt | 24 - .../document_001_metadata.json | 12 - .../document_002_metadata.json | 12 - .../document_002_structured_content_1.json | 134 -- .../20251127-114147-275_m_1_1_3/message.json | 19 - .../message_text.txt | 4 - .../document_001_memo_analysis_summary.txt | 10 - .../document_001_metadata.json | 12 - .../document_002_metadata.json | 12 - .../document_002_structured_content_2.json | 52 - .../20251127-114229-639_m_1_1_4/message.json | 19 - .../message_text.txt | 4 - .../document_001_memo_analysis_report_1.txt | 22 - .../document_001_metadata.json | 12 - .../document_002_metadata.json | 12 - .../document_002_structured_content_3.json | 136 -- .../20251127-114301-221_m_1_1_5/message.json | 19 - .../message_text.txt | 4 - .../document_001_memo_summary.txt | 12 - .../document_001_metadata.json | 12 - .../document_002_metadata.json | 12 - .../document_002_structured_content_4.json | 62 - .../20251127-114309-479_m_1_1_0/message.json | 19 - .../message_text.txt | 4 - .../20251127-114310-696_m_1_0_0/message.json | 19 - .../message_text.txt | 4 - ...51119-100038-001-intentanalysis_prompt.txt | 48 - ...119-100041-002-intentanalysis_response.txt | 10 - ...51119-103736-003-intentanalysis_prompt.txt | 48 - ...119-103742-004-intentanalysis_response.txt | 16 - ...51119-103802-005-intentanalysis_prompt.txt | 48 - ...119-103808-006-intentanalysis_response.txt | 16 - ...51119-104317-007-intentanalysis_prompt.txt | 88 - ...119-104324-008-intentanalysis_response.txt | 18 - ...51119-104747-009-intentanalysis_prompt.txt | 88 - ...119-104754-010-intentanalysis_response.txt | 17 - ...51119-104856-011-intentanalysis_prompt.txt | 88 - ...119-104902-012-intentanalysis_response.txt | 17 - ...51119-105033-013-intentanalysis_prompt.txt | 88 - ...119-105039-014-intentanalysis_response.txt | 17 - ...119-110440-016-intentanalysis_response.txt | 17 - ...51119-125234-017-intentanalysis_prompt.txt | 89 - ...119-125239-018-intentanalysis_response.txt | 16 - ...51119-125657-019-intentanalysis_prompt.txt | 89 - ...119-125702-020-intentanalysis_response.txt | 16 - ...51119-125750-021-intentanalysis_prompt.txt | 89 - ...119-125756-022-intentanalysis_response.txt | 20 - ...51119-141840-023-intentanalysis_prompt.txt | 89 - ...119-141848-024-intentanalysis_response.txt | 16 - ...51119-144901-025-intentanalysis_prompt.txt | 89 - ...119-144909-026-intentanalysis_response.txt | 17 - ...51119-145121-027-intentanalysis_prompt.txt | 89 - ...119-145129-028-intentanalysis_response.txt | 17 - ...51119-145151-029-intentanalysis_prompt.txt | 89 - ...119-145202-030-intentanalysis_response.txt | 18 - ...51119-145222-031-intentanalysis_prompt.txt | 89 - ...119-145229-032-intentanalysis_response.txt | 14 - ...51119-145449-033-intentanalysis_prompt.txt | 89 - ...119-145452-034-intentanalysis_response.txt | 12 - ...51120-154518-035-intentanalysis_prompt.txt | 89 - ...120-154524-036-intentanalysis_response.txt | 18 - ...51120-154559-037-intentanalysis_prompt.txt | 89 - ...120-154607-038-intentanalysis_response.txt | 17 - ...51120-154715-039-intentanalysis_prompt.txt | 89 - ...120-154718-040-intentanalysis_response.txt | 10 - ...51120-154742-041-intentanalysis_prompt.txt | 89 - ...120-154746-042-intentanalysis_response.txt | 10 - ...251127-113945-043-userintention_prompt.txt | 28 - ...1127-113947-044-userintention_response.txt | 8 - ...51127-113949-045-intentanalysis_prompt.txt | 30 - ...127-113951-046-intentanalysis_response.txt | 14 - .../20251127-113951-047-taskplan_prompt.txt | 100 - .../20251127-113957-048-taskplan_response.txt | 20 - .../20251127-113959-049-actionplan_prompt.txt | 87 - ...0251127-114003-050-actionplan_response.txt | 10 - .../20251127-114003-051-paramplan_prompt.txt | 62 - ...20251127-114005-052-paramplan_response.txt | 10 - ...-114007-053-document_generation_prompt.txt | 84 - ...14016-054-document_generation_response.txt | 89 - ...7-055-document_generation_final_result.txt | 105 -- ...127-114022-056-renderer_styling_prompt.txt | 66 - ...7-114022-057-renderer_styling_response.txt | 56 - ...14022-058-document_generation_response.txt | 4 - ...27-114024-059-contentvalidation_prompt.txt | 57 - ...-114031-060-contentvalidation_response.txt | 24 - .../20251127-114031-061-refinement_prompt.txt | 79 - ...0251127-114032-062-refinement_response.txt | 6 - .../20251127-114033-063-actionplan_prompt.txt | 92 - ...0251127-114037-064-actionplan_response.txt | 10 - .../20251127-114038-065-paramplan_prompt.txt | 62 - ...20251127-114040-066-paramplan_response.txt | 10 - ...1127-114102-067-extraction_merged_text.txt | 103 - ...-114103-068-document_generation_prompt.txt | 189 -- ...14109-069-document_generation_response.txt | 117 -- ...9-070-document_generation_final_result.txt | 133 -- ...14109-071-document_generation_response.txt | 4 - ...27-114110-072-contentvalidation_prompt.txt | 57 - ...-114115-073-contentvalidation_response.txt | 24 - .../20251127-114115-074-refinement_prompt.txt | 77 - ...0251127-114116-075-refinement_response.txt | 6 - .../20251127-114118-076-actionplan_prompt.txt | 96 - ...0251127-114127-077-actionplan_response.txt | 10 - .../20251127-114127-078-paramplan_prompt.txt | 62 - ...20251127-114129-079-paramplan_response.txt | 10 - ...1127-114140-080-extraction_merged_text.txt | 11 - ...-114141-081-document_generation_prompt.txt | 97 - ...14146-082-document_generation_response.txt | 49 - ...6-083-document_generation_final_result.txt | 51 - ...14146-084-document_generation_response.txt | 4 - ...27-114147-085-contentvalidation_prompt.txt | 57 - ...-114155-086-contentvalidation_response.txt | 24 - .../20251127-114155-087-refinement_prompt.txt | 75 - ...0251127-114157-088-refinement_response.txt | 6 - .../20251127-114158-089-actionplan_prompt.txt | 100 - ...0251127-114159-090-actionplan_response.txt | 10 - .../20251127-114200-091-paramplan_prompt.txt | 62 - ...20251127-114201-092-paramplan_response.txt | 10 - ...1127-114214-093-extraction_merged_text.txt | 65 - ...-114214-094-document_generation_prompt.txt | 151 -- ...14228-095-document_generation_response.txt | 121 -- ...8-096-document_generation_final_result.txt | 135 -- ...14228-097-document_generation_response.txt | 4 - ...27-114229-098-contentvalidation_prompt.txt | 57 - ...-114235-099-contentvalidation_response.txt | 24 - .../20251127-114235-100-refinement_prompt.txt | 80 - ...0251127-114237-101-refinement_response.txt | 6 - .../20251127-114238-102-actionplan_prompt.txt | 104 - ...0251127-114240-103-actionplan_response.txt | 10 - .../20251127-114241-104-paramplan_prompt.txt | 62 - ...20251127-114242-105-paramplan_response.txt | 10 - ...1127-114250-106-extraction_merged_text.txt | 14 - ...-114251-107-document_generation_prompt.txt | 100 - ...14259-108-document_generation_response.txt | 57 - ...9-109-document_generation_final_result.txt | 61 - ...14259-110-document_generation_response.txt | 4 - ...27-114301-111-contentvalidation_prompt.txt | 57 - ...-114306-112-contentvalidation_response.txt | 24 - .../20251127-114306-113-refinement_prompt.txt | 75 - ...0251127-114308-114-refinement_response.txt | 6 - ...1201-155926-001-intentanalysis_prompt.txt} | 2 +- ...201-155933-002-intentanalysis_response.txt | 17 + .../connectors/connectorSwissTopoMapServer.py | 419 ++++ modules/routes/routeRealEstate.py | 854 +++++++-- requirements.txt | 8 +- 180 files changed, 10905 insertions(+), 8458 deletions(-) create mode 100644 docs/code-documentation/date-time-handling.md create mode 100644 docs/frontend-documentation/chat-playground-page-requirements.md create mode 100644 docs/frontend-documentation/chat-playground-workflow-journeys.md create mode 100644 docs/frontend-documentation/connection-page-customer-journeys.md create mode 100644 docs/frontend-documentation/connection-page-requirements.md create mode 100644 docs/frontend-documentation/dynamic-forms-and-pagination.md create mode 100644 docs/frontend-documentation/file-page-customer-journeys.md create mode 100644 docs/frontend-documentation/file-page-requirements.md create mode 100644 docs/frontend-documentation/prompt-page-customer-journeys.md create mode 100644 docs/frontend-documentation/prompt-page-requirements.md create mode 100644 docs/frontend-documentation/user-page-customer-journeys.md create mode 100644 docs/frontend-documentation/user-page-requirements.md create mode 100644 docs/frontend-documentation/voice-service-customer-journeys.md create mode 100644 docs/frontend-documentation/voice-service-page-requirements.md create mode 100644 docs/frontend-documentation/workflow-page-customer-journeys.md create mode 100644 docs/frontend-documentation/workflow-page-requirements.md delete mode 100644 docs/frontend-documentation/workflow-routes-frontend.md create mode 100644 docs/real-estate-feature-integration-guide/14-stac-api-integration.md delete mode 100644 logs/debug/messages/20251127-113948-147_m_1_0_0/message.json delete mode 100644 logs/debug/messages/20251127-113948-147_m_1_0_0/message_text.txt delete mode 100644 logs/debug/messages/20251127-113957-841_m_1_1_0/message.json delete mode 100644 logs/debug/messages/20251127-113957-841_m_1_1_0/message_text.txt delete mode 100644 logs/debug/messages/20251127-113958-980_m_1_1_0/message.json delete mode 100644 logs/debug/messages/20251127-113958-980_m_1_1_0/message_text.txt delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/message.json delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/message_text.txt delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/round1_task1_action1_results/document_001_metadata.json delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/round1_task1_action1_results/document_001_test_document_memo.docx delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/round1_task1_action1_results/document_002_metadata.json delete mode 100644 logs/debug/messages/20251127-114024-001_m_1_1_1/round1_task1_action1_results/document_002_structured_content.json delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/message.json delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/message_text.txt delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/round1_task1_action2_results/document_001_memo_analysis_report.txt delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/round1_task1_action2_results/document_001_metadata.json delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/round1_task1_action2_results/document_002_metadata.json delete mode 100644 logs/debug/messages/20251127-114110-763_m_1_1_2/round1_task1_action2_results/document_002_structured_content_1.json delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/message.json delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/message_text.txt delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/round1_task1_action3_results/document_001_memo_analysis_summary.txt delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/round1_task1_action3_results/document_001_metadata.json delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/round1_task1_action3_results/document_002_metadata.json delete mode 100644 logs/debug/messages/20251127-114147-275_m_1_1_3/round1_task1_action3_results/document_002_structured_content_2.json delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/message.json delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/message_text.txt delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/round1_task1_action4_results/document_001_memo_analysis_report_1.txt delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/round1_task1_action4_results/document_001_metadata.json delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/round1_task1_action4_results/document_002_metadata.json delete mode 100644 logs/debug/messages/20251127-114229-639_m_1_1_4/round1_task1_action4_results/document_002_structured_content_3.json delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/message.json delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/message_text.txt delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/round1_task1_action5_results/document_001_memo_summary.txt delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/round1_task1_action5_results/document_001_metadata.json delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/round1_task1_action5_results/document_002_metadata.json delete mode 100644 logs/debug/messages/20251127-114301-221_m_1_1_5/round1_task1_action5_results/document_002_structured_content_4.json delete mode 100644 logs/debug/messages/20251127-114309-479_m_1_1_0/message.json delete mode 100644 logs/debug/messages/20251127-114309-479_m_1_1_0/message_text.txt delete mode 100644 logs/debug/messages/20251127-114310-696_m_1_0_0/message.json delete mode 100644 logs/debug/messages/20251127-114310-696_m_1_0_0/message_text.txt delete mode 100644 logs/debug/prompts/20251119-100038-001-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-100041-002-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-103736-003-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-103742-004-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-103802-005-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-103808-006-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-104317-007-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-104324-008-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-104747-009-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-104754-010-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-104856-011-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-104902-012-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-105033-013-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-105039-014-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-110440-016-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-125234-017-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-125239-018-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-125657-019-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-125702-020-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-125750-021-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-125756-022-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-141840-023-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-141848-024-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-144901-025-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-144909-026-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-145121-027-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-145129-028-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-145151-029-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-145202-030-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-145222-031-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-145229-032-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251119-145449-033-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251119-145452-034-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251120-154518-035-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251120-154524-036-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251120-154559-037-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251120-154607-038-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251120-154715-039-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251120-154718-040-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251120-154742-041-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251120-154746-042-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251127-113945-043-userintention_prompt.txt delete mode 100644 logs/debug/prompts/20251127-113947-044-userintention_response.txt delete mode 100644 logs/debug/prompts/20251127-113949-045-intentanalysis_prompt.txt delete mode 100644 logs/debug/prompts/20251127-113951-046-intentanalysis_response.txt delete mode 100644 logs/debug/prompts/20251127-113951-047-taskplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-113957-048-taskplan_response.txt delete mode 100644 logs/debug/prompts/20251127-113959-049-actionplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114003-050-actionplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114003-051-paramplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114005-052-paramplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114007-053-document_generation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114016-054-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114017-055-document_generation_final_result.txt delete mode 100644 logs/debug/prompts/20251127-114022-056-renderer_styling_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114022-057-renderer_styling_response.txt delete mode 100644 logs/debug/prompts/20251127-114022-058-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114024-059-contentvalidation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114031-060-contentvalidation_response.txt delete mode 100644 logs/debug/prompts/20251127-114031-061-refinement_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114032-062-refinement_response.txt delete mode 100644 logs/debug/prompts/20251127-114033-063-actionplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114037-064-actionplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114038-065-paramplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114040-066-paramplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114102-067-extraction_merged_text.txt delete mode 100644 logs/debug/prompts/20251127-114103-068-document_generation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114109-069-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114109-070-document_generation_final_result.txt delete mode 100644 logs/debug/prompts/20251127-114109-071-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114110-072-contentvalidation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114115-073-contentvalidation_response.txt delete mode 100644 logs/debug/prompts/20251127-114115-074-refinement_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114116-075-refinement_response.txt delete mode 100644 logs/debug/prompts/20251127-114118-076-actionplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114127-077-actionplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114127-078-paramplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114129-079-paramplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114140-080-extraction_merged_text.txt delete mode 100644 logs/debug/prompts/20251127-114141-081-document_generation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114146-082-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114146-083-document_generation_final_result.txt delete mode 100644 logs/debug/prompts/20251127-114146-084-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114147-085-contentvalidation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114155-086-contentvalidation_response.txt delete mode 100644 logs/debug/prompts/20251127-114155-087-refinement_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114157-088-refinement_response.txt delete mode 100644 logs/debug/prompts/20251127-114158-089-actionplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114159-090-actionplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114200-091-paramplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114201-092-paramplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114214-093-extraction_merged_text.txt delete mode 100644 logs/debug/prompts/20251127-114214-094-document_generation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114228-095-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114228-096-document_generation_final_result.txt delete mode 100644 logs/debug/prompts/20251127-114228-097-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114229-098-contentvalidation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114235-099-contentvalidation_response.txt delete mode 100644 logs/debug/prompts/20251127-114235-100-refinement_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114237-101-refinement_response.txt delete mode 100644 logs/debug/prompts/20251127-114238-102-actionplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114240-103-actionplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114241-104-paramplan_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114242-105-paramplan_response.txt delete mode 100644 logs/debug/prompts/20251127-114250-106-extraction_merged_text.txt delete mode 100644 logs/debug/prompts/20251127-114251-107-document_generation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114259-108-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114259-109-document_generation_final_result.txt delete mode 100644 logs/debug/prompts/20251127-114259-110-document_generation_response.txt delete mode 100644 logs/debug/prompts/20251127-114301-111-contentvalidation_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114306-112-contentvalidation_response.txt delete mode 100644 logs/debug/prompts/20251127-114306-113-refinement_prompt.txt delete mode 100644 logs/debug/prompts/20251127-114308-114-refinement_response.txt rename logs/debug/prompts/{20251119-110433-015-intentanalysis_prompt.txt => 20251201-155926-001-intentanalysis_prompt.txt} (98%) create mode 100644 logs/debug/prompts/20251201-155933-002-intentanalysis_response.txt create mode 100644 modules/connectors/connectorSwissTopoMapServer.py diff --git a/config.ini b/config.ini index ab0b6712..88a80b11 100644 --- a/config.ini +++ b/config.ini @@ -34,4 +34,11 @@ Web_Crawl_RETRY_DELAY = 2 # Web Research configuration Web_Research_MAX_DEPTH = 2 Web_Research_MAX_LINKS_PER_DOMAIN = 4 -Web_Research_CRAWL_TIMEOUT_MINUTES = 10 \ No newline at end of file +Web_Research_CRAWL_TIMEOUT_MINUTES = 10 + +# STAC API Connector configuration (Swiss Topo) +Connector_StacSwisstopo_BASE_URL = https://data.geo.admin.ch/api/stac/v1 +Connector_StacSwisstopo_TIMEOUT = 30 +Connector_StacSwisstopo_MAX_RETRIES = 3 +Connector_StacSwisstopo_RETRY_DELAY = 1.0 +Connector_StacSwisstopo_ENABLE_CACHE = True \ No newline at end of file diff --git a/docs/code-documentation/date-time-handling.md b/docs/code-documentation/date-time-handling.md new file mode 100644 index 00000000..b77dc980 --- /dev/null +++ b/docs/code-documentation/date-time-handling.md @@ -0,0 +1,365 @@ +# Date and Time Handling + +This document describes how dates and times are handled throughout the gateway project, including storage formats, transformations, and retrieval mechanisms. + +## Overview + +The gateway uses **Unix timestamps** (floats representing seconds since epoch) as the standard format for all date and time values. This ensures consistency across different database backends and eliminates timezone-related issues by always working in UTC. + +## Core Components + +### Time Utilities Module + +The primary module for date/time handling is `modules/shared/timeUtils.py`, which provides: + +#### `getUtcTimestamp() -> float` + +Returns the current UTC timestamp as a float (seconds since Unix epoch with millisecond precision). + +**Implementation:** +- Uses Python's `time.time()` which returns seconds since epoch as a float +- Provides millisecond precision +- Always returns UTC time + +#### `getUtcNow() -> datetime` + +Returns the current UTC time as a `datetime` object with timezone information. + +#### `parseTimestamp(value: Any, default: Optional[float] = None) -> Optional[float]` + +**Critical function for database retrieval** - Parses timestamp values from various formats and converts them to float. + +This function handles the transformation/decoding of timestamps when reading from the database, especially important for PostgreSQL connectors that may return numeric fields as strings in some environments (e.g., Azure PostgreSQL). + +**Supported input formats:** +- `float`: Returns as-is +- `int`: Converts to float +- `str`: Attempts to parse as numeric string (e.g., "1234567890.123") +- `None`: Returns default value (or None if no default provided) + +**Usage:** Call `parseTimestamp()` with the database value and an optional default. For example: `parseTimestamp(db_value, default=getUtcTimestamp())`. + +**Why this is needed:** +- PostgreSQL connectors (especially Azure PostgreSQL) may return numeric fields as strings +- Ensures consistent float type regardless of database return format +- Provides safe fallback with default values + +#### `createExpirationTimestamp(expiresInSeconds: int) -> float` + +Creates an expiration timestamp by adding seconds to the current UTC timestamp. Call with the number of seconds until expiration, for example: `createExpirationTimestamp(3600)` for 1 hour from now. + +## Database Storage + +### Storage Format + +All timestamps are stored in the database as **floats** (Unix timestamps in seconds): + +- **PostgreSQL**: Stored as `NUMERIC` or `DOUBLE PRECISION` type +- **JSON Database**: Stored as JSON number (float) in record files + +### Saving Timestamps + +#### PostgreSQL Connector (`connectorDbPostgre.py`) + +When saving records, timestamp fields (`_createdAt`, `_modifiedAt`) are handled specially. The connector checks if the value is a string and attempts to convert it to float before storing. + +**Process:** +1. Timestamp values are converted to float if they're strings +2. Stored directly as numeric values in PostgreSQL +3. No encryption or encoding - stored as plain numeric values + +#### JSON Connector (`connectorDbJson.py`) + +Timestamps are stored directly as JSON numbers. The connector calls `getUtcTimestamp()` to get the current time and sets `_createdAt` on creation and `_modifiedAt` on every save operation. + +**Process:** +1. Timestamps are generated as floats using `getUtcTimestamp()` +2. Stored as JSON numbers in record files +3. No transformation needed - JSON natively supports float numbers + +### Retrieving Timestamps + +#### PostgreSQL Connector + +When reading from PostgreSQL, timestamps may be returned in different formats: + +- **Expected**: Float values +- **Actual (Azure PostgreSQL)**: Sometimes returned as strings +- **Solution**: Use `parseTimestamp()` to normalize + +**Example from code:** In `interfaceDbChatObjects.py`, timestamps are parsed using `parseTimestamp(msg.get("publishedAt"), default=getUtcTimestamp())`. + +#### JSON Connector + +Timestamps are read directly from JSON and typically remain as floats, but `parseTimestamp()` is still used for safety to ensure consistent float type regardless of JSON parsing quirks. Call `parseTimestamp(record.get("timestamp"), default=getUtcTimestamp())` when reading timestamp fields. + +## Data Model Definitions + +Timestamps are defined in Pydantic models using the `float` type with `getUtcTimestamp` as the default factory. For example, in `ChatLog` model, the `timestamp` field uses `Field(default_factory=getUtcTimestamp, ...)`. + +**Common timestamp fields:** +- `_createdAt`: When the record was created +- `_modifiedAt`: When the record was last modified +- `publishedAt`: When a message was published +- `timestamp`: Generic timestamp field +- `expiresAt`: When something expires +- `connectedAt`: When a connection was established +- `lastChecked`: When something was last verified +- `creationDate`: When something was created + +## Transformation Flow + +### Saving to Database + +``` +Application Code + ↓ +getUtcTimestamp() → float (e.g., 1234567890.123) + ↓ +Database Connector + ↓ +PostgreSQL: Store as NUMERIC/DOUBLE PRECISION +JSON: Store as JSON number +``` + +### Reading from Database + +``` +Database + ↓ +PostgreSQL: May return as float, int, or string +JSON: Returns as float (or int if no decimals) + ↓ +parseTimestamp() → Normalizes to float + ↓ +Application Code (always receives float) +``` + +## Key Points + +1. **No Encryption**: Timestamps are **not encrypted**. They are stored as plain numeric values (floats) in the database. The "encrypted format" you may have seen refers to the numeric Unix timestamp format, which is not human-readable but is not encrypted. + +2. **Type Transformation**: The main transformation happens when **reading** from the database: + - Database may return timestamps as strings (especially Azure PostgreSQL) + - `parseTimestamp()` converts strings/int/float → float + - This ensures consistent float type in application code + +3. **UTC Only**: All timestamps are in UTC. No timezone conversions happen at the database level. + +4. **Millisecond Precision**: Timestamps use float type, providing millisecond precision (e.g., `1234567890.123`). + +5. **Default Values**: When timestamps are missing or invalid, `parseTimestamp()` can provide safe defaults using the `default` parameter. + +## Usage Examples + +### Creating a Record with Timestamps + +When creating records, call `getUtcTimestamp()` to set `_createdAt` and `_modifiedAt` fields. These are typically auto-set by the database connectors. + +### Reading and Using Timestamps + +After retrieving a record from the database, use `parseTimestamp(record.get("publishedAt"), default=getUtcTimestamp())` to safely parse the timestamp value before using it for filtering or comparison. + +### Filtering by Timestamp + +When filtering messages or records by timestamp, iterate through the results and use `parseTimestamp(msg.get("publishedAt"), default=getUtcTimestamp())` to parse each timestamp, then compare against your threshold value. + +### Sorting by Timestamp + +When sorting logs or records by timestamp, use `parseTimestamp()` in the sort key function, for example: `logs.sort(key=lambda x: parseTimestamp(x.get("timestamp"), default=0))`. + +## Common Patterns + +### Automatic Timestamp Management + +Database connectors automatically manage `_createdAt` and `_modifiedAt`: + +- `_createdAt`: Set only on record creation (if not already present) +- `_modifiedAt`: Updated on every save operation + +### Timestamp Filtering + +When filtering records by timestamp, always use `parseTimestamp()` to handle all database return types. Call `parseTimestamp(record.get("timestamp"), default=0)` before comparison. Do not directly compare timestamp values as they may be strings from the database. + +### Expiration Timestamps + +For expiration logic, use `createExpirationTimestamp(3600)` to create an expiration timestamp, then compare it with the current time using `getUtcTimestamp()`. Parse any stored expiration timestamps using `parseTimestamp()` before comparison. + +## Database-Specific Notes + +### PostgreSQL (Azure) + +- May return numeric fields as strings +- Always use `parseTimestamp()` when reading timestamp fields +- Stored as `NUMERIC` or `DOUBLE PRECISION` type + +### JSON Database + +- Timestamps stored as JSON numbers +- Usually returned as floats, but `parseTimestamp()` provides safety +- No special handling needed beyond normalization + +## Troubleshooting + +### Issue: Timestamp is a string instead of float + +**Solution**: Use `parseTimestamp()` to convert: `parseTimestamp(string_timestamp, default=getUtcTimestamp())`. + +### Issue: Timestamp is None + +**Solution**: Provide a default value: `parseTimestamp(record.get("timestamp"), default=getUtcTimestamp())`. + +### Issue: Timestamp comparison fails + +**Cause**: Comparing string to float +**Solution**: Always parse first using `parseTimestamp(value, default=0)` before any comparison operations. + +## Summary + +The date/time handling system: + +1. **Stores** timestamps as Unix timestamps (floats) in UTC +2. **Transforms** database return values (string/int/float) → float using `parseTimestamp()` +3. **Provides** utilities for timestamp generation, parsing, and expiration +4. **Ensures** consistency across different database backends +5. **Handles** edge cases (None values, string returns, invalid formats) + +The transformation you mentioned is the **type normalization** that happens when reading from the database, not encryption. Timestamps are stored as plain numeric values and converted to consistent float types for application use. + +--- + +## Frontend Requirements and Implementation + +### API Response Format + +The backend API returns timestamps as **Unix timestamps (floats)** in all JSON responses. Timestamps are always in UTC and represented as numbers (not strings). + +**Example API Response:** The API returns timestamps as numeric values in JSON, for example: `_createdAt: 1704067200.123`, `_modifiedAt: 1704067300.456`, `publishedAt: 1704067250.789`, `expiresAt: 1704153600.0`. + +**Important Notes:** +- Timestamps are **always numbers** (float) in JSON responses +- All timestamps are in **UTC** (no timezone information in the value) +- Timestamps have **millisecond precision** (decimal places) +- Timestamp fields may be `null` or `undefined` if not set + +### Frontend Requirements + +#### 1. Timestamp Decoding Module + +The frontend **must** implement a core timestamp utility module that handles: + +- **Decoding/parsing** timestamp values from API responses +- **Type normalization** (handles number, string, null, undefined) +- **Conversion** to JavaScript Date objects +- **Formatting** for display (relative time, absolute date/time) +- **Timezone handling** (convert UTC to user's local timezone) + +#### 2. Required Functionality + +The frontend timestamp module must provide: + +1. **Parse/Decode Function**: Convert API timestamp (number/string/null) → JavaScript Date +2. **Format Functions**: Convert Date → human-readable strings +3. **Relative Time**: "2 hours ago", "in 5 minutes", etc. +4. **Absolute Time**: "2024-01-01 12:30:45 UTC" or localized format +5. **Comparison Utilities**: Compare timestamps, check expiration, etc. +6. **Safe Defaults**: Handle null/undefined/invalid values gracefully + +#### 3. Display Requirements + +Based on frontend documentation requirements, timestamps should be displayed as: + +- **List Views**: Relative time ("2 hours ago") for recent items, absolute date for older items +- **Detail Views**: Absolute date/time with timezone information +- **Filters**: Date/time pickers that convert to/from Unix timestamps +- **Sorting**: Sort by timestamp value (numeric comparison) + +### Core Frontend Timestamp Module + +The frontend should implement a core timestamp utility module in `src/utils/timestampUtils.ts` (or `.js`) that provides the following functions: + +#### Required Functions + +- **`parseTimestamp(value, defaultValue)`**: Parse a timestamp value from the API and convert to JavaScript Date. Handles number, string, null, and undefined inputs. Validates timestamp range (1970-2100) and converts seconds to milliseconds for JavaScript Date constructor. + +- **`getUtcTimestamp()`**: Get current UTC timestamp as Unix timestamp (float). Returns `Date.now() / 1000`. + +- **`formatRelativeTime(timestamp, options)`**: Format timestamp as relative time string. Returns strings like "just now", "2 minutes ago", "3 hours ago", "2 days ago", or "in 5 minutes" for future timestamps. Options include `includeSeconds`, `futurePrefix`, and `pastSuffix`. + +- **`formatAbsoluteTime(timestamp, options)`**: Format timestamp as absolute date/time string. Options include `includeTime`, `includeSeconds`, `includeTimezone`, and `format` ('iso', 'local', or 'utc'). + +- **`formatTimestamp(timestamp, options)`**: Smart formatting that uses relative time for recent items (default < 24 hours) and absolute time for older items. Options include `relativeThreshold`, `showRelative`, and `showAbsolute`. + +- **`isExpired(expiresAt)`**: Check if a timestamp has expired (is in the past). Returns true if expired, false otherwise. + +- **`isFuture(timestamp)`**: Check if a timestamp is in the future. Returns true if in future, false otherwise. + +- **`compareTimestamps(timestamp1, timestamp2)`**: Compare two timestamps. Returns -1 if timestamp1 < timestamp2, 0 if equal, 1 if timestamp1 > timestamp2. + +- **`dateToTimestamp(date)`**: Convert JavaScript Date to Unix timestamp (float). Defaults to current date if not provided. + +- **`toISOString(timestamp)`**: Convert Unix timestamp to ISO 8601 string. + +#### Usage Examples + +**Basic Usage:** Import functions from the timestamp utils module. Use `parseTimestamp(apiData._createdAt)` to parse timestamps from API responses. Use `formatTimestamp(apiData._createdAt)` for smart display formatting (returns relative time for recent items, absolute time for older). Use `formatRelativeTime(apiData._createdAt)` for relative time strings like "2 hours ago". Use `formatAbsoluteTime(apiData._createdAt, { format: 'utc' })` for absolute time strings. + +**In React Components:** Import `parseTimestamp`, `formatTimestamp`, and `isExpired` from the timestamp utils module. Call `parseTimestamp(workflow._createdAt)` to parse timestamps. Use `formatTimestamp(workflow._createdAt)` to display formatted time. Use `isExpired(expiresAt)` to check if a token has expired. + +**Sorting:** Import `compareTimestamps` and use it in sort functions: `workflows.sort((a, b) => compareTimestamps(a._createdAt, b._createdAt))`. + +**Filtering:** Import `isExpired` and use it to filter arrays: `tokens.filter(token => !isExpired(token.expiresAt))`. + +### Frontend Integration Guidelines + +#### 1. Always Use the Timestamp Module + +**✅ DO:** Import and use `parseTimestamp()` from the timestamp utils module. Call `parseTimestamp(apiData._createdAt)` to safely parse timestamps. + +**❌ DON'T:** Do not assume timestamps are always numbers and directly create Date objects like `new Date(apiData._createdAt * 1000)` as this may fail if the value is a string or null. + +#### 2. Handle Null/Undefined Values + +**✅ DO:** Always provide a default value when calling `parseTimestamp()`, for example: `parseTimestamp(apiData.expiresAt, new Date())`. Check if the returned date is valid before using it. + +**❌ DON'T:** Do not assume timestamps always exist. Do not directly create Date objects without checking for null values first. + +#### 3. Use Appropriate Formatting + +- **List Views**: Use `formatTimestamp()` for smart relative/absolute formatting +- **Detail Views**: Use `formatAbsoluteTime()` with timezone information +- **Filters**: Convert Date picker values to Unix timestamps using `dateToTimestamp()` + +#### 4. Timezone Considerations + +- All backend timestamps are in **UTC** +- Frontend should convert to **user's local timezone** for display +- Use `formatAbsoluteTime()` with `format: 'local'` for user-friendly display +- Always show timezone information in detail views + +### Testing the Timestamp Module + +**Test Cases to Cover:** +1. Parse number timestamps (float and int) +2. Parse string timestamps +3. Handle null/undefined values +4. Handle invalid values (NaN, out of range) +5. Format relative time (past and future) +6. Format absolute time (UTC and local) +7. Compare timestamps +8. Check expiration +9. Convert Date to timestamp + +**Example Test:** Import functions from the timestamp utils module and test that `parseTimestamp()` correctly handles number timestamps, string timestamps, and null values. Test that `formatRelativeTime()` correctly formats timestamps as relative time strings. Test that `isExpired()` correctly identifies expired timestamps. + +### Summary: Frontend Timestamp Handling + +1. **Always decode** API timestamps using `parseTimestamp()` - handles number/string/null +2. **Format appropriately** - relative for recent, absolute for older items +3. **Handle timezones** - convert UTC to user's local timezone for display +4. **Provide defaults** - handle null/undefined gracefully +5. **Use consistently** - use the core module throughout the project +6. **Test thoroughly** - cover all input formats and edge cases + +The core timestamp module ensures consistent, safe handling of timestamps across the entire frontend application, matching the backend's `parseTimestamp()` functionality for type normalization and error handling. + diff --git a/docs/code-documentation/security-api.md b/docs/code-documentation/security-api.md index 25c7ec99..79bdfdeb 100644 --- a/docs/code-documentation/security-api.md +++ b/docs/code-documentation/security-api.md @@ -506,3 +506,4 @@ async def get_sensitive_data( - [Architecture Overview](./architecture-overview.md) - Overall system architecture + diff --git a/docs/frontend-documentation/chat-playground-page-requirements.md b/docs/frontend-documentation/chat-playground-page-requirements.md new file mode 100644 index 00000000..5549fde8 --- /dev/null +++ b/docs/frontend-documentation/chat-playground-page-requirements.md @@ -0,0 +1,786 @@ +# Chat Playground Page Requirements + +This document contains the complete frontend requirements for the chat playground page and workflow management components. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) + +--- + +## Overview + +The chat playground page enables users to create, manage, and track AI-powered workflows that process user requests through task planning and action execution. The frontend consists of a single page (`/chat-playground` or `/workflows/playground`) with different views/states: + +- **Input View** - Start new workflows or continue existing ones with prompt input, mode selection, and file attachments +- **Workflow View** - Live tracking of workflow execution with messages, logs, and statistics +- **Workflow History View** - View completed workflows with full message history + +All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints. Views are managed through component state and routing within the same page, not as separate routes. + +**Note:** Workflows are user-scoped. Users can only see and manage their own workflows. The backend enforces this security. + +--- + +## Page Structure and Layout + +### Chat Playground Page (`/chat-playground` or `/workflows/playground`) + +The chat playground page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component. + +### Input View + +**State:** `view === 'input'` or `selectedWorkflowId === null` (starting new workflow) + +**What the user sees:** + +- **Main Content Area:** + - Chat input form with the following components: + - **Workflow Dropdown** - Select previous workflow to continue (optional, shows "New Workflow" by default) + - **Prompt Dropdown** - Select saved prompt template (optional) + - **Prompt Text Input** - Multi-line text area for user input (required) + - **Workflow Mode Selector** - Radio buttons or tabs for Actionplan, Dynamic, or Template (required) + - **Neutralization Toggle** - Checkbox/toggle to enable/disable data neutralization (optional) + - **File Attachment Area** - Drop zone with drag-and-drop support, plus "Attach File" button and "Browse Files" button + - **Action Buttons:** + - "Start Workflow" button (when no workflow selected) + - "Continue Workflow" or "Send" button (when workflow selected) + +- **File Attachment Display:** + - List of attached files with preview (name, size, type) + - Remove button for each attached file + - Visual feedback for drag-and-drop (highlight, border, overlay when dragging) + +- **Workflow Context Display** (when workflow selected): + - Previous messages from selected workflow displayed in chat view + - Workflow status indicator + - Workflow mode pre-selected from selected workflow + +### Workflow View + +**State:** `view === 'workflow'` and `selectedWorkflowId !== null` (active workflow tracking) + +**What the user sees:** + +- **Main Content Area:** + - **Chat Interface:** + - Message history displayed chronologically + - User messages and assistant responses + - File attachments displayed as part of each message + - Each file attachment shows: + - File name, size, and type/icon + - Action buttons: "Show", "Download", "Delete" + - File preview (if applicable) when "Show" is clicked + - Auto-scroll to latest message (optional, user can disable) + + - **Log Panel** (optional, can be toggled): + - Execution logs displayed chronologically + - Log level indicators (info, warning, error) + - Timestamps for each log entry + + - **Statistics Panel** (optional, can be toggled): + - Performance metrics + - Task completion status + - Execution time + + - **Workflow Status Indicator:** + - Current workflow status (running, completed, stopped, failed) + - Visual status badge with color coding + - Neutralization indicator (if enabled) + +- **Action Buttons:** + - "Stop" button (when workflow is running) + - "Delete Message" button (on individual messages) + - **File Action Buttons** (on each file attachment in messages): + - "Show" button - Opens file preview/viewer + - "Download" button - Downloads file to user's device + - "Delete" button - Removes file from message (with confirmation) + - "Back to Input" button (return to input view) + +- **Live Updates:** + - Real-time polling for new messages, logs, and statistics + - Visual indicators for new content + - Automatic UI updates without page refresh + +--- + +## User Interactions and Functionality + +### Starting a New Workflow + +**Workflow Selection:** +- User sees workflow dropdown with "New Workflow" as default option +- Dropdown shows list of previous workflows (name, status, last activity) +- Selecting "New Workflow" clears any selected workflow context +- Selecting a previous workflow loads its context (messages, mode) + +**Prompt Selection:** +- User can optionally select a saved prompt from dropdown +- Selecting a prompt pre-fills the prompt text field +- User can still edit the pre-filled text +- Prompt selection is optional + +**Workflow Mode Selection:** +- User must select one of three modes: + - **Actionplan** - Traditional task planning (shows description on selection) + - **Dynamic** - Iterative dynamic-style processing (shows description on selection) + - **Template** - Template-based processing (shows description on selection) +- Mode selection is required before starting workflow +- Visual indicator shows selected mode + +**Neutralization Toggle:** +- User can toggle neutralization on/off +- Frontend checks neutralization config status +- If config exists and enabled, neutralization is enabled for workflow +- If config disabled or not found, neutralization is disabled +- User can configure neutralization settings on separate settings page +- Toggle shows current state (enabled/disabled indicator) + +**File Attachment:** +- **Drag and Drop:** + - User drags files over drop zone + - Visual feedback shown (highlight, border, overlay) + - User drops files onto drop zone + - Files processed and uploaded automatically + - File preview shown immediately + +- **Button Upload:** + - User clicks "Attach File" or "Upload File" button + - File picker dialog opens + - User selects files from device + - Files uploaded and preview shown + +- **Browse Existing Files:** + - User clicks "Browse Files" or "Select File" button + - File browser/selector opens with paginated file list + - User selects existing files + - Selected files added to attachment list + +- **File Management:** + - Attached files shown in list with name, size, type + - Remove button for each file + - Multiple files can be attached + - Files validated before upload (size limits, type restrictions) + +**Form Validation:** +- Required fields: prompt text, workflow mode +- Optional fields: prompt selection, neutralization, files +- Validation errors shown inline +- Form cannot be submitted until required fields are filled + +**Workflow Submission:** +- User clicks "Start Workflow" button +- Form validates (required fields, types, workflowMode) +- If validation fails, show errors +- If validation passes: + - Build UserInputRequest with prompt, listFileId (if files attached), userLanguage + - Show loading state + - Submit to `/api/chat/playground/start` with workflowMode query param + - On success: Navigate to workflow view, start polling + - On error: Show error message, revert optimistic updates + +### Continuing an Existing Workflow + +**Workflow Selection:** +- User selects previous workflow from dropdown +- Frontend loads workflow data via `GET /api/workflows/workflowId` +- Previous messages displayed in chat view +- Workflow mode pre-selected from selected workflow +- Selected workflow name/ID shown + +**Additional Input:** +- User can optionally select a prompt (pre-fills text) +- User enters or edits prompt text +- User can toggle neutralization +- User can attach files (same methods as starting new workflow) + +**Workflow Continuation:** +- User clicks "Continue" or "Send" button +- Form validates (required fields) +- If validation passes: + - Build UserInputRequest with prompt, listFileId (if files attached) + - Show optimistic update (add user message to UI) + - Submit to `/api/chat/playground/start` with workflowId and workflowMode query params + - On success: Continue polling, update workflow view + - On error: Revert optimistic update, show error + +### Live Tracking Workflow Progress + +**Polling Mechanism:** +- Start polling when workflow view is active +- Poll interval: every 2 seconds (configurable) +- Poll endpoint: `GET /api/chat/playground/{workflowId}/chatData` +- Use `afterTimestamp` query param for selective data transfer + +**Data Updates:** +- Compare new data with existing data +- If new data available: + - Append new messages to chat view + - Append new logs to log panel + - Update statistics display + - Update workflow status indicator + - Scroll to latest content (if auto-scroll enabled) +- If no new data, continue polling silently + +**Polling Control:** +- Stop polling when workflow status is "completed", "stopped", or "failed" +- Stop polling when user navigates away +- Show final status when workflow completes +- Handle errors gracefully (404 stops polling, shows error) + +**Visual Feedback:** +- Loading indicators during polling +- New content indicators +- Status change animations +- Progress indicators for long-running workflows + +### Stopping a Running Workflow + +**Stop Action:** +- User clicks "Stop" button (only visible when workflow is running) +- Confirmation dialog appears: "Stop this workflow?" +- User can cancel or confirm + +**Stop Submission:** +- If user confirms: + - Show optimistic update (status to "stopping") + - Submit to `POST /api/chat/playground/{workflowId}/stop` + - On success: Stop polling, update UI with stopped status + - On error: Revert optimistic update, show error + +### Viewing Files in Messages + +**Show File:** +- User clicks "Show" button on file attachment in message +- Frontend fetches file data via `GET /api/files/{fileId}/download` or preview endpoint +- File preview/viewer opens (modal, sidebar, or inline) +- Preview supports different file types: + - Images → Display image viewer + - PDFs → Display PDF viewer + - Text files → Display text content + - Other types → Show file info or download prompt +- User can close preview to return to message view + +**Download File:** +- User clicks "Download" button on file attachment in message +- Frontend triggers download via `GET /api/files/{fileId}/download` +- Browser automatically downloads file with proper filename +- File name properly encoded for Unicode characters +- Handle 403 (permission denied) and 404 (file not found) errors + +### Deleting Context from a Workflow + +**Delete Message:** +- User clicks "Delete" button on message +- Confirmation dialog: "Delete this message? This will remove it from the workflow context." +- If user confirms: + - Show optimistic update (remove message from UI) + - Submit to `DELETE /api/workflows/{workflowId}/messages/{messageId}` + - On success: Keep optimistic update, refresh workflow data + - On error: Revert optimistic update, show error + +**Delete File from Message:** +- User clicks "Delete" button on file attachment in message +- Confirmation dialog: "Delete this file? This will remove it from the message context." +- If user confirms: + - Show optimistic update (remove file from UI) + - Submit to `DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId}` + - On success: Keep optimistic update, refresh message data + - On error: Revert optimistic update, show error + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by chat playground pages: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/chat/playground/start` | POST | Start new workflow or continue existing | User clicks "Start Workflow" or "Continue" | Current user only | +| `/api/chat/playground/{workflowId}/stop` | POST | Stop running workflow | User clicks "Stop" button | Current user only | +| `/api/chat/playground/{workflowId}/chatData` | GET | Get unified chat data for polling | Live tracking (polling every 2 seconds) | Current user only | +| `/api/workflows/` | GET | Get all workflows for current user | Load workflow dropdown, initial page load | Current user only | +| `/api/workflows/{workflowId}` | GET | Get workflow by ID | User selects workflow from dropdown | Current user only | +| `/api/workflows/{workflowId}/messages/{messageId}` | DELETE | Delete message from workflow | User confirms message deletion | Current user only | +| `/api/workflows/{workflowId}/messages/{messageId}/files/{fileId}` | DELETE | Delete file from message | User confirms file deletion | Current user only | +| `/api/prompts` | GET | Get all prompts for current user | Load prompt dropdown | Current user only | +| `/api/prompts/{promptId}` | GET | Get prompt by ID | User selects prompt from dropdown | Current user only | +| `/api/files/upload` | POST | Upload new file | User drags/drops or clicks upload | Current user only | +| `/api/files/list` | GET | Get all files for current user | User clicks "Browse Files" | Current user only | +| `/api/files/{fileId}/download` | GET | Download file | User clicks "Download" button on file | Current user only | +| `/api/neutralization/config` | GET | Get neutralization config | User toggles neutralization | Current user only | +| `/api/attributes/ChatWorkflow` | GET | Get field definitions | Page load (once per page) | All authenticated users | +| `/api/attributes/UserInputRequest` | GET | Get field definitions | Page load (once per page) | All authenticated users | + +### API Request Patterns + +**Start Workflow Request:** +``` +POST /api/chat/playground/start?workflowMode=Dynamic +Content-Type: application/json +Body: { + "prompt": "User prompt text here...", + "listFileId": ["fileId1", "fileId2"], + "userLanguage": "en" +} +``` +- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template" +- `workflowId` query parameter is optional (for continuing existing workflow) +- `listFileId` array contains file IDs to attach (optional) +- `prompt` field contains user's prompt text (required) +- `userLanguage` should match user's preferred language +- Handle 403 (permission denied) and 400 (validation errors) + +**Continue Workflow Request:** +``` +POST /api/chat/playground/start?workflowId=workflow-id&workflowMode=Dynamic +Content-Type: application/json +Body: { + "prompt": "Additional prompt text...", + "listFileId": ["fileId1"], + "userLanguage": "en" +} +``` +- `workflowId` query parameter is required (ID of workflow to continue) +- `workflowMode` query parameter is required (from selected workflow) +- Same body structure as start workflow +- Handle 403, 404 (workflow not found), and 400 errors + +**Stop Workflow Request:** +``` +POST /api/chat/playground/{workflowId}/stop +``` +- No body required +- Returns updated ChatWorkflow with status "stopped" +- Handle 403 (permission denied) and 404 (workflow not found) + +**Get Chat Data Request (Polling):** +``` +GET /api/chat/playground/{workflowId}/chatData?afterTimestamp=1234567890.123 +``` +- `afterTimestamp` query parameter is optional (Unix timestamp for selective data transfer) +- Returns unified chat data: `{messages: [], logs: [], stats: []}` +- Data is chronologically ordered by `_createdAt` timestamp +- Handle 404 (workflow not found) - stop polling + +**Get Workflows Request:** +``` +GET /api/workflows/ +``` +- Returns paginated workflows list +- Can include pagination parameter: `?pagination={"page":1,"pageSize":10,"sort":[]}` +- Used to populate workflow dropdown +- Returns only current user's workflows + +**Get Workflow Request:** +``` +GET /api/workflows/{workflowId} +``` +- Returns full workflow data including messages, logs, stats +- Used when user selects workflow from dropdown +- Handle 404 (workflow not found) + +**Upload File Request:** +``` +POST /api/files/upload +Content-Type: multipart/form-data +Body: { + file: , + workflowId: "optional-workflow-id" (optional) +} +``` +- File sent as multipart/form-data +- `workflowId` is optional form field +- Handle 403 (permission denied), 413 (file too large), and 400 (validation errors) +- Response includes duplicate information + +**Get Prompts Request:** +``` +GET /api/prompts +``` +- Returns paginated prompts list +- Used to populate prompt dropdown +- Returns only current user's prompts + +**Get Prompt Request:** +``` +GET /api/prompts/{promptId} +``` +- Returns prompt details (name, content) +- Used when user selects prompt from dropdown +- Handle 404 (prompt not found) + +**Get Neutralization Config Request:** +``` +GET /api/neutralization/config +``` +- Returns neutralization configuration (enabled status, settings) +- Used when user toggles neutralization +- Returns default config if none exists + +**Delete Message Request:** +``` +DELETE /api/workflows/{workflowId}/messages/{messageId} +``` +- Deletes message from workflow +- Updates workflow's messageIds list +- Handle 403 (permission denied) and 404 (message not found) + +**Download File Request:** +``` +GET /api/files/{fileId}/download +``` +- Returns file content with Content-Disposition header +- Browser automatically triggers download +- Filename properly encoded for Unicode characters +- Handle 403 (permission denied) and 404 (file not found) + +**Delete File Request:** +``` +DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId} +``` +- Deletes file reference from message +- Handle 403 (permission denied) and 404 (file not found) + +### Response Handling + +**Start/Continue Workflow Response:** +```json +{ + "id": "workflow-id", + "status": "running", + "workflowMode": "Dynamic", + "messages": [...], + "logs": [...], + "stats": [...], + ... +} +``` +- Returns ChatWorkflow object with status "running" +- Includes all workflow data + +**Chat Data Response (Polling):** +```json +{ + "messages": [ + { + "id": "message-id", + "role": "user", + "content": "...", + "_createdAt": 1234567890.123, + ... + } + ], + "logs": [ + { + "id": "log-id", + "level": "info", + "message": "...", + "_createdAt": 1234567890.124, + ... + } + ], + "stats": [ + { + "id": "stat-id", + "metric": "...", + "value": 123, + "_createdAt": 1234567890.125, + ... + } + ] +} +``` +- All data types in chronological order by `_createdAt` +- Empty arrays if no new data + +**Error Responses:** +- 403 Forbidden → Show permission error message +- 404 Not Found → Show "not found" error message +- 400 Bad Request → Display validation errors from response +- 413 Request Entity Too Large → Show file size error +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Complete Field List + +The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for workflows and user input. All of these are provided by the backend through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints and should never be hardcoded in the frontend. + +#### ChatWorkflow Fields + +**Identification Fields:** +- `id` - Unique workflow identifier (text, readonly, not required, visible) +- `mandateId` - ID of the mandate this workflow belongs to (text, readonly, not required, visible) +- `name` - Workflow name (text, editable, not required, visible) + +**Workflow Properties:** +- `status` - Workflow status (select, readonly, not required, visible) + - Options: "running", "completed", "stopped", "failed" + - Each option has localized labels (en/fr) +- `workflowMode` - Execution mode (select, readonly, not required, visible) + - Options: "Actionplan", "Dynamic", "Template" + - Each option has localized labels (en/fr) +- `currentRound` - Current user interaction round (number, readonly, not required, visible) +- `currentTask` - Current task in task plan (number, readonly, not required, visible) +- `currentAction` - Current action within task (number, readonly, not required, visible) +- `totalTasks` - Number of tasks in task plan (number, readonly, not required, visible) +- `totalActions` - Number of actions in current task (number, readonly, not required, visible) +- `maxSteps` - Maximum steps for Dynamic mode (number, readonly, not required, visible) + +**Timestamp Fields:** +- `startedAt` - When workflow was created (timestamp, readonly, not required, visible) +- `lastActivity` - Last activity timestamp (timestamp, readonly, not required, visible) + +**Related Data:** +- `messages` - List of ChatMessage objects (array, readonly, not required, visible) +- `logs` - List of ChatLog objects (array, readonly, not required, visible) +- `stats` - List of ChatStat objects (array, readonly, not required, visible) +- `tasks` - List of task objects (array, readonly, not required, visible) + +#### UserInputRequest Fields + +**Input Fields:** +- `prompt` - User prompt text (textarea, editable, required, visible) +- `listFileId` - Array of file IDs to attach (array, editable, not required, visible) +- `userLanguage` - User's preferred language (select, editable, not required, visible) + - Options: "en", "fr", etc. + - Each option has localized labels + +#### Prompt Fields + +**Prompt Properties:** +- `id` - Unique prompt identifier (text, readonly, not required, visible) +- `mandateId` - ID of the mandate this prompt belongs to (text, readonly, not required, visible) +- `name` - Prompt name (text, readonly, not required, visible) +- `content` - Prompt content (textarea, readonly, not required, visible) + +### Attribute Definition Structure + +Each field returned from `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` contains: + +- `name` - Field name (e.g., "status", "workflowMode", "prompt", "listFileId") +- `type` - Field data type (e.g., "text", "select", "textarea", "array", "timestamp", "number") +- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"}) +- `description` - Field description text +- `required` - Boolean indicating if field is required +- `readonly` - Boolean indicating if field is read-only +- `editable` - Boolean indicating if field can be edited (inverse of readonly) +- `visible` - Boolean indicating if field should be displayed in UI +- `options` - Array of options for select fields (each option has `value` and localized `label`) + +--- + +## Dynamic Rendering Guidelines + +The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded. + +### Form Field Generation + +When rendering input forms: + +1. Fetch attribute definitions from `/api/attributes/UserInputRequest` and `/api/attributes/ChatWorkflow` +2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show +3. For each editable field, generate appropriate form input based on `type`: + - `text` fields → Text input + - `textarea` fields → Multi-line text area + - `select` fields → Dropdown/select input with options from `options` array (use localized labels) + - `array` fields → Array input with add/remove controls + - `number` fields → Number input +4. Use `label` property for field labels (localized) +5. Use `required` property to show required indicators (asterisk, etc.) +6. Use `description` property to show help text or tooltips +7. Validate form before submission: + - Check all `required: true` fields have values + - Validate types (e.g., array fields must be arrays) + - Validate select fields (value must be in options array) +8. On submit, build UserInputRequest object with all form data + +### Workflow Mode Selector Generation + +When rendering workflow mode selector: + +1. Fetch attribute definitions from `/api/attributes/ChatWorkflow` +2. Find `workflowMode` field +3. Extract `options` array from field definition +4. Generate radio buttons or tabs for each option +5. Use localized labels from options: `option.label[userLanguage]` +6. Show description/help text when option is selected +7. Mark one option as required (user must select before starting) + +### Dropdown Generation + +**Workflow Dropdown:** +1. Fetch workflows via `GET /api/workflows/` +2. Display workflows in dropdown with name, status, last activity +3. Add "New Workflow" as default/first option +4. When workflow selected, load full workflow data +5. Display previous messages when workflow selected + +**Prompt Dropdown:** +1. Fetch prompts via `GET /api/prompts` +2. Display prompts in dropdown with name +3. When prompt selected, fetch prompt details and pre-fill text field +4. Allow user to edit pre-filled text + +### File Attachment UI Generation + +**Drop Zone:** +1. Create drop zone area with visual boundaries +2. Handle drag events (dragenter, dragover, dragleave, drop) +3. Show visual feedback when files dragged over (highlight, border, overlay) +4. Process dropped files and upload automatically +5. Show file preview immediately after drop + +**File Upload Button:** +1. Create file input element (hidden) +2. Trigger file picker on button click +3. Handle multiple file selection +4. Upload files and show preview + +**File Browser:** +1. Fetch files via `GET /api/files/list` +2. Display files in browser/selector with pagination +3. Allow multiple file selection +4. Add selected files to attachment list + +**File List Display:** +1. Show attached files with name, size, type +2. Display remove button for each file +3. Update list when files added or removed + +### Message Display Generation + +When rendering messages in workflow view: + +1. Fetch messages from workflow data or chatData endpoint +2. Display messages chronologically +3. Format based on message role: + - User messages → Right-aligned or distinct styling + - Assistant messages → Left-aligned or distinct styling +4. Display file attachments as part of each message: + - Show file name, size, and type/icon for each attachment + - Display file attachments in organized list or grid within message + - For each file attachment, render action buttons: + - **"Show" button** - Opens file preview/viewer + - **"Download" button** - Triggers file download + - **"Delete" button** - Removes file from message (with confirmation) + - File preview can be displayed inline, in modal, or sidebar + - Support different file type previews (images, PDFs, text, etc.) +5. Show timestamps (relative or absolute) +6. Add delete button for each message (if user has permission) + +### Log Display Generation + +When rendering logs in log panel: + +1. Fetch logs from workflow data or chatData endpoint +2. Display logs chronologically +3. Format based on log level: + - Info → Default styling + - Warning → Yellow/orange styling + - Error → Red styling +4. Show timestamps for each log entry +5. Support filtering by log level (optional) + +### Statistics Display Generation + +When rendering statistics in stats panel: + +1. Fetch stats from workflow data or chatData endpoint +2. Display statistics in organized format +3. Format based on metric type: + - Numbers → Display with appropriate units + - Percentages → Display as percentage + - Timestamps → Format as duration or absolute time +4. Update statistics in real-time during polling + +### Display Formatting + +When displaying field values: + +1. Use `type` property to determine formatting: + - `text` → Display as-is (may need HTML escaping) + - `textarea` → Preserve line breaks + - `select` → Look up value in `options` array and display localized label + - `timestamp` → Format as relative time or absolute date/time + - `number` → Format with appropriate decimal places + - `array` → Display as list or comma-separated +2. Handle `null` or `undefined` values gracefully (show "-" or "Not set") +3. Use `readonly` property to determine if field should show edit indicators +4. Special formatting for workflow fields: + - Status → Color-code badges (Running = blue, Completed = green, Stopped = gray, Failed = red) + - Workflow Mode → Display as badge with icon + - Timestamps → Show relative time in list view, absolute date in detail view + +### Localization + +All labels and options support multiple languages: + +1. Use user's preferred language (from user settings or browser locale) +2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback +3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback +4. If label for current language is missing, fall back to English + +### Polling Implementation + +**Polling Setup:** +1. Start polling when workflow view is active +2. Use `setInterval` or similar mechanism (2 second interval) +3. Store last timestamp to use in `afterTimestamp` parameter +4. Stop polling when workflow completes or user navigates away + +**Polling Logic:** +1. Call `GET /api/chat/playground/{workflowId}/chatData?afterTimestamp={lastTimestamp}` +2. Compare returned data with existing data +3. Append new messages, logs, stats to UI +4. Update last timestamp +5. Check workflow status - stop polling if completed/stopped/failed +6. Handle errors gracefully (404 stops polling) + +**Performance Considerations:** +1. Debounce rapid updates +2. Batch UI updates +3. Use virtual scrolling for long message lists +4. Limit polling frequency +5. Stop polling when tab is not visible (Page Visibility API) + +### Key Principles + +- Never hardcode field names, labels, types, or validation rules +- Always fetch attribute definitions from backend before rendering UI +- Use attribute metadata to determine what to display and how to display it +- Support all field types dynamically - if backend adds new types, frontend should handle them +- Respect `visible`, `editable`, `readonly`, and `required` flags from backend +- Use localized labels from backend metadata +- Generate forms, dropdowns, and displays entirely from attribute definitions +- When backend adds new fields, frontend should automatically display them without code changes +- Handle all error cases gracefully (403, 404, 400, 413, 500) +- Provide user feedback for all actions (loading states, success messages, error messages) +- **All workflows are user-scoped** (backend enforces this) +- **Polling should be efficient** (use selective data transfer with afterTimestamp) +- **Optimistic updates** for better UX (show changes immediately, revert on error) + +--- + +## Summary + +This document provides complete frontend requirements for the chat playground page and workflow management components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints. + +**Key Architecture Pattern:** The chat playground interface is a single page (`/chat-playground`) with different views managed through component state. All interactions happen within the same page component without separate routes. + +**Security Note:** Workflows are user-scoped. Users can only see and manage their own workflows. The backend enforces this security, and the frontend should never attempt to access other users' workflows. + +**Real-Time Updates:** The workflow view uses polling-based live tracking to show real-time updates. Polling should be efficient using selective data transfer with timestamps. + +For generic patterns that apply across all entity types (not just workflows), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md). + diff --git a/docs/frontend-documentation/chat-playground-workflow-journeys.md b/docs/frontend-documentation/chat-playground-workflow-journeys.md new file mode 100644 index 00000000..6dc9566c --- /dev/null +++ b/docs/frontend-documentation/chat-playground-workflow-journeys.md @@ -0,0 +1,542 @@ +# Chat Playground and Workflow Live Tracking Frontend Documentation + +This document describes customer journeys for managing chat playground workflows and live tracking workflow execution through the frontend, focusing on how users interact with workflow management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Starting a New Workflow](#customer-journey-1-starting-a-new-workflow) +3. [Customer Journey 2: Continuing an Existing Workflow](#customer-journey-2-continuing-an-existing-workflow) +4. [Customer Journey 3: Live Tracking Workflow Progress](#customer-journey-3-live-tracking-workflow-progress) +5. [Customer Journey 4: Stopping a Running Workflow](#customer-journey-4-stopping-a-running-workflow) +6. [Customer Journey 5: Deleting Context from a Workflow](#customer-journey-5-deleting-context-from-a-workflow) + +--- + +## Overview + +The chat playground routes (`/api/chat/playground`) and workflow routes (`/api/workflows`) enable users to create, manage, and track AI-powered workflows that process user requests through task planning and action execution. These routes support **workflow lifecycle management** including creation, live tracking, modification, and deletion. + +**Key Principles:** +- **User-Centric**: Documentation organized around what users want to accomplish +- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata +- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend +- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully +- **User-Scoped**: Users can only see and manage their own workflows +- **Real-Time Updates**: Polling-based live tracking for workflow progress + +--- + +## Customer Journey 1: Starting a New Workflow + +### User Goal +"I want to start a new AI workflow to process my request." + +### User Story +As a user, I want to start a new workflow by optionally selecting a saved prompt template, providing or editing my input prompt, choosing a workflow mode (Actionplan for traditional task planning, Dynamic for iterative processing, or Template for template-based processing), optionally enabling data neutralization for privacy compliance, and optionally attaching files, so the system can begin processing my request in the appropriate mode with sensitive data protected if needed. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to chat playground + Frontend->>Backend: GET /api/attributes/ChatWorkflow + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/attributes/UserInputRequest + Backend-->>Frontend: Input request field definitions + Frontend->>Frontend: Generate input form from attributes + Frontend->>Backend: GET /api/prompts + Backend-->>Frontend: Paginated prompts list + Frontend-->>User: Display chat input form with mode selector
(Actionplan, Dynamic, Template)
+ prompt dropdown selector + + alt User optionally selects a prompt + User->>Frontend: Click prompt dropdown + Frontend->>Frontend: Display available prompts list
(from cached prompts data) + User->>Frontend: Select prompt from dropdown + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Selected prompt details
(name, content) + Frontend->>Frontend: Pre-fill prompt text field with prompt content + Frontend->>Frontend: Show selected prompt name + Frontend-->>User: Display prompt text pre-filled
(user can still edit) + end + + User->>Frontend: Enter or edit prompt text + + alt User selects workflow mode + alt User selects "Actionplan" mode + User->>Frontend: Click "Actionplan" mode option + Frontend->>Frontend: Show mode description/help text
(traditional task planning) + Frontend->>Frontend: Set workflowMode to "Actionplan" + Frontend-->>User: Display selected mode indicator + else User selects "Dynamic" mode + User->>Frontend: Click "Dynamic" mode option + Frontend->>Frontend: Show mode description/help text
(iterative dynamic-style processing) + Frontend->>Frontend: Set workflowMode to "Dynamic" + Frontend-->>User: Display selected mode indicator + else User selects "Template" mode + User->>Frontend: Click "Template" mode option + Frontend->>Frontend: Show mode description/help text
(template-based processing) + Frontend->>Frontend: Set workflowMode to "Template" + Frontend-->>User: Display selected mode indicator + end + end + + alt User optionally enables neutralization + User->>Frontend: Click "Enable Neutralization" toggle + Frontend->>Backend: GET /api/neutralization/config + Backend-->>Frontend: Neutralization config (enabled status) + alt Config exists and enabled + Frontend->>Frontend: Mark neutralization as enabled for workflow + Frontend-->>User: Show neutralization enabled indicator
(uses existing config) + else Config disabled or not found + Frontend->>Frontend: Mark neutralization as disabled + Frontend-->>User: Show neutralization disabled
(user can configure on settings page) + end + end + + alt User optionally attaches files + alt User drags and drops files + User->>Frontend: Drag file(s) over drop zone + Frontend->>Frontend: Show visual feedback
(highlight drop zone, border, overlay) + Frontend-->>User: Display drop zone active state + User->>Frontend: Drop file(s) onto drop zone + Frontend->>Frontend: Process dropped files + Frontend->>Frontend: Show file preview with name and size + Frontend->>Frontend: Optimistic update: Add file to attachment list + Frontend->>Backend: POST /api/files/upload
+ multipart/form-data (file) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show permission error + else File too large (413) + Backend-->>Frontend: 413 Request Entity Too Large + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show file size error + else Success (201) + Backend-->>Frontend: FileItem object + duplicate info + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Store fileId for later use + Frontend-->>User: Show file attached successfully + end + else User uploads new file via button + User->>Frontend: Click "Attach File" or "Upload File" button + Frontend->>Frontend: Open file picker dialog + User->>Frontend: Select file(s) from device + Frontend->>Frontend: Show file preview with name and size + Frontend->>Frontend: Optimistic update: Add file to attachment list + Frontend->>Backend: POST /api/files/upload
+ multipart/form-data (file) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show permission error + else File too large (413) + Backend-->>Frontend: 413 Request Entity Too Large + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show file size error + else Success (201) + Backend-->>Frontend: FileItem object + duplicate info + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Store fileId for later use + Frontend-->>User: Show file attached successfully + end + else User selects existing file + User->>Frontend: Click "Browse Files" or "Select File" button + Frontend->>Backend: GET /api/files/list + Backend-->>Frontend: Paginated files list + Frontend->>Frontend: Display file browser/selector + Frontend-->>User: Show available files + User->>Frontend: Select file(s) from list + Frontend->>Frontend: Add fileId(s) to attachment list + Frontend-->>User: Show selected files in attachment list + end + end + + User->>Frontend: Click "Start Workflow" button + + Frontend->>Frontend: Validate form (required fields, types, workflowMode) + alt Validation fails (missing workflowMode or prompt) + Frontend-->>User: Show validation errors
(e.g., "Workflow mode is required") + else Validation passes + Frontend->>Frontend: Build UserInputRequest with listFileId array (if files attached) + alt Neutralization enabled + Frontend->>Frontend: Neutralization will be applied automatically
by backend during workflow processing + end + Frontend->>Frontend: Optimistic update: Show loading state, create workflow placeholder + Frontend->>Backend: POST /api/chat/playground/start
+ workflowMode query param (Actionplan/Dynamic/Template)
+ UserInputRequest body
(includes listFileId if files attached) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created ChatWorkflow (status: "running")
with files attached (if any)
(neutralized if neutralization enabled) + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Navigate to workflow view + Frontend->>Frontend: Start polling for updates + alt Neutralization enabled + Frontend->>Frontend: Show neutralization indicator in workflow view + Frontend->>Frontend: Option to resolve text back to original when viewing + end + Frontend-->>User: Display workflow with live tracking
(files visible if attached, neutralized if enabled) + end + end +``` + +--- + +## Customer Journey 2: Continuing an Existing Workflow + +### User Goal +"I want to continue a workflow I started earlier by selecting it from a list and adding more input." + +### User Story +As a user, I want to select a previous workflow from a dropdown on the chat interface page and continue it by providing additional input, so the system can process my new request in the context of the previous conversation. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to chat playground + Frontend->>Backend: GET /api/attributes/ChatWorkflow + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/attributes/UserInputRequest + Backend-->>Frontend: Input request field definitions + Frontend->>Backend: GET /api/workflows/ + Backend-->>Frontend: Paginated workflows list + Frontend->>Backend: GET /api/prompts + Backend-->>Frontend: Paginated prompts list + Frontend->>Frontend: Generate input form from attributes + Frontend-->>User: Display chat input form with
workflow dropdown selector
+ mode selector + prompt dropdown + + alt User selects previous workflow from dropdown + User->>Frontend: Click workflow dropdown + Frontend->>Frontend: Display available workflows list
(from cached workflows data) + User->>Frontend: Select workflow from dropdown + Frontend->>Backend: GET /api/workflows/workflowId + Backend-->>Frontend: Selected workflow data
(status, messages, workflowMode, etc.) + Frontend->>Frontend: Load workflow history + Frontend->>Frontend: Display previous messages in chat view + Frontend->>Frontend: Set workflowMode from selected workflow + Frontend->>Frontend: Show selected workflow name/ID + Frontend-->>User: Display workflow context
(previous messages visible,
workflow mode pre-selected) + end + + alt User optionally selects a prompt + User->>Frontend: Click prompt dropdown + Frontend->>Frontend: Display available prompts list
(from cached prompts data) + User->>Frontend: Select prompt from dropdown + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Selected prompt details
(name, content) + Frontend->>Frontend: Pre-fill prompt text field with prompt content + Frontend->>Frontend: Show selected prompt name + Frontend-->>User: Display prompt text pre-filled
(user can still edit) + end + + User->>Frontend: Enter or edit prompt text + + alt User optionally enables/disables neutralization + User->>Frontend: Click "Enable Neutralization" toggle + Frontend->>Backend: GET /api/neutralization/config + Backend-->>Frontend: Neutralization config (enabled status) + alt Config exists and enabled + Frontend->>Frontend: Mark neutralization as enabled for workflow + Frontend-->>User: Show neutralization enabled indicator
(uses existing config) + else Config disabled or not found + Frontend->>Frontend: Mark neutralization as disabled + Frontend-->>User: Show neutralization disabled
(user can configure on settings page) + end + end + + alt User optionally attaches files + alt User drags and drops files + User->>Frontend: Drag file(s) over drop zone + Frontend->>Frontend: Show visual feedback
(highlight drop zone, border, overlay) + Frontend-->>User: Display drop zone active state + User->>Frontend: Drop file(s) onto drop zone + Frontend->>Frontend: Process dropped files + Frontend->>Frontend: Show file preview with name and size + Frontend->>Frontend: Optimistic update: Add file to attachment list + Frontend->>Backend: POST /api/files/upload
+ multipart/form-data (file)
+ workflowId (optional) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show permission error + else File too large (413) + Backend-->>Frontend: 413 Request Entity Too Large + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show file size error + else Success (201) + Backend-->>Frontend: FileItem object + duplicate info + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Store fileId for later use + Frontend-->>User: Show file attached successfully + end + else User uploads new file via button + User->>Frontend: Click "Attach File" or "Upload File" button + Frontend->>Frontend: Open file picker dialog + User->>Frontend: Select file(s) from device + Frontend->>Frontend: Show file preview with name and size + Frontend->>Frontend: Optimistic update: Add file to attachment list + Frontend->>Backend: POST /api/files/upload
+ multipart/form-data (file)
+ workflowId (optional) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show permission error + else File too large (413) + Backend-->>Frontend: 413 Request Entity Too Large + Frontend->>Frontend: Revert optimistic update: Remove file from list + Frontend-->>User: Show file size error + else Success (201) + Backend-->>Frontend: FileItem object + duplicate info + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Store fileId for later use + Frontend-->>User: Show file attached successfully + end + else User selects existing file + User->>Frontend: Click "Browse Files" or "Select File" button + Frontend->>Backend: GET /api/files/list + Backend-->>Frontend: Paginated files list + Frontend->>Frontend: Display file browser/selector + Frontend-->>User: Show available files + User->>Frontend: Select file(s) from list + Frontend->>Frontend: Add fileId(s) to attachment list + Frontend-->>User: Show selected files in attachment list + end + end + + User->>Frontend: Click "Continue" or "Send" button + + Frontend->>Frontend: Validate form (required fields, workflowMode) + alt Validation fails (missing workflowMode or prompt) + Frontend-->>User: Show validation errors
(e.g., "Workflow mode is required") + else Validation passes + Frontend->>Frontend: Build UserInputRequest with listFileId array (if files attached) + alt Neutralization enabled + Frontend->>Frontend: Neutralization will be applied automatically
by backend during workflow processing + end + Frontend->>Frontend: Optimistic update: Add user message to UI + Frontend->>Backend: POST /api/chat/playground/start
+ workflowId query param (from selected workflow)
+ workflowMode query param (from selected workflow)
+ UserInputRequest body
(includes listFileId if files attached) + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error + else Workflow not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show not found error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Updated ChatWorkflow (status: "running")
with new files attached (if any)
(neutralized if neutralization enabled) + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Navigate to workflow view or update current view + Frontend->>Frontend: Start/continue polling for updates + alt Neutralization enabled + Frontend->>Frontend: Show neutralization indicator in workflow view + Frontend->>Frontend: Option to resolve text back to original when viewing + end + Frontend-->>User: Display updated workflow with new input
(files visible if attached, neutralized if enabled) + end + end +``` + +--- + +## Customer Journey 3: Live Tracking Workflow Progress + +### User Goal +"I want to see real-time updates as my workflow processes my request." + +### User Story +As a user, I want to see live updates including new messages, execution logs, and statistics as my workflow processes, so I can monitor progress and understand what the system is doing. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: View active workflow + Frontend->>Frontend: Start polling interval (e.g., every 2 seconds) + + loop Polling cycle + Frontend->>Backend: GET /api/chat/playground/workflowId/chatData
+ afterTimestamp query param (optional) + alt Workflow not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Stop polling + Frontend-->>User: Show error, navigate away + else Success (200) + Backend-->>Frontend: Unified chat data
{messages: [], logs: [], stats: []}
(chronologically ordered by _createdAt) + Frontend->>Frontend: Compare with existing data + alt New data available + Frontend->>Frontend: Append new messages to chat view + Frontend->>Frontend: Append new logs to log panel + Frontend->>Frontend: Update statistics display + Frontend->>Frontend: Update workflow status indicator + Frontend->>Frontend: Scroll to latest content (if auto-scroll enabled) + Frontend-->>User: Display new messages, logs, stats + else No new data + Frontend->>Frontend: Continue polling silently + end + + alt Workflow status is "completed" or "stopped" or "failed" + Frontend->>Frontend: Stop polling + Frontend->>Frontend: Show final status + Frontend-->>User: Display completed workflow + end + end + end + + alt User manually stops polling + User->>Frontend: Navigate away or close tab + Frontend->>Frontend: Stop polling interval + end +``` + +--- + +## Customer Journey 4: Stopping a Running Workflow + +### User Goal +"I want to stop a workflow that is currently running." + +### User Story +As a user, I want to stop a running workflow by clicking a stop button, so I can halt processing if I no longer need the results or if something is taking too long. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: View running workflow + Frontend->>Frontend: Display "Stop" button + User->>Frontend: Click "Stop" button + + Frontend->>Frontend: Show confirmation dialog
"Stop this workflow?" + alt User cancels + User->>Frontend: Click "Cancel" + Frontend->>Frontend: Close dialog + Frontend-->>User: Dialog closed, workflow continues + else User confirms + User->>Frontend: Click "Confirm" + Frontend->>Frontend: Optimistic update: Update status to "stopping" + Frontend->>Backend: POST /api/chat/playground/workflowId/stop + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error + else Workflow not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Updated ChatWorkflow (status: "stopped") + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Stop polling for updates + Frontend->>Backend: GET /api/workflows/workflowId (refetch) + Backend-->>Frontend: Final workflow state + Frontend->>Frontend: Update UI with stopped status + Frontend-->>User: Show stopped workflow with final state + end + end +``` + +--- + +## Customer Journey 5: Deleting Context from a Workflow + +### User Goal +"I want to remove messages or files from a workflow to clean up the context." + +### User Story +As a user, I want to delete individual messages or files attached to messages in a workflow, so I can remove unwanted context and keep the workflow focused on what's relevant. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + alt User deletes message from workflow + User->>Frontend: View workflow with messages + User->>Frontend: Click "Delete" button on message + Frontend->>Frontend: Show confirmation dialog
"Delete this message?
This will remove it from the workflow context." + alt User cancels + User->>Frontend: Click "Cancel" + Frontend->>Frontend: Close dialog + Frontend-->>User: Dialog closed, message remains + else User confirms + User->>Frontend: Click "Confirm" or "Delete" + Frontend->>Frontend: Optimistic update: Remove message from UI + Frontend->>Backend: DELETE /api/workflows/workflowId/messages/messageId + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore message + Frontend-->>User: Show permission error + else Message not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore message + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Success response
{workflowId, messageId, message: "Message deleted successfully"} + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/workflows/workflowId (refetch) + Backend-->>Frontend: Updated workflow (messageIds updated) + Frontend->>Frontend: Update UI with fresh workflow data + Frontend-->>User: Show message removed from workflow + end + end + end + + alt User deletes file from message + User->>Frontend: View message with file attachments + User->>Frontend: Click "Delete" button on file attachment + Frontend->>Frontend: Show confirmation dialog
"Delete this file?
This will remove it from the message context." + alt User cancels + User->>Frontend: Click "Cancel" + Frontend->>Frontend: Close dialog + Frontend-->>User: Dialog closed, file remains + else User confirms + User->>Frontend: Click "Confirm" or "Delete" + Frontend->>Frontend: Optimistic update: Remove file from UI + Frontend->>Backend: DELETE /api/workflows/workflowId/messages/messageId/files/fileId + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore file + Frontend-->>User: Show permission error + else File not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore file + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Success response
{workflowId, messageId, fileId, message: "File reference deleted successfully"} + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/workflows/workflowId/messages/messageId (refetch) + Backend-->>Frontend: Updated message (files list updated) + Frontend->>Frontend: Update UI with fresh message data + Frontend-->>User: Show file removed from message + end + end + end +``` + diff --git a/docs/frontend-documentation/connection-page-customer-journeys.md b/docs/frontend-documentation/connection-page-customer-journeys.md new file mode 100644 index 00000000..2e0dc279 --- /dev/null +++ b/docs/frontend-documentation/connection-page-customer-journeys.md @@ -0,0 +1,293 @@ +# Connection Routes Frontend Documentation + +This document describes customer journeys for managing connections through the frontend, focusing on how users interact with connection management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Discovering and Browsing Connections](#customer-journey-1-discovering-and-browsing-connections) +3. [Customer Journey 2: Creating New Connections](#customer-journey-2-creating-new-connections) +4. [Customer Journey 3: Editing Connection Properties](#customer-journey-3-editing-connection-properties) +5. [Customer Journey 4: Refreshing Connection Tokens](#customer-journey-4-refreshing-connection-tokens) +6. [Customer Journey 5: Deleting Connections](#customer-journey-5-deleting-connections) + +--- + +## Overview + +The connection routes (`/api/connections`) enable users to manage their OAuth connections (Google, Microsoft) within their account. These routes focus on **connection administration** including creation, editing, token refresh, and deletion. + +**Key Principles:** +- **User-Centric**: Documentation organized around what users want to accomplish +- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata +- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend +- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully +- **User-Scoped**: Users can only see and manage their own connections + +--- + +## Customer Journey 1: Discovering and Browsing Connections + +### User Goal +"I want to see all my connections and find the one I'm looking for." + +### User Story +As a user, I want to browse my connections, search for specific connections, filter by any field, sort them by different criteria, and quickly identify connections by their authority, status, and token status. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to /connections + Frontend->>Backend: GET /api/attributes/UserConnection + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/connections/ + Backend-->>Frontend: Connections list (with token status) + Frontend->>Frontend: Generate table columns from attributes + Frontend->>Frontend: Generate filter controls from attributes + Frontend->>Frontend: Render connections table + search + filters + Frontend->>Frontend: Render action buttons in table (Edit, Delete, Refresh Token) + Frontend-->>User: Display connection list with search/filter UI + action buttons + + alt User performs general search + User->>Frontend: Type in search box (e.g., "google") + Frontend->>Frontend: Update search query + Frontend->>Backend: GET /api/connections/ (client-side filter) + Frontend-->>User: Display matching connections + end + + alt User applies field filter + User->>Frontend: Select filter field (e.g., "Authority") + Frontend->>Frontend: Show filter options from attribute metadata + User->>Frontend: Select filter value (e.g., "google") + Frontend->>Frontend: Update filter parameters + Frontend->>Backend: GET /api/connections/ (client-side filter) + Frontend-->>User: Display filtered connections + end + + alt User combines search + filter + sort + User->>Frontend: Apply search + filter + sort + Frontend->>Frontend: Combine all parameters + Frontend->>Backend: GET /api/connections/ (client-side filter/sort) + Frontend-->>User: Display results + end + + User->>Frontend: Click column header (e.g., "Status") + Frontend->>Frontend: Update sort parameters + Frontend->>Backend: GET /api/connections/ (client-side sort) + Backend-->>Frontend: Connections list + Frontend-->>User: Display sorted connections +``` + +--- + +## Customer Journey 2: Creating New Connections + +### User Goal +"I want to create new OAuth connections for my account." + +### User Story +As a user, I want to create a new connection by clicking either "Connect Google" or "Connect Microsoft" button, which will immediately initiate the OAuth flow. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + alt User clicks "Connect Google" button + User->>Frontend: Click "Connect Google" button + Frontend->>Frontend: Optimistic update: Show loading state, add connection to UI immediately + Frontend->>Backend: POST /api/connections/ + {type: "google"} + else User clicks "Connect Microsoft" button + User->>Frontend: Click "Connect Microsoft" button + Frontend->>Frontend: Optimistic update: Show loading state, add connection to UI immediately + Frontend->>Backend: POST /api/connections/ + {type: "msft"} + end + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove connection from UI + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update: Remove connection from UI + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created connection object (status: PENDING) + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: POST /api/connections/connectionId/connect + Backend-->>Frontend: {authUrl: "/api/google/login?state=..."} or {authUrl: "/api/msft/login?state=..."} + Frontend->>Frontend: Navigate to authUrl (OAuth flow) + Frontend-->>User: Redirect to OAuth provider + end +``` + +--- + +## Customer Journey 3: Editing Connection Properties + +### User Goal +"I want to change connection settings like its status or external email." + +### User Story +As a user, I want to edit a connection's properties through a popup/modal form that only shows fields I'm allowed to edit, with validation and clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Edit" button in table row + Frontend->>Backend: GET /api/connections/connectionId + Backend-->>Frontend: Current connection data + + Frontend->>Backend: GET /api/attributes/UserConnection + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend->>Frontend: Pre-populate form with connection data + Frontend->>Frontend: Open popup/modal with edit form + Frontend-->>User: Display edit form in popup/modal + + User->>Frontend: Modify form fields + User->>Frontend: Click "Save" + + Frontend->>Frontend: Validate form (required fields, types) + alt Validation fails + Frontend-->>User: Show validation errors in modal + else Validation passes + Frontend->>Frontend: Optimistic update: Apply changes to UI immediately + Frontend->>Backend: PUT /api/connections/connectionId + form data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error in modal + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show backend validation errors in modal + else Success (200) + Backend-->>Frontend: Updated connection + Frontend->>Frontend: Keep optimistic update (or refresh from response) + Frontend->>Backend: GET /api/connections/ (refetch) + Backend-->>Frontend: Updated connections list + Frontend->>Frontend: Update table with fresh data + Frontend->>Frontend: Close popup/modal + Frontend-->>User: Show updated connection in table + end + end + + alt User clicks Cancel + User->>Frontend: Click "Cancel" button + Frontend->>Frontend: Close popup/modal without saving + Frontend-->>User: Modal closed, no changes + end +``` + +--- + +## Customer Journey 4: Refreshing Connection Tokens + +### User Goal +"I want to refresh the OAuth token for a connection that is expired or about to expire." + +### User Story +As a user, I want to refresh the OAuth token for a connection by clicking a refresh button, so the connection remains active. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Refresh Token" button in table + Frontend->>Frontend: Show loading state + Frontend->>Frontend: Optimistic update: Update token status to "refreshing" + + alt Connection authority is Microsoft + Frontend->>Backend: POST /api/msft/refresh + {connectionId: connectionId} + else Connection authority is Google + Frontend->>Backend: POST /api/google/refresh + {connectionId: connectionId} + end + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error + else Connection not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: {message: "Token refreshed successfully", expires_at: timestamp, expires_in_seconds: number} + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/connections/ (refetch) + Backend-->>Frontend: Updated connections list with new token status + Frontend->>Frontend: Update table with fresh data + Frontend-->>User: Show success message, updated token status + end +``` + +--- + +## Customer Journey 5: Deleting Connections + +### User Goal +"I want to delete connections that are no longer needed." + +### User Story +As a user, I want to delete connections with a clear confirmation to prevent accidental deletion. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Delete" button + Frontend->>Backend: GET /api/connections/ + Backend-->>Frontend: Connections list + Frontend->>Frontend: Find connection by ID (for name/authority) + Frontend->>Frontend: Show confirmation dialog
"Delete 'Google Connection'?" + User->>Frontend: Cancel deletion + Frontend-->>User: Dialog closed, no action + + User->>Frontend: Click "Delete" button again + Frontend->>Backend: GET /api/connections/ + Backend-->>Frontend: Connections list + Frontend->>Frontend: Show confirmation dialog + User->>Frontend: Confirm deletion + Frontend->>Frontend: Optimistic update: Remove connection from UI immediately + Frontend->>Backend: DELETE /api/connections/connectionId + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore connection in UI + Frontend-->>User: Show permission error + else Not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore connection in UI + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update (connection already removed) + Frontend->>Frontend: Show success message + Frontend-->>User: Display connection list (without deleted connection) + end +``` + diff --git a/docs/frontend-documentation/connection-page-requirements.md b/docs/frontend-documentation/connection-page-requirements.md new file mode 100644 index 00000000..49ecdfd0 --- /dev/null +++ b/docs/frontend-documentation/connection-page-requirements.md @@ -0,0 +1,491 @@ +# Connection Page Requirements + +This document contains the complete frontend requirements for all connection management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) + +--- + +## Overview + +The connection management page enables users to manage their OAuth connections (Google, Microsoft) within their account. The frontend consists of a single page (`/connections`) with different views/states: + +- **List View** - Browse, search, filter, and sort connections (all information displayed in table) +- **Edit View** - Edit connection properties in popup/modal + +All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/UserConnection` endpoint. Views are managed through component state and routing within the same page, not as separate routes. + +**Note:** Connections are user-scoped. Users can only see and manage their own connections. The backend enforces this security. + +--- + +## Page Structure and Layout + +### Connection Management Page (`/connections`) + +The connection management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component. + +### List View + +**State:** `view === 'list'` or `selectedConnectionId === null` + +**What the user sees:** + +- **Main Content Area:** + - Table or card grid displaying all connections for the current user + - Each connection row/card shows: authority, external username, external email, status, token status, connected at, last checked + - **Action buttons column** in table (rendered on first load): + - "Edit" button - opens popup/modal edit form + - "Delete" button - shows confirmation dialog and deletes connection + - "Refresh Token" button - refreshes OAuth token for the connection + - All necessary connection information displayed in table (no detail view needed) + +- **Search and Filter Controls:** + - General search input box (searches across all text fields) + - Field-specific filter controls (one filter per visible field) + - Active filter indicators (chips/badges showing applied filters) + - "Clear all filters" button when filters are active + - **Note:** Filtering and sorting are done client-side (connections endpoint returns all user connections) + +- **Sorting Controls:** + - Clickable column headers with sort indicators (up/down arrows) + - Visual indication of current sort field and direction + - Support for multi-level sorting + - **Note:** Sorting is done client-side + +- **Action Buttons:** + - "Connect Google" button - creates Google connection and initiates OAuth flow + - "Connect Microsoft" button - creates Microsoft connection and initiates OAuth flow + +### Edit View (Popup/Modal) + +**State:** `view === 'edit'` and `selectedConnectionId !== null` (popup/modal overlay) + +**What the user sees:** + +- **Edit Form in Popup/Modal:** + - Dynamic form with editable connection fields only + - Field labels with required indicators (asterisk for required fields) + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + - Form pre-populated with current connection values + - Save and Cancel buttons in modal footer + - On save: Updates connection, closes modal, refreshes table + - On cancel: Closes modal without saving + +- **Confirmation Dialogs:** + - Delete confirmation dialog + +--- + +## User Interactions and Functionality + +### Browsing and Discovery + +**Search Functionality:** +- User types in general search box +- Frontend debounces input (300-500ms delay) +- Search applies across all text fields in connection objects +- **Client-side filtering** (connections endpoint returns all user connections) +- Results update automatically + +**Field Filtering:** +- User selects field to filter by +- Frontend shows appropriate filter UI based on field type: + - Text fields → Text input with operator selection (contains, equals, startsWith, endsWith) + - Select fields → Dropdown with options from backend metadata + - Timestamp fields → Date picker with comparison operators or date range picker +- User applies filter → Filter appears as active chip/badge +- User can remove individual filters +- Multiple filters work together (AND logic) +- **Client-side filtering** (no backend pagination) + +**Sorting:** +- User clicks column header +- Sort direction toggles (asc → desc → remove) +- Multiple columns can be sorted (multi-level sorting) +- Sort indicators show on column headers +- All filters and search preserved when sorting +- **Client-side sorting** (no backend pagination) + +**View Switching:** +- All connection information displayed in table (no detail view navigation needed) + +### Creating Connections + +**Create Interaction:** +- User clicks "Connect Google" button → Immediately creates Google connection and initiates OAuth flow +- OR user clicks "Connect Microsoft" button → Immediately creates Microsoft connection and initiates OAuth flow +- No dialog or selection step needed + +**Connection Creation:** +- Connection created with PENDING status +- OAuth flow automatically initiated via `/api/connections/{connectionId}/connect` +- User redirected to OAuth provider +- After OAuth completion, connection status updated to ACTIVE + +**Connection Submission:** +- For Google: Connection type sent as `{type: "google"}` +- For Microsoft: Connection type sent as `{type: "msft"}` +- Success → Connection created, OAuth flow initiated, user redirected +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Editing Connections + +**Edit Interaction:** +- User clicks "Edit" button in table row → Opens popup/modal edit form +- Form pre-populated with current connection values +- User modifies fields (typically externalEmail, status) +- Client-side validation shows errors immediately +- User clicks Save → Form validates and submits +- User clicks Cancel → Closes modal without saving + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., email fields must be valid email format) +- Select field validation (value must be in options array) +- Validation errors displayed inline below fields + +**Form Submission:** +- Only changed fields sent (or all form data) +- Success → Close popup/modal, refresh table, show success message +- Error handling: + - 403 (permission denied) → Show permission error in modal + - 400 (validation errors) → Display backend validation errors in modal + - Other errors → Show generic error message in modal + +### Refreshing Connection Tokens + +**Refresh Token Action:** +- User clicks "Refresh Token" button in table +- Frontend shows loading state +- Frontend determines connection authority (Google or Microsoft) +- Frontend calls appropriate refresh endpoint: + - Microsoft: `POST /api/msft/refresh` with `{connectionId: connectionId}` + - Google: `POST /api/google/refresh` with `{connectionId: connectionId}` +- Success → Token refreshed, connection status updated, table refreshed +- Error handling: + - 403 (permission denied) → Show permission error + - 404 (connection not found) → Show not found error + - Other errors → Show generic error message + +**Implementation Notes:** +- Refresh button should be disabled or show loading state during refresh +- Token status should update immediately after successful refresh +- Connection status may change from "expired" to "active" after refresh + +### Deleting Connections + +**Delete Action:** +- User clicks delete button in table +- Confirmation dialog appears with connection authority/type +- Warning about permanent deletion +- User confirms → Connection deleted +- User cancels → Dialog closes, no action + +**Delete Success Handling:** +- Success message displayed +- Remove connection from list or refresh table + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by connection pages: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/connections/` | GET | Get all connections for current user | Initial page load | Current user only (returns only user's connections) | +| `/api/connections/` | POST | Create new connection | User selects connection type | Current user only | +| `/api/connections/{connectionId}` | PUT | Update connection | Edit form submission | Current user only | +| `/api/connections/{connectionId}` | DELETE | Delete connection | User confirms deletion | Current user only | +| `/api/connections/{connectionId}/connect` | POST | Initiate OAuth flow | After connection creation | Current user only | +| `/api/msft/refresh` | POST | Refresh Microsoft token | User clicks refresh token for MSFT connection | Current user only | +| `/api/google/refresh` | POST | Refresh Google token | User clicks refresh token for Google connection | Current user only | +| `/api/attributes/UserConnection` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users | + +### API Request Patterns + +**Get Connections Request:** +``` +GET /api/connections/ +``` +- Returns all connections for the current user (no pagination) +- Response includes token status information +- Filtering and sorting done client-side + +**Create Connection Request:** +``` +POST /api/connections/ +Content-Type: application/json +Body: { + "type": "google" | "msft" +} +``` +- Creates connection with PENDING status +- Returns created connection object +- Handle 403 (permission denied) and 400 (validation errors) + +**Connect Service Request:** +``` +POST /api/connections/{connectionId}/connect +``` +- Returns `{authUrl: "/api/google/login?state=..."}` or `{authUrl: "/api/msft/login?state=..."}` +- Frontend should navigate to the authUrl to initiate OAuth flow +- Called automatically after connection creation + +**Update Request:** +``` +PUT /api/connections/{connectionId} +Content-Type: application/json +Body: {fieldName: value, ...} +``` +- Send only changed fields or all form data +- Handle 403 (permission denied) and 400 (validation errors) + +**Refresh Token Request:** +``` +POST /api/msft/refresh +Content-Type: application/json +Body: {"connectionId": "connection-id"} +``` +OR +``` +POST /api/google/refresh +Content-Type: application/json +Body: {"connectionId": "connection-id"} +``` +- Returns `{message: "Token refreshed successfully", expires_at: timestamp, expires_in_seconds: number}` +- Handle 403 (permission denied) and 404 (connection not found) + +**Delete Requests:** +``` +DELETE /api/connections/{connectionId} +``` +- Delete operation requires user confirmation +- Handle 403 (permission denied) and 404 (not found) gracefully + +### Response Handling + +**Get Connections Response:** +```json +[ + { + "id": "...", + "userId": "...", + "authority": "google", + "externalId": "...", + "externalUsername": "...", + "externalEmail": "...", + "status": "active", + "connectedAt": 1234567890, + "lastChecked": 1234567890, + "expiresAt": 1234567890, + "tokenStatus": "active", + "tokenExpiresAt": 1234567890 + }, + ... +] +``` +- Returns array of connections (no pagination) +- Each connection includes token status information + +**Error Responses:** +- 403 Forbidden → Show permission error message +- 404 Not Found → Show "not found" error message +- 400 Bad Request → Display validation errors from response +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Complete Field List + +The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for connections. All of these are provided by the backend through the `/api/attributes/UserConnection` endpoint and should never be hardcoded in the frontend. + +#### Core Connection Fields + +**Identification Fields:** +- `id` - Unique connection identifier (text, readonly, not required, visible) +- `userId` - ID of the user this connection belongs to (text, readonly, not required, visible) + +**Connection Properties:** +- `authority` - Authentication authority (select, readonly, not required, visible) + - Options: "local", "google", "msft" + - Each option has localized labels (en/fr) +- `externalId` - User ID in the external system (text, readonly, not required, visible) +- `externalUsername` - Username in the external system (text, editable, required, visible) +- `externalEmail` - Email in the external system (email, editable, not required, visible) +- `status` - Connection status (select, editable, not required, visible) + - Options: "active", "inactive", "expired", "pending" + - Each option has localized labels (en/fr) + +**Timestamp Fields:** +- `connectedAt` - When the connection was established (timestamp, readonly, not required, visible) +- `lastChecked` - When the connection was last verified (timestamp, readonly, not required, visible) +- `expiresAt` - When the connection expires (timestamp, readonly, not required, visible) + +**Token Status Fields:** +- `tokenStatus` - Current token status (select, readonly, not required, visible) + - Options: "active", "expired", "none" + - Each option has localized labels (en/fr) +- `tokenExpiresAt` - When the current token expires (timestamp, readonly, not required, visible) + +### Attribute Definition Structure + +Each field returned from `/api/attributes/UserConnection` contains: + +- `name` - Field name (e.g., "authority", "status", "externalEmail", "id") +- `type` - Field data type (e.g., "text", "select", "email", "timestamp", "checkbox") +- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"}) +- `description` - Field description text +- `required` - Boolean indicating if field is required +- `readonly` - Boolean indicating if field is read-only +- `editable` - Boolean indicating if field can be edited (inverse of readonly) +- `visible` - Boolean indicating if field should be displayed in UI +- `options` - Array of options for select fields (each option has `value` and localized `label`) + +--- + +## Dynamic Rendering Guidelines + +The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded. + +### Table Column Generation + +When rendering the connection list table: + +1. Fetch attribute definitions from `/api/attributes/UserConnection` +2. Filter attributes where `visible: true` to determine which columns to display +3. Use `label` property for column headers (select appropriate language based on user preference) +4. Use `type` property to determine how to format cell values: + - `text` fields → Display as plain text + - `email` fields → Display as clickable mailto link + - `select` fields → Display value using label from options array (match value to option.value, then display option.label) + - `timestamp` fields → Format as relative time ("2 hours ago") or absolute date/time based on user preference + - `checkbox` fields → Display as checkmark icon or "Yes"/"No" text +5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are) +6. Generate click handlers for column headers to update sort parameters (client-side sorting) +7. **Add Actions Column:** + - Render action buttons in each table row on first load + - Include "Edit" button - opens popup/modal edit form + - Include "Delete" button - shows confirmation dialog + - Include "Refresh Token" button - refreshes OAuth token (only for Google/MSFT connections) + - Buttons should be visible and accessible in each row + +### Filter Control Generation + +When rendering filter controls: + +1. Fetch attribute definitions from `/api/attributes/UserConnection` +2. Filter attributes where `visible: true` to determine which filters to show +3. For each visible field, generate appropriate filter UI based on `type`: + - `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - `email` fields → Email input filter + - `select` fields → Dropdown filter with options from `options` array (use localized labels) + - `timestamp` fields → Date range picker or single date picker with comparison operators + - `checkbox` fields → Boolean toggle filter (true/false/any) +4. Use `label` property for filter labels (localized) +5. When user applies filter, update client-side filter state +6. Display active filters as chips/badges showing field label and value +7. Allow removing individual filters +8. **Note:** All filtering is done client-side (connections endpoint returns all user connections) + +### Search Implementation + +For general search functionality: + +1. Display a single search input box (not field-specific) +2. When user types, update client-side search state +3. Debounce search input (wait 300-500ms after user stops typing before filtering) +4. Search applies across all text fields in the connection object +5. **Note:** All searching is done client-side (connections endpoint returns all user connections) + +### Form Field Generation + +When rendering edit forms: + +1. Fetch attribute definitions from `/api/attributes/UserConnection` +2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show +3. For each editable field, generate appropriate form input based on `type`: + - `text` fields → Text input + - `email` fields → Email input + - `select` fields → Dropdown/select input with options from `options` array (use localized labels) + - `timestamp` fields → Date/time picker + - `checkbox` fields → Checkbox input +4. Use `label` property for field labels (localized) +5. Use `required` property to show required indicators (asterisk, etc.) +6. Use `description` property to show help text or tooltips +7. Validate form before submission: + - Check all `required: true` fields have values + - Validate types (e.g., email fields must be valid email format) + - Validate select fields (value must be in options array) +8. On submit, send only changed fields or all form data to update endpoint + +### Display Formatting + +When displaying field values: + +1. Use `type` property to determine formatting: + - `text` → Display as-is (may need HTML escaping) + - `email` → Display as clickable mailto link + - `select` → Look up value in `options` array and display localized label + - `timestamp` → Format as relative time or absolute date/time + - `checkbox` → Display as checkmark icon or "Yes"/"No" text +2. Handle `null` or `undefined` values gracefully (show "-" or "Not set") +3. Use `readonly` property to determine if field should show edit indicators +4. Special formatting for connection fields: + - Authority → Display as badge with icon (Google, Microsoft) + - Status → Color-code badges (Active = green, Inactive = gray, Expired = red, Pending = yellow) + - Token Status → Color-code badges (Active = green, Expired = red, None = gray) + - Timestamps → Show relative time in list view, absolute date in detail view + +### Localization + +All labels and options support multiple languages: + +1. Use user's preferred language (from user settings or browser locale) +2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback +3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback +4. If label for current language is missing, fall back to English + +### Key Principles + +- Never hardcode field names, labels, types, or validation rules +- Always fetch attribute definitions from backend before rendering UI +- Use attribute metadata to determine what to display and how to display it +- Support all field types dynamically - if backend adds new types, frontend should handle them +- Respect `visible`, `editable`, `readonly`, and `required` flags from backend +- Use localized labels from backend metadata +- Generate filters, forms, and tables entirely from attribute definitions +- When backend adds new fields, frontend should automatically display them without code changes +- Handle all error cases gracefully (403, 404, 400, 500) +- Provide user feedback for all actions (loading states, success messages, error messages) +- **All filtering and sorting is done client-side** (connections endpoint returns all user connections) +- **Users can only see and manage their own connections** (backend enforces this) + +--- + +## Summary + +This document provides complete frontend requirements for all connection management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/UserConnection` endpoint. + +**Key Architecture Pattern:** The connection management interface is a single page (`/connections`) with different views managed through component state. All interactions happen within the same page component without separate routes. + +**Security Note:** Connections are user-scoped. Users can only see and manage their own connections. The backend enforces this security, and the frontend should never attempt to access other users' connections. + +For generic patterns that apply across all entity types (not just connections), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md). + diff --git a/docs/frontend-documentation/dynamic-forms-and-pagination.md b/docs/frontend-documentation/dynamic-forms-and-pagination.md new file mode 100644 index 00000000..d699c449 --- /dev/null +++ b/docs/frontend-documentation/dynamic-forms-and-pagination.md @@ -0,0 +1,689 @@ +# Dynamic Forms and Pagination - Generic Frontend Patterns + +This document describes the generic, reusable patterns for dynamic form generation and pagination that apply across all entity types in the frontend. These patterns enable completely backend-driven UI generation with no hardcoding. + +## Table of Contents + +1. [Overview](#overview) +2. [Backend Metadata System](#backend-metadata-system) +3. [Dynamic Form Generation](#dynamic-form-generation) +4. [Pagination System](#pagination-system) +5. [Search and Filtering](#search-and-filtering) +6. [Sorting](#sorting) +7. [Localization](#localization) +8. [Implementation Patterns](#implementation-patterns) + +--- + +## Overview + +The frontend uses a **completely backend-driven approach** for generating forms, tables, filters, and pagination controls. All field definitions, labels, validation rules, and UI structure come from the backend through the attribute definition system. + +### Key Principles + +- **No Hardcoding**: Field names, labels, types, validation rules, and options are never hardcoded +- **Backend-Driven**: All UI components generated from backend metadata +- **Entity-Agnostic**: Same patterns work for workflows, users, mandates, files, prompts, automations, etc. +- **Automatic Updates**: When backend adds new fields, frontend automatically displays them without code changes +- **Localization**: All labels and options support multiple languages from backend + +### Applicable Entity Types + +These patterns apply to any entity type that has: +- An attributes endpoint: `GET /api/attributes/{EntityType}` +- A list endpoint supporting pagination: `GET /api/{entities}/?pagination=...` +- CRUD operations: Create, Read, Update, Delete + +Examples: `ChatWorkflow`, `User`, `Mandate`, `FileItem`, `Prompt`, `AutomationDefinition`, `ChatMessage`, `ChatLog`, etc. + +--- + +## Backend Metadata System + +### Attribute Definition Endpoint + +Every entity type exposes an attributes endpoint that provides complete metadata: + +``` +GET /api/attributes/{EntityType} +``` + +**Examples:** +- `GET /api/attributes/ChatWorkflow` +- `GET /api/attributes/User` +- `GET /api/attributes/Mandate` +- `GET /api/attributes/FileItem` +- `GET /api/attributes/Prompt` + +### Attribute Definition Structure + +Each attribute returned from the endpoint contains: + +- **`name`** - Field name (e.g., "status", "name", "email", "createdAt") +- **`type`** - Field data type (e.g., "text", "select", "integer", "timestamp", "checkbox", "email", "url") +- **`label`** - Localized field label (object with language keys: `{"en": "English Label", "fr": "French Label"}`) +- **`description`** - Field description text (for help text/tooltips) +- **`required`** - Boolean indicating if field is required for validation +- **`readonly`** - Boolean indicating if field is read-only (cannot be edited) +- **`editable`** - Boolean indicating if field can be edited (inverse of readonly) +- **`visible`** - Boolean indicating if field should be displayed in UI +- **`options`** - Array of options for select fields (each option has `value` and localized `label`) + +### Response Format + +The attributes endpoint returns: + +```json +{ + "entityType": "ChatWorkflow", + "attributes": [ + { + "name": "status", + "type": "select", + "label": {"en": "Status", "fr": "Statut"}, + "description": "Current status of the workflow", + "required": false, + "readonly": false, + "editable": true, + "visible": true, + "options": [ + {"value": "running", "label": {"en": "Running", "fr": "En cours"}}, + {"value": "completed", "label": {"en": "Completed", "fr": "Terminé"}} + ] + }, + { + "name": "name", + "type": "text", + "label": {"en": "Name", "fr": "Nom"}, + "description": "Name of the workflow", + "required": true, + "readonly": false, + "editable": true, + "visible": true + } + // ... more attributes + ] +} +``` + +--- + +## Dynamic Form Generation + +Dynamic forms are generated entirely from backend attribute definitions. The same pattern works for create forms, edit forms, and inline editing. + +### Form Generation Process + +1. **Fetch Attribute Definitions** + - Call `GET /api/attributes/{EntityType}` when form component mounts + - Store attribute definitions in component state + +2. **Filter Attributes** + - For edit forms: Filter where `visible: true` AND `editable: true` + - For create forms: Filter where `visible: true` AND `editable: true` (may exclude readonly fields) + - For display-only: Filter where `visible: true` + +3. **Generate Form Fields** + - Iterate through filtered attributes + - Generate appropriate input component based on `type` + - Use `label` for field labels (localized) + - Use `description` for help text/tooltips + - Use `required` to show required indicators + +4. **Handle Form Submission** + - Validate form using attribute metadata + - Send form data to appropriate endpoint (POST for create, PUT for update) + - Handle success/error responses + +### Field Type to Input Component Mapping + +Based on the `type` property, generate appropriate input components: + +- **`text`** → Text input (single line) +- **`textarea`** → Multi-line text area +- **`select`** → Dropdown/select input with options from `options` array +- **`integer`** → Number input (integer only) +- **`float`** or **`number`** → Number input (decimal allowed) +- **`timestamp`** → Date/time picker +- **`date`** → Date picker (date only) +- **`time`** → Time picker (time only) +- **`checkbox`** → Checkbox input (boolean) +- **`email`** → Email input (with email validation) +- **`url`** → URL input (with URL validation) +- **`password`** → Password input (masked) +- **`file`** → File upload input + +### Form Field Rendering Rules + +For each form field: + +1. **Field Label** + - Use `label[userLanguage]` or `label.en` as fallback + - Show required indicator (asterisk, etc.) if `required: true` + +2. **Input Component** + - Generate based on `type` property + - For `select` fields: Populate options from `options` array, use localized labels + - For `integer`/`number` fields: Set appropriate min/max constraints if available + - For `timestamp`/`date`/`time` fields: Use appropriate date/time picker component + +3. **Help Text** + - Display `description` as help text or tooltip + - Show below or next to input field + +4. **Validation** + - Mark field as required if `required: true` + - Validate type (e.g., integer fields must be numbers) + - Validate select fields (value must be in options array) + - Validate email/url fields with appropriate regex patterns + +5. **Disabled State** + - Disable input if `readonly: true` or `editable: false` + - Show read-only indicator if applicable + +### Form Validation + +Before form submission: + +1. **Required Field Validation** + - Check all fields where `required: true` have non-empty values + - Show error messages for missing required fields + +2. **Type Validation** + - Validate integer fields contain valid integers + - Validate number fields contain valid numbers + - Validate email fields contain valid email addresses + - Validate URL fields contain valid URLs + - Validate timestamp/date fields contain valid dates + +3. **Option Validation** + - For select fields, ensure value exists in `options` array + - Show error if invalid option selected + +4. **Custom Validation** + - Apply any additional validation rules from backend metadata if available + +### Form Submission + +On form submit: + +1. **Collect Form Data** + - Gather values from all form fields + - Use attribute `name` as keys in form data object + +2. **Prepare Request** + - For create: `POST /api/{entities}` with form data + - For update: `PUT /api/{entities}/{id}` with form data + - Include only changed fields (for updates) or all form data (for creates) + +3. **Handle Response** + - On success: Show success message, navigate or refresh as appropriate + - On error: Display validation errors from backend, highlight invalid fields + +--- + +## Pagination System + +Pagination is a unified system that works across all list endpoints. It supports pagination, sorting, filtering, and general search in a consistent way. + +### Pagination Endpoint Pattern + +All list endpoints support pagination through a query parameter: + +``` +GET /api/{entities}/?pagination={JSON_ENCODED_PAGINATION_PARAMS} +``` + +**Examples:** +- `GET /api/workflows/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}` +- `GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[{"field":"name","direction":"asc"}],"filters":{"status":"active"}}` +- `GET /api/files/list?pagination={"page":2,"pageSize":50,"sort":[],"filters":{"search":"report"}}` + +### Pagination Request Parameters + +The `pagination` query parameter is a JSON-encoded object with the following structure: + +**`PaginationParams` Structure:** +- **`page`** - Current page number (1-based, minimum 1) +- **`pageSize`** - Number of items per page (minimum 1, maximum 1000) +- **`sort`** - Array of sort field configurations + - Each sort field contains: + - `field` - Field name to sort by (must match an attribute name) + - `direction` - Sort direction: "asc" or "desc" +- **`filters`** - Filter criteria dictionary (see [Search and Filtering](#search-and-filtering)) + +**Example:** +```json +{ + "page": 1, + "pageSize": 20, + "sort": [ + {"field": "lastActivity", "direction": "desc"}, + {"field": "name", "direction": "asc"} + ], + "filters": { + "search": "invoice", + "status": "running" + } +} +``` + +### Pagination Response Structure + +All paginated endpoints return data in this format: + +```json +{ + "items": [ + // Array of entity objects + ], + "pagination": { + "currentPage": 1, + "pageSize": 20, + "totalItems": 45, + "totalPages": 3, + "sort": [ + {"field": "lastActivity", "direction": "desc"} + ], + "filters": { + "search": "invoice", + "status": "running" + } + } +} +``` + +**`PaginationMetadata` Structure:** +- **`currentPage`** - Current page number (1-based) +- **`pageSize`** - Number of items per page +- **`totalItems`** - Total number of items across all pages (after filters applied) +- **`totalPages`** - Total number of pages (calculated from totalItems / pageSize) +- **`sort`** - Current sort configuration applied (array of SortField objects) +- **`filters`** - Current filters applied (mirrors request filters) + +### Pagination UI Components + +Generate pagination controls using the `pagination` metadata from response: + +1. **Page Information Display** + - Show "Page X of Y" (using `currentPage` and `totalPages`) + - Show "Showing X-Y of Z items" (calculate from `currentPage`, `pageSize`, `totalItems`) + +2. **Page Navigation Controls** + - Previous page button (disabled if `currentPage === 1`) + - Next page button (disabled if `currentPage === totalPages`) + - Page number buttons (show current page and adjacent pages) + - First page button (if not on first page) + - Last page button (if not on last page) + +3. **Page Size Selector** + - Dropdown to change `pageSize` (common options: 10, 20, 50, 100) + - When changed, reset to page 1 and refetch + +4. **Page Change Handler** + - When user clicks page number or navigation button: + - Update `page` in pagination parameters + - Preserve all filters and sort settings + - Refetch data with updated pagination + +### Non-Paginated Requests + +If user wants all items without pagination: + +- Omit `pagination` parameter entirely: `GET /api/{entities}/` +- Backend returns all items (still wrapped in `PaginatedResponse` with `pagination: null`) + +--- + +## Search and Filtering + +The pagination system supports both general search and field-specific filtering. Both are combined in the `filters` object. + +### General Search + +General search searches across all text fields in the entity. + +**Implementation:** +1. Display a single search input box (not field-specific) +2. When user types, update `filters.search` in pagination parameters +3. Debounce search input (wait 300-500ms after user stops typing before sending request) +4. Reset to page 1 when search query changes +5. Combine search with field-specific filters (both are in the `filters` object) + +**Filter Structure:** +```json +{ + "filters": { + "search": "invoice" + } +} +``` + +### Field-Specific Filtering + +Field-specific filters allow filtering by individual fields with various operators. + +**Filter Structure:** + +Simple equals filter: +```json +{ + "filters": { + "status": "running" + } +} +``` + +Filter with operator: +```json +{ + "filters": { + "name": { + "operator": "contains", + "value": "workflow" + } + } +} +``` + +**Supported Operators:** +- **`equals`** or **`eq`** - Exact match +- **`contains`** - Substring match (case-insensitive for strings) +- **`startsWith`** - String starts with (case-insensitive) +- **`endsWith`** - String ends with (case-insensitive) +- **`gt`** - Greater than (for numbers/dates) +- **`gte`** - Greater than or equal +- **`lt`** - Less than +- **`lte`** - Less than or equal +- **`in`** - Value in list (array of values) +- **`notIn`** - Value not in list (array of values) + +**Multiple Filters:** +All filters are combined with AND logic: +```json +{ + "filters": { + "search": "invoice", + "status": "running", + "currentRound": { + "operator": "gt", + "value": 0 + } + } +} +``` + +### Filter Control Generation + +Generate filter controls dynamically from attribute definitions: + +1. **Fetch Attribute Definitions** + - Call `GET /api/attributes/{EntityType}` when filter component mounts + - Filter attributes where `visible: true` to determine which filters to show + +2. **Generate Filter UI by Type** + - **`text`** fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - **`select`** fields → Dropdown filter with options from `options` array (use localized labels) + - **`integer`** or **`number`** fields → Number range filter (min/max inputs) or single number input with comparison operators (gt, gte, lt, lte) + - **`timestamp`** or **`date`** fields → Date range picker or single date picker with comparison operators + - **`checkbox`** fields → Boolean toggle filter (true/false/any) + +3. **Filter Labels** + - Use `label` property for filter labels (localized) + - Display filter label next to filter control + +4. **Apply Filters** + - When user applies filter, update `filters[fieldName]` in pagination parameters + - Support multiple filters simultaneously + - Reset to page 1 when filters change + - Refetch data with updated filters + +5. **Active Filter Indicators** + - Display active filters as chips/badges showing field label and value + - Allow removing individual filters by removing them from `filters` object + - Show "Clear all filters" button when filters are active + +### Combined Search and Filters + +Search and field filters work together: + +- Both are stored in the `filters` object +- All filters are combined with AND logic +- When any filter changes, combine all and refetch +- Preserve all active filters when sorting or changing pages + +--- + +## Sorting + +Sorting allows users to order list items by one or more fields. + +### Sort Configuration + +Sorting is configured in the `sort` array of pagination parameters: + +```json +{ + "sort": [ + {"field": "lastActivity", "direction": "desc"}, + {"field": "name", "direction": "asc"} + ] +} +``` + +- Multiple sort fields create multi-level sorting (sorts by first field, then by second field for ties) +- Sort fields are applied in order (first field is primary sort, second is secondary sort, etc.) + +### Sort UI Implementation + +1. **Column Header Sorting** + - Make column headers clickable for sortable columns + - Show sort indicator (arrow up/down) next to column header when sorted + - Clicking a column header: + - If not currently sorted by that column: Add sort field with "asc" direction + - If sorted ascending: Change to "desc" + - If sorted descending: Remove sort field (or change to "asc" if keeping) + - Update `sort` array in pagination parameters + - Preserve all filters and search + - Refetch data with updated sort + +2. **Sort Indicator Display** + - Show up arrow (↑) for ascending sort + - Show down arrow (↓) for descending sort + - Show both arrows when column is sortable but not currently sorted + - Hide sort indicators for non-sortable columns + +3. **Multi-Level Sort** + - When user clicks a second column header, add it to the `sort` array + - Display multiple sort indicators if multiple columns are sorted + - Allow removing individual sort fields + +### Sortable Columns + +Determine which columns are sortable: + +- All visible columns can potentially be sortable +- Backend handles sorting logic, so frontend can attempt to sort any field +- If backend doesn't support sorting a field, it will ignore that sort field +- Readonly fields may still be sortable (e.g., timestamps, IDs) + +--- + +## Localization + +All labels and options support multiple languages from the backend. + +### Language Detection + +1. **User Language Preference** + - Get user's preferred language from user settings + - Fall back to browser locale if user setting not available + - Default to "en" (English) if no language detected + +2. **Label Access Pattern** + - Access localized labels from `label` object: `label[userLanguage]` + - Fall back to `label.en` if label for current language is missing + - For select options: `option.label[userLanguage]` or `option.label.en` as fallback + +### Localized Components + +Apply localization to: + +1. **Form Fields** + - Field labels: `attribute.label[userLanguage]` + - Help text/descriptions: `attribute.description` (may be localized if backend provides) + - Select options: `option.label[userLanguage]` + - Validation error messages: Use localized messages + +2. **Table Columns** + - Column headers: `attribute.label[userLanguage]` + - Cell values for select fields: `option.label[userLanguage]` + +3. **Filter Controls** + - Filter labels: `attribute.label[userLanguage]` + - Filter options: `option.label[userLanguage]` + +4. **Pagination Controls** + - "Page X of Y" text: Use localized strings + - "Showing X-Y of Z items" text: Use localized strings + - Button labels (Previous, Next, etc.): Use localized strings + +--- + +## Implementation Patterns + +### Pattern 1: Generic List Page Component + +A reusable list page component that works for any entity type: + +**Component Structure:** +1. Accept `entityType` as prop (e.g., "ChatWorkflow", "User", "Mandate") +2. Fetch attributes: `GET /api/attributes/{entityType}` +3. Fetch list data: `GET /api/{entities}/?pagination=...` +4. Generate table columns from attributes +5. Generate filter controls from attributes +6. Handle pagination, search, filtering, and sorting +7. Handle row clicks (navigate to detail page) + +**State Management:** +- Store attribute definitions +- Store pagination parameters (page, pageSize, sort, filters) +- Store pagination metadata from response +- Store list items +- Store loading/error states + +**User Interactions:** +- Search input → Update `filters.search` +- Filter controls → Update `filters[fieldName]` +- Column header clicks → Update `sort` array +- Page navigation → Update `page` +- Page size change → Update `pageSize`, reset to page 1 + +### Pattern 2: Generic Form Component + +A reusable form component that works for any entity type: + +**Component Structure:** +1. Accept `entityType` and `mode` as props ("create" or "edit") +2. Accept `entityId` as prop (for edit mode) +3. Fetch attributes: `GET /api/attributes/{entityType}` +4. Fetch entity data (for edit mode): `GET /api/{entities}/{id}` +5. Generate form fields from attributes +6. Handle form submission +7. Handle validation + +**Form Field Generation:** +- Filter attributes: `visible: true` AND `editable: true` +- Generate input components based on `type` +- Apply labels, descriptions, required indicators +- Handle validation + +**Form Submission:** +- Validate form using attribute metadata +- For create: `POST /api/{entities}` with form data +- For update: `PUT /api/{entities}/{id}` with form data +- Handle success/error responses + +### Pattern 3: Generic Table Component + +A reusable table component that works for any entity type: + +**Component Structure:** +1. Accept `attributes` and `items` as props +2. Generate columns from attributes (filter `visible: true`) +3. Render table rows with formatted cell values +4. Handle column header clicks for sorting +5. Handle row clicks for navigation + +**Cell Value Formatting:** +- Use `type` property to determine formatting +- Format select fields using options array +- Format timestamps as relative/absolute time +- Format numbers with separators +- Handle null/undefined values + +### Pattern 4: Generic Filter Component + +A reusable filter component that works for any entity type: + +**Component Structure:** +1. Accept `attributes` and `filters` as props +2. Generate filter controls from attributes (filter `visible: true`) +3. Handle filter changes +4. Display active filters as chips/badges +5. Allow removing individual filters + +**Filter Control Generation:** +- Generate appropriate filter UI based on `type` +- Use localized labels +- Support multiple operators for text/number fields +- Update filters object and trigger refetch + +### Key Implementation Guidelines + +1. **Never Hardcode** + - Never hardcode field names, labels, types, or validation rules + - Always fetch attribute definitions from backend + - Use attribute metadata for all UI generation + +2. **Entity-Agnostic** + - Same components work for all entity types + - Pass `entityType` as parameter to determine endpoints + - Use generic prop names (attributes, items, etc.) + +3. **State Management** + - Keep pagination state separate from entity data + - Preserve filters and sort when changing pages + - Reset to page 1 when filters/search change + +4. **Error Handling** + - Handle API errors gracefully + - Display validation errors from backend + - Show loading states during API calls + +5. **Performance** + - Debounce search input (300-500ms) + - Cache attribute definitions (don't refetch on every render) + - Use pagination to limit data fetched + +6. **Accessibility** + - Use semantic HTML for forms and tables + - Provide ARIA labels for form fields + - Ensure keyboard navigation works + - Support screen readers + +--- + +## Summary + +This generic system enables: + +- **Complete Backend-Driven UI**: All forms, tables, filters generated from backend metadata +- **Zero Hardcoding**: No field definitions, labels, or validation rules in frontend code +- **Automatic Updates**: New backend fields automatically appear in frontend +- **Consistent UX**: Same patterns across all entity types +- **Localization**: Multi-language support from backend metadata +- **Reusable Components**: Generic components work for all entity types + +By following these patterns, the frontend becomes a thin presentation layer that dynamically renders UI based on backend metadata, ensuring consistency, maintainability, and automatic adaptation to backend changes. + diff --git a/docs/frontend-documentation/file-page-customer-journeys.md b/docs/frontend-documentation/file-page-customer-journeys.md new file mode 100644 index 00000000..46dd557b --- /dev/null +++ b/docs/frontend-documentation/file-page-customer-journeys.md @@ -0,0 +1,335 @@ +# File Routes Frontend Documentation + +This document describes customer journeys for managing files through the frontend, focusing on how users interact with file management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Discovering and Browsing Files](#customer-journey-1-discovering-and-browsing-files) +3. [Customer Journey 2: Uploading Files](#customer-journey-2-uploading-files) +4. [Customer Journey 3: Editing File Properties](#customer-journey-3-editing-file-properties) +5. [Customer Journey 4: Downloading Files](#customer-journey-4-downloading-files) +6. [Customer Journey 5: Adding File to Prompt](#customer-journey-5-adding-file-to-prompt) +7. [Customer Journey 6: Deleting Files](#customer-journey-6-deleting-files) + +--- + +## Overview + +The file routes (`/api/files`) enable users to manage files within their mandate. These routes focus on **file administration** including upload, editing, download, preview, and deletion. + +**Key Principles:** +- **User-Centric**: Documentation organized around what users want to accomplish +- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata +- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend +- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully +- **Mandate-Scoped**: Files are managed within the context of mandates + +--- + +## Customer Journey 1: Discovering and Browsing Files + +### User Goal +"I want to see all files in my mandate and find the one I'm looking for." + +### User Story +As a user, I want to browse files, search for specific files, filter by any field, sort them by different criteria, and quickly identify files by their name, size, type, and creation date. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to /files + Frontend->>Backend: GET /api/attributes/FileItem + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/files/list?pagination=... + Backend-->>Frontend: Paginated files list + Frontend->>Frontend: Generate table columns from attributes + Frontend->>Frontend: Generate filter controls from attributes + Frontend->>Frontend: Render files table + search + filters + Frontend->>Frontend: Render action buttons in table (Edit, Delete, Download, Add to Prompt) + Frontend-->>User: Display file list with search/filter UI + action buttons + + alt User performs general search + User->>Frontend: Type in search box (e.g., "invoice") + Frontend->>Frontend: Update search query + Frontend->>Backend: GET /api/files/list?pagination=...filters:{"search":"invoice"} + Backend-->>Frontend: Filtered files list + Frontend-->>User: Display matching files + end + + alt User applies field filter + User->>Frontend: Select filter field (e.g., "MIME Type") + Frontend->>Frontend: Show filter options from attribute metadata + User->>Frontend: Select filter value (e.g., "application/pdf") + Frontend->>Frontend: Update filter parameters + Frontend->>Backend: GET /api/files/list?pagination=...filters:{"mimeType":"application/pdf"} + Backend-->>Frontend: Filtered files list + Frontend-->>User: Display filtered files + end + + alt User combines search + filter + sort + User->>Frontend: Apply search + filter + sort + Frontend->>Frontend: Combine all parameters + Frontend->>Backend: GET /api/files/list?pagination=...filters:{"search":"invoice","mimeType":"application/pdf"}...sort:desc + Backend-->>Frontend: Filtered, sorted files list + Frontend-->>User: Display results + end + + User->>Frontend: Click column header (e.g., "File Size") + Frontend->>Frontend: Update sort parameters + Frontend->>Backend: GET /api/files/list?pagination=...sort:desc + Backend-->>Frontend: Sorted files list + Frontend-->>User: Display sorted files +``` + +--- + +## Customer Journey 2: Uploading Files + +### User Goal +"I want to upload new files to my mandate." + +### User Story +As a user, I want to upload files by selecting them from my device. The system should validate file size, handle duplicates, and show clear feedback about the upload status. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + alt User clicks "Upload File" button + User->>Frontend: Click "Upload File" button + Frontend->>Frontend: Show file upload dialog/input + Frontend-->>User: Display file picker + User->>Frontend: Select file(s) from device + else User drags and drops files + User->>Frontend: Drag file(s) over upload area + Frontend->>Frontend: Highlight drop zone + User->>Frontend: Drop file(s) on upload area + Frontend->>Frontend: Accept dropped files + end + + Frontend->>Frontend: Optimistic update: Show loading state, add file to UI immediately + Frontend->>Backend: POST /api/files/upload + file data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Remove file from UI + Frontend-->>User: Show permission error + else Success (201) + Backend-->>Frontend: Created file object + duplicate info + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/files/list?pagination=... (refetch) + Backend-->>Frontend: Updated files list + Frontend->>Frontend: Update table with fresh data + Frontend-->>User: Show success message (with duplicate info if applicable) + end +``` + +--- + +## Customer Journey 3: Editing File Properties + +### User Goal +"I want to change the file name through an edit form." + +### User Story +As a user, I want to edit a file's name through a popup/modal form, with validation and clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Edit" button in table row + Frontend->>Backend: GET /api/files/fileId + Backend-->>Frontend: Current file data + + Frontend->>Backend: GET /api/attributes/FileItem + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend->>Frontend: Pre-populate form with file data + Frontend->>Frontend: Open popup/modal with edit form + Frontend-->>User: Display edit form in popup/modal + + User->>Frontend: Modify file name + User->>Frontend: Click "Save" + + Frontend->>Frontend: Validate form (required fields, types) + alt Validation fails + Frontend-->>User: Show validation errors in modal + else Validation passes + Frontend->>Frontend: Optimistic update: Apply changes to UI immediately + Frontend->>Backend: PUT /api/files/fileId + form data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error in modal + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show backend validation errors in modal + else Success (200) + Backend-->>Frontend: Updated file + Frontend->>Frontend: Keep optimistic update (or refresh from response) + Frontend->>Backend: GET /api/files/list?pagination=... (refetch) + Backend-->>Frontend: Updated files list + Frontend->>Frontend: Update table with fresh data + Frontend->>Frontend: Close popup/modal + Frontend-->>User: Show updated file name in table + end + end + + alt User clicks Cancel + User->>Frontend: Click "Cancel" button + Frontend->>Frontend: Close popup/modal without saving + Frontend-->>User: Modal closed, no changes + end +``` + +--- + +## Customer Journey 4: Downloading Files + +### User Goal +"I want to download files to my device." + +### User Story +As a user, I want to download files by clicking a download button, so I can save them locally on my device. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Download" button in table + Frontend->>Frontend: Show loading state + Frontend->>Backend: GET /api/files/fileId/download + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>User: Show permission error + else File not found (404) + Backend-->>Frontend: 404 Not Found + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: File content with Content-Disposition header + Frontend->>Frontend: Trigger browser download + Frontend-->>User: File downloads to device + end +``` + +--- + +## Customer Journey 5: Adding File to Prompt + +### User Goal +"I want to use a file with a prompt in the chat playground." + +### User Story +As a user, I want to add a file to the chat playground so I can use it with a prompt to start a workflow. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Add to Prompt" button in table + Frontend->>Backend: GET /api/files/fileId + Backend-->>Frontend: File object (id, fileName) + + Frontend->>Frontend: Navigate to /chat-playground + Frontend->>Frontend: Pre-select file in file picker/attachments + Frontend->>Frontend: Show file name as context + Frontend-->>User: Display chat playground with file attached + + User->>Frontend: Enter prompt text + User->>Frontend: Optionally add more files + User->>Frontend: Click "Start" or "Send" button + + Frontend->>Frontend: Validate user input (prompt required) + alt Validation fails + Frontend-->>User: Show validation errors + else Validation passes + Frontend->>Backend: POST /api/chat/playground/start?workflowMode=Dynamic
Body: {prompt: userPrompt, listFileId: [fileId, ...], userLanguage: "en"} + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created workflow object + Frontend->>Frontend: Update chat playground UI with workflow + Frontend-->>User: Show workflow started, display messages/logs + end + end +``` + +--- + +## Customer Journey 6: Deleting Files + +### User Goal +"I want to delete files that are no longer needed." + +### User Story +As a user, I want to delete files with a clear confirmation to prevent accidental deletion. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Delete" button + Frontend->>Backend: GET /api/files/fileId + Backend-->>Frontend: File data (for name) + Frontend->>Frontend: Show confirmation dialog
"Delete 'File Name'?" + User->>Frontend: Cancel deletion + Frontend-->>User: Dialog closed, no action + + User->>Frontend: Click "Delete" button again + Frontend->>Backend: GET /api/files/fileId + Backend-->>Frontend: File data + Frontend->>Frontend: Show confirmation dialog + User->>Frontend: Confirm deletion + Frontend->>Frontend: Optimistic update: Remove file from UI immediately + Frontend->>Backend: DELETE /api/files/fileId + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore file in UI + Frontend-->>User: Show permission error + else Not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore file in UI + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update (file already removed) + Frontend->>Frontend: Show success message + Frontend->>Frontend: Navigate to /files (if on detail page) + Frontend-->>User: Display file list (without deleted file) + end +``` + diff --git a/docs/frontend-documentation/file-page-requirements.md b/docs/frontend-documentation/file-page-requirements.md new file mode 100644 index 00000000..3ff423d8 --- /dev/null +++ b/docs/frontend-documentation/file-page-requirements.md @@ -0,0 +1,574 @@ +# File Page Requirements + +This document contains the complete frontend requirements for all file management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) + +--- + +## Overview + +The file management page enables users to manage files within their mandate. The frontend consists of a single page (`/files`) with different views/states: + +- **List View** - Browse, search, filter, and sort files (all information displayed in table) +- **Edit View** - Edit file properties in popup/modal +- **Upload View** - Upload new files + +All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/FileItem` endpoint. Views are managed through component state and routing within the same page, not as separate routes. + +--- + +## Page Structure and Layout + +### File Management Page (`/files`) + +The file management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component. + +### List View + +**State:** `view === 'list'` or `selectedFileId === null` + +**What the user sees:** + +- **Main Content Area:** + - Table or card grid displaying all files in the mandate + - Each file row/card shows: file name, MIME type, file size, creation date, mandate ID + - **Action buttons column** in table (rendered on first load): + - "Edit" button - opens popup/modal edit form for file name + - "Delete" button - shows confirmation dialog and deletes file + - "Download" button - downloads file to user's device + - "Add to Prompt" button - navigates to `/chat-playground` with file attached + - All necessary file information displayed in table (no detail view needed) + +- **Search and Filter Controls:** + - General search input box (searches across all text fields) + - Field-specific filter controls (one filter per visible field) + - Active filter indicators (chips/badges showing applied filters) + - "Clear all filters" button when filters are active + +- **Sorting Controls:** + - Clickable column headers with sort indicators (up/down arrows) + - Visual indication of current sort field and direction + - Support for multi-level sorting + +- **Pagination Controls:** + - Page information display ("Page X of Y", "Showing 1-20 of 45 files") + - Previous/Next page buttons + - Page number buttons + - Page size selector (10, 20, 50, 100 items per page) + +- **Action Buttons:** + - "Upload File" button - opens file upload dialog + +### Edit View (Popup/Modal) + +**State:** `view === 'edit'` and `selectedFileId !== null` (popup/modal overlay) + +**What the user sees:** + +- **Edit Form in Popup/Modal:** + - Dynamic form with editable file fields only (typically fileName) + - Field labels with required indicators (asterisk for required fields) + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + - Form pre-populated with current file values + - Save and Cancel buttons in modal footer + - On save: Updates file name, closes modal, refreshes table + - On cancel: Closes modal without saving + +### Upload View + +**State:** `view === 'upload'` or upload dialog open + +**What the user sees:** + +- **Upload Dialog/Form:** + - File input/picker for selecting files + - Drag-and-drop area with visual feedback + - Selected files list with preview + - Upload progress indicator + - Duplicate file handling information + +- **Action Buttons:** + - Upload button (starts upload) + - Cancel button (closes upload dialog) + +- **Confirmation Dialogs:** + - Delete confirmation dialog (on file detail page) + +--- + +## User Interactions and Functionality + +### Browsing and Discovery + +**Search Functionality:** +- User types in general search box +- Frontend debounces input (300-500ms delay) +- Search applies across all text fields in file objects +- Results update automatically +- Page resets to page 1 when search changes + +**Field Filtering:** +- User selects field to filter by +- Frontend shows appropriate filter UI based on field type: + - Text fields → Text input with operator selection (contains, equals, startsWith, endsWith) + - Integer fields → Number input with comparison operators (gt, gte, lt, lte) or range inputs + - Timestamp fields → Date picker with comparison operators or date range picker + - Select fields → Dropdown with options from backend metadata +- User applies filter → Filter appears as active chip/badge +- User can remove individual filters +- Multiple filters work together (AND logic) +- Page resets to page 1 when filters change + +**Sorting:** +- User clicks column header +- Sort direction toggles (asc → desc → remove) +- Multiple columns can be sorted (multi-level sorting) +- Sort indicators show on column headers +- All filters and search preserved when sorting + +**Pagination:** +- User clicks page number or navigation button +- Page updates and data refetches +- All filters, search, and sort preserved +- User changes page size → Page resets to 1, data refetches + +**View Switching:** +- All file information displayed in table (no detail view navigation needed) + +### Uploading Files + +**Upload Interaction:** +- User clicks "Upload File" button → Opens upload dialog/form +- OR user drags and drops file(s) onto upload area +- Drag and drop area highlights when files are dragged over +- User selects file(s) from device picker OR drops file(s) on upload area +- File upload starts immediately (no size validation) +- User clicks Cancel → Closes upload dialog, no action + +**Drag and Drop Support:** +- Upload area supports drag and drop functionality +- Visual feedback when files are dragged over (highlight drop zone) +- Multiple files can be dropped at once +- Files are accepted and uploaded immediately upon drop + +**Upload Submission:** +- File sent as multipart/form-data +- Optional `workflowId` parameter can be included +- No file size validation (all file sizes accepted) +- Success → File appears in list, show success message with duplicate info if applicable +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +**Duplicate Handling:** +- Backend returns duplicate information in response +- Frontend displays appropriate message: + - Exact duplicate → "File already exists with identical content. Reusing existing file." + - Name conflict → "File already exists with different content. Uploaded as '[new name]'." + - New file → "File uploaded successfully" + +### Editing Files + +**Edit Interaction:** +- User clicks "Edit" button in table row → Opens popup/modal edit form +- Form pre-populated with current file values +- User modifies file name in form +- Client-side validation shows errors immediately +- User clicks Save → Form validates and submits +- User clicks Cancel → Closes modal without saving + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., text fields must be valid text) +- Validation errors displayed inline below fields + +**Form Submission:** +- Only changed fields sent (or all form data) +- Success → Close popup/modal, refresh table, show success message +- Error handling: + - 403 (permission denied) → Show permission error in modal + - 400 (validation errors) → Display backend validation errors in modal + - Other errors → Show generic error message in modal + +### Downloading Files + +**Download Action:** +- User clicks "Download" button in table +- Frontend shows loading state +- Frontend calls `GET /api/files/{fileId}/download` +- Browser triggers download with proper filename +- Success → File downloads to user's device +- Error handling: + - 403 (permission denied) → Show permission error + - 404 (not found) → Show not found error + - Other errors → Show generic error message + +**Implementation Notes:** +- Download should use proper Content-Disposition header handling +- Filename should be properly encoded for Unicode characters + +### Adding File to Prompt + +**Add to Prompt Action:** +- User clicks "Add to Prompt" button in table +- Frontend fetches file data to get file ID +- Frontend navigates to `/chat-playground` page +- Frontend pre-selects the file in the file picker/attachments area +- Frontend displays file name as context +- User can enter prompt text and optionally add more files +- User clicks "Start" or "Send" button +- Frontend calls `POST /api/chat/playground/start` with file ID in `listFileId` array + +**Add to Prompt Submission:** +- File ID included in `listFileId` array in request body +- Prompt text required (user must enter prompt) +- Success → Workflow starts with file attached, chat playground updates +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Deleting Files + +**Delete Action:** +- User clicks delete button (on detail page or list) +- Confirmation dialog appears with file name +- Warning about permanent deletion +- User confirms → File deleted +- User cancels → Dialog closes, no action + +**Delete Success Handling:** +- Success message displayed +- Remove file from list or refresh table + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by file pages: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/files/list` | GET | Get all files (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) | +| `/api/files/{fileId}` | GET | Get file details | Detail page load, edit page load | All authenticated users | +| `/api/files/{fileId}` | PUT | Update file | Edit form submission | All authenticated users | +| `/api/files/{fileId}` | DELETE | Delete file | User confirms deletion | All authenticated users | +| `/api/files/upload` | POST | Upload file | User selects and uploads file | All authenticated users | +| `/api/files/{fileId}/download` | GET | Download file | User clicks download button | All authenticated users | +| `/api/files/stats` | GET | Get file statistics | Optional: display statistics on page | All authenticated users | +| `/api/chat/playground/start` | POST | Start workflow with file | User clicks "Add to Prompt" and starts workflow | All authenticated users | +| `/api/attributes/FileItem` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users | + +### API Request Patterns + +**Pagination Request:** +``` +GET /api/files/list?pagination={"page":1,"pageSize":20,"sort":[],"filters":null} +``` +- `pagination` parameter is JSON-encoded string +- If user wants all files: omit `pagination` parameter entirely +- Filters structure: `{"search":"query","fieldName":"value",...}` +- Optional `mandateId` query parameter to filter by mandate + +**Upload Request:** +``` +POST /api/files/upload +Content-Type: multipart/form-data +Body: { + file: , + workflowId: "optional-workflow-id" (optional) +} +``` +- File sent as multipart/form-data +- `workflowId` is optional form field +- No file size limits (all sizes accepted) +- Handle 403 (permission denied) and 400 (validation errors) +- Response includes duplicate information: + ```json + { + "message": "File uploaded successfully", + "file": {...}, + "duplicateType": "new_file" | "exact_duplicate" | "name_conflict", + "originalFileName": "...", + "storedFileName": "...", + "isDuplicate": false + } + ``` + +**Update Request:** +``` +PUT /api/files/{fileId} +Content-Type: application/json +Body: {fieldName: value, ...} +``` +- Send only changed fields or all form data +- Handle 403 (permission denied) and 400 (validation errors) + +**Download Request:** +``` +GET /api/files/{fileId}/download +``` +- Returns file content with Content-Disposition header +- Browser automatically triggers download +- Filename properly encoded for Unicode characters + +**Add to Prompt Request:** +``` +POST /api/chat/playground/start?workflowMode=Dynamic +Content-Type: application/json +Body: { + "prompt": "User prompt text here...", + "listFileId": ["fileId1", "fileId2"], + "userLanguage": "en" +} +``` +- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template" (default: "Dynamic") +- `listFileId` array contains file IDs to attach (includes the file from "Add to Prompt" button) +- `prompt` field contains user's prompt text +- `userLanguage` should match user's preferred language +- Handle 403 (permission denied) and 400 (validation errors) + +**Delete Requests:** +``` +DELETE /api/files/{fileId} +``` +- Delete operation requires user confirmation +- Handle 403 (permission denied) and 404 (not found) gracefully + +### Response Handling + +**Paginated Response:** +```json +{ + "items": [...], + "pagination": { + "currentPage": 1, + "pageSize": 20, + "totalItems": 45, + "totalPages": 3, + "sort": [...], + "filters": {...} + } +} +``` + +**Error Responses:** +- 403 Forbidden → Show permission error message +- 404 Not Found → Show "not found" error message +- 400 Bad Request → Display validation errors from response +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Complete Field List + +The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for files. All of these are provided by the backend through the `/api/attributes/FileItem` endpoint and should never be hardcoded in the frontend. + +#### Core File Fields + +**Identification Fields:** +- `id` - Unique file identifier (text, readonly, not required, visible) +- `mandateId` - ID of the mandate this file belongs to (text, readonly, not required, visible) + +**File Properties:** +- `fileName` - Name of the file (text, editable, required, visible) +- `mimeType` - MIME type of the file (text, readonly, not required, visible) +- `fileHash` - Hash of the file (text, readonly, not required, visible) +- `fileSize` - Size of the file in bytes (integer, readonly, not required, visible) +- `creationDate` - Date when the file was created (timestamp, readonly, not required, visible) + +### Pagination Parameters + +**Request Parameters (`PaginationParams`):** +- `page` - Current page number (1-based, minimum 1) +- `pageSize` - Number of items per page (minimum 1, maximum 1000) +- `sort` - Array of sort field configurations + - Each sort field contains: + - `field` - Field name to sort by (must match a file field name) + - `direction` - Sort direction: "asc" or "desc" +- `filters` - Filter criteria dictionary + - `search` - General search term (searches across all text fields, case-insensitive) + - Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}` + - Supported operators: "equals", "contains", "startsWith", "endsWith", "gt", "gte", "lt", "lte", "in", "notIn" + +**Response Metadata (`PaginationMetadata`):** +- `currentPage` - Current page number (1-based) +- `pageSize` - Number of items per page +- `totalItems` - Total number of items across all pages (after filters applied) +- `totalPages` - Total number of pages (calculated from totalItems / pageSize) +- `sort` - Current sort configuration applied (array of SortField objects) +- `filters` - Current filters applied (mirrors request filters) + +### Attribute Definition Structure + +Each field returned from `/api/attributes/FileItem` contains: + +- `name` - Field name (e.g., "fileName", "mimeType", "fileSize", "id") +- `type` - Field data type (e.g., "text", "integer", "timestamp", "checkbox") +- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"}) +- `description` - Field description text +- `required` - Boolean indicating if field is required +- `readonly` - Boolean indicating if field is read-only +- `editable` - Boolean indicating if field can be edited (inverse of readonly) +- `visible` - Boolean indicating if field should be displayed in UI +- `options` - Array of options for select fields (each option has `value` and localized `label`) + +--- + +## Dynamic Rendering Guidelines + +The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded. + +### Table Column Generation + +When rendering the file list table: + +1. Fetch attribute definitions from `/api/attributes/FileItem` +2. Filter attributes where `visible: true` to determine which columns to display +3. Use `label` property for column headers (select appropriate language based on user preference) +4. Use `type` property to determine how to format cell values: + - `text` fields → Display as plain text + - `integer` fields → Display as formatted number (for fileSize, show human-readable format like "1.5 MB") + - `timestamp` fields → Format as relative time ("2 hours ago") or absolute date/time based on user preference + - `select` fields → Display value using label from options array (match value to option.value, then display option.label) + - `checkbox` fields → Display as checkmark icon or "Yes"/"No" text +5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are) +6. Generate click handlers for column headers to update sort parameters and refetch data +7. **Add Actions Column:** + - Render action buttons in each table row on first load + - Include "Edit" button - opens popup/modal edit form for file name + - Include "Delete" button - shows confirmation dialog + - Include "Download" button - triggers file download + - Include "Add to Prompt" button - navigates to `/chat-playground` with file attached + - Buttons should be visible and accessible in each row + +### Filter Control Generation + +When rendering filter controls: + +1. Fetch attribute definitions from `/api/attributes/FileItem` +2. Filter attributes where `visible: true` to determine which filters to show +3. For each visible field, generate appropriate filter UI based on `type`: + - `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - `integer` fields → Number range filter (min/max inputs) or single number input with comparison operators (gt, gte, lt, lte) + - `timestamp` fields → Date range picker or single date picker with comparison operators + - `select` fields → Dropdown filter with options from `options` array (use localized labels) + - `checkbox` fields → Boolean toggle filter (true/false/any) +4. Use `label` property for filter labels (localized) +5. When user applies filter, update `filters` object in pagination parameters and refetch data +6. Display active filters as chips/badges showing field label and value +7. Allow removing individual filters by removing them from `filters` object + +### Search Implementation + +For general search functionality: + +1. Display a single search input box (not field-specific) +2. When user types, update `filters.search` in pagination parameters +3. Debounce search input (wait 300-500ms after user stops typing before sending request) +4. Search applies across all text fields in the file object +5. Reset to page 1 when search query changes +6. Combine search with field-specific filters (both are in the `filters` object) + +### Form Field Generation + +When rendering edit forms: + +1. Fetch attribute definitions from `/api/attributes/FileItem` +2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show +3. For each editable field, generate appropriate form input based on `type`: + - `text` fields → Text input + - `integer` fields → Number input with appropriate min/max constraints + - `timestamp` fields → Date/time picker + - `select` fields → Dropdown/select input with options from `options` array (use localized labels) + - `checkbox` fields → Checkbox input +4. Use `label` property for field labels (localized) +5. Use `required` property to show required indicators (asterisk, etc.) +6. Use `description` property to show help text or tooltips +7. Validate form before submission: + - Check all `required: true` fields have values + - Validate types (e.g., integer fields must be numbers) + - Validate select fields (value must be in options array) +8. On submit, send only changed fields or all form data to update endpoint + +### Display Formatting + +When displaying field values: + +1. Use `type` property to determine formatting: + - `text` → Display as-is (may need HTML escaping) + - `integer` → Format with thousand separators if needed + - For `fileSize` field specifically → Format as human-readable (e.g., "1.5 MB", "500 KB", "2.3 GB") + - `timestamp` → Format as relative time or absolute date/time + - `select` → Look up value in `options` array and display localized label + - `checkbox` → Display as checkmark icon or "Yes"/"No" text +2. Handle `null` or `undefined` values gracefully (show "-" or "Not set") +3. Use `readonly` property to determine if field should show edit indicators +4. Special formatting for file fields: + - File Size → Always show in human-readable format (bytes → KB → MB → GB) + - MIME Type → Display as badge with icon if possible + - File Hash → Display as truncated hash (first 8-12 characters) with copy button + - Creation Date → Show relative time in list view, absolute date in detail view + +### File Size Formatting + +For the `fileSize` field (integer in bytes), always format as human-readable: + +```typescript +function formatFileSize(bytes: number): string { + if (bytes === 0) return '0 Bytes'; + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; +} +``` + +### Localization + +All labels and options support multiple languages: + +1. Use user's preferred language (from user settings or browser locale) +2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback +3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback +4. If label for current language is missing, fall back to English + +### Key Principles + +- Never hardcode field names, labels, types, or validation rules +- Always fetch attribute definitions from backend before rendering UI +- Use attribute metadata to determine what to display and how to display it +- Support all field types dynamically - if backend adds new types, frontend should handle them +- Respect `visible`, `editable`, `readonly`, and `required` flags from backend +- Use localized labels from backend metadata +- Generate filters, forms, and tables entirely from attribute definitions +- When backend adds new fields, frontend should automatically display them without code changes +- Handle all error cases gracefully (403, 404, 400, 413, 500) +- Provide user feedback for all actions (loading states, success messages, error messages) +- Format file sizes in human-readable format +- Handle file uploads with proper duplicate detection feedback + +--- + +## Summary + +This document provides complete frontend requirements for all file management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/FileItem` endpoint. + +**Key Architecture Pattern:** The file management interface is a single page (`/files`) with different views managed through component state. All interactions happen within the same page component without separate routes. + +For generic patterns that apply across all entity types (not just files), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md). + diff --git a/docs/frontend-documentation/prompt-page-customer-journeys.md b/docs/frontend-documentation/prompt-page-customer-journeys.md new file mode 100644 index 00000000..b22628bc --- /dev/null +++ b/docs/frontend-documentation/prompt-page-customer-journeys.md @@ -0,0 +1,349 @@ +# Prompt Routes Frontend Documentation + +This document describes customer journeys for managing prompts through the frontend, focusing on how users interact with prompt management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Discovering and Browsing Prompts](#customer-journey-1-discovering-and-browsing-prompts) +3. [Customer Journey 2: Viewing Prompt Details](#customer-journey-2-viewing-prompt-details) +4. [Customer Journey 3: Creating New Prompts](#customer-journey-3-creating-new-prompts) +5. [Customer Journey 4: Editing Prompt Properties](#customer-journey-4-editing-prompt-properties) +6. [Customer Journey 5: Starting a Prompt Workflow](#customer-journey-5-starting-a-prompt-workflow) +7. [Customer Journey 6: Deleting Prompts](#customer-journey-6-deleting-prompts) + +--- + +## Overview + +The prompt routes (`/api/prompts`) enable users to manage prompts within their mandate. These routes focus on **prompt administration** including creation, editing, and deletion. + +**Key Principles:** +- **User-Centric**: Documentation organized around what users want to accomplish +- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata +- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend +- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully +- **Mandate-Scoped**: Prompts are managed within the context of mandates + +--- + +## Customer Journey 1: Discovering and Browsing Prompts + +### User Goal +"I want to see all prompts in my mandate and find the one I'm looking for." + +### User Story +As a user, I want to browse prompts, search for specific prompts, filter by any field, sort them by different criteria, and quickly identify prompts by their name and content. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to /prompts + Frontend->>Backend: GET /api/attributes/Prompt + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/prompts/?pagination=... + Backend-->>Frontend: Paginated prompts list + Frontend->>Frontend: Generate table columns from attributes + Frontend->>Frontend: Generate filter controls from attributes + Frontend->>Frontend: Render prompts table + search + filters + Frontend->>Frontend: Render action buttons in table (Start Prompt, Edit, Delete) + Frontend-->>User: Display prompt list with search/filter UI + action buttons + + alt User performs general search + User->>Frontend: Type in search box (e.g., "invoice") + Frontend->>Frontend: Update search query + Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"search":"invoice"} + Backend-->>Frontend: Filtered prompts list + Frontend-->>User: Display matching prompts + end + + alt User applies field filter + User->>Frontend: Select filter field (e.g., "Name") + Frontend->>Frontend: Show filter options from attribute metadata + User->>Frontend: Select filter value (e.g., "Invoice") + Frontend->>Frontend: Update filter parameters + Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"name":"Invoice"} + Backend-->>Frontend: Filtered prompts list + Frontend-->>User: Display filtered prompts + end + + alt User combines search + filter + sort + User->>Frontend: Apply search + filter + sort + Frontend->>Frontend: Combine all parameters + Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"search":"invoice","name":"Invoice"}...sort:desc + Backend-->>Frontend: Filtered, sorted prompts list + Frontend-->>User: Display results + end + + User->>Frontend: Click column header (e.g., "Name") + Frontend->>Frontend: Update sort parameters + Frontend->>Backend: GET /api/prompts/?pagination=...sort:desc + Backend-->>Frontend: Sorted prompts list + Frontend-->>User: Display sorted prompts + + User->>Frontend: Click prompt row + Frontend->>Frontend: Navigate to /prompts/promptId + Frontend-->>User: Show prompt detail page +``` + +--- + +## Customer Journey 2: Viewing Prompt Details + +### User Goal +"I want to see everything about a specific prompt—its name and full content." + +### User Story +As a user, I want to open a prompt and see its complete information, including name, content, and mandate association. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click prompt from list + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Prompt object + + Frontend->>Backend: GET /api/attributes/Prompt + Backend-->>Frontend: Field definitions + + Frontend->>Frontend: Generate UI from metadata + Frontend->>Frontend: Render prompt info section + Frontend->>Frontend: Separate editable vs read-only fields + Frontend-->>User: Display complete prompt view + + alt User has editable fields and permission + Frontend->>Frontend: Show "Edit Prompt" button + end + + alt User has permission + Frontend->>Frontend: Show "Delete Prompt" button + end +``` + +--- + +## Customer Journey 3: Creating New Prompts + +### User Goal +"I want to create new prompts for my mandate." + +### User Story +As a user, I want to create a new prompt by filling out a form with its name and content. The form should validate all required fields and show clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Create Prompt" button + Frontend->>Frontend: Navigate to /prompts/create + + Frontend->>Backend: GET /api/attributes/Prompt + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend-->>User: Display create prompt form + + User->>Frontend: Fill in form fields + User->>Frontend: Click "Create" + + Frontend->>Frontend: Validate form (required fields, types) + alt Validation fails + Frontend-->>User: Show validation errors + else Validation passes + Frontend->>Frontend: Optimistic update: Show loading state, prepare UI for new prompt + Frontend->>Backend: POST /api/prompts + form data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Show form with error + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update: Show form with errors + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created prompt object + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/prompts/promptId (refetch) + Backend-->>Frontend: Created prompt object + Frontend->>Frontend: Update UI with fresh data + Frontend->>Frontend: Navigate to prompt detail page + Frontend-->>User: Show created prompt + end + end +``` + +--- + +## Customer Journey 4: Editing Prompt Properties + +### User Goal +"I want to change prompt settings like its name or content." + +### User Story +As a user, I want to edit a prompt's properties through a form that only shows fields I'm allowed to edit, with validation and clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Edit" button + Frontend->>Frontend: Navigate to /prompts/id/edit + + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Current prompt data + + Frontend->>Backend: GET /api/attributes/Prompt + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend->>Frontend: Pre-populate form with prompt data + Frontend-->>User: Display edit form + + User->>Frontend: Modify form fields + User->>Frontend: Click "Save" + + Frontend->>Frontend: Validate form (required fields, types) + alt Validation fails + Frontend-->>User: Show validation errors + else Validation passes + Frontend->>Frontend: Optimistic update: Apply changes to UI immediately + Frontend->>Backend: PUT /api/prompts/promptId + form data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Updated prompt + Frontend->>Frontend: Keep optimistic update (or refresh from response) + Frontend->>Backend: GET /api/prompts/promptId (refetch) + Backend-->>Frontend: Updated prompt object + Frontend->>Frontend: Update UI with fresh data + Frontend->>Frontend: Navigate to detail page + Frontend-->>User: Show updated prompt + end + end +``` + +--- + +## Customer Journey 5: Starting a Prompt Workflow + +### User Goal +"I want to start a workflow using a prompt I've created." + +### User Story +As a user, I want to start a workflow in the chat playground using a prompt's content, so I can execute the prompt and see the results. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Start Prompt" button in table + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Prompt object (name, content) + + Frontend->>Frontend: Navigate to /chat-playground + Frontend->>Frontend: Pre-fill prompt content in chat input + Frontend->>Frontend: Show prompt name as context + Frontend-->>User: Display chat playground with prompt loaded + + User->>Frontend: Optionally modify prompt or add files + User->>Frontend: Click "Start" or "Send" button + + Frontend->>Frontend: Validate user input + alt Validation fails + Frontend-->>User: Show validation errors + else Validation passes + Frontend->>Backend: POST /api/chat/playground/start?workflowMode=Dynamic
Body: {prompt: promptContent, listFileId: [...], userLanguage: "en"} + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>User: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created workflow object + Frontend->>Frontend: Update chat playground UI with workflow + Frontend-->>User: Show workflow started, display messages/logs + end + end +``` + +--- + +## Customer Journey 6: Deleting Prompts + +### User Goal +"I want to delete prompts that are no longer needed." + +### User Story +As a user, I want to delete prompts with a clear confirmation to prevent accidental deletion. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Click "Delete" button + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Prompt data (for name) + Frontend->>Frontend: Show confirmation dialog
"Delete 'Prompt Name'?" + User->>Frontend: Cancel deletion + Frontend-->>User: Dialog closed, no action + + User->>Frontend: Click "Delete" button again + Frontend->>Backend: GET /api/prompts/promptId + Backend-->>Frontend: Prompt data + Frontend->>Frontend: Show confirmation dialog + User->>Frontend: Confirm deletion + Frontend->>Frontend: Optimistic update: Remove prompt from UI immediately + Frontend->>Backend: DELETE /api/prompts/promptId + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore prompt in UI + Frontend-->>User: Show permission error + else Not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore prompt in UI + Frontend-->>User: Show not found error + else Success (200) + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update (prompt already removed) + Frontend->>Frontend: Show success message + Frontend->>Frontend: Navigate to /prompts (if on detail page) + Frontend-->>User: Display prompt list (without deleted prompt) + end +``` + diff --git a/docs/frontend-documentation/prompt-page-requirements.md b/docs/frontend-documentation/prompt-page-requirements.md new file mode 100644 index 00000000..bcc224a6 --- /dev/null +++ b/docs/frontend-documentation/prompt-page-requirements.md @@ -0,0 +1,549 @@ +# Prompt Page Requirements + +This document contains the complete frontend requirements for all prompt management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) + +--- + +## Overview + +The prompt management page enables users to manage prompts within their mandate. The frontend consists of a single page (`/prompts`) with different views/states: + +- **List View** - Browse, search, filter, and sort prompts +- **Edit View** - Edit prompt properties +- **Create View** - Create new prompts + +All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/Prompt` endpoint. Views are managed through component state and routing within the same page, not as separate routes. + +--- + +## Page Structure and Layout + +### Prompt Management Page (`/prompts`) + +The prompt management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component. + +### List View + +**State:** `view === 'list'` or `selectedPromptId === null` + +**What the user sees:** + +- **Main Content Area:** + - Table or card grid displaying all prompts in the mandate + - Each prompt row/card shows: name, content preview, mandate ID + - **Action buttons column** in table (rendered on first load): + - "Start Prompt" button - navigates to `/chat-playground` and starts workflow with prompt content + - "Edit" button - switches to Edit View + - "Delete" button - shows confirmation dialog and deletes prompt + - Clickable rows/cards that switch to Detail View (set selectedPromptId and view state) + +- **Search and Filter Controls:** + - General search input box (searches across all text fields) + - Field-specific filter controls (one filter per visible field) + - Active filter indicators (chips/badges showing applied filters) + - "Clear all filters" button when filters are active + +- **Sorting Controls:** + - Clickable column headers with sort indicators (up/down arrows) + - Visual indication of current sort field and direction + - Support for multi-level sorting + +- **Pagination Controls:** + - Page information display ("Page X of Y", "Showing 1-20 of 45 prompts") + - Previous/Next page buttons + - Page number buttons + - Page size selector (10, 20, 50, 100 items per page) + +- **Action Buttons:** + - "Create Prompt" button - switches to Create View + +### Detail View + +**State:** `view === 'detail'` and `selectedPromptId !== null` + +**What the user sees:** + +- **Prompt Header Section:** + - Prompt name (editable indicator if user has permission) + - Mandate ID (read-only) + +- **Prompt Information Section:** + - All prompt properties displayed as formatted fields + - Read-only fields shown as formatted text + - Editable fields shown with edit indicators (if user has permission) + - Special formatting: + - Content → Display as formatted textarea or code block (if applicable) + - Name → Display as heading + +- **Action Buttons:** + - Start Prompt button - navigates to `/chat-playground` and starts workflow with prompt content + - Edit button (if user has permission and editable fields exist) - switches to Edit View + - Delete button (if user has permission) + +### Edit View + +**State:** `view === 'edit'` and `selectedPromptId !== null` + +**What the user sees:** + +- **Form Section:** + - Dynamic form with editable prompt fields only + - Field labels with required indicators (asterisk for required fields) + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + +- **Action Buttons:** + - Save button (submits form) + - Cancel button (switches back to Detail View) + +### Create View + +**State:** `view === 'create'` + +**What the user sees:** + +- **Form Section:** + - Dynamic form with all editable prompt fields + - Field labels with required indicators + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + +- **Action Buttons:** + - Create button (submits form) + - Cancel button (switches back to List View) + +- **Confirmation Dialogs:** + - Delete confirmation dialog (on prompt detail page) + +--- + +## User Interactions and Functionality + +### Browsing and Discovery + +**Search Functionality:** +- User types in general search box +- Frontend debounces input (300-500ms delay) +- Search applies across all text fields in prompt objects +- Results update automatically +- Page resets to page 1 when search changes + +**Field Filtering:** +- User selects field to filter by +- Frontend shows appropriate filter UI based on field type: + - Text fields → Text input with operator selection (contains, equals, startsWith, endsWith) + - Textarea fields → Text input filter + - Select fields → Dropdown with options from backend metadata + - Email fields → Email input filter + - Checkbox fields → Boolean toggle (true/false/any) +- User applies filter → Filter appears as active chip/badge +- User can remove individual filters +- Multiple filters work together (AND logic) +- Page resets to page 1 when filters change + +**Sorting:** +- User clicks column header +- Sort direction toggles (asc → desc → remove) +- Multiple columns can be sorted (multi-level sorting) +- Sort indicators show on column headers +- All filters and search preserved when sorting + +**Pagination:** +- User clicks page number or navigation button +- Page updates and data refetches +- All filters, search, and sort preserved +- User changes page size → Page resets to 1, data refetches + +**View Switching:** +- User clicks prompt row/card → Switches to Detail View (set selectedPromptId and view state) +- User clicks prompt name → Switches to Detail View (set selectedPromptId and view state) + +### Viewing Prompt Details + +**Information Display:** +- All prompt fields displayed using dynamic rendering +- Read-only fields shown as formatted text +- Editable fields shown with edit indicators +- Special fields formatted appropriately (content as formatted text) + +**Action Availability:** +- Edit button shown if editable fields exist and user has permission +- Delete button shown if user has permission + +### Creating Prompts + +**Form Interaction:** +- User clicks "Create Prompt" button → Switches to Create View (set `view: 'create'`) +- Form shows all editable fields +- User fills in fields +- Client-side validation shows errors immediately +- User clicks Create → Form validates and submits +- User clicks Cancel → Switches back to List View (set `view: 'list'`, `selectedPromptId: null`) + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., textarea fields must be valid text) +- Validation errors displayed inline below fields + +**Form Submission:** +- Prompt data sent as Prompt object +- Success → Switch to Detail View for created prompt (set `selectedPromptId` to new prompt ID, `view: 'detail'`) +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Editing Prompts + +**Form Interaction:** +- User clicks "Edit" button → Switches to Edit View (set `view: 'edit'`) +- Form pre-populated with current prompt values +- User modifies fields +- Client-side validation shows errors immediately +- User clicks Save → Form validates and submits +- User clicks Cancel → Switches back to Detail View (set `view: 'detail'`) + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., textarea fields must be valid text) +- Validation errors displayed inline below fields + +**Form Submission:** +- Only changed fields sent (or all form data) +- Success → Switch back to Detail View (set `view: 'detail'`) and show success message +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Starting Prompts + +**Start Prompt Action:** +- User clicks "Start Prompt" button in table row or detail page +- Frontend fetches prompt data to get prompt content +- Frontend navigates to `/chat-playground` page +- Frontend pre-fills the chat input with the prompt's content +- Frontend displays prompt name as context (optional) +- User can optionally modify the prompt or add files before starting +- User clicks "Start" or "Send" button in chat playground +- Frontend calls `POST /api/chat/playground/start` with: + - `workflowMode` query parameter: "Dynamic" (default) or user-selected mode + - `userInput` body: `{prompt: promptContent, listFileId: [...], userLanguage: "en"}` + +**Start Prompt Submission:** +- Success → Workflow starts, chat playground updates with workflow data, messages/logs appear +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +**Implementation Notes:** +- Action buttons (Start Prompt, Edit, Delete) are rendered in the table on first load +- Buttons should be visible in each table row +- Start Prompt button should be clearly distinguished (e.g., primary button style) +- Navigation to chat playground should preserve prompt context + +### Deleting Prompts + +**Delete Action:** +- User clicks delete button (on detail page or list) +- Confirmation dialog appears with prompt name +- Warning about permanent deletion +- User confirms → Prompt deleted +- User cancels → Dialog closes, no action + +**Delete Success Handling:** +- Success message displayed +- If in Detail View → Switch back to List View (set `view: 'list'`, `selectedPromptId: null`) +- If in List View → Remove prompt from list or refresh + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by prompt pages: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/prompts/` | GET | Get all prompts (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) | +| `/api/prompts/{promptId}` | GET | Get prompt details | Detail page load, edit page load | All authenticated users | +| `/api/prompts/{promptId}` | PUT | Update prompt | Edit form submission | All authenticated users | +| `/api/prompts/{promptId}` | DELETE | Delete prompt | User confirms deletion | All authenticated users | +| `/api/prompts` | POST | Create prompt | Create form submission | All authenticated users | +| `/api/attributes/Prompt` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users | +| `/api/chat/playground/start` | POST | Start workflow with prompt | User clicks "Start Prompt" button | All authenticated users | + +### API Request Patterns + +**Pagination Request:** +``` +GET /api/prompts/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null} +``` +- `pagination` parameter is JSON-encoded string +- If user wants all prompts: omit `pagination` parameter entirely +- Filters structure: `{"search":"query","fieldName":"value",...}` +- Optional `mandateId` query parameter to filter by mandate + +**Create Request:** +``` +POST /api/prompts +Content-Type: application/json +Body: { + "name": "Invoice Processing", + "content": "Process the following invoice..." +} +``` +- All Prompt model fields sent as Prompt object +- Handle 403 (permission denied) and 400 (validation errors) + +**Update Request:** +``` +PUT /api/prompts/{promptId} +Content-Type: application/json +Body: {fieldName: value, ...} +``` +- Send only changed fields or all form data +- Handle 403 (permission denied) and 400 (validation errors) + +**Start Prompt Request:** +``` +POST /api/chat/playground/start?workflowMode=Dynamic +Content-Type: application/json +Body: { + "prompt": "Prompt content here...", + "listFileId": ["file1", "file2"], + "userLanguage": "en" +} +``` +- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template" (default: "Dynamic") +- `prompt` field contains the prompt's content +- `listFileId` is optional array of file IDs to attach +- `userLanguage` should match user's preferred language +- Handle 403 (permission denied) and 400 (validation errors) + +**Delete Requests:** +``` +DELETE /api/prompts/{promptId} +``` +- Delete operation requires user confirmation +- Handle 403 (permission denied) and 404 (not found) gracefully + +### Response Handling + +**Paginated Response:** +```json +{ + "items": [...], + "pagination": { + "currentPage": 1, + "pageSize": 20, + "totalItems": 45, + "totalPages": 3, + "sort": [...], + "filters": {...} + } +} +``` + +**Error Responses:** +- 403 Forbidden → Show permission error message +- 404 Not Found → Show "not found" error message +- 400 Bad Request → Display validation errors from response +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Complete Field List + +The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for prompts. All of these are provided by the backend through the `/api/attributes/Prompt` endpoint and should never be hardcoded in the frontend. + +#### Core Prompt Fields + +**Identification Fields:** +- `id` - Unique prompt identifier (text, readonly, not required, visible) +- `mandateId` - ID of the mandate this prompt belongs to (text, readonly, not required, visible) + +**Content Fields:** +- `name` - Name of the prompt (text, editable, required, visible) +- `content` - Content of the prompt (textarea, editable, required, visible) + +### Pagination Parameters + +**Request Parameters (`PaginationParams`):** +- `page` - Current page number (1-based, minimum 1) +- `pageSize` - Number of items per page (minimum 1, maximum 1000) +- `sort` - Array of sort field configurations + - Each sort field contains: + - `field` - Field name to sort by (must match a prompt field name) + - `direction` - Sort direction: "asc" or "desc" +- `filters` - Filter criteria dictionary + - `search` - General search term (searches across all text fields, case-insensitive) + - Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}` + - Supported operators: "equals", "contains", "startsWith", "endsWith", "in", "notIn" + +**Response Metadata (`PaginationMetadata`):** +- `currentPage` - Current page number (1-based) +- `pageSize` - Number of items per page +- `totalItems` - Total number of items across all pages (after filters applied) +- `totalPages` - Total number of pages (calculated from totalItems / pageSize) +- `sort` - Current sort configuration applied (array of SortField objects) +- `filters` - Current filters applied (mirrors request filters) + +### Attribute Definition Structure + +Each field returned from `/api/attributes/Prompt` contains: + +- `name` - Field name (e.g., "name", "content", "id") +- `type` - Field data type (e.g., "text", "textarea", "select", "checkbox") +- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"}) +- `description` - Field description text +- `required` - Boolean indicating if field is required +- `readonly` - Boolean indicating if field is read-only +- `editable` - Boolean indicating if field can be edited (inverse of readonly) +- `visible` - Boolean indicating if field should be displayed in UI +- `options` - Array of options for select fields (each option has `value` and localized `label`) + +--- + +## Dynamic Rendering Guidelines + +The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded. + +### Table Column Generation + +When rendering the prompt list table: + +1. Fetch attribute definitions from `/api/attributes/Prompt` +2. Filter attributes where `visible: true` to determine which columns to display +3. Use `label` property for column headers (select appropriate language based on user preference) +4. Use `type` property to determine how to format cell values: + - `text` fields → Display as plain text + - `textarea` fields → Display as truncated text with "..." or expandable preview + - `select` fields → Display value using label from options array (match value to option.value, then display option.label) + - `checkbox` fields → Display as checkmark icon or "Yes"/"No" text +5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are) +6. Generate click handlers for column headers to update sort parameters and refetch data +7. **Add Actions Column:** + - Render action buttons in each table row on first load + - Include "Start Prompt" button (primary style) - navigates to `/chat-playground` with prompt content + - Include "Edit" button - switches to Edit View + - Include "Delete" button - shows confirmation dialog + - Buttons should be visible and accessible in each row + +### Filter Control Generation + +When rendering filter controls: + +1. Fetch attribute definitions from `/api/attributes/Prompt` +2. Filter attributes where `visible: true` to determine which filters to show +3. For each visible field, generate appropriate filter UI based on `type`: + - `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - `textarea` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - `email` fields → Email input filter + - `select` fields → Dropdown filter with options from `options` array (use localized labels) + - `checkbox` fields → Boolean toggle filter (true/false/any) +4. Use `label` property for filter labels (localized) +5. When user applies filter, update `filters` object in pagination parameters and refetch data +6. Display active filters as chips/badges showing field label and value +7. Allow removing individual filters by removing them from `filters` object + +### Search Implementation + +For general search functionality: + +1. Display a single search input box (not field-specific) +2. When user types, update `filters.search` in pagination parameters +3. Debounce search input (wait 300-500ms after user stops typing before sending request) +4. Search applies across all text fields in the prompt object +5. Reset to page 1 when search query changes +6. Combine search with field-specific filters (both are in the `filters` object) + +### Form Field Generation + +When rendering edit forms: + +1. Fetch attribute definitions from `/api/attributes/Prompt` +2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show +3. For each editable field, generate appropriate form input based on `type`: + - `text` fields → Text input + - `textarea` fields → Textarea input (with appropriate rows/height) + - `email` fields → Email input + - `select` fields → Dropdown/select input with options from `options` array (use localized labels) + - `checkbox` fields → Checkbox input +4. Use `label` property for field labels (localized) +5. Use `required` property to show required indicators (asterisk, etc.) +6. Use `description` property to show help text or tooltips +7. Validate form before submission: + - Check all `required: true` fields have values + - Validate types (e.g., textarea fields must be valid text) + - Validate select fields (value must be in options array) +8. On submit, send only changed fields or all form data to update endpoint + +### Create Form Field Generation + +When rendering create forms: + +1. Follow same pattern as edit forms for Prompt model fields +2. On submit, send Prompt object fields in request body + +### Display Formatting + +When displaying field values: + +1. Use `type` property to determine formatting: + - `text` → Display as-is (may need HTML escaping) + - `textarea` → Display as formatted text (preserve line breaks, may truncate with "Read more" link) + - `select` → Look up value in `options` array and display localized label + - `checkbox` → Display as checkmark icon or "Yes"/"No" text +2. Handle `null` or `undefined` values gracefully (show "-" or "Not set") +3. Use `readonly` property to determine if field should show edit indicators +4. For content field (textarea), consider: + - Truncating long content in list view with "Show more" link + - Showing full content in detail view + - Preserving formatting (line breaks, whitespace) + +### Localization + +All labels and options support multiple languages: + +1. Use user's preferred language (from user settings or browser locale) +2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback +3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback +4. If label for current language is missing, fall back to English + +### Key Principles + +- Never hardcode field names, labels, types, or validation rules +- Always fetch attribute definitions from backend before rendering UI +- Use attribute metadata to determine what to display and how to display it +- Support all field types dynamically - if backend adds new types, frontend should handle them +- Respect `visible`, `editable`, `readonly`, and `required` flags from backend +- Use localized labels from backend metadata +- Generate filters, forms, and tables entirely from attribute definitions +- When backend adds new fields, frontend should automatically display them without code changes +- Handle all error cases gracefully (403, 404, 400, 500) +- Provide user feedback for all actions (loading states, success messages, error messages) + +--- + +## Summary + +This document provides complete frontend requirements for all prompt management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/Prompt` endpoint. + +**Key Architecture Pattern:** The prompt management interface is a single page (`/prompts`) with different views managed through component state. All interactions happen within the same page component without separate routes. + +For generic patterns that apply across all entity types (not just prompts), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md). + diff --git a/docs/frontend-documentation/user-page-customer-journeys.md b/docs/frontend-documentation/user-page-customer-journeys.md new file mode 100644 index 00000000..9fe6283c --- /dev/null +++ b/docs/frontend-documentation/user-page-customer-journeys.md @@ -0,0 +1,516 @@ +# User Routes Frontend Documentation + +This document describes customer journeys for managing users through the frontend, focusing on how administrators interact with user management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required. + +**IMPORTANT:** All user management pages are **admin-only**. Non-admin users should not see navigation links or be able to access these pages. The frontend must check user privileges before rendering user management UI. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Discovering and Browsing Users](#customer-journey-1-discovering-and-browsing-users) +3. [Customer Journey 2: Viewing User Details](#customer-journey-2-viewing-user-details) +4. [Customer Journey 3: Creating New Users](#customer-journey-3-creating-new-users) +5. [Customer Journey 4: Editing User Properties](#customer-journey-4-editing-user-properties) +6. [Customer Journey 5: Enabling and Disabling Users](#customer-journey-5-enabling-and-disabling-users) +7. [Customer Journey 6: Resetting User Passwords](#customer-journey-6-resetting-user-passwords) +8. [Customer Journey 7: Revoking User Sessions](#customer-journey-7-revoking-user-sessions) +9. [Customer Journey 8: Deleting Users](#customer-journey-8-deleting-users) +9. [Backend Metadata System](#backend-metadata-system) +10. [Implementation Patterns](#implementation-patterns) + +--- + +## Overview + +The user routes (`/api/users`) enable administrators to manage users within their mandate. These routes focus on **user administration** including creation, editing, password management, and deletion. + +**Key Principles:** +- **Admin-Only**: All user management functionality is restricted to administrators +- **User-Centric**: Documentation organized around what administrators want to accomplish +- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata +- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend +- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully +- **Mandate-Scoped**: Users are managed within the context of mandates + +--- + +## Customer Journey 1: Discovering and Browsing Users + +### User Goal +"As an administrator, I want to see all users in my mandate and find the one I'm looking for." + +### User Story +As an administrator, I want to browse users, search for specific users, filter by any field, sort them by different criteria, and quickly identify which users are enabled, their privilege levels, and their authentication methods. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Navigate to /users (admin only) + Frontend->>Frontend: Check if user is admin + alt User is not admin + Frontend-->>Admin: Redirect to unauthorized page or hide navigation + else User is admin + Frontend->>Backend: GET /api/attributes/User + Backend-->>Frontend: Attribute definitions (fields, labels, types) + Frontend->>Backend: GET /api/users/?pagination=... + Backend-->>Frontend: Paginated users list + Frontend->>Frontend: Generate table columns from attributes + Frontend->>Frontend: Generate filter controls from attributes + Frontend->>Frontend: Render users table + search + filters + Frontend-->>Admin: Display user list with search/filter UI + end + + alt Admin performs general search + Admin->>Frontend: Type in search box (e.g., "john") + Frontend->>Frontend: Update search query + Frontend->>Backend: GET /api/users/?pagination=...filters:{"search":"john"} + Backend-->>Frontend: Filtered users list + Frontend-->>Admin: Display matching users + end + + alt Admin applies field filter + Admin->>Frontend: Select filter field (e.g., "Privilege") + Frontend->>Frontend: Show filter options from attribute metadata + Admin->>Frontend: Select filter value (e.g., "admin") + Frontend->>Frontend: Update filter parameters + Frontend->>Backend: GET /api/users/?pagination=...filters:{"privilege":"admin"} + Backend-->>Frontend: Filtered users list + Frontend-->>Admin: Display filtered users + end + + alt Admin combines search + filter + sort + Admin->>Frontend: Apply search + filter + sort + Frontend->>Frontend: Combine all parameters + Frontend->>Backend: GET /api/users/?pagination=...filters:{"search":"john","privilege":"admin"}...sort:desc + Backend-->>Frontend: Filtered, sorted users list + Frontend-->>Admin: Display results + end + + Admin->>Frontend: Click column header (e.g., "Email") + Frontend->>Frontend: Update sort parameters + Frontend->>Backend: GET /api/users/?pagination=...sort:desc + Backend-->>Frontend: Sorted users list + Frontend-->>Admin: Display sorted users + + Admin->>Frontend: Click user row + Frontend->>Frontend: Navigate to /users/userId + Frontend-->>Admin: Show user detail page +``` + +--- + +## Customer Journey 2: Viewing User Details + +### User Goal +"As an administrator, I want to see everything about a specific user—their account information, privilege level, and status." + +### User Story +As an administrator, I want to open a user and see their complete information, including username, email, full name, language preference, enabled status, privilege level, authentication authority, and mandate association. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click user from list + Frontend->>Backend: GET /api/users/userId + Backend-->>Frontend: User object + + Frontend->>Backend: GET /api/attributes/User + Backend-->>Frontend: Field definitions + + Frontend->>Frontend: Generate UI from metadata + Frontend->>Frontend: Render user info section + Frontend->>Frontend: Separate editable vs read-only fields + Frontend-->>Admin: Display complete user view + + alt User has editable fields and admin has permission + Frontend->>Frontend: Show "Edit User" button + end + + alt Admin has permission + Frontend->>Frontend: Show "Reset Password" button + Frontend->>Frontend: Show "Revoke Sessions" button + Frontend->>Frontend: Show "Delete User" button + end + + alt Admin clicks "Revoke Sessions" + Admin->>Frontend: Click "Revoke Sessions" button + Frontend->>Frontend: Show revocation dialog + Admin->>Frontend: Select authority filter (optional) + Admin->>Frontend: Enter reason (optional) + Admin->>Frontend: Click "Revoke" + Frontend->>Frontend: Optimistic update: Show loading state + Frontend->>Backend: POST /api/admin/tokens/revoke/user + alt Success + Backend-->>Frontend: {"revoked": count} + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/users/userId (refetch) + Backend-->>Frontend: Updated user object + Frontend->>Frontend: Update UI with fresh data + Frontend-->>Admin: Show success message + else Error (403/400/500) + Backend-->>Frontend: Error response + Frontend->>Frontend: Revert optimistic update + Frontend-->>Admin: Show error message + end + end + + alt Admin clicks "Reset Password" + Admin->>Frontend: Click "Reset Password" button + Frontend->>Frontend: Show password reset dialog + Admin->>Frontend: Enter new password + Admin->>Frontend: Confirm password + Admin->>Frontend: Click "Reset" + Frontend->>Frontend: Optimistic update: Show loading state + Frontend->>Backend: POST /api/users/userId/reset-password + alt Success + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update + Frontend->>Backend: GET /api/users/userId (refetch) + Backend-->>Frontend: Updated user object + Frontend->>Frontend: Update UI with fresh data + Frontend-->>Admin: Show success message + else Error (403/400/500) + Backend-->>Frontend: Error response + Frontend->>Frontend: Revert optimistic update + Frontend-->>Admin: Show error message + end + end + + alt Admin clicks "Delete User" + Admin->>Frontend: Click "Delete User" button + Frontend->>Backend: GET /api/users/userId + Backend-->>Frontend: User data (for name) + Frontend->>Frontend: Show confirmation dialog + Admin->>Frontend: Confirm deletion + Frontend->>Frontend: Optimistic update: Remove user from UI + Frontend->>Backend: DELETE /api/users/userId + alt Success + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update + Frontend->>Frontend: Navigate to /users + Frontend-->>Admin: Show success message + else Error (403/404/500) + Backend-->>Frontend: Error response + Frontend->>Frontend: Revert optimistic update + Frontend-->>Admin: Show error message + end + end +``` + + +## Customer Journey 3: Creating New Users + +### User Goal +"As an administrator, I want to create new users for my mandate." + +### User Story +As an administrator, I want to create a new user by filling out a form with their username, email, full name, language preference, privilege level, and initial password. The form should validate all required fields and show clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click "Create User" button + Frontend->>Frontend: Navigate to /users/create + + Frontend->>Backend: GET /api/attributes/User + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend->>Frontend: Add password field (special case) + Frontend-->>Admin: Display create user form + + Admin->>Frontend: Fill in form fields + Admin->>Frontend: Enter password + Admin->>Frontend: Click "Create" + + Frontend->>Frontend: Validate form (required fields, types, email format) + alt Validation fails + Frontend-->>Admin: Show validation errors + else Validation passes + Frontend->>Backend: POST /api/users + form data + password + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>Admin: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>Admin: Show backend validation errors + else Success (200) + Backend-->>Frontend: Created user object + Frontend->>Frontend: Navigate to user detail page + Frontend-->>Admin: Show created user + end + end +``` + +## Customer Journey 4: Editing User Properties + +### User Goal +"As an administrator, I want to change user settings like their name, email, privilege level, or enabled status." + +### User Story +As an administrator, I want to edit a user's properties through a form that only shows fields I'm allowed to edit, with validation and clear error messages. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click "Edit" button + Frontend->>Frontend: Navigate to /users/id/edit + + Frontend->>Backend: GET /api/users/userId + Backend-->>Frontend: Current user data + + Frontend->>Backend: GET /api/attributes/User + Backend-->>Frontend: Field definitions (editable fields) + + Frontend->>Frontend: Filter editable fields + Frontend->>Frontend: Generate form from attributes + Frontend->>Frontend: Pre-populate form with user data + Frontend-->>Admin: Display edit form + + Admin->>Frontend: Modify form fields + Admin->>Frontend: Click "Save" + + Frontend->>Frontend: Validate form (required fields, types) + alt Validation fails + Frontend-->>Admin: Show validation errors + else Validation passes + Frontend->>Frontend: Optimistic update: Apply changes to UI immediately + Frontend->>Backend: PUT /api/users/userId + form data + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update + Frontend-->>Admin: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend->>Frontend: Revert optimistic update + Frontend-->>Admin: Show backend validation errors + else Success (200) + Backend-->>Frontend: Updated user + Frontend->>Frontend: Keep optimistic update (or refresh from response) + Frontend->>Frontend: Navigate to detail page + Frontend-->>Admin: Show updated user + end + end +``` + +--- + +## Customer Journey 5: Enabling and Disabling Users + +### User Goal +"As an administrator, I want to quickly enable or disable users directly from the user list without navigating to their detail page." + +### User Story +As an administrator, I want to toggle a user's enabled status directly in the user list table. When I click the toggle, it should immediately update the user's status in the backend with an optimistic update, so the UI feels responsive and confident. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: View user list table + Frontend->>Backend: GET /api/users/?pagination=... + Backend-->>Frontend: Paginated users list + Frontend->>Frontend: Render table with enabled toggle column + Frontend-->>Admin: Display user list with enabled toggles + + Admin->>Frontend: Click enabled toggle for user + Frontend->>Frontend: Optimistic update: Toggle switch immediately
(enabled: true → false or false → true) + Frontend->>Backend: PUT /api/users/userId + {enabled: newValue} + alt Success (200) + Backend->>Backend: Update user enabled status + Backend-->>Frontend: Updated user object + Frontend->>Frontend: Keep optimistic update (toggle already changed) + Frontend->>Backend: GET /api/users/?pagination=... (refetch list) + Backend-->>Frontend: Updated users list + Frontend->>Frontend: Update table with fresh data + Frontend-->>Admin: Show subtle success indicator (optional) + else Error (403/400/404/500) + Backend-->>Frontend: Error response + Frontend->>Frontend: Revert optimistic update: Toggle back to original state + Frontend-->>Admin: Show error message + end +``` + +## Customer Journey 6: Resetting User Passwords + +### User Goal +"As an administrator, I want to reset a user's password when they forget it or need a new one." + +### User Story +As an administrator, I want to reset a user's password by entering a new password. The system should validate password strength and automatically revoke all existing tokens for security. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click "Reset Password" button + Frontend->>Frontend: Show password reset dialog + + Admin->>Frontend: Enter new password + Admin->>Frontend: Confirm new password + Admin->>Frontend: Click "Reset" + + Frontend->>Frontend: Validate password (min 8 characters) + Frontend->>Frontend: Validate passwords match + alt Validation fails + Frontend-->>Admin: Show validation errors + else Validation passes + Frontend->>Backend: POST /api/users/userId/reset-password + newPassword + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>Admin: Show permission error + else Validation error (400) + Backend-->>Frontend: 400 Bad Request (password too short) + Frontend-->>Admin: Show validation error + else Success (200) + Backend->>Backend: Reset password + Backend->>Backend: Revoke all user tokens + Backend-->>Frontend: Success response + Frontend-->>Admin: Show success message + end + end +``` + +### Frontend Requirements + +> **📋 Complete frontend requirements for this journey are documented in [User Page Requirements](./user-page-requirements.md#customer-journey-6-resetting-user-passwords)** + +The frontend must implement a password reset dialog with password strength validation. This is an admin-only action. + +```typescript +const handleResetPassword = async (userId: string, newPassword: string) => { + // Validate password strength + if (newPassword.length < 8) { + showError('Password must be at least 8 characters long'); + return; + } + + const response = await fetch(`/api/users/${userId}/reset-password`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ newPassword }) + }); + + if (response.ok) { + showSuccess('Password reset successfully. All user sessions have been revoked.'); + } else { + const error = await response.json(); + showError(error.detail || 'Failed to reset password'); + } +}; +``` + +--- + +## Customer Journey 7: Revoking User Sessions + +### User Goal +"As an administrator, I want to revoke all active sessions for a user to force them to log in again." + +### User Story +As an administrator, I want to revoke all active tokens/sessions for a user, optionally filtered by authentication authority (local, Google, Microsoft). This is useful for security purposes, such as when a user's account may have been compromised or when they need to be logged out of all devices. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click "Revoke Sessions" button + Frontend->>Frontend: Show session revocation dialog + + Admin->>Frontend: Optionally select authority filter (local/Google/Microsoft) + Admin->>Frontend: Optionally enter reason + Admin->>Frontend: Click "Revoke Sessions" + + Frontend->>Backend: POST /api/admin/tokens/revoke/user + {userId, authority?, reason?} + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend-->>Admin: Show permission error + else Success (200) + Backend->>Backend: Revoke all active tokens for user + Backend-->>Frontend: {"revoked": count} + Frontend-->>Admin: Show success message with count + end +``` + +--- + +## Customer Journey 8: Deleting Users + +### User Goal +"As an administrator, I want to delete users that are no longer needed." + +### User Story +As an administrator, I want to delete users with a clear confirmation to prevent accidental deletion. + +### User Story Flow + +```mermaid +sequenceDiagram + participant Admin + participant Frontend + participant Backend + + Admin->>Frontend: Click "Delete" button + Frontend->>Backend: GET /api/users/userId + Backend-->>Frontend: User data (for name) + Frontend->>Frontend: Show confirmation dialog
"Delete 'User Name'?" + Admin->>Frontend: Cancel deletion + Frontend-->>Admin: Dialog closed, no action + + Admin->>Frontend: Click "Delete" button again + Frontend->>Backend: GET /api/users/userId + Backend-->>Frontend: User data + Frontend->>Frontend: Show confirmation dialog + Admin->>Frontend: Confirm deletion + Frontend->>Frontend: Optimistic update: Remove user from UI immediately + Frontend->>Backend: DELETE /api/users/userId + + alt Permission denied (403) + Backend-->>Frontend: 403 Forbidden + Frontend->>Frontend: Revert optimistic update: Restore user in UI + Frontend-->>Admin: Show permission error + else Not found (404) + Backend-->>Frontend: 404 Not Found + Frontend->>Frontend: Revert optimistic update: Restore user in UI + Frontend-->>Admin: Show not found error + else Success (200) + Backend-->>Frontend: Success response + Frontend->>Frontend: Keep optimistic update (user already removed) + Frontend->>Frontend: Show success message + Frontend->>Frontend: Navigate to /users (if on detail page) + Frontend-->>Admin: Display user list (without deleted user) + end +``` \ No newline at end of file diff --git a/docs/frontend-documentation/user-page-requirements.md b/docs/frontend-documentation/user-page-requirements.md new file mode 100644 index 00000000..28e98ad5 --- /dev/null +++ b/docs/frontend-documentation/user-page-requirements.md @@ -0,0 +1,843 @@ +# User Page Requirements + +This document contains the complete frontend requirements for all user management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required. + +**IMPORTANT:** All user management pages are **admin-only**. Non-admin users should not see navigation links or be able to access these pages. The frontend must check user privileges before rendering user management UI. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) +7. [Admin Access Control](#admin-access-control) + +--- + +## Overview + +The user management page enables administrators to manage users within their mandate. The frontend consists of a single page (`/users`) with different views/states: + +- **List View** - Browse, search, filter, and sort users (admin-only) +- **Detail View** - View complete user information (admin-only) +- **Edit View** - Edit user properties (admin-only) +- **Create View** - Create new users (admin-only) + +All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/User` endpoint. Views are managed through component state and routing within the same page, not as separate routes. + +--- + +## Page Structure and Layout + +### User Management Page (`/users`) + +**Access Control:** Admin-only. Non-admin users should not see this page or navigation links to it. + +The user management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component. + +### List View + +**State:** `view === 'list'` or `selectedUserId === null` + +**What the administrator sees:** + +- **Main Content Area:** + - Table or card grid displaying all users in the mandate + - Each user row/card shows: username, email, full name, privilege badge, enabled toggle (interactive switch), authentication authority + - Enabled toggle is clickable and immediately updates user status with optimistic update + - Clickable rows/cards that switch to Detail View (set selectedUserId and view state) + +- **Search and Filter Controls:** + - General search input box (searches across all text fields) + - Field-specific filter controls (one filter per visible field) + - Active filter indicators (chips/badges showing applied filters) + - "Clear all filters" button when filters are active + +- **Sorting Controls:** + - Clickable column headers with sort indicators (up/down arrows) + - Visual indication of current sort field and direction + - Support for multi-level sorting + +- **Pagination Controls:** + - Page information display ("Page X of Y", "Showing 1-20 of 45 users") + - Previous/Next page buttons + - Page number buttons + - Page size selector (10, 20, 50, 100 items per page) + +- **Action Buttons:** + - "Create User" button (admin-only) - switches to Create View + +### Detail View + +**State:** `view === 'detail'` and `selectedUserId !== null` + +**Access Control:** Admin-only. + +**What the administrator sees:** + +- **User Header Section:** + - Username (editable indicator if user has permission) + - Full name (if available) + - Privilege badge with color coding + - Enabled status indicator + +- **User Information Section:** + - All user properties displayed as formatted fields + - Read-only fields shown as formatted text + - Editable fields shown with edit indicators (if admin has permission) + - Special formatting: + - Privilege → Color-coded badge (User/Admin/SysAdmin) + - Enabled → Checkmark icon or "Enabled"/"Disabled" text + - Authentication Authority → Badge with icon + - Email → Clickable mailto link + +- **Action Buttons:** + - Edit button (if admin has permission and editable fields exist) - switches to Edit View + - Reset Password button (admin-only) + - Revoke Sessions button (admin-only) + - Delete button (if admin has permission) + +### Edit View + +**State:** `view === 'edit'` and `selectedUserId !== null` + +**Access Control:** Admin-only. + +**What the administrator sees:** + +- **Form Section:** + - Dynamic form with editable user fields only + - Field labels with required indicators (asterisk for required fields) + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + +- **Action Buttons:** + - Save button (submits form) + - Cancel button (switches back to Detail View) + +### Create View + +**State:** `view === 'create'` + +**Access Control:** Admin-only. + +**What the administrator sees:** + +- **Form Section:** + - Dynamic form with all editable user fields + - Password field (special field, not in User model attributes) + - Confirm password field (frontend-only validation) + - Field labels with required indicators + - Help text/tooltips from field descriptions + - Input validation errors displayed inline + +- **Action Buttons:** + - Create button (submits form) + - Cancel button (switches back to List View) + +- **Confirmation Dialogs:** + - Delete confirmation dialog (on user detail page) + - Password reset confirmation dialog + +--- + +## User Interactions and Functionality + +### Admin Access Control + +**Before Rendering Any User Management UI:** + +1. Check if current user has admin or sysadmin privilege +2. If not admin: + - Hide navigation links to user management pages + - Redirect if user tries to access pages directly + - Show unauthorized access message +3. If admin: + - Render user management UI normally + - Handle 403 errors gracefully (may occur if permissions change) + +### Browsing and Discovery + +**Search Functionality:** +- Administrator types in general search box +- Frontend debounces input (300-500ms delay) +- Search applies across all text fields in user objects +- Results update automatically +- Page resets to page 1 when search changes + +**Field Filtering:** +- Administrator selects field to filter by +- Frontend shows appropriate filter UI based on field type: + - Text fields → Text input with operator selection (contains, equals, startsWith, endsWith) + - Select fields → Dropdown with options from backend metadata + - Email fields → Email input filter + - Checkbox fields → Boolean toggle (true/false/any) +- Administrator applies filter → Filter appears as active chip/badge +- Administrator can remove individual filters +- Multiple filters work together (AND logic) +- Page resets to page 1 when filters change + +**Sorting:** +- Administrator clicks column header +- Sort direction toggles (asc → desc → remove) +- Multiple columns can be sorted (multi-level sorting) +- Sort indicators show on column headers +- All filters and search preserved when sorting + +**Pagination:** +- Administrator clicks page number or navigation button +- Page updates and data refetches +- All filters, search, and sort preserved +- Administrator changes page size → Page resets to 1, data refetches + +**View Switching:** +- Administrator clicks user row/card → Switches to Detail View (set `selectedUserId` and `view: 'detail'`) +- Administrator clicks username → Switches to Detail View (set `selectedUserId` and `view: 'detail'`) + +### Viewing User Details + +**Information Display:** +- All user fields displayed using dynamic rendering +- Read-only fields shown as formatted text +- Editable fields shown with edit indicators +- Special fields formatted appropriately (privilege badges, enabled status, email links) + +**Action Availability:** +- Edit button shown if editable fields exist and admin has permission +- Reset Password button always shown (admin-only action) +- Revoke Sessions button always shown (admin-only action) +- Delete button shown if admin has permission + +### Creating Users + +**Form Interaction:** +- Administrator clicks "Create User" button → Switches to Create View (set `view: 'create'`) +- Form shows all editable fields plus password field +- Administrator fills in fields +- Client-side validation shows errors immediately +- Administrator clicks Create → Form validates and submits +- Administrator clicks Cancel → Switches back to List View (set `view: 'list'`, `selectedUserId: null`) + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., email fields must be valid email format) +- Select field validation (value must be in options array) +- Password validation (minimum 8 characters) +- Password confirmation validation (must match password) +- Validation errors displayed inline below fields + +**Form Submission:** +- User data sent as User object +- Password sent as separate field in request body +- Success → Switch to Detail View for created user (set `selectedUserId` to new user ID, `view: 'detail'`) +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Editing Users + +**Form Interaction:** +- Administrator clicks "Edit" button → Switches to Edit View (set `view: 'edit'`) +- Form pre-populated with current user values +- Administrator modifies fields +- Client-side validation shows errors immediately +- Administrator clicks Save → Form validates and submits +- Administrator clicks Cancel → Switches back to Detail View (set `view: 'detail'`) + +**Form Validation:** +- Required field validation (shows error if empty) +- Type validation (e.g., email fields must be valid email format) +- Select field validation (value must be in options array) +- Validation errors displayed inline below fields + +**Form Submission:** +- Only changed fields sent (or all form data) +- Success → Switch back to Detail View (set `view: 'detail'`) and show success message +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (validation errors) → Display backend validation errors + - Other errors → Show generic error message + +### Enabling and Disabling Users + +**Toggle Interaction:** +- Administrator views user list table +- Table displays enabled/disabled status as toggle switch in "Enabled" column +- Administrator clicks toggle switch for a user +- Frontend immediately updates toggle state (optimistic update) +- Frontend sends PUT request to update user's enabled property +- Administrator sees immediate feedback (toggle changes instantly) + +**Toggle Submission:** +- Success → Keep optimistic update, refetch user list to ensure consistency +- Error → Revert toggle to original state, show error message +- No confirmation dialog needed - toggle is immediate and reversible + +**Implementation Notes:** +- Toggle should be part of the main table column +- Use optimistic updates for instant feedback +- Refetch list after successful update +- Handle errors gracefully by reverting toggle state + +### Customer Journey 5: Enabling and Disabling Users + +> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-5-enabling-and-disabling-users)** + +### Resetting User Passwords + +**Password Reset Interaction:** +- Administrator clicks "Reset Password" button +- Password reset dialog appears +- Administrator enters new password +- Administrator confirms new password +- Client-side validation: + - Password must be at least 8 characters + - Passwords must match +- Administrator clicks Reset → Password reset request sent +- Administrator clicks Cancel → Dialog closes, no action + +**Password Reset Submission:** +- Success → Show success message, close dialog +- Backend automatically revokes all user tokens +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (password too short) → Show validation error + - Other errors → Show generic error message + +### Revoking User Sessions + +**Session Revocation Interaction:** +- Administrator clicks "Revoke Sessions" button +- Session revocation dialog appears +- Administrator optionally selects authority filter: + - All authorities (default) - revokes all sessions + - Local only - revokes only local authentication sessions + - Google only - revokes only Google OAuth sessions + - Microsoft only - revokes only Microsoft OAuth sessions +- Administrator optionally enters reason (for audit logging) +- Administrator clicks "Revoke Sessions" → Session revocation request sent +- Administrator clicks Cancel → Dialog closes, no action + +**Session Revocation Submission:** +- Success → Show success message with count of revoked sessions, close dialog +- User will need to log in again on all affected devices +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (invalid parameters) → Show validation error + - Other errors → Show generic error message + +**Use Cases:** +- Security incident: User's account may have been compromised +- Device management: User lost a device or needs to log out of specific service +- Account suspension: Temporarily disable user access +- Force re-authentication: Make user log in again without changing password + +**Password Reset Interaction:** +- Administrator clicks "Reset Password" button +- Password reset dialog appears +- Administrator enters new password +- Administrator confirms new password +- Client-side validation: + - Password must be at least 8 characters + - Passwords must match +- Administrator clicks Reset → Password reset request sent +- Administrator clicks Cancel → Dialog closes, no action + +**Password Reset Submission:** +- Success → Show success message, close dialog +- Backend automatically revokes all user tokens +- Error handling: + - 403 (permission denied) → Show permission error + - 400 (password too short) → Show validation error + - Other errors → Show generic error message + +### Customer Journey 7: Revoking User Sessions + +> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-7-revoking-user-sessions)** + +### Deleting Users + +**Delete Action:** +- Administrator clicks delete button (on detail page or list) +- Confirmation dialog appears with user name/username +- Warning about permanent deletion +- Administrator confirms → User deleted +- Administrator cancels → Dialog closes, no action + +**Delete Success Handling:** +- Success message displayed +- If in Detail View → Switch back to List View (set `view: 'list'`, `selectedUserId: null`) +- If in List View → Remove user from list or refresh + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by user pages: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/users/` | GET | Get all users (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) | +| `/api/users/{userId}` | GET | Get user details | Detail page load, edit page load | All authenticated users | +| `/api/users/{userId}` | PUT | Update user | Edit form submission | All authenticated users | +| `/api/users/{userId}` | DELETE | Delete user | User confirms deletion | All authenticated users | +| `/api/users` | POST | Create user | Create form submission | All authenticated users | +| `/api/users/{userId}/reset-password` | POST | Reset user password | Admin confirms password reset | **Admin-only** | +| `/api/admin/tokens/revoke/user` | POST | Revoke all active sessions for a user | Admin confirms session revocation | **Admin-only** | +| `/api/users/change-password` | POST | Change current user's password | User changes own password | Current user only (not admin-only) | +| `/api/attributes/User` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users | + +### API Request Patterns + +**Pagination Request:** +``` +GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null} +``` +- `pagination` parameter is JSON-encoded string +- If user wants all users: omit `pagination` parameter entirely +- Filters structure: `{"search":"query","fieldName":"value",...}` +- Optional `mandateId` query parameter to filter by mandate + +**Create Request:** +``` +POST /api/users +Content-Type: application/json +Body: { + "username": "john.doe", + "email": "john@example.com", + "fullName": "John Doe", + "language": "en", + "enabled": true, + "privilege": "user", + "authenticationAuthority": "local", + "password": "securepassword123" +} +``` +- Password is sent as separate field in body (not part of User model) +- All User model fields sent as User object +- Handle 403 (permission denied) and 400 (validation errors) + +**Update Request:** +``` +PUT /api/users/{userId} +Content-Type: application/json +Body: {fieldName: value, ...} +``` +- Send only changed fields or all form data +- Handle 403 (permission denied) and 400 (validation errors) + +**Password Reset Request:** +``` +POST /api/users/{userId}/reset-password +Content-Type: application/json +Body: {"newPassword": "newsecurepassword123"} +``` +- **Admin-only endpoint** +- Password must be at least 8 characters +- Backend automatically revokes all user tokens +- Handle 403 (permission denied) and 400 (validation errors) + +**Session Revocation Request:** +``` +POST /api/admin/tokens/revoke/user +Content-Type: application/json +Body: { + "userId": "user-id-here", + "authority": "local", // Optional: "local", "google", "msft", or omit for all + "reason": "Security incident" // Optional reason for audit logging +} +``` +- **Admin-only endpoint** +- `userId` is required +- `authority` is optional - if omitted, revokes all sessions regardless of authority +- `reason` is optional - defaults to "admin revoke" if not provided +- Returns `{"revoked": count}` - number of sessions revoked +- Handle 403 (permission denied) and 400 (validation errors) + +**Delete Requests:** +``` +DELETE /api/users/{userId} +``` +- Delete operation requires user confirmation +- Handle 403 (permission denied) and 404 (not found) gracefully + +### Response Handling + +**Paginated Response:** +```json +{ + "items": [...], + "pagination": { + "currentPage": 1, + "pageSize": 20, + "totalItems": 45, + "totalPages": 3, + "sort": [...], + "filters": {...} + } +} +``` + +**Error Responses:** +- 403 Forbidden → Show permission error message (admin-only actions) +- 404 Not Found → Show "not found" error message +- 400 Bad Request → Display validation errors from response +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Complete Field List + +The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for users. All of these are provided by the backend through the `/api/attributes/User` endpoint and should never be hardcoded in the frontend. + +#### Core User Fields + +**Identification Fields:** +- `id` - Unique user identifier (text, readonly, not required, visible) +- `mandateId` - ID of the mandate this user belongs to (text, readonly, not required, visible) + +**Account Fields:** +- `username` - Username for login (text, editable, required, visible) +- `email` - Email address of the user (email, editable, required, visible) +- `fullName` - Full name of the user (text, editable, not required, visible) + +**Configuration Fields:** +- `language` - Preferred language of the user (select, editable, required, visible) + - Options: "de", "en", "fr", "it" + - Each option has localized labels (en/fr) +- `enabled` - Indicates whether the user is enabled (checkbox, editable, not required, visible) +- `privilege` - Permission level (select, editable, required, visible) + - Options: "user", "admin", "sysadmin" + - Each option has localized labels (en/fr) +- `authenticationAuthority` - Primary authentication authority (select, readonly, not required, visible) + - Options: "local", "google", "msft" + - Each option has localized labels (en/fr) + +**Special Fields (Not in User Model):** +- `password` - Password field for create forms (password, not in attributes, required for creation) +- `confirmPassword` - Password confirmation (password, frontend-only, required for creation) + +### Pagination Parameters + +**Request Parameters (`PaginationParams`):** +- `page` - Current page number (1-based, minimum 1) +- `pageSize` - Number of items per page (minimum 1, maximum 1000) +- `sort` - Array of sort field configurations + - Each sort field contains: + - `field` - Field name to sort by (must match a user field name) + - `direction` - Sort direction: "asc" or "desc" +- `filters` - Filter criteria dictionary + - `search` - General search term (searches across all text fields, case-insensitive) + - Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}` + - Supported operators: "equals", "contains", "startsWith", "endsWith", "in", "notIn" + +**Response Metadata (`PaginationMetadata`):** +- `currentPage` - Current page number (1-based) +- `pageSize` - Number of items per page +- `totalItems` - Total number of items across all pages (after filters applied) +- `totalPages` - Total number of pages (calculated from totalItems / pageSize) +- `sort` - Current sort configuration applied (array of SortField objects) +- `filters` - Current filters applied (mirrors request filters) + +### Attribute Definition Structure + +Each field returned from `/api/attributes/User` contains: + +- `name` - Field name (e.g., "username", "email", "privilege") +- `type` - Field data type (e.g., "text", "email", "select", "checkbox") +- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"}) +- `description` - Field description text +- `required` - Boolean indicating if field is required +- `readonly` - Boolean indicating if field is read-only +- `editable` - Boolean indicating if field can be edited (inverse of readonly) +- `visible` - Boolean indicating if field should be displayed in UI +- `options` - Array of options for select fields (each option has `value` and localized `label`) + +--- + +## Dynamic Rendering Guidelines + +The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded. + +### Table Column Generation + +When rendering the user list table: + +1. Fetch attribute definitions from `/api/attributes/User` +2. Filter attributes where `visible: true` to determine which columns to display +3. Use `label` property for column headers (select appropriate language based on user preference) +4. Use `type` property to determine how to format cell values: + - `text` fields → Display as plain text + - `email` fields → Display as clickable mailto link + - `select` fields → Display value using label from options array (match value to option.value, then display option.label) + - `checkbox` fields → Display as checkmark icon or "Enabled"/"Disabled" text +5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are) +6. Generate click handlers for column headers to update sort parameters and refetch data + +### Filter Control Generation + +When rendering filter controls: + +1. Fetch attribute definitions from `/api/attributes/User` +2. Filter attributes where `visible: true` to determine which filters to show +3. For each visible field, generate appropriate filter UI based on `type`: + - `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators) + - `email` fields → Email input filter + - `select` fields → Dropdown filter with options from `options` array (use localized labels) + - `checkbox` fields → Boolean toggle filter (true/false/any) +4. Use `label` property for filter labels (localized) +5. When administrator applies filter, update `filters` object in pagination parameters and refetch data +6. Display active filters as chips/badges showing field label and value +7. Allow removing individual filters by removing them from `filters` object + +### Search Implementation + +For general search functionality: + +1. Display a single search input box (not field-specific) +2. When administrator types, update `filters.search` in pagination parameters +3. Debounce search input (wait 300-500ms after user stops typing before sending request) +4. Search applies across all text fields in the user object +5. Reset to page 1 when search query changes +6. Combine search with field-specific filters (both are in the `filters` object) + +### Form Field Generation + +When rendering edit forms: + +1. Fetch attribute definitions from `/api/attributes/User` +2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show +3. For each editable field, generate appropriate form input based on `type`: + - `text` fields → Text input + - `email` fields → Email input + - `select` fields → Dropdown/select input with options from `options` array (use localized labels) + - `checkbox` fields → Checkbox input +4. Use `label` property for field labels (localized) +5. Use `required` property to show required indicators (asterisk, etc.) +6. Use `description` property to show help text or tooltips +7. Validate form before submission: + - Check all `required: true` fields have values + - Validate types (e.g., email fields must be valid email format) + - Validate select fields (value must be in options array) +8. On submit, send only changed fields or all form data to update endpoint + +### Create Form Field Generation + +When rendering create forms: + +1. Follow same pattern as edit forms for User model fields +2. **Add password field** (not in User model attributes): + - Password input field + - Confirm password input field (frontend-only validation) + - Both fields required for creation + - Validate password strength (minimum 8 characters) + - Validate passwords match +3. On submit, send User object fields plus `password` as separate field in request body + +### Display Formatting + +When displaying field values: + +1. Use `type` property to determine formatting: + - `text` → Display as-is (may need HTML escaping) + - `email` → Display as clickable mailto link + - `select` → Look up value in `options` array and display localized label + - `checkbox` → Display as checkmark icon or "Enabled"/"Disabled" text +2. Handle `null` or `undefined` values gracefully (show "-" or "Not set") +3. Use `readonly` property to determine if field should show edit indicators +4. Special formatting for privilege field: + - Color-code badges (User = blue, Admin = orange, SysAdmin = red) + - Use localized labels from options + +### Localization + +All labels and options support multiple languages: + +1. Use user's preferred language (from user settings or browser locale) +2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback +3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback +4. If label for current language is missing, fall back to English + +### Key Principles + +- Never hardcode field names, labels, types, or validation rules +- Always fetch attribute definitions from backend before rendering UI +- Use attribute metadata to determine what to display and how to display it +- Support all field types dynamically - if backend adds new types, frontend should handle them +- Respect `visible`, `editable`, `readonly`, and `required` flags from backend +- Use localized labels from backend metadata +- Generate filters, forms, and tables entirely from attribute definitions +- When backend adds new fields, frontend should automatically display them without code changes +- Handle all error cases gracefully (403, 404, 400, 500) +- Provide user feedback for all actions (loading states, success messages, error messages) +- **Always check admin privileges before rendering user management UI** + +--- + +## Admin Access Control + +### Frontend Access Control + +The frontend must implement access control to ensure only administrators can access user management pages: + +**1. Navigation Link Visibility:** +```typescript +// Only show user management link if user is admin +{currentUser?.privilege === 'admin' || currentUser?.privilege === 'sysadmin' ? ( + Manage Users +) : null} +``` + +**2. Route Protection:** +```typescript +// Protect route with admin check - single route for all views +function UserManagementPage() { + const { currentUser } = useAuth(); + const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list'); + const [selectedUserId, setSelectedUserId] = useState(null); + + // Check admin status + if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') { + return ; + } + + // Render appropriate view based on state + if (view === 'list') { + return { setSelectedUserId(id); setView('detail'); }} onCreate={() => setView('create')} />; + } else if (view === 'detail' && selectedUserId) { + return setView('edit')} onBack={() => { setSelectedUserId(null); setView('list'); }} />; + } else if (view === 'edit' && selectedUserId) { + return setView('detail')} onCancel={() => setView('detail')} />; + } else if (view === 'create') { + return { setSelectedUserId(userId); setView('detail'); }} onCancel={() => setView('list')} />; + } + + return null; +} +``` + +**3. Component-Level Checks:** +```typescript +// Check admin status before rendering components +function ListView({ onUserSelect }) { + const { currentUser } = useAuth(); + + if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') { + return ; + } + + // Render list view UI + return ( +
+ + {/* List table */} +
+ ); +} +``` + +**4. Error Handling:** +```typescript +// Handle 403 errors gracefully +try { + const response = await fetch('/api/users/userId/reset-password', { + method: 'POST', + body: JSON.stringify({ newPassword }) + }); + + if (response.status === 403) { + showError('You do not have permission to reset passwords'); + return; + } + + // Handle other responses +} catch (error) { + showError('Failed to reset password'); +} +``` + +**5. View State Management:** +```typescript +// Manage views within the same page component +function UserManagementPage() { + const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list'); + const [selectedUserId, setSelectedUserId] = useState(null); + + // Switch to detail view + const handleUserSelect = (userId: string) => { + setSelectedUserId(userId); + setView('detail'); + }; + + // Switch to edit view + const handleEdit = () => { + setView('edit'); + }; + + // Switch to create view + const handleCreate = () => { + setSelectedUserId(null); + setView('create'); + }; + + // Switch back to list view + const handleBackToList = () => { + setSelectedUserId(null); + setView('list'); + }; + + // Render based on view state + return ( + <> + {view === 'list' && } + {view === 'detail' && selectedUserId && } + {view === 'edit' && selectedUserId && setView('detail')} onCancel={() => setView('detail')} />} + {view === 'create' && { setSelectedUserId(userId); setView('detail'); }} onCancel={handleBackToList} />} + + ); +} +``` + +### Admin-Only Actions + +The following actions are admin-only and should only be available to administrators: + +- **Reset User Password** (`POST /api/users/{userId}/reset-password`) + - Only admins can reset other users' passwords + - Backend enforces this with privilege check + - Frontend should hide button for non-admins + +- **User Management Page** + - The user management page should be admin-only + - Navigation links should be hidden for non-admins + - Direct URL access should show unauthorized message for non-admins + +### Security Best Practices + +1. **Never trust frontend-only checks** - Backend always enforces permissions +2. **Handle 403 errors gracefully** - Show appropriate error messages +3. **Hide UI elements** - Don't show admin actions to non-admins +4. **Redirect unauthorized access** - Redirect non-admins away from admin pages +5. **Log security events** - Backend logs admin actions (handled by backend) + +--- + +## Summary + +This document provides complete frontend requirements for all user management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/User` endpoint. + +**Critical Security Requirement:** All user management pages are **admin-only**. The frontend must: +- Check user privileges before rendering navigation links +- Check user privileges before allowing access to pages +- Handle 403 Forbidden errors gracefully +- Never expose user management UI to non-admin users + +For generic patterns that apply across all entity types (not just users), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md). + diff --git a/docs/frontend-documentation/voice-service-customer-journeys.md b/docs/frontend-documentation/voice-service-customer-journeys.md new file mode 100644 index 00000000..3164dc2e --- /dev/null +++ b/docs/frontend-documentation/voice-service-customer-journeys.md @@ -0,0 +1,474 @@ +# Voice Service Customer Journeys + +This document describes customer journeys for the Google Cloud Voice Services, focusing on how users interact with speech-to-text, translation, text-to-speech, and real-time voice interpretation features. + +## Table of Contents + +1. [Overview](#overview) +2. [Customer Journey 1: Converting Speech to Text](#customer-journey-1-converting-speech-to-text) +3. [Customer Journey 2: Translating Text](#customer-journey-2-translating-text) +4. [Customer Journey 3: Real-time Voice Interpretation](#customer-journey-3-real-time-voice-interpretation) +5. [Customer Journey 4: Converting Text to Speech](#customer-journey-4-converting-text-to-speech) +6. [Customer Journey 5: Managing Voice Settings](#customer-journey-5-managing-voice-settings) +7. [Customer Journey 6: Discovering Available Languages and Voices](#customer-journey-6-discovering-available-languages-and-voices) +8. [Customer Journey 7: Real-time Speech-to-Text via WebSocket](#customer-journey-7-real-time-speech-to-text-via-websocket) +9. [Customer Journey 8: Real-time Text-to-Speech via WebSocket](#customer-journey-8-real-time-text-to-speech-via-websocket) + +--- + +## Overview + +The voice service routes (`/api/voice-google`) enable users to interact with Google Cloud voice services including Speech-to-Text, Translation, Text-to-Speech, and real-time voice interpretation. These routes support both HTTP REST endpoints for file-based processing and WebSocket endpoints for real-time streaming. + +**Key Principles:** +- **User-Centric**: Documentation organized around what users want to accomplish +- **Multi-Modal**: Supports both file upload and real-time streaming +- **Language-Aware**: All operations support multiple languages with user-configurable defaults +- **Settings-Driven**: User preferences stored and applied automatically + +--- + +## Customer Journey 1: Converting Speech to Text + +### User Goal +"I want to record my speech and convert it into text." + +### User Story +As a user, I want to record my speech through the frontend microphone and get the transcribed text with confidence scores and language detection. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Select language (default: de-DE) + User->>Frontend: Click "Start Recording" + Frontend->>Frontend: Request microphone access + alt Microphone access denied + Frontend-->>User: Show permission error + else Microphone access granted + Frontend->>Frontend: Start audio recording + Frontend-->>User: Show recording indicator (red dot, timer) + + User->>Frontend: Speak into microphone + Frontend->>Frontend: Capture audio stream + + User->>Frontend: Click "Stop Recording" + Frontend->>Frontend: Stop audio recording + Frontend->>Frontend: Convert audio stream to audio file + Frontend->>Frontend: Validate audio file (size, format) + + alt File validation fails + Frontend-->>User: Show validation error + else File validation passes + Frontend->>Frontend: Show loading state + Frontend->>Backend: POST /api/voice-google/speech-to-text
(audioFile, language) + + alt Authentication fails (401) + Backend-->>Frontend: 401 Unauthorized + Frontend-->>User: Show authentication error + else Invalid audio format (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show format error message + else Speech recognition fails (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show recognition error + else Success (200) + Backend-->>Frontend: {success: true, text, confidence, language, audio_info} + Frontend->>Frontend: Display transcribed text + Frontend->>Frontend: Display confidence score + Frontend->>Frontend: Display detected language + Frontend->>Frontend: Display audio metadata + Frontend-->>User: Show transcription result with metadata + end + end + end +``` + +--- + +## Customer Journey 2: Translating Text + +### User Goal +"I want to translate text from one language to another." + +### User Story +As a user, I want to enter text and translate it between languages, seeing both the original and translated text. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Enter text to translate + User->>Frontend: Select source language (default: de) + User->>Frontend: Select target language (default: en) + User->>Frontend: Click "Translate" + + Frontend->>Frontend: Validate text is not empty + alt Text is empty + Frontend-->>User: Show validation error + else Text validation passes + Frontend->>Frontend: Show loading state + Frontend->>Backend: POST /api/voice-google/translate
(text, sourceLanguage, targetLanguage) + + alt Authentication fails (401) + Backend-->>Frontend: 401 Unauthorized + Frontend-->>User: Show authentication error + else Empty text (400) + Backend-->>Frontend: 400 Bad Request + Frontend-->>User: Show empty text error + else Translation fails (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show translation error + else Success (200) + Backend-->>Frontend: {success: true, original_text, translated_text, source_language, target_language} + Frontend->>Frontend: Display original text + Frontend->>Frontend: Display translated text + Frontend->>Frontend: Display language information + Frontend-->>User: Show translation result + end + end +``` + +--- + +## Customer Journey 3: Real-time Voice Interpretation + +### User Goal +"I want to speak in one language and get the translated text in another language." + +### User Story +As a user, I want to record my speech through the frontend microphone and receive both the transcribed text in the source language and its translation in the target language. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Select source language (default: de-DE) + User->>Frontend: Select target language (default: en-US) + User->>Frontend: Click "Start Recording" + Frontend->>Frontend: Request microphone access + alt Microphone access denied + Frontend-->>User: Show permission error + else Microphone access granted + Frontend->>Frontend: Start audio recording + Frontend-->>User: Show recording indicator (red dot, timer) + + User->>Frontend: Speak into microphone + Frontend->>Frontend: Capture audio stream + + User->>Frontend: Click "Stop Recording" + Frontend->>Frontend: Stop audio recording + Frontend->>Frontend: Convert audio stream to audio file + Frontend->>Frontend: Validate audio file + + alt File validation fails + Frontend-->>User: Show validation error + else File validation passes + Frontend->>Frontend: Show loading state + Frontend->>Backend: POST /api/voice-google/realtime-interpreter
(audioFile, fromLanguage, toLanguage, connectionId?) + + alt Authentication fails (401) + Backend-->>Frontend: 401 Unauthorized + Frontend-->>User: Show authentication error + else Invalid audio format (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show format error + else Interpretation fails (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show interpretation error + else Success (200) + Backend-->>Frontend: {success: true, original_text, translated_text, confidence, source_language, target_language, audio_info} + Frontend->>Frontend: Display original transcribed text + Frontend->>Frontend: Display translated text + Frontend->>Frontend: Display confidence score + Frontend->>Frontend: Display language information + Frontend->>Frontend: Display audio metadata + Frontend-->>User: Show interpretation result with both texts + end + end + end +``` + +--- + +## Customer Journey 4: Converting Text to Speech + +### User Goal +"I want to convert written text into spoken audio." + +### User Story +As a user, I want to enter text, select a language and voice, and receive an audio file of the spoken text. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Enter text to speak + User->>Frontend: Select language (default: de-DE) + User->>Frontend: Select voice (optional, default from settings) + User->>Frontend: Click "Generate Speech" + + Frontend->>Frontend: Validate text is not empty + alt Text is empty + Frontend-->>User: Show validation error + else Text validation passes + Frontend->>Frontend: Show loading state + Frontend->>Backend: POST /api/voice-google/text-to-speech
(text, language, voice?) + + alt Authentication fails (401) + Backend-->>Frontend: 401 Unauthorized + Frontend-->>User: Show authentication error + else Empty text (400) + Backend-->>Frontend: 400 Bad Request + Frontend-->>User: Show empty text error + else Text-to-Speech fails (400) + Backend-->>Frontend: 400 Bad Request + error details + Frontend-->>User: Show TTS error + else Success (200) + Backend-->>Frontend: Audio file (audio/mpeg)
Headers: X-Voice-Name, X-Language-Code + Frontend->>Frontend: Create audio blob from response + Frontend->>Frontend: Create download link or audio player + Frontend->>Frontend: Display voice name and language + Frontend-->>User: Show audio player with download option + end + end +``` + +--- + +## Customer Journey 5: Managing Voice Settings + +### User Goal +"I want to configure my default voice settings for speech recognition, translation, and text-to-speech." + +### User Story +As a user, I want to view and update my voice settings including default languages, voice preferences, and translation settings. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Navigate to voice settings + Frontend->>Backend: GET /api/voice-google/settings + Backend-->>Frontend: {success: true, data: {user_settings, default_settings}} + Frontend->>Frontend: Pre-populate form with user_settings or default_settings + Frontend-->>User: Display settings form + + alt User views settings only + User->>Frontend: View current settings + Frontend-->>User: Display settings (read-only or editable) + else User updates settings + User->>Frontend: Modify settings (sttLanguage, ttsLanguage, ttsVoice, translationEnabled, targetLanguage) + User->>Frontend: Click "Save Settings" + + Frontend->>Frontend: Validate required fields (sttLanguage, ttsLanguage, ttsVoice) + alt Validation fails + Frontend-->>User: Show validation errors + else Validation passes + Frontend->>Frontend: Show loading state + Frontend->>Backend: POST /api/voice-google/settings
(settings object) + + alt Authentication fails (401) + Backend-->>Frontend: 401 Unauthorized + Frontend-->>User: Show authentication error + else Missing required field (400) + Backend-->>Frontend: 400 Bad Request + field name + Frontend-->>User: Show missing field error + else Save fails (500) + Backend-->>Frontend: 500 Internal Server Error + Frontend-->>User: Show save error + else Success (200) + Backend-->>Frontend: {success: true, message, data: settings} + Frontend->>Frontend: Update UI with saved settings + Frontend->>Frontend: Show success message + Frontend-->>User: Display confirmation and updated settings + end + end + end +``` + +--- + +## Customer Journey 6: Discovering Available Languages and Voices + +### User Goal +"I want to see what languages and voices are available for speech and translation services." + +### User Story +As a user, I want to browse available languages and filter voices by language to configure my preferences. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + alt User wants to see available languages + User->>Frontend: Navigate to language selection + Frontend->>Backend: GET /api/voice-google/languages + Backend-->>Frontend: {success: true, languages: [...]} + Frontend->>Frontend: Display language list + Frontend-->>User: Show available languages + end + + alt User wants to see available voices + User->>Frontend: Navigate to voice selection + User->>Frontend: Optionally select language filter + Frontend->>Backend: GET /api/voice-google/voices
?language_code=de-DE (optional) + Backend-->>Frontend: {success: true, voices: [...], language_filter: "de-DE"} + Frontend->>Frontend: Display voice list + Frontend->>Frontend: Group voices by language if no filter + Frontend-->>User: Show available voices + end + + alt User filters voices by language + User->>Frontend: Select language in filter + Frontend->>Backend: GET /api/voice-google/voices?language_code=selected + Backend-->>Frontend: Filtered voices list + Frontend->>Frontend: Update voice list + Frontend-->>User: Show filtered voices + end +``` + +--- + +## Customer Journey 7: Real-time Speech-to-Text via WebSocket + +### User Goal +"I want to get real-time transcription as I speak, without uploading a complete audio file." + +### User Story +As a user, I want to establish a WebSocket connection and stream audio chunks to receive live transcription results. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Initiate real-time speech-to-text + User->>Frontend: Select language (default: de-DE) + Frontend->>Frontend: Start audio capture + Frontend->>Backend: WebSocket: /api/voice-google/ws/speech-to-text
?userId=user&language=de-DE + + Backend->>Backend: Accept WebSocket connection + Backend->>Backend: Initialize voice interface + Backend-->>Frontend: {type: "connected", connection_id, message} + Frontend-->>User: Show "Connected" status + + loop User speaks + User->>Frontend: Speak into microphone + Frontend->>Frontend: Capture audio chunk + Frontend->>Frontend: Encode audio chunk to base64 + Frontend->>Backend: {type: "audio_chunk", data: base64_audio, timestamp} + + alt Processing error + Backend->>Backend: Log error + Backend-->>Frontend: {type: "error", error: "..."} + Frontend-->>User: Show error message + else Success + Backend->>Backend: Process audio chunk (Speech-to-Text) + Backend-->>Frontend: {type: "transcription_result", text, confidence, is_final} + Frontend->>Frontend: Update transcription display + Frontend-->>User: Show live transcription (interim or final) + end + end + + alt User sends ping + User->>Frontend: Keep-alive ping + Frontend->>Backend: {type: "ping", timestamp} + Backend-->>Frontend: {type: "pong", timestamp} + end + + alt User stops or disconnects + User->>Frontend: Stop recording + Frontend->>Backend: Close WebSocket + Backend->>Backend: Cleanup connection + Frontend-->>User: Show disconnected status + end +``` + +--- + +## Customer Journey 8: Real-time Text-to-Speech via WebSocket + +### User Goal +"I want to send text and receive audio streams in real-time without waiting for a complete file." + +### User Story +As a user, I want to establish a WebSocket connection, send text messages, and receive audio chunks for playback. + +### User Story Flow + +```mermaid +sequenceDiagram + participant User + participant Frontend + participant Backend + + User->>Frontend: Initiate real-time text-to-speech + User->>Frontend: Select language (default: de-DE) + User->>Frontend: Select voice (default: de-DE-Wavenet-A) + Frontend->>Backend: WebSocket: /api/voice-google/ws/text-to-speech
?userId=user&language=de-DE&voice=de-DE-Wavenet-A + + Backend->>Backend: Accept WebSocket connection + Backend-->>Frontend: {type: "connected", connection_id, message} + Frontend-->>User: Show "Connected" status + + loop User sends text + User->>Frontend: Enter text to speak + User->>Frontend: Click "Speak" or send + Frontend->>Backend: {type: "text_to_speak", text: "..."} + + alt Processing error + Backend->>Backend: Log error + Backend-->>Frontend: {type: "error", error: "..."} + Frontend-->>User: Show error message + else Success + Backend->>Backend: Process text-to-speech + Backend-->>Frontend: {type: "audio_data", audio: base64_audio, format: "mp3"} + Frontend->>Frontend: Decode base64 audio + Frontend->>Frontend: Create audio blob + Frontend->>Frontend: Play audio or queue for playback + Frontend-->>User: Play generated speech audio + end + end + + alt User sends ping + User->>Frontend: Keep-alive ping + Frontend->>Backend: {type: "ping", timestamp} + Backend-->>Frontend: {type: "pong", timestamp} + end + + alt User disconnects + User->>Frontend: Close connection + Frontend->>Backend: Close WebSocket + Backend->>Backend: Cleanup connection + Frontend-->>User: Show disconnected status + end +``` + diff --git a/docs/frontend-documentation/voice-service-page-requirements.md b/docs/frontend-documentation/voice-service-page-requirements.md new file mode 100644 index 00000000..3135fb4b --- /dev/null +++ b/docs/frontend-documentation/voice-service-page-requirements.md @@ -0,0 +1,1081 @@ +# Voice Service Page Requirements + +This document contains the complete frontend requirements for the voice service page, enabling users to interact with Google Cloud voice services including Speech-to-Text, Translation, Text-to-Speech, and real-time voice interpretation. All UI components should use user settings as defaults but allow overrides. + +## Table of Contents + +1. [Overview](#overview) +2. [Page Structure and Layout](#page-structure-and-layout) +3. [User Interactions and Functionality](#user-interactions-and-functionality) +4. [Backend Routes and API Integration](#backend-routes-and-api-integration) +5. [Field and Attribute Reference](#field-and-attribute-reference) +6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines) + +--- + +## Overview + +The voice service page enables users to interact with Google Cloud voice services through a unified interface. The frontend consists of a single page (`/voice` or `/voice-service`) with different sections/tabs for each feature: + +- **Speech-to-Text Section** - Record speech and convert to text +- **Translation Section** - Translate text between languages +- **Voice Interpretation Section** - Record speech and get translated text +- **Text-to-Speech Section** - Convert text to spoken audio +- **Settings Section** - Configure default voice settings +- **Real-time WebSocket Features** - Live streaming for speech-to-text and text-to-speech + +All features use user settings as defaults (loaded from `/api/voice-google/settings`) but allow users to override settings per operation. The page supports both HTTP REST endpoints for file-based processing and WebSocket endpoints for real-time streaming. + +**Key Principles:** +- **Settings-Driven**: User preferences loaded and applied automatically +- **Multi-Modal**: Supports both recording and real-time streaming +- **Language-Aware**: All operations support multiple languages +- **User-Scoped**: Settings are user-specific and stored per user + +--- + +## Page Structure and Layout + +### Voice Service Page (`/voice` or `/voice-service`) + +The voice service page uses a tabbed or sectioned interface to organize different voice features. Each section is self-contained but shares common settings and reusable UI components. + +### Reusable UI Components + +The page is composed of reusable components that can be combined in different ways to create each feature section: + +#### Language Selector Component + +A dropdown selector for choosing languages, used across multiple sections: + +- **Properties:** + - Default value from user settings (configurable: `sttLanguage`, `ttsLanguage`, or custom) + - Supports language codes with region (e.g., "de-DE", "en-US") or without region (e.g., "de", "en") + - Options populated from `/api/voice-google/languages` (cached) + - Shows language code and display name + - Optional: Search/filter functionality + +- **Usage:** + - Voice Recording Section (Speech-to-Text mode): Single language selector (default: `sttLanguage`) + - Text Processing Section (Translation mode): Two language selectors (source and target, defaults vary) + - Voice Recording Section (Voice Interpretation mode): Two language selectors (source and target with region codes) + - Text Processing Section (Text-to-Speech mode): Single language selector (default: `ttsLanguage`) + - Settings Section: Multiple language selectors for different purposes + +#### Voice Selector Component + +A dropdown selector for choosing TTS voices, filtered by selected language: + +- **Properties:** + - Default value from user settings (`ttsVoice`) + - Options populated from `/api/voice-google/voices?language_code={selectedLanguage}` + - Automatically updates when language changes + - Shows voice name, language, and gender/type information + - Optional: Search/filter functionality + +- **Usage:** + - Text Processing Section (Text-to-Speech mode): Single voice selector + - Settings Section: Single voice selector (filtered by TTS language) + +#### Recording Controls Component + +Controls for starting and stopping audio recording: + +- **Properties:** + - "Start Recording" button (shown when not recording) + - "Stop Recording" button (shown when recording) + - Recording indicator (red dot, timer showing duration) + - Optional: Visual waveform or audio level indicator + - Handles microphone permission requests + +- **Usage:** + - Voice Recording Section (Speech-to-Text mode): Recording controls + language selector + - Voice Recording Section (Voice Interpretation mode): Recording controls + source/target language selectors + - Voice Recording Section (WebSocket mode): Recording controls + WebSocket connection controls + +#### Text Input Component + +Multi-line textarea for text input: + +- **Properties:** + - Multi-line textarea + - Optional: Character count + - Optional: Placeholder text + - Validation: Required or optional based on context + +- **Usage:** + - Text Processing Section (Translation mode): Text input + language selectors + - Text Processing Section (Text-to-Speech mode): Text input + language/voice selectors + - Text Processing Section (WebSocket mode): Text input + WebSocket controls + +#### Result Display Component + +Generic component for displaying operation results: + +- **Properties:** + - Text display area (read-only or editable) + - Optional: Multiple text areas (e.g., original and translated) + - Metadata display (confidence, language, audio info, etc.) + - Action buttons: Copy, Clear, Download (context-dependent) + - Optional: Additional actions (Swap, Regenerate, etc.) + +- **Variants:** + - **Text Result:** Displays transcribed or translated text with metadata + - **Dual Text Result:** Displays original and translated text side-by-side + - **Audio Result:** Displays audio player with download option and metadata + +- **Usage:** + - Voice Recording Section (Speech-to-Text mode): Text result with confidence, language, audio metadata + - Text Processing Section (Translation mode): Dual text result with language information + - Voice Recording Section (Voice Interpretation mode): Dual text result with confidence, languages, audio metadata + - Text Processing Section (Text-to-Speech mode): Audio result with voice name, language, download option + +#### Audio Player Component + +HTML5 audio player for playback: + +- **Properties:** + - HTML5 audio element with controls (play, pause, volume, progress) + - Download button + - Metadata display (voice name, language, format) + - Optional: Regenerate button + +- **Usage:** + - Text Processing Section (Text-to-Speech mode): Audio playback of generated speech + - Text Processing Section (WebSocket mode): Sequential playback of audio chunks + +#### WebSocket Connection Controls Component + +Controls for managing WebSocket connections: + +- **Properties:** + - "Connect" button (establishes WebSocket connection) + - "Disconnect" button (closes WebSocket connection) + - Connection status indicator (connected, disconnected, connecting, error) + - Connection ID display (optional) + +- **Usage:** + - Voice Recording Section (WebSocket mode): Connection controls + recording controls + live transcription + - Text Processing Section (WebSocket mode): Connection controls + text input + audio playback + +#### Live Transcription Display Component + +Real-time transcription display for WebSocket mode: + +- **Properties:** + - Updates in real-time as results arrive + - Distinguishes between interim results (grayed out, updating) and final results (confirmed, stable) + - Shows confidence scores (optional) + - Scrolls to latest content automatically + +- **Usage:** + - Voice Recording Section (WebSocket mode): Live transcription display + +#### Status Indicators Component + +Visual indicators for operation status: + +- **Properties:** + - Loading state (spinner, progress bar) + - Error messages (red text, error icon) + - Success messages (green text, success icon) + - Microphone permission status + - Recording status (idle, recording, processing) + - Connection status (for WebSocket mode) + +- **Usage:** + - All sections: Loading, error, and success states + - Recording sections: Microphone permission and recording status + - WebSocket sections: Connection status + +#### Settings Form Component + +Form for managing user voice settings: + +- **Properties:** + - Multiple language selectors (STT, TTS, target) + - Voice selector (filtered by TTS language) + - Translation enabled toggle/checkbox + - Conditional fields (target language shown when translation enabled) + - Action buttons: Save, Reset to Defaults, Browse Languages, Browse Voices + +- **Usage:** + - Settings Section: Complete settings form + +#### Language/Voice Browser Component + +Modal or sidebar for browsing available languages and voices: + +- **Properties:** + - List display with search/filter functionality + - Language browser: Shows language code and display name + - Voice browser: Shows voice name, language, gender/type, with optional language filter + - Select button to use selected item + - Can be opened from language/voice selectors or settings + +- **Usage:** + - Language Browser: Opened from language selectors or settings + - Voice Browser: Opened from voice selector or settings + +### Page Sections + +The page is organized into three main sections, each supporting multiple operation modes: + +#### Text Processing Section + +Supports operations that use text input: **Translation** and **Text-to-Speech**. + +**Mode Toggle:** +- User can switch between "Translation" and "Text-to-Speech" modes +- Mode selection determines which components and options are displayed + +**Translation Mode:** +- Text Input + Language Selectors (source/target) + Dual Text Result Display + Status Indicators +- Action button: "Translate" + +**Text-to-Speech Mode:** +- Text Input + Language Selector + Voice Selector + Audio Result Display + Status Indicators +- Action button: "Generate Speech" + +**WebSocket Real-time Mode (optional toggle):** +- For Text-to-Speech: WebSocket Connection Controls + Text Input + Audio Player + Status Indicators +- User can toggle between HTTP and WebSocket modes + +#### Voice Recording Section + +Supports operations that use audio recording: **Speech-to-Text** and **Voice Interpretation**. + +**Mode Toggle:** +- User can switch between "Speech-to-Text" and "Voice Interpretation" modes +- Mode selection determines which components and options are displayed + +**Speech-to-Text Mode:** +- Language Selector + Recording Controls + Text Result Display + Status Indicators + +**Voice Interpretation Mode:** +- Language Selectors (source/target) + Recording Controls + Dual Text Result Display + Status Indicators + +**WebSocket Real-time Mode (optional toggle):** +- For Speech-to-Text: WebSocket Connection Controls + Recording Controls + Live Transcription Display + Status Indicators +- User can toggle between HTTP and WebSocket modes + +#### Settings Section + +Standalone section for managing user voice settings: + +- Settings Form + Status Indicators +- Includes: Language selectors, voice selector, translation toggle, action buttons + +--- + +## User Interactions and Functionality + +### Loading User Settings + +**On Page Load:** +- Frontend calls `GET /api/voice-google/settings` +- If user settings exist, use them as defaults +- If no user settings, use default settings from response +- Pre-populate all language and voice selectors with settings +- Store settings in component state for quick access + +**Settings Structure:** +```json +{ + "success": true, + "data": { + "user_settings": { + "sttLanguage": "de-DE", + "ttsLanguage": "de-DE", + "ttsVoice": "de-DE-Wavenet-A", + "translationEnabled": true, + "targetLanguage": "en-US" + }, + "default_settings": { + "sttLanguage": "de-DE", + "ttsLanguage": "de-DE", + "ttsVoice": "de-DE-Wavenet-A", + "translationEnabled": true, + "targetLanguage": "en-US" + } + } +} +``` + +### Text Processing Section + +The Text Processing Section supports two modes: **Translation** and **Text-to-Speech**. Users can switch between modes using a mode toggle. The section also supports an optional WebSocket real-time mode toggle. + +#### Translation Mode (HTTP) + +**Workflow:** +1. User switches to Translation mode (if not already selected) +2. User enters text in input field +3. User selects source language (default from settings or "de") +4. User selects target language (default from `targetLanguage` or "en") +5. User clicks "Translate" button +6. Frontend validates text is not empty +7. If validation fails: + - Show error: "Please enter text to translate" +8. If validation passes: + - Show loading state + - Create FormData with text, sourceLanguage, targetLanguage + - Submit to `POST /api/voice-google/translate` + - Handle response: + - Success: Display original and translated text side-by-side + - Error: Show error message + +**Additional Features:** +- Swap languages button: Swaps source and target languages +- Copy buttons: Copy original or translated text to clipboard +- Clear button: Clear input and results + +**Form Validation:** +- Text input must not be empty +- Source and target languages must be different (optional validation) + +**Error Handling:** +- 401 Unauthorized → Show authentication error +- 400 Bad Request → Show error details (empty text, invalid languages, etc.) +- 500 Internal Server Error → Show generic error message + +#### Text-to-Speech Mode (HTTP) + +**Workflow:** +1. User switches to Text-to-Speech mode (if not already selected) +2. User enters text in input field +3. User selects language (default from `ttsLanguage` setting) +4. User selects voice (default from `ttsVoice` setting) + - Voice dropdown updates when language changes + - Frontend calls `GET /api/voice-google/voices?language_code={selectedLanguage}` + - Populate voice dropdown with available voices +5. User clicks "Generate Speech" button +6. Frontend validates text is not empty +7. If validation fails: + - Show error: "Please enter text to convert to speech" +8. If validation passes: + - Show loading state + - Create FormData with text, language, voice + - Submit to `POST /api/voice-google/text-to-speech` + - Handle response: + - Success: Create audio blob from response, display audio player, show download button + - Error: Show error message + +**Audio Playback:** +- Create HTML5 audio element from response blob +- Display audio controls (play, pause, volume, progress) +- Extract voice name and language from response headers (`X-Voice-Name`, `X-Language-Code`) +- Display voice information + +**Form Validation:** +- Text input must not be empty +- Language must be selected +- Voice must be selected + +**Error Handling:** +- 401 Unauthorized → Show authentication error +- 400 Bad Request → Show error details +- 500 Internal Server Error → Show generic error message + +#### Text-to-Speech Mode (WebSocket Real-time) + +**Connection Workflow:** +1. User switches to Text-to-Speech mode +2. User toggles to WebSocket real-time mode +3. User selects language and voice (defaults from settings) +4. User clicks "Connect" button +5. Frontend establishes WebSocket connection to `/api/voice-google/ws/text-to-speech?userId={userId}&language={language}&voice={voice}` +6. Backend sends connection confirmation +7. Frontend shows "Connected" status +8. User enters text and clicks "Speak" button +9. Frontend sends text via WebSocket: `{type: "text_to_speak", text: "..."}` +10. Backend processes text and sends audio: `{type: "audio_data", audio: base64_audio, format: "mp3"}` +11. Frontend decodes base64 audio, creates audio blob, plays audio +12. User can send multiple texts while connected +13. User clicks "Disconnect" to close WebSocket + +**Audio Playback:** +- Queue audio chunks for sequential playback +- Or play chunks immediately as received +- Show playback progress + +**Error Handling:** +- WebSocket connection errors → Show error message, allow retry +- Processing errors → Show error message from backend: `{type: "error", error: "..."}` + +### Voice Recording Section + +The Voice Recording Section supports two modes: **Speech-to-Text** and **Voice Interpretation**. Users can switch between modes using a mode toggle. The section also supports an optional WebSocket real-time mode toggle. + +#### Speech-to-Text Mode (HTTP) + +**Recording Workflow:** +1. User switches to Speech-to-Text mode (if not already selected) +2. User selects language (default from `sttLanguage` setting) +3. User clicks "Start Recording" +4. Frontend requests microphone access via `navigator.mediaDevices.getUserMedia()` +5. If permission denied: + - Show error message: "Microphone access denied. Please enable microphone permissions in your browser settings." + - Disable recording button +6. If permission granted: + - Start MediaRecorder API + - Show recording indicator (red dot, start timer) + - Capture audio stream +7. User speaks into microphone +8. User clicks "Stop Recording" +9. Frontend stops MediaRecorder +10. Convert audio stream to audio file (Blob) +11. Validate audio file (size, format) +12. If validation fails: + - Show error: "Invalid audio format or file too large" +13. If validation passes: + - Show loading state + - Create FormData with audio file and language + - Submit to `POST /api/voice-google/speech-to-text` + - Handle response: + - Success: Display transcribed text, confidence, language, metadata + - Error: Show error message + +**Form Validation:** +- Language must be selected +- Audio file must be valid format (WebM, WAV, MP3, etc.) +- Audio file size must be within limits + +**Error Handling:** +- 401 Unauthorized → Show authentication error, redirect to login +- 400 Bad Request → Show error details from response +- 500 Internal Server Error → Show generic error message + +#### Voice Interpretation Mode (HTTP) + +**Recording and Interpretation Workflow:** +1. User switches to Voice Interpretation mode (if not already selected) +2. User selects source language (default from `sttLanguage` setting) +3. User selects target language (default from `targetLanguage` setting) +4. User clicks "Start Recording" +5. Frontend requests microphone access +6. If permission granted: + - Start recording + - Show recording indicator +7. User speaks into microphone +8. User clicks "Stop Recording" +9. Frontend stops recording and converts to audio file +10. Validate audio file +11. If validation passes: + - Show loading state + - Create FormData with audioFile, fromLanguage, toLanguage + - Submit to `POST /api/voice-google/realtime-interpreter` + - Handle response: + - Success: Display original text and translated text + - Error: Show error message + +**Form Validation:** +- Source and target languages must be selected +- Audio file must be valid + +**Error Handling:** +- Same as Speech-to-Text errors + +#### Speech-to-Text Mode (WebSocket Real-time) + +**Connection Workflow:** +1. User switches to Speech-to-Text mode +2. User toggles to WebSocket real-time mode +3. User selects language (default from settings) +4. User clicks "Connect" button or switches to WebSocket mode +5. Frontend establishes WebSocket connection to `/api/voice-google/ws/speech-to-text?userId={userId}&language={language}` +6. Backend sends connection confirmation: `{type: "connected", connection_id, message}` +7. Frontend shows "Connected" status +8. User clicks "Start Recording" +9. Frontend requests microphone access +10. If permission granted: + - Start MediaRecorder + - Start capturing audio chunks + - Encode chunks to base64 + - Send chunks via WebSocket: `{type: "audio_chunk", data: base64_audio, timestamp}` +11. Backend processes chunks and sends results: + - `{type: "transcription_result", text, confidence, is_final}` +12. Frontend displays results: + - Interim results (is_final: false) → Grayed out, updating + - Final results (is_final: true) → Confirmed, stable +13. User clicks "Stop Recording" or "Disconnect" +14. Frontend stops recording and closes WebSocket + +**Keep-Alive:** +- Frontend sends ping messages periodically: `{type: "ping", timestamp}` +- Backend responds with: `{type: "pong", timestamp}` + +**Error Handling:** +- WebSocket connection errors → Show error message, allow retry +- Processing errors → Show error message from backend: `{type: "error", error: "..."}` + +### Settings Section + +**Viewing Settings:** +1. User navigates to Settings section +2. Frontend calls `GET /api/voice-google/settings` +3. Display current settings in form +4. If no user settings, show default settings + +**Updating Settings:** +1. User modifies settings in form: + - `sttLanguage` - Required + - `ttsLanguage` - Required + - `ttsVoice` - Required + - `translationEnabled` - Optional (default: true) + - `targetLanguage` - Optional (default: "en-US") +2. User clicks "Save Settings" button +3. Frontend validates required fields +4. If validation fails: + - Show error: "Please fill in all required fields" +5. If validation passes: + - Show loading state + - Build settings object + - Submit to `POST /api/voice-google/settings` with settings object + - Handle response: + - Success: Show success message, update UI, update defaults for other sections + - Error: Show error message + +**Voice Selection:** +- When user changes `ttsLanguage`, frontend should: + 1. Call `GET /api/voice-google/voices?language_code={newLanguage}` + 2. Update voice dropdown with filtered voices + 3. If current voice is not available in new language, select first available voice or clear selection + +**Form Validation:** +- `sttLanguage` is required +- `ttsLanguage` is required +- `ttsVoice` is required +- `targetLanguage` is required if `translationEnabled` is true + +**Error Handling:** +- 401 Unauthorized → Show authentication error +- 400 Bad Request → Show error details (missing required fields) +- 500 Internal Server Error → Show generic error message + +**Voice Selection:** +- When user changes `ttsLanguage`, frontend should: + 1. Call `GET /api/voice-google/voices?language_code={newLanguage}` + 2. Update voice dropdown with filtered voices + 3. If current voice is not available in new language, select first available voice or clear selection + +**Form Validation:** +- `sttLanguage` is required +- `ttsLanguage` is required +- `ttsVoice` is required +- `targetLanguage` is required if `translationEnabled` is true + +**Error Handling:** +- 401 Unauthorized → Show authentication error +- 400 Bad Request → Show error details (missing required fields) +- 500 Internal Server Error → Show generic error message + +### Discovering Available Languages and Voices + +This functionality is available from multiple locations (Settings section, language selectors, voice selectors) and opens a modal/sidebar browser. + +**Browsing Languages:** +1. User clicks "Load Available Languages" button (in Settings or language selector) +2. Frontend calls `GET /api/voice-google/languages` +3. Display languages in modal/sidebar +4. Show language code and display name +5. User can search/filter languages +6. User clicks "Select" to use language +7. Update language selector with selected language + +**Browsing Voices:** +1. User clicks "Load Available Voices" button (in Settings or voice selector) +2. User optionally selects language filter +3. Frontend calls `GET /api/voice-google/voices?language_code={selectedLanguage}` (if filter selected) + - Or `GET /api/voice-google/voices` (if no filter) +4. Display voices in modal/sidebar +5. Show voice name, language, gender/type +6. Group voices by language if no filter +7. User can search/filter voices +8. User clicks "Select" to use voice +9. Update voice selector with selected voice + +--- + +## Backend Routes and API Integration + +### Complete Route Reference + +All backend routes used by voice service page: + +| Route | Method | Purpose | When Used | Access Control | +|-------|--------|---------|-----------|----------------| +| `/api/voice-google/speech-to-text` | POST | Convert speech to text | User stops recording | Current user only | +| `/api/voice-google/translate` | POST | Translate text | User clicks "Translate" | Current user only | +| `/api/voice-google/realtime-interpreter` | POST | Speech to translated text | User stops recording in interpreter mode | Current user only | +| `/api/voice-google/text-to-speech` | POST | Convert text to speech | User clicks "Generate Speech" | Current user only | +| `/api/voice-google/languages` | GET | Get available languages | User browses languages | Current user only | +| `/api/voice-google/voices` | GET | Get available voices | User browses voices or changes language | Current user only | +| `/api/voice-google/settings` | GET | Get voice settings | Page load, settings view | Current user only | +| `/api/voice-google/settings` | POST | Save voice settings | User saves settings | Current user only | +| `/api/voice-google/health` | GET | Health check | Optional: on page load | Current user only | +| `/api/voice-google/ws/speech-to-text` | WebSocket | Real-time speech-to-text | User connects WebSocket | Current user only | +| `/api/voice-google/ws/text-to-speech` | WebSocket | Real-time text-to-speech | User connects WebSocket | Current user only | +| `/api/voice-google/ws/realtime-interpreter` | WebSocket | Real-time interpretation | User connects WebSocket (future) | Current user only | + +### API Request Patterns + +**Speech-to-Text Request:** +``` +POST /api/voice-google/speech-to-text +Content-Type: multipart/form-data +Body: { + audioFile: , + language: "de-DE" +} +``` +- `audioFile` is required (audio file from recording) +- `language` is required (language code like "de-DE", "en-US") +- Handle 400 (invalid format), 401 (unauthorized), 500 errors + +**Translation Request:** +``` +POST /api/voice-google/translate +Content-Type: multipart/form-data +Body: { + text: "Text to translate", + sourceLanguage: "de", + targetLanguage: "en" +} +``` +- `text` is required (non-empty string) +- `sourceLanguage` is required (language code like "de", "en") +- `targetLanguage` is required (language code like "de", "en") +- Handle 400 (empty text, invalid languages), 401, 500 errors + +**Real-time Interpreter Request:** +``` +POST /api/voice-google/realtime-interpreter +Content-Type: multipart/form-data +Body: { + audioFile: , + fromLanguage: "de-DE", + toLanguage: "en-US", + connectionId: "optional-connection-id" +} +``` +- `audioFile` is required +- `fromLanguage` is required (language code with region) +- `toLanguage` is required (language code with region) +- `connectionId` is optional +- Handle same errors as speech-to-text + +**Text-to-Speech Request:** +``` +POST /api/voice-google/text-to-speech +Content-Type: multipart/form-data +Body: { + text: "Text to speak", + language: "de-DE", + voice: "de-DE-Wavenet-A" +} +``` +- `text` is required (non-empty string) +- `language` is required (language code with region) +- `voice` is optional (voice name, defaults to system default) +- Response is audio file (audio/mpeg) with headers: + - `X-Voice-Name`: Voice name used + - `X-Language-Code`: Language code used +- Handle 400 (empty text), 401, 500 errors + +**Get Languages Request:** +``` +GET /api/voice-google/languages +``` +- Returns: `{success: true, languages: [...]}` +- Languages array contains language objects with code and name +- Handle 400, 401, 500 errors + +**Get Voices Request:** +``` +GET /api/voice-google/voices?language_code=de-DE +``` +- `language_code` query parameter is optional +- If provided, filters voices by language +- Returns: `{success: true, voices: [...], language_filter: "de-DE"}` +- Voices array contains voice objects with name, language, gender, etc. +- Handle 400, 401, 500 errors + +**Get Settings Request:** +``` +GET /api/voice-google/settings +``` +- Returns: `{success: true, data: {user_settings, default_settings}}` +- `user_settings` may be null if no settings exist +- `default_settings` always present +- Handle 401, 500 errors + +**Save Settings Request:** +``` +POST /api/voice-google/settings +Content-Type: application/json +Body: { + "sttLanguage": "de-DE", + "ttsLanguage": "de-DE", + "ttsVoice": "de-DE-Wavenet-A", + "translationEnabled": true, + "targetLanguage": "en-US" +} +``` +- Required fields: `sttLanguage`, `ttsLanguage`, `ttsVoice` +- Optional fields: `translationEnabled` (default: true), `targetLanguage` (default: "en-US") +- Returns: `{success: true, message: "...", data: settings}` +- Handle 400 (missing required fields), 401, 500 errors + +**WebSocket Connection:** +``` +WebSocket: /api/voice-google/ws/speech-to-text?userId={userId}&language={language} +WebSocket: /api/voice-google/ws/text-to-speech?userId={userId}&language={language}&voice={voice} +``` +- Query parameters: `userId`, `language`, `voice` (for TTS) +- Backend sends connection confirmation on connect +- Client sends messages: `{type: "audio_chunk", data: base64, timestamp}` or `{type: "text_to_speak", text: "..."}` +- Backend sends messages: `{type: "transcription_result", text, confidence, is_final}` or `{type: "audio_data", audio: base64, format: "mp3"}` +- Handle connection errors, processing errors + +### Response Handling + +**Speech-to-Text Response:** +```json +{ + "success": true, + "text": "Transcribed text here", + "confidence": 0.95, + "language": "de-DE", + "audio_info": { + "size": 12345, + "format": "webm", + "estimated_duration": 3.5 + } +} +``` + +**Translation Response:** +```json +{ + "success": true, + "original_text": "Original text", + "translated_text": "Translated text", + "source_language": "de", + "target_language": "en" +} +``` + +**Real-time Interpreter Response:** +```json +{ + "success": true, + "original_text": "Original transcribed text", + "translated_text": "Translated text", + "confidence": 0.95, + "source_language": "de-DE", + "target_language": "en-US", + "audio_info": { + "size": 12345, + "format": "webm", + "estimated_duration": 3.5 + } +} +``` + +**Text-to-Speech Response:** +- Binary audio file (audio/mpeg) +- Headers: + - `Content-Type: audio/mpeg` + - `Content-Disposition: attachment; filename=speech.mp3` + - `X-Voice-Name: de-DE-Wavenet-A` + - `X-Language-Code: de-DE` + +**Languages Response:** +```json +{ + "success": true, + "languages": [ + { + "code": "de-DE", + "name": "German (Germany)" + }, + ... + ] +} +``` + +**Voices Response:** +```json +{ + "success": true, + "voices": [ + { + "name": "de-DE-Wavenet-A", + "language": "de-DE", + "gender": "FEMALE", + "ssml_gender": "FEMALE" + }, + ... + ], + "language_filter": "de-DE" +} +``` + +**Settings Response:** +```json +{ + "success": true, + "data": { + "user_settings": { + "sttLanguage": "de-DE", + "ttsLanguage": "de-DE", + "ttsVoice": "de-DE-Wavenet-A", + "translationEnabled": true, + "targetLanguage": "en-US" + }, + "default_settings": { + "sttLanguage": "de-DE", + "ttsLanguage": "de-DE", + "ttsVoice": "de-DE-Wavenet-A", + "translationEnabled": true, + "targetLanguage": "en-US" + } + } +} +``` + +**Error Responses:** +- 400 Bad Request → Display validation errors from response `detail` field +- 401 Unauthorized → Show authentication error, redirect to login +- 500 Internal Server Error → Show generic error message + +--- + +## Field and Attribute Reference + +### Voice Settings Fields + +The following fields are used for voice settings. These are not provided by a backend attributes endpoint but are defined by the API contract: + +**Required Fields:** +- `sttLanguage` - Speech-to-Text language (text/select, editable, required, visible) + - Format: Language code with region (e.g., "de-DE", "en-US") + - Default: "de-DE" +- `ttsLanguage` - Text-to-Speech language (text/select, editable, required, visible) + - Format: Language code with region (e.g., "de-DE", "en-US") + - Default: "de-DE" +- `ttsVoice` - Text-to-Speech voice name (text/select, editable, required, visible) + - Format: Voice identifier (e.g., "de-DE-Wavenet-A") + - Default: "de-DE-Wavenet-A" + - Options populated from `/api/voice-google/voices?language_code={ttsLanguage}` + +**Optional Fields:** +- `translationEnabled` - Enable translation features (checkbox, editable, not required, visible) + - Type: boolean + - Default: true +- `targetLanguage` - Target language for translation (text/select, editable, not required, visible) + - Format: Language code with region (e.g., "en-US", "fr-FR") + - Default: "en-US" + - Shown when `translationEnabled` is true + +### Language and Voice Data Structures + +**Language Object:** +- `code` - Language code (e.g., "de-DE", "en-US") +- `name` - Display name (e.g., "German (Germany)", "English (United States)") + +**Voice Object:** +- `name` - Voice identifier (e.g., "de-DE-Wavenet-A") +- `language` - Language code (e.g., "de-DE") +- `gender` - Voice gender (e.g., "FEMALE", "MALE", "NEUTRAL") +- `ssml_gender` - SSML gender identifier +- Additional metadata may be available + +--- + +## Dynamic Rendering Guidelines + +### Settings-Driven Defaults + +All voice operations should use user settings as defaults: + +1. **On Page Load:** + - Call `GET /api/voice-google/settings` + - Store settings in component state + - Pre-populate all selectors with settings values + - Use `default_settings` if `user_settings` is null + +2. **Language Selectors:** + - Speech-to-Text: Default to `sttLanguage` from settings + - Text-to-Speech: Default to `ttsLanguage` from settings + - Translation Source: Default to language derived from `sttLanguage` (remove region code) + - Translation Target: Default to `targetLanguage` from settings + +3. **Voice Selector:** + - Default to `ttsVoice` from settings + - When language changes, fetch voices for new language + - If default voice not available in new language, select first available + +4. **After Settings Update:** + - Refresh settings from backend + - Update all selectors with new defaults + - Show success message + +### Audio Recording Implementation + +**MediaRecorder API:** +1. Request microphone access: `navigator.mediaDevices.getUserMedia({ audio: true })` +2. Create MediaRecorder with appropriate MIME type: + - Prefer WebM: `new MediaRecorder(stream, { mimeType: 'audio/webm' })` + - Fallback to browser default +3. Start recording: `mediaRecorder.start()` +4. Capture data chunks: `mediaRecorder.ondataavailable` +5. Stop recording: `mediaRecorder.stop()` +6. Convert chunks to Blob: `new Blob(chunks, { type: 'audio/webm' })` +7. Create File object for upload: `new File([blob], 'recording.webm', { type: 'audio/webm' })` + +**Recording Indicators:** +- Show visual indicator (red dot, pulsing animation) +- Display timer (MM:SS format) +- Show audio level/waveform (optional, using AudioContext API) + +**Error Handling:** +- Microphone permission denied → Show clear error message with instructions +- No microphone available → Disable recording, show message +- Recording errors → Show error, allow retry + +### Language and Voice Selection + +**Language Dropdowns:** +1. Optionally fetch languages from `/api/voice-google/languages` on page load +2. Cache languages in component state +3. Display languages with code and name +4. Allow search/filter +5. Use settings default as initial selection + +**Voice Dropdown:** +1. When TTS language changes: + - Call `GET /api/voice-google/voices?language_code={selectedLanguage}` + - Update dropdown with filtered voices + - Select default voice if available, otherwise first voice +2. Display voice name and gender/type +3. Allow search/filter +4. Show loading state while fetching voices + +### WebSocket Implementation + +**Connection Management:** +1. Create WebSocket connection with query parameters +2. Handle connection events: + - `onopen` → Show connected status + - `onmessage` → Process incoming messages + - `onerror` → Show error, allow retry + - `onclose` → Show disconnected status, cleanup +3. Send keep-alive pings periodically (every 30 seconds) +4. Handle reconnection on disconnect + +**Message Handling:** +1. Parse incoming JSON messages +2. Handle message types: + - `connected` → Update connection status + - `transcription_result` → Update transcription display (interim vs final) + - `audio_data` → Decode base64, create blob, play audio + - `error` → Show error message + - `pong` → Update last ping time +3. Send messages: + - `audio_chunk` → Encode audio to base64, include timestamp + - `text_to_speak` → Include text + - `ping` → Include timestamp + +**Audio Chunking (Speech-to-Text):** +1. Capture audio chunks from MediaRecorder +2. Encode chunks to base64 +3. Send chunks via WebSocket as they're captured +4. Buffer chunks if needed for reliable transmission + +**Audio Playback (Text-to-Speech):** +1. Receive base64 audio chunks +2. Decode base64 to binary +3. Create audio blob +4. Queue for sequential playback or play immediately +5. Use HTML5 Audio API for playback + +### Form Validation + + +**Voice Recording Section:** +- **Speech-to-Text Mode:** Language must be selected, audio file must exist and be valid format, audio file size must be within limits +- **Voice Interpretation Mode:** Source and target languages must be selected, audio file must be valid + +**Text Processing Section:** +- **Translation Mode:** Text must not be empty, source and target languages must be selected, source and target languages should be different (optional validation) +- **Text-to-Speech Mode:** Text must not be empty, language must be selected, voice must be selected + +**Settings Section:** +- `sttLanguage` is required +- `ttsLanguage` is required +- `ttsVoice` is required +- `targetLanguage` is required if `translationEnabled` is true + +### Error Display + +**Error Messages:** +- Display errors prominently (red text, error icon) +- Show specific error details from backend when available +- Provide actionable guidance (e.g., "Please enable microphone permissions") +- Allow retry for transient errors + +**Loading States:** +- Show loading spinner during API calls +- Disable form inputs during processing +- Show progress indicators for long operations + +### Audio Playback + +**HTML5 Audio Player:** +1. Create audio element: `