├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.jp.md
├── README.md
├── architecture.drawio
├── deployment
├── contact-surveys-amazon-connect.yaml
├── frontend
│ ├── asset-manifest.json
│ ├── config.js
│ ├── favicon.ico
│ ├── favicon.png
│ ├── index.html
│ ├── robots.txt
│ └── static
│ │ ├── css
│ │ ├── main.09784eec.css
│ │ └── main.09784eec.css.map
│ │ ├── js
│ │ ├── 787.91799eaa.chunk.js
│ │ ├── 787.91799eaa.chunk.js.map
│ │ ├── main.3336631e.js
│ │ ├── main.3336631e.js.LICENSE.txt
│ │ └── main.3336631e.js.map
│ │ └── media
│ │ └── ico_connect.c4b4b06e46441b63ec178326f8a9e34e.svg
└── uuid-layer.zip
├── docs
├── README.md
├── api
│ ├── README.md
│ └── openapi.yaml
├── architecture
│ ├── README.md
│ ├── component-diagram.md
│ └── data-flow.md
├── backend
│ ├── README.md
│ └── lambda-functions.md
├── deployment
│ ├── README.md
│ └── cloudformation-parameters.md
├── frontend
│ ├── README.md
│ └── components.md
├── infra.dot
├── infra.svg
└── user-guides
│ ├── README.md
│ ├── admin-guide.md
│ └── contact-center-manager-guide.md
├── examples
├── 1-Survey Example Disconnect
└── 2-Simple Survey Example
├── generate-react-cli.json
├── img
├── Architecture-ExperienceBuilder.png
├── Architecture.png
├── application-deploy-success.png
├── cf-stack-params.png
├── cloudformation-launch-stack.png
├── simple-survey-example-definition.png
├── simple-survey-example-disconnect-flow.png
├── simple-survey-example-flag.png
├── simple-survey-example-id.png
├── simple-survey-example-inbound-flow-1.png
├── simple-survey-example-inbound-flow-2.png
├── simple-survey-example-questions.png
├── simple-survey-example-results.png
└── simple-survey-example-task-description.png
├── lambdas
├── api
│ └── index.js
├── cognitoValidateUser
│ └── index.js
├── getSurveyConfig
│ └── index.js
├── processReviewFlags
│ └── index.js
├── surveyUtils
│ └── index.js
└── writeSurveyResults
│ └── index.js
├── package-lock.json
├── package.json
├── public
├── config.js
├── favicon.ico
├── favicon.png
├── index.html
└── robots.txt
├── src
├── .env.production
├── App.css
├── App.test.tsx
├── App.tsx
├── components
│ ├── Authentication
│ │ ├── Authentication.css
│ │ └── Authentication.tsx
│ ├── ChangePassword
│ │ ├── ChangePassword.css
│ │ └── ChangePassword.tsx
│ ├── ForgotPassword
│ │ └── ForgotPassword.tsx
│ ├── Home
│ │ └── Home.tsx
│ ├── Logout
│ │ ├── Logout.css
│ │ └── Logout.tsx
│ ├── Survey
│ │ └── Survey.tsx
│ └── SurveysList
│ │ └── SurveysList.tsx
├── ico_connect.svg
├── index.css
├── index.tsx
├── models
│ └── SurveyModel.tsx
├── react-app-env.d.ts
├── reportWebVitals.ts
└── setupTests.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /lambdas/*/*.zip
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.development
18 | .env.test.local
19 | .env.production.local
20 | cfn_nag_output.txt
21 | npm_audit_results.txt
22 | .vscode
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [0.1.0] - Pre-release
8 |
9 | Intial commit prior to public release.
10 |
11 | ## [1.0.0] - Initial release
12 |
13 | ## [1.0.1] - API Gateway logging fix
14 | Fix for issue with deployment when users try to deploy in an AWS account that has not been configured for API Gateway logging.
15 |
16 | ## [1.0.2] - Results filtering
17 | Fix for results not being filtered properly when choosing to filter by date.
18 |
19 | ## [1.1] - Added support for CHAT, auto-verify admin user, and update to Node 16
20 | Added support for surveys to accomodate the CHAT channel. In addition, the "admin" user created when the solution is deployed will now have their email address automatically verified allowing for a more robust password management workflow.
21 | All runtimes for Lambda functions have also been updated to Node 16, with plans to update to Node 20 soon.
22 |
23 | ## [1.2] - nodejs22.x upgrade
24 | All Lambdas now run with nodejs22.x runtime.
25 | Architecture diagram updated to reflect chat support.
26 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *main* branch.
27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 3. Ensure local tests pass.
35 | 4. Commit to your fork using clear commit messages.
36 | 5. Send us a pull request, answering any default questions in the pull request interface.
37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38 |
39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 |
43 | ## Finding contributions to work on
44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.
45 |
46 |
47 | ## Code of Conduct
48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
50 | opensource-codeofconduct@amazon.com with any additional questions or comments.
51 |
52 |
53 | ## Security issue notifications
54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
55 |
56 |
57 | ## Licensing
58 |
59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 |
--------------------------------------------------------------------------------
/README.jp.md:
--------------------------------------------------------------------------------
1 | # Amazon Connect での顧客アンケート収集
2 |
3 | 顧客へのアンケートは、コンタクトセンターが提供する顧客体験やサービスを微調整していくための診断ツールとして重要なものです。これは問い合わせ体験への評価だけでなく、体験後の顧客の購買意欲や動機や意向を組織が理解するのにも役立ちます。
4 |
5 | このプロジェクトは、ユーザーがアンケートを作成・管理し、Amazon Connect でそのアンケートを使用し、結果を可視化する、一貫したソリューションを提供することを目的としています。
6 | ソリューションのデプロイ後、ユーザーは安全なウェブアプリケーションにアクセスしてアンケートを定義したり、既存のアンケートを参照/編集したり、アンケートごとの集計結果を視覚化したりすることができます。
7 |
8 |
9 | ソリューションの構成:
10 | - 管理用ウェブアプリケーション
11 | - アンケートの設定を保存するデータストア
12 | - アンケートの結果を保存するデータストア
13 | - 動的に、最適なアンケートを再生するコンタクトフローモジュール
14 |
15 | このソリューションを活用すると、以下のようなシナリオでアンケートを実施することができます:
16 | - 顧客との会話の後のアンケート
17 | - アウトバウンド型のアンケート (startOutboundContactAPIと組み合わせる)
18 |
19 | これらのシナリオの実装方法の詳細については [使用例](#使用例) を確認してください。
20 |
21 | ## アーキテクチャ
22 |
23 | 
24 |
25 | このソリューションは、必要なリソースをデプロイし、以下のように動作します:
26 |
27 | 1. Amazon S3 に保存されたフロントエンドの静的コンテンツを Amazon CloudFront を通じて公開し、Amazon Cognito によってユーザー管理を行います。
28 | 2. 必要なフローモジュールが Amazon Connect インスタンスにデプロイされます。
29 | 3. 管理者はウェブアプリケーションを使用して、必要に応じてアンケートを定義します。
30 | 4. アンケートの設定は Amazon DynamoDB に保存されます。
31 | 5. 問い合わせに対してフローモジュールが実行され、提供するアンケートを識別するためのコンタクト属性が設定されます。
32 | 6. コンタクトフローモジュールは、その問い合わせ用のアンケートの設定を取得します。
33 | 7. その問い合わせでアンケートが実施され、顧客はアンケートに回答します。
34 | 8. 個々の問い合わせのアンケート結果は Amazon DynamoDB テーブルに保存され、必要に応じて Amazon Connect Task が生成されます。
35 |
36 | ## デプロイ
37 |
38 | このソリューションをデプロイするには、以下の権限が必要です:
39 | - S3 バケットの作成と管理
40 | - Amazon DynamoDB リソースの作成と管理
41 | - Amazon API Gateway リソースの作成と管理
42 | - Amazon CloudFront リソースの作成と管理
43 | - Amazon Cognito リソースの作成と管理
44 | - AWS Lambda リソースの作成と管理
45 | - Amazon Connect リソースの作成と管理
46 |
47 | 通常、このソリューションのデプロイは、AWS 環境にフルアクセスできるユーザーで行います。
48 |
49 | 1. 「Launch Stack」 ボタンをクリックして、ご希望のリージョンにソリューションをデプロイします。これは Amazon Connect インスタンスがデプロイされているリージョンと同一である必要があります。
50 |
51 | [](https://console.aws.amazon.com/cloudformation/home?#/stacks/new?stackName=Production&templateURL=https://aws-contact-center-blog.s3.us-west-2.amazonaws.com/amazon-connect-post-call-surveys/contact-surveys-amazon-connect.yaml)
52 |
53 | 2. 必要なパラメータ:
54 | - このソリューションの初期ユーザーの メールアドレス
55 | - このソリューションで使用する Amazon Connect インスタンスの ARN
56 | - このソリューションで使用する Amazon Connect インスタンスのエイリアス
57 | - このソリューションが生成するタスクの送信先になるフローの ID
58 |
59 | **補足:** もし、このソリューションが生成するタスクを処理するためのフローが決まっていない場合は、Amazon Connect インスタンスでデフォルトで使用できる *Sample inbound flow (first contact experience)* の IDを指定してください。
60 |
61 | 
62 |
63 | 3. スタックの作成 ボタンをクリックして処理を進めます。
64 |
65 | **補足:** スタックのデプロイが完了するまで約 5 分かかります。また、ユーザー名と一時パスワードが記載されたメールが届きます。
66 |
67 | 4. スタックがデプロイされたら、 **出力** タブを開いて **AdminUser** の値とこのアプリケーションの URL をメモします。
68 |
69 | 5. メモした URL に移動して、上で確認した *Username* でログインします。 *password* はメールで受け取った仮パスワードを入力します。
70 |
71 | **補足:** 初回ログイン時にパスワードの変更を求められます。
72 |
73 | 6. 以下の画面が表示されたら、ソリューションは正常にデプロイされています。
74 |
75 | 
76 |
77 | ## 使用例
78 |
79 | 以下の例は、このソリューションをどのように使用できるかを理解するのに役立ちます。例を見ていく前に、ソリューションのデプロイが完了していることを確認してください。
80 |
81 | ### シンプルな応対後のアンケート(post-contact survey)を行い、低評価の結果にはレビューのためのフラグを立てる
82 |
83 | この例では、顧客の回答が低い場合に Amazon Connect Task を通じてスーバーバイザーにアラートを送信する、簡単な post-contact survey の実装方法を学びます。
84 |
85 | 1. このソリューションによってデプロイされた Contact Surveys for Amazon Connect アプリケーションを使ってアンケートを作成します。
86 |
87 | 
88 |
89 | 1. アンケートに質問をいくつか追加します。
90 |
91 | 
92 |
93 | 3. どれか一つの質問で, **Additional settings** をクリックし、 **Flag for review** にチェックを入れて閾値を設定します。
94 |
95 | 
96 |
97 | この閾値を下回るスコアが入力されると、Amazon Connect のタスクが開始されます。このタスクは、ソリューションをデプロイしたときに指定したフローにルーティングされます。
98 |
99 | 4. Save をクリックします。一覧をリフレッシュし、新しく作成したアンケートの **Id** をメモします。
100 |
101 | 
102 |
103 | **補足:** 皆さんの環境で作成したアンケートの Id は、このスクリーンショットとは違うものになります。
104 |
105 | 5. 皆さんの Amazon Connect で新しいフローを作成し、[*Survey Example Disconnect* フロー](/examples/1-Survey%20Example%20Disconnect) をインポートします。フローを公開する前に、「**呼び出しモジュール**」ブロックで、皆さんのインスタンスに作成されている *Contact Survey* が指定されていることを確認します。
106 |
107 | **補足:** サンプルフローは "examples" フォルダー内にあります。
108 |
109 | 
110 |
111 | 6. ステップ 5 と同様に、[*Simple Survey Example* フロー](/examples/2-Simple%20Survey%20Example) をインポートします。いくつか設定変更する必要があるので、ここではまだ公開はしません。
112 |
113 | **補足:** サンプルフローは "examples" フォルダー内にあります。
114 |
115 | 7. 「*切断フローを設定する*」ブロックをクリックします。 このブロック内で、切断フローとしてステップ 5 でインポートした *Survey Example Disconnect* を設定します。
116 |
117 | 
118 |
119 | 8. 「**コンタクト属性の設定**」ブロックをクリックします。このブロックでは *surveyId* というコンタクト属性を設定します。*surveyId* の*値*欄に、ステップ 4 でメモした *Id* をペーストします。
120 |
121 | 
122 |
123 | **補足:** ある問い合わせにおいて再生されるアンケートは、*surveyId* コンタクト属性に基づいて決定されると言うことを理解することが重要です。ここでは、コンタクトフローでその値を明示的に設定することで、再生するアンケートを静的に定義しています。もちろん、IVR での選択、連絡先の転送先のキュー、その連絡先に一致するコンタクトレンズのカテゴリー、またはその他のコンタクト属性などに基づいて、この属性を動的に設定することもできます。
124 |
125 | 9. フローを保存して、公開します。
126 |
127 | **補足:** このフローで処理されたコンタクトは、*BasicQueue* にキューイングされます。別のキューでテストを実行したい場合は、**作業キューの設定** ブロックを適宜調整してください。
128 |
129 | 10. *Simple Survey Example* を、テストに使用する任意の DID 番号に紐づけます。
130 |
131 | 11. テスト用に選択した番号に電話をかけます。このアンケートは、顧客との対話の最後に実行するので、コールが発信されるキューに受付可のエージェントがいることを確認してください。
132 |
133 | 12. 顧客側が電話につながっている間に、エージェント側の通話を終了します。顧客はアンケートに誘導されます。
134 |
135 | 13. 顧客側は最初の質問を聞いたら、*2*(すなわち、ステップ3で定義された閾値より低いスコア)と答えます。2番目の質問に対しては、0から5の間の任意の数字を入力します。
136 |
137 | 14. 顧客が最初の質問に対して低いスコアをつけたので、スーパーバイザーがレビューするためのタスクが作成されます。このタスクは、ソリューションのデプロイ時に定義されたコンタクトフローによって処理されます。
138 |
139 | **補足:** ここでの例では、すべての Amazon Connect インスタンスで利用可能な *Sample inbound flow (first contact experience)* を使用することにしました。このフローは、タスクを *BasicQueue* に誘導します。実際のシナリオでは、ニーズに応じてこれらのタスクの配信ロジックを処理する特定のコンタクトフローを作成してください。
140 |
141 | 15. このタスクはスーパーバイザーによって受信され、そこには低評価の会話の詳細が含まれています。
142 |
143 | 
144 |
145 | 16. Contact Surveys for Amazon Connect アプリケーションを使用して、アンケートの集計結果を可視化することができます。アンケートを選択し、**Results**タブに移動するだけです。また、**Export** ボタンをクリックして、個々の結果をエクスポートすることもできます。
146 |
147 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Contact Surveys for Amazon Connect
2 |
3 | Surveys are important as a diagnostic tool to fine-tune the experience and service delivered. They not only assess perceptions of experiences, but also help an organization understand customer motivations and intentions following the experience.
4 |
5 | This project is aimed at delivering an end-to-end solution that will enable users to create and manage surveys, use these surveys with their Amazon Connect contact centre, and visualise their results.
6 | Once deployed, users can access a secure web application to define surveys, consult / edit existing surveys, and visualise aggregated results per survey.
7 |
8 | The solution is composed of:
9 | - a web application for management
10 | - a data-store to hold survey configuration
11 | - a data-store to hold results
12 | - a Contact Flow Module that will dynamically play the right survey for to a contact
13 |
14 | Thanks to the flexible nature of this solution, surveys can be played in these scenario:
15 | - reactively, after a contact (inbound voice, outbound voice, chat) with a customer
16 | - proactively, in combination with the startOutboundContact API
17 |
18 | To find more information about how to implement these scenario, see [Example usage](#example-usage)
19 |
20 | ## Architecture
21 |
22 | 
23 |
24 | The solution deploys the required resources and follow the pattern:
25 |
26 | 1. Amazon S3 stores and serves the frontend static content through Amazon Cloudfront and restricted by Amazon Cognito for user management
27 | 2. The required Contact Flow Module is deployed in the Amazon Connect instance
28 | 3. Administrators use the web application to define contact surveys according to their needs
29 | 4. The configuration of the surveys is stored in Amazon DynamoDB
30 | 5. When required, the Contact Flow Module is invoked for a contact, with a contact attribute set to identify the survey to be offered
31 | 6. The Contact Flow Module retrieves the configuration of the survey for the contact
32 | 7. The contact is offered the survey, and the survey is answered
33 | 8. Results are stored in an Amazon DynamoDB table for the individual contact and if required, an Amazon Connect Task is created
34 |
35 | ## Deployment
36 |
37 | To deploy this solution, you will need to have the following permissions in your AWS account:
38 | - Create and manage S3 buckets
39 | - Create and manage Amazon DynamoDB resources
40 | - Create and manage AWS API Gateway resources
41 | - Create and manage Amazon Cloudfront resources
42 | - Create and manage Amazon Cognito resources
43 | - Create and manage AWS Lambda resources
44 | - Create and manage Amazon Connect resources
45 | - Create and manage Lex bots
46 |
47 | Typically, this solution should be deployed by a user with full access to your AWS environment.
48 |
49 | 1. Click on the "Launch Stack" button to deploy the solution in your preferred region. This will be he same region that was used to deploy your Amazon Connect instance.
50 |
51 | [](https://console.aws.amazon.com/cloudformation/home?#/stacks/new?stackName=Production&templateURL=https://aws-contact-center-blog.s3.us-west-2.amazonaws.com/amazon-connect-post-call-surveys/contact-surveys-amazon-connect.yaml)
52 |
53 | 2. Provide the required parameters:
54 | - an email address for the initial user of the solution
55 | - the ARN of the Amazon Connect instance you want to use with this solution
56 | - the alias of the Amazon Connect instance you want to use with this solution
57 | - the ID of the Contact Flow to which task created by this solution will be sent to
58 |
59 | **Note:** If you are unsure about which Contact Flow to choose to process the tasks generated by the solution, use the ID of the *Sample inbound flow (first contact experience)* available by default in your Amazon Connect instance.
60 |
61 | 
62 |
63 | 3. Proceed with the stack creation steps.
64 |
65 | **Note:** It will take approximately 5 minutes for the stack to complete the deployment. You will receive an email containing a temporary password.
66 |
67 | 4. Once the stack is deployed, in the **Output** tab, note the value of the **AdminUser** and the URL of the application.
68 |
69 | 5. Navigate to the URL noted just above. Log in to the application with the *Username* collected in the output of the Cloudformation stack, and the *password* received during the deployment.
70 |
71 | **Note:** You will be required to change your password at first login.
72 |
73 | 6. If you see the following screen, the solution has been successfully deployed, and you are good to go.
74 |
75 | 
76 |
77 | ## Example usage
78 |
79 | The following examples will help you understand how you can use this solution to cater for typical use cases. Make sure you have deployed the solution before going through each of the examples.
80 |
81 | ### Simple post-contact survey, with low-score flagged for review
82 |
83 | In this example, you will learn to implement a simple post-contact survey that will alert a supervisor through an Amazon Connect Task every time a customer replies to a given question with a low score.
84 |
85 | 1. Create a new survey using the Contact Surveys for Amazon Connect application deployed with the solution:
86 |
87 | 
88 |
89 | 2. Add a couple of questions to your survey:
90 |
91 | 
92 |
93 | 3. For one of these questions, select **Additional settings**, tick the **Flag for review**, and define the threshold:
94 |
95 | 
96 |
97 | Any contact that inputs a score lower than the defined threshold to that question will trigger a task in Amazon Connect. This task will be routed through the Contact Flow defined when the solution was deployed.
98 |
99 | 4. Save, refresh the list, and note the **Id** of your new survey.
100 |
101 | 
102 |
103 | **Note:** the ID of your survey will be different from the one on the screenshot.
104 |
105 | 5. In you Amazon Connect instance, create a new Contact Flow and import the [*Survey Example Disconnect* flow](/examples/1-Survey%20Example%20Disconnect). Before publishing, make sure that the **Invoke module** block is pointing to the *Contact Survey* module available in your Amazon Connect instance.
106 |
107 | **Note:** the contact flow can be found in the "examples" folder
108 |
109 | 
110 |
111 | 6. Repeat step 5 to import the [*Simple Survey Example* flow](/examples/2-Simple%20Survey%20Example). Don't publish it just yet, you will need to make some configuration adjustments.
112 |
113 | **Note:** the contact flow can be found in the "examples" folder
114 |
115 | 7. Locate the *Set Disconnect Flow* block. Configure this block to set the disconnect flow to the *Survey Example Disconnect* flow imported at step 5.
116 |
117 | 
118 |
119 | 8. Locate the **Set Contact Attributes** block. This block sets a single *surveyId* contact attribute. Paste the *id* of your survey (noted at step 4) in the *Value* field of the *surveyId* contact attribute.
120 |
121 | 
122 |
123 | **Note:** It is important to understand that the survey that will be played to a contact is based on the value of the *surveyId* contact attribute. Here, we are defining the survey to play for a contact in a static fashion by explicitly setting its value in the contact flow. You could of course set this attribute dynamically based on, for example, choices made in an IVR, the queue the contact was transferred to, Contact Lens categories matched for that contact, or any other contact attributes.
124 |
125 | 9. Save and publish the flow.
126 |
127 | **Note:** contacts processed by this flow will be queued on the *BasicQueue* which is available in your Amazon Connect instance. If you want to execute the test with a different queue, adjust the **Set working queue** block accordingly.
128 |
129 | 10. Associate the *Simple Survey Example* contact flow to any DID available to you for testing.
130 |
131 | 11. Place a call to the number you have selected for testing. Since we are intending to run this survey at the end of the customer interaction, make sure you have an agent available on the queue where the call is going to be directed.
132 |
133 | 12. While the customer stays on the line, end the call for the agent's end. The customer will be directed to the survey.
134 |
135 | 13. The customer hears the first question, and answer *2* (i.e. a score lower than the threshold defined at step 3). For the second question, the customer enters any digit between 0 and 5.
136 |
137 | 14. Since the customer has given a low score to our first question, a task is created for a supervisor to review. This task is processed by the Contact Flow defined during the deployment of the solution.
138 |
139 | **Note:** for the purpose of this example, we have decided to use the *Sample inbound flow (first contact experience)* that is available to all Amazon Connect instances. This flow will direct the task to the *BasicQueue*. In a real world scenario, create a specific contact flow to handle the distribution logic of these tasks according to your needs.
140 |
141 | 15. The task is received by a supervisor and contains the details of the interaction that was poorly rated.
142 |
143 | 
144 |
145 | 16. You can visualise the aggregated results for your survey using the Contact Surveys for Amazon Connect application. Simply select the survey, and navigate to the **Results** tab. You can also export the individual results by clicking on the **Export** button.
146 |
147 | 
148 |
--------------------------------------------------------------------------------
/deployment/frontend/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "/static/css/main.09784eec.css",
4 | "main.js": "/static/js/main.3336631e.js",
5 | "static/js/787.91799eaa.chunk.js": "/static/js/787.91799eaa.chunk.js",
6 | "static/media/ico_connect.svg": "/static/media/ico_connect.c4b4b06e46441b63ec178326f8a9e34e.svg",
7 | "index.html": "/index.html",
8 | "main.09784eec.css.map": "/static/css/main.09784eec.css.map",
9 | "main.3336631e.js.map": "/static/js/main.3336631e.js.map",
10 | "787.91799eaa.chunk.js.map": "/static/js/787.91799eaa.chunk.js.map"
11 | },
12 | "entrypoints": [
13 | "static/css/main.09784eec.css",
14 | "static/js/main.3336631e.js"
15 | ]
16 | }
--------------------------------------------------------------------------------
/deployment/frontend/config.js:
--------------------------------------------------------------------------------
1 | // this file will be overwritten when the CFT stack is deployed
2 |
3 | window.app_configuration = {
4 | cognito_pool_id: "",
5 | cognito_client_id: "",
6 | api_endpoint: "",
7 | };
8 |
9 |
--------------------------------------------------------------------------------
/deployment/frontend/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/amazon-connect-contact-surveys/d50af0afb6216e989aded5431a62fe3e223a13f4/deployment/frontend/favicon.ico
--------------------------------------------------------------------------------
/deployment/frontend/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/amazon-connect-contact-surveys/d50af0afb6216e989aded5431a62fe3e223a13f4/deployment/frontend/favicon.png
--------------------------------------------------------------------------------
/deployment/frontend/index.html:
--------------------------------------------------------------------------------
1 |
Contact Surveys for Amazon Connect
--------------------------------------------------------------------------------
/deployment/frontend/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/deployment/frontend/static/js/787.91799eaa.chunk.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkamazon_connect_surveys_react=self.webpackChunkamazon_connect_surveys_react||[]).push([[787],{787:function(e,n,t){t.r(n),t.d(n,{getCLS:function(){return y},getFCP:function(){return g},getFID:function(){return C},getLCP:function(){return P},getTTFB:function(){return D}});var i,r,a,o,u=function(e,n){return{name:e,value:void 0===n?-1:n,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,n){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var t=new PerformanceObserver((function(e){return e.getEntries().map(n)}));return t.observe({type:e,buffered:!0}),t}}catch(e){}},f=function(e,n){var t=function t(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),n&&(removeEventListener("visibilitychange",t,!0),removeEventListener("pagehide",t,!0)))};addEventListener("visibilitychange",t,!0),addEventListener("pagehide",t,!0)},s=function(e){addEventListener("pageshow",(function(n){n.persisted&&e(n)}),!0)},m=function(e,n,t){var i;return function(r){n.value>=0&&(r||t)&&(n.delta=n.value-(i||0),(n.delta||void 0===i)&&(i=n.value,e(n)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var n=e.timeStamp;v=n}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,n){var t,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime-1&&e(n)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var n=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-n.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,t())}},p=c("layout-shift",v);p&&(t=m(i,r,n),f((function(){p.takeRecords().map(v),t(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),t=m(i,r,n)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,n){i||(i=n,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,n){var t=function(){L(e,n),r()},i=function(){r()},r=function(){removeEventListener("pointerup",t,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",t,E),addEventListener("pointercancel",i,E)}(n,e):L(n,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(n){return e(n,b,E)}))},C=function(e,n){var t,a=l(),v=u("FID"),p=function(e){e.startTimeperformance.now())return;t.entries=[n],e(t)}catch(e){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("load",(function(){return setTimeout(n,0)}))}}}]);
2 | //# sourceMappingURL=787.91799eaa.chunk.js.map
--------------------------------------------------------------------------------
/deployment/frontend/static/js/787.91799eaa.chunk.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"static/js/787.91799eaa.chunk.js","mappings":"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","sources":["../node_modules/web-vitals/dist/web-vitals.js"],"sourcesContent":["var e,t,n,i,r=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:\"v2-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12)}},a=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if(\"first-input\"===e&&!(\"PerformanceEventTiming\"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},o=function(e,t){var n=function n(i){\"pagehide\"!==i.type&&\"hidden\"!==document.visibilityState||(e(i),t&&(removeEventListener(\"visibilitychange\",n,!0),removeEventListener(\"pagehide\",n,!0)))};addEventListener(\"visibilitychange\",n,!0),addEventListener(\"pagehide\",n,!0)},u=function(e){addEventListener(\"pageshow\",(function(t){t.persisted&&e(t)}),!0)},c=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},f=-1,s=function(){return\"hidden\"===document.visibilityState?0:1/0},m=function(){o((function(e){var t=e.timeStamp;f=t}),!0)},v=function(){return f<0&&(f=s(),m(),u((function(){setTimeout((function(){f=s(),m()}),0)}))),{get firstHiddenTime(){return f}}},d=function(e,t){var n,i=v(),o=r(\"FCP\"),f=function(e){\"first-contentful-paint\"===e.name&&(m&&m.disconnect(),e.startTime-1&&e(t)},f=r(\"CLS\",0),s=0,m=[],v=function(e){if(!e.hadRecentInput){var t=m[0],i=m[m.length-1];s&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(s+=e.value,m.push(e)):(s=e.value,m=[e]),s>f.value&&(f.value=s,f.entries=m,n())}},h=a(\"layout-shift\",v);h&&(n=c(i,f,t),o((function(){h.takeRecords().map(v),n(!0)})),u((function(){s=0,l=-1,f=r(\"CLS\",0),n=c(i,f,t)})))},T={passive:!0,capture:!0},y=new Date,g=function(i,r){e||(e=r,t=i,n=new Date,w(removeEventListener),E())},E=function(){if(t>=0&&t1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,t){var n=function(){g(e,t),r()},i=function(){r()},r=function(){removeEventListener(\"pointerup\",n,T),removeEventListener(\"pointercancel\",i,T)};addEventListener(\"pointerup\",n,T),addEventListener(\"pointercancel\",i,T)}(t,e):g(t,e)}},w=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(t){return e(t,S,T)}))},L=function(n,f){var s,m=v(),d=r(\"FID\"),p=function(e){e.startTimeperformance.now())return;n.entries=[t],e(n)}catch(e){}},\"complete\"===document.readyState?setTimeout(t,0):addEventListener(\"load\",(function(){return setTimeout(t,0)}))};export{h as getCLS,d as getFCP,L as getFID,F as getLCP,P as getTTFB};\n"],"names":["e","t","n","i","r","name","value","delta","entries","id","concat","Date","now","Math","floor","random","a","PerformanceObserver","supportedEntryTypes","includes","self","getEntries","map","observe","type","buffered","o","document","visibilityState","removeEventListener","addEventListener","u","persisted","c","f","s","m","timeStamp","v","setTimeout","firstHiddenTime","d","disconnect","startTime","push","window","performance","getEntriesByName","requestAnimationFrame","p","l","h","hadRecentInput","length","takeRecords","T","passive","capture","y","g","w","E","entryType","target","cancelable","processingStart","forEach","S","L","b","F","once","P","getEntriesByType","timing","max","navigationStart","responseStart","readyState"],"sourceRoot":""}
--------------------------------------------------------------------------------
/deployment/frontend/static/js/main.3336631e.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*!
7 | * JavaScript Cookie v2.2.1
8 | * https://github.com/js-cookie/js-cookie
9 | *
10 | * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
11 | * Released under the MIT license
12 | */
13 |
14 | /*!
15 | * The buffer module from node.js, for the browser.
16 | *
17 | * @author Feross Aboukhadijeh
18 | * @license MIT
19 | */
20 |
21 | /*!
22 | * cookie
23 | * Copyright(c) 2012-2014 Roman Shtylman
24 | * Copyright(c) 2015 Douglas Christopher Wilson
25 | * MIT Licensed
26 | */
27 |
28 | /*! *****************************************************************************
29 | Copyright (c) Microsoft Corporation.
30 |
31 | Permission to use, copy, modify, and/or distribute this software for any
32 | purpose with or without fee is hereby granted.
33 |
34 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
35 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
37 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
38 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
39 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
40 | PERFORMANCE OF THIS SOFTWARE.
41 | ***************************************************************************** */
42 |
43 | /*! https://mths.be/punycode v1.3.2 by @mathias */
44 |
45 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */
46 |
47 | /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
48 |
49 | /**
50 | * @license React
51 | * react-dom.production.min.js
52 | *
53 | * Copyright (c) Facebook, Inc. and its affiliates.
54 | *
55 | * This source code is licensed under the MIT license found in the
56 | * LICENSE file in the root directory of this source tree.
57 | */
58 |
59 | /**
60 | * @license React
61 | * react-jsx-runtime.production.min.js
62 | *
63 | * Copyright (c) Facebook, Inc. and its affiliates.
64 | *
65 | * This source code is licensed under the MIT license found in the
66 | * LICENSE file in the root directory of this source tree.
67 | */
68 |
69 | /**
70 | * @license React
71 | * react.production.min.js
72 | *
73 | * Copyright (c) Facebook, Inc. and its affiliates.
74 | *
75 | * This source code is licensed under the MIT license found in the
76 | * LICENSE file in the root directory of this source tree.
77 | */
78 |
79 | /**
80 | * @license React
81 | * scheduler.production.min.js
82 | *
83 | * Copyright (c) Facebook, Inc. and its affiliates.
84 | *
85 | * This source code is licensed under the MIT license found in the
86 | * LICENSE file in the root directory of this source tree.
87 | */
88 |
89 | /**
90 | * @remix-run/router v1.0.2
91 | *
92 | * Copyright (c) Remix Software Inc.
93 | *
94 | * This source code is licensed under the MIT license found in the
95 | * LICENSE.md file in the root directory of this source tree.
96 | *
97 | * @license MIT
98 | */
99 |
100 | /**
101 | * React Router v6.4.2
102 | *
103 | * Copyright (c) Remix Software Inc.
104 | *
105 | * This source code is licensed under the MIT license found in the
106 | * LICENSE.md file in the root directory of this source tree.
107 | *
108 | * @license MIT
109 | */
110 |
111 | /** @license React v16.13.1
112 | * react-is.production.min.js
113 | *
114 | * Copyright (c) Facebook, Inc. and its affiliates.
115 | *
116 | * This source code is licensed under the MIT license found in the
117 | * LICENSE file in the root directory of this source tree.
118 | */
119 |
--------------------------------------------------------------------------------
/deployment/frontend/static/media/ico_connect.c4b4b06e46441b63ec178326f8a9e34e.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/deployment/uuid-layer.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/amazon-connect-contact-surveys/d50af0afb6216e989aded5431a62fe3e223a13f4/deployment/uuid-layer.zip
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Amazon Connect Post-Contact Survey Solution Documentation
2 |
3 | Welcome to the comprehensive documentation for the Amazon Connect Post-Contact Survey Solution. This documentation provides detailed information about the architecture, components, and usage of the solution.
4 |
5 | ## Documentation Structure
6 |
7 | - **[Architecture](./architecture/README.md)**: System design, component relationships, and data flows
8 | - **[Frontend](./frontend/README.md)**: React application structure, components, and state management
9 | - **[Backend](./backend/README.md)**: Lambda functions, DynamoDB tables, and AWS service integrations
10 | - **[API](./api/README.md)**: API specifications, endpoints, and usage examples
11 | - **[Deployment](./deployment/README.md)**: Deployment guides, prerequisites, and configuration
12 | - **[User Guides](./user-guides/README.md)**: End-user and administrator guides
13 |
14 | ## Solution Overview
15 |
16 | The Amazon Connect Post-Contact Survey Solution enables organizations to gather customer feedback through automated surveys after contact center interactions. The solution supports custom survey configurations and automated task creation based on response thresholds.
17 |
18 | ### Key Features
19 |
20 | - **Customizable Surveys**: Create and manage surveys with configurable questions and rating scales
21 | - **Multi-Channel Support**: Collect feedback via voice (DTMF) and chat interactions
22 | - **Automated Task Creation**: Generate tasks for agents when survey responses meet specific criteria
23 | - **Secure Authentication**: Admin interface protected by Amazon Cognito
24 | - **Comprehensive Reporting**: View and analyze survey results through the admin interface
25 |
26 | ### Technology Stack
27 |
28 | - **Frontend**: React.js
29 | - **Backend**: AWS Lambda (Node.js)
30 | - **Database**: Amazon DynamoDB
31 | - **Authentication**: Amazon Cognito
32 | - **Contact Center**: Amazon Connect
33 | - **API**: Amazon API Gateway
34 | - **Content Delivery**: Amazon CloudFront
35 | - **Storage**: Amazon S3
36 |
37 | For a quick start guide, see the [Deployment Guide](./deployment/README.md).
38 |
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | # API Documentation
2 |
3 | The Amazon Connect Post-Contact Survey Solution provides a RESTful API for managing surveys and retrieving results. This document provides detailed information about the API endpoints, request/response formats, and authentication requirements.
4 |
5 | ## API Overview
6 |
7 | The API is built using Amazon API Gateway and AWS Lambda. It provides the following endpoints:
8 |
9 | - `/surveys`: Manages survey configurations
10 | - `/results`: Retrieves survey results
11 |
12 | ## Authentication
13 |
14 | All API endpoints require authentication using Amazon Cognito. The API uses the `COGNITO_USER_POOLS` authorization type with a Cognito User Pool Authorizer.
15 |
16 | ### Authentication Headers
17 |
18 | ```
19 | Authorization: Bearer
20 | ```
21 |
22 | ### Obtaining a JWT Token
23 |
24 | 1. Authenticate with Amazon Cognito using the user credentials
25 | 2. Receive a JWT token in the response
26 | 3. Include the token in the `Authorization` header of API requests
27 |
28 | ## API Endpoints
29 |
30 | ### Survey Management
31 |
32 | #### List Surveys
33 |
34 | Retrieves all available surveys.
35 |
36 | **Request:**
37 | - **Method:** POST
38 | - **Endpoint:** `/surveys`
39 | - **Headers:**
40 | - `Content-Type: application/json`
41 | - `Authorization: Bearer `
42 | - **Body:**
43 | ```json
44 | {
45 | "operation": "list"
46 | }
47 | ```
48 |
49 | **Response:**
50 | - **Status Code:** 200 OK
51 | - **Body:**
52 | ```json
53 | {
54 | "success": true,
55 | "data": [
56 | {
57 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
58 | "surveyName": "Customer Satisfaction",
59 | "min": 1,
60 | "max": 5,
61 | "introPrompt": "Please rate your experience",
62 | "outroPrompt": "Thank you for your feedback",
63 | "question_1": "How satisfied were you with our service?",
64 | "question_2": "How likely are you to recommend us?",
65 | "flag_question_1": 3,
66 | "flag_question_2": 3
67 | }
68 | ]
69 | }
70 | ```
71 |
72 | #### Create Survey
73 |
74 | Creates a new survey.
75 |
76 | **Request:**
77 | - **Method:** POST
78 | - **Endpoint:** `/surveys`
79 | - **Headers:**
80 | - `Content-Type: application/json`
81 | - `Authorization: Bearer `
82 | - **Body:**
83 | ```json
84 | {
85 | "operation": "create",
86 | "data": {
87 | "surveyName": "Customer Satisfaction",
88 | "min": 1,
89 | "max": 5,
90 | "introPrompt": "Please rate your experience",
91 | "outroPrompt": "Thank you for your feedback",
92 | "questions": [
93 | "How satisfied were you with our service?",
94 | "How likely are you to recommend us?"
95 | ],
96 | "flags": [3, 3]
97 | }
98 | }
99 | ```
100 |
101 | **Response:**
102 | - **Status Code:** 200 OK
103 | - **Body:**
104 | ```json
105 | {
106 | "success": true,
107 | "data": "550e8400-e29b-41d4-a716-446655440000"
108 | }
109 | ```
110 |
111 | #### Update Survey
112 |
113 | Updates an existing survey.
114 |
115 | **Request:**
116 | - **Method:** POST
117 | - **Endpoint:** `/surveys`
118 | - **Headers:**
119 | - `Content-Type: application/json`
120 | - `Authorization: Bearer `
121 | - **Body:**
122 | ```json
123 | {
124 | "operation": "create",
125 | "data": {
126 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
127 | "surveyName": "Customer Satisfaction",
128 | "min": 1,
129 | "max": 5,
130 | "introPrompt": "Please rate your experience",
131 | "outroPrompt": "Thank you for your feedback",
132 | "questions": [
133 | "How satisfied were you with our service?",
134 | "How likely are you to recommend us?",
135 | "How would you rate our response time?"
136 | ],
137 | "flags": [3, 3, 3]
138 | }
139 | }
140 | ```
141 |
142 | **Response:**
143 | - **Status Code:** 200 OK
144 | - **Body:**
145 | ```json
146 | {
147 | "success": true,
148 | "data": "550e8400-e29b-41d4-a716-446655440000"
149 | }
150 | ```
151 |
152 | #### Delete Survey
153 |
154 | Deletes an existing survey.
155 |
156 | **Request:**
157 | - **Method:** POST
158 | - **Endpoint:** `/surveys`
159 | - **Headers:**
160 | - `Content-Type: application/json`
161 | - `Authorization: Bearer `
162 | - **Body:**
163 | ```json
164 | {
165 | "operation": "delete",
166 | "data": {
167 | "surveyId": "550e8400-e29b-41d4-a716-446655440000"
168 | }
169 | }
170 | ```
171 |
172 | **Response:**
173 | - **Status Code:** 200 OK
174 | - **Body:**
175 | ```json
176 | {
177 | "success": true
178 | }
179 | ```
180 |
181 | ### Survey Results
182 |
183 | #### Get Survey Results
184 |
185 | Retrieves results for a specific survey.
186 |
187 | **Request:**
188 | - **Method:** POST
189 | - **Endpoint:** `/results`
190 | - **Headers:**
191 | - `Content-Type: application/json`
192 | - `Authorization: Bearer `
193 | - **Body:**
194 | ```json
195 | {
196 | "operation": "results",
197 | "data": {
198 | "surveyId": "550e8400-e29b-41d4-a716-446655440000"
199 | }
200 | }
201 | ```
202 |
203 | **Response:**
204 | - **Status Code:** 200 OK
205 | - **Body:**
206 | ```json
207 | {
208 | "success": true,
209 | "data": [
210 | {
211 | "contactId": "12345678-1234-1234-1234-123456789012",
212 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
213 | "survey_result_1": "4",
214 | "survey_result_2": "5",
215 | "timestamp": 1647532800
216 | },
217 | {
218 | "contactId": "87654321-4321-4321-4321-210987654321",
219 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
220 | "survey_result_1": "3",
221 | "survey_result_2": "4",
222 | "timestamp": 1647533800
223 | }
224 | ]
225 | }
226 | ```
227 |
228 | ## Error Handling
229 |
230 | ### Authentication Errors
231 |
232 | - **Status Code:** 401 Unauthorized
233 | - **Body:**
234 | ```json
235 | {
236 | "message": "Unauthorized"
237 | }
238 | ```
239 |
240 | ### Validation Errors
241 |
242 | - **Status Code:** 400 Bad Request
243 | - **Body:**
244 | ```json
245 | {
246 | "success": false,
247 | "message": "Unsupported operation"
248 | }
249 | ```
250 |
251 | ### Server Errors
252 |
253 | - **Status Code:** 500 Internal Server Error
254 | - **Body:**
255 | ```json
256 | {
257 | "success": false,
258 | "message": "Something went terribly wrong."
259 | }
260 | ```
261 |
262 | ## API Gateway Configuration
263 |
264 | The API Gateway is configured with the following settings:
265 |
266 | - **Stage:** `dev`
267 | - **Logging Level:** `ERROR`
268 | - **CORS:** Enabled
269 | - **Authorization:** Cognito User Pools
270 | - **Integration Type:** Lambda Proxy
271 |
272 | ## Example API Usage
273 |
274 | ### Using cURL
275 |
276 | ```bash
277 | # Get JWT token
278 | TOKEN=$(curl -X POST \
279 | -H "Content-Type: application/json" \
280 | -d '{"AuthParameters":{"USERNAME":"admin","PASSWORD":"password"},"AuthFlow":"USER_PASSWORD_AUTH","ClientId":"your-client-id"}' \
281 | https://cognito-idp.us-west-2.amazonaws.com/ | jq -r '.AuthenticationResult.IdToken')
282 |
283 | # List surveys
284 | curl -X POST \
285 | -H "Content-Type: application/json" \
286 | -H "Authorization: Bearer $TOKEN" \
287 | -d '{"operation":"list"}' \
288 | https://your-api-gateway-id.execute-api.us-west-2.amazonaws.com/dev/surveys
289 | ```
290 |
291 | ### Using JavaScript
292 |
293 | ```javascript
294 | // Get JWT token
295 | const getToken = async () => {
296 | const response = await fetch('https://your-cognito-domain.auth.us-west-2.amazoncognito.com/oauth2/token', {
297 | method: 'POST',
298 | headers: {
299 | 'Content-Type': 'application/x-www-form-urlencoded'
300 | },
301 | body: new URLSearchParams({
302 | grant_type: 'password',
303 | client_id: 'your-client-id',
304 | username: 'admin',
305 | password: 'password'
306 | })
307 | });
308 | const data = await response.json();
309 | return data.id_token;
310 | };
311 |
312 | // List surveys
313 | const listSurveys = async (token) => {
314 | const response = await fetch('https://your-api-gateway-id.execute-api.us-west-2.amazonaws.com/dev/surveys', {
315 | method: 'POST',
316 | headers: {
317 | 'Content-Type': 'application/json',
318 | 'Authorization': `Bearer ${token}`
319 | },
320 | body: JSON.stringify({
321 | operation: 'list'
322 | })
323 | });
324 | return await response.json();
325 | };
326 |
327 | // Usage
328 | (async () => {
329 | const token = await getToken();
330 | const surveys = await listSurveys(token);
331 | console.log(surveys);
332 | })();
333 | ```
334 |
335 | ## API Limitations
336 |
337 | - Maximum request size: 10 MB
338 | - Maximum response size: 10 MB
339 | - Rate limit: 10,000 requests per second
340 | - Timeout: 29 seconds
341 |
--------------------------------------------------------------------------------
/docs/api/openapi.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | title: Amazon Connect Post-Contact Survey API
4 | description: API for managing surveys and retrieving results
5 | version: 1.0.0
6 | servers:
7 | - url: https://{apiGatewayId}.execute-api.{region}.amazonaws.com/dev
8 | variables:
9 | apiGatewayId:
10 | default: your-api-gateway-id
11 | description: API Gateway ID
12 | region:
13 | default: us-west-2
14 | description: AWS Region
15 | paths:
16 | /surveys:
17 | post:
18 | summary: Manage surveys
19 | description: Create, update, list, or delete surveys
20 | security:
21 | - CognitoAuth: []
22 | requestBody:
23 | required: true
24 | content:
25 | application/json:
26 | schema:
27 | oneOf:
28 | - $ref: '#/components/schemas/ListSurveysRequest'
29 | - $ref: '#/components/schemas/CreateSurveyRequest'
30 | - $ref: '#/components/schemas/DeleteSurveyRequest'
31 | responses:
32 | '200':
33 | description: Successful operation
34 | content:
35 | application/json:
36 | schema:
37 | oneOf:
38 | - $ref: '#/components/schemas/ListSurveysResponse'
39 | - $ref: '#/components/schemas/CreateSurveyResponse'
40 | - $ref: '#/components/schemas/DeleteSurveyResponse'
41 | '400':
42 | description: Bad request
43 | content:
44 | application/json:
45 | schema:
46 | $ref: '#/components/schemas/ErrorResponse'
47 | '401':
48 | description: Unauthorized
49 | content:
50 | application/json:
51 | schema:
52 | $ref: '#/components/schemas/ErrorResponse'
53 | '500':
54 | description: Internal server error
55 | content:
56 | application/json:
57 | schema:
58 | $ref: '#/components/schemas/ErrorResponse'
59 | options:
60 | summary: CORS support
61 | description: Enable CORS by returning correct headers
62 | responses:
63 | '200':
64 | description: CORS headers
65 | headers:
66 | Access-Control-Allow-Headers:
67 | schema:
68 | type: string
69 | Access-Control-Allow-Methods:
70 | schema:
71 | type: string
72 | Access-Control-Allow-Origin:
73 | schema:
74 | type: string
75 | /results:
76 | post:
77 | summary: Retrieve survey results
78 | description: Get results for a specific survey
79 | security:
80 | - CognitoAuth: []
81 | requestBody:
82 | required: true
83 | content:
84 | application/json:
85 | schema:
86 | $ref: '#/components/schemas/GetResultsRequest'
87 | responses:
88 | '200':
89 | description: Successful operation
90 | content:
91 | application/json:
92 | schema:
93 | $ref: '#/components/schemas/GetResultsResponse'
94 | '400':
95 | description: Bad request
96 | content:
97 | application/json:
98 | schema:
99 | $ref: '#/components/schemas/ErrorResponse'
100 | '401':
101 | description: Unauthorized
102 | content:
103 | application/json:
104 | schema:
105 | $ref: '#/components/schemas/ErrorResponse'
106 | '500':
107 | description: Internal server error
108 | content:
109 | application/json:
110 | schema:
111 | $ref: '#/components/schemas/ErrorResponse'
112 | options:
113 | summary: CORS support
114 | description: Enable CORS by returning correct headers
115 | responses:
116 | '200':
117 | description: CORS headers
118 | headers:
119 | Access-Control-Allow-Headers:
120 | schema:
121 | type: string
122 | Access-Control-Allow-Methods:
123 | schema:
124 | type: string
125 | Access-Control-Allow-Origin:
126 | schema:
127 | type: string
128 | components:
129 | securitySchemes:
130 | CognitoAuth:
131 | type: http
132 | scheme: bearer
133 | bearerFormat: JWT
134 | schemas:
135 | ListSurveysRequest:
136 | type: object
137 | required:
138 | - operation
139 | properties:
140 | operation:
141 | type: string
142 | enum: [list]
143 | CreateSurveyRequest:
144 | type: object
145 | required:
146 | - operation
147 | - data
148 | properties:
149 | operation:
150 | type: string
151 | enum: [create]
152 | data:
153 | type: object
154 | required:
155 | - surveyName
156 | - min
157 | - max
158 | - introPrompt
159 | - outroPrompt
160 | - questions
161 | - flags
162 | properties:
163 | surveyId:
164 | type: string
165 | description: Survey ID (required for updates, omit for new surveys)
166 | surveyName:
167 | type: string
168 | description: Name of the survey
169 | min:
170 | type: integer
171 | description: Minimum rating value
172 | max:
173 | type: integer
174 | description: Maximum rating value
175 | introPrompt:
176 | type: string
177 | description: Introduction prompt
178 | outroPrompt:
179 | type: string
180 | description: Conclusion prompt
181 | questions:
182 | type: array
183 | description: Survey questions
184 | items:
185 | type: string
186 | flags:
187 | type: array
188 | description: Flag thresholds for questions
189 | items:
190 | type: integer
191 | DeleteSurveyRequest:
192 | type: object
193 | required:
194 | - operation
195 | - data
196 | properties:
197 | operation:
198 | type: string
199 | enum: [delete]
200 | data:
201 | type: object
202 | required:
203 | - surveyId
204 | properties:
205 | surveyId:
206 | type: string
207 | description: Survey ID to delete
208 | GetResultsRequest:
209 | type: object
210 | required:
211 | - operation
212 | - data
213 | properties:
214 | operation:
215 | type: string
216 | enum: [results]
217 | data:
218 | type: object
219 | required:
220 | - surveyId
221 | properties:
222 | surveyId:
223 | type: string
224 | description: Survey ID to get results for
225 | ListSurveysResponse:
226 | type: object
227 | required:
228 | - success
229 | - data
230 | properties:
231 | success:
232 | type: boolean
233 | example: true
234 | data:
235 | type: array
236 | items:
237 | type: object
238 | properties:
239 | surveyId:
240 | type: string
241 | example: 550e8400-e29b-41d4-a716-446655440000
242 | surveyName:
243 | type: string
244 | example: Customer Satisfaction
245 | min:
246 | type: integer
247 | example: 1
248 | max:
249 | type: integer
250 | example: 5
251 | introPrompt:
252 | type: string
253 | example: Please rate your experience
254 | outroPrompt:
255 | type: string
256 | example: Thank you for your feedback
257 | question_1:
258 | type: string
259 | example: How satisfied were you with our service?
260 | question_2:
261 | type: string
262 | example: How likely are you to recommend us?
263 | flag_question_1:
264 | type: integer
265 | example: 3
266 | flag_question_2:
267 | type: integer
268 | example: 3
269 | CreateSurveyResponse:
270 | type: object
271 | required:
272 | - success
273 | - data
274 | properties:
275 | success:
276 | type: boolean
277 | example: true
278 | data:
279 | type: string
280 | example: 550e8400-e29b-41d4-a716-446655440000
281 | DeleteSurveyResponse:
282 | type: object
283 | required:
284 | - success
285 | properties:
286 | success:
287 | type: boolean
288 | example: true
289 | GetResultsResponse:
290 | type: object
291 | required:
292 | - success
293 | - data
294 | properties:
295 | success:
296 | type: boolean
297 | example: true
298 | data:
299 | type: array
300 | items:
301 | type: object
302 | properties:
303 | contactId:
304 | type: string
305 | example: 12345678-1234-1234-1234-123456789012
306 | surveyId:
307 | type: string
308 | example: 550e8400-e29b-41d4-a716-446655440000
309 | survey_result_1:
310 | type: string
311 | example: "4"
312 | survey_result_2:
313 | type: string
314 | example: "5"
315 | timestamp:
316 | type: integer
317 | example: 1647532800
318 | ErrorResponse:
319 | type: object
320 | required:
321 | - success
322 | - message
323 | properties:
324 | success:
325 | type: boolean
326 | example: false
327 | message:
328 | type: string
329 | example: Something went terribly wrong.
330 |
--------------------------------------------------------------------------------
/docs/architecture/README.md:
--------------------------------------------------------------------------------
1 | # Architecture Overview
2 |
3 | The Amazon Connect Post-Contact Survey Solution uses a serverless architecture built on AWS services. This document provides a comprehensive overview of the system architecture, component interactions, and data flows.
4 |
5 | ## Architecture Diagram
6 |
7 | 
8 |
9 | ## System Components
10 |
11 | ### Amazon Connect Components
12 | - **Contact Flow Module**: Executes the survey flow after a contact ends
13 | - **Amazon Lex Bot**: Processes text responses for chat-based surveys
14 | - **Tasks**: Created automatically for flagged survey responses
15 |
16 | ### AWS Lambda Functions
17 | - **GetSurveyConfig**: Retrieves survey configuration from DynamoDB
18 | - **WriteSurveyResults**: Stores survey responses in DynamoDB
19 | - **ProcessSurveyFlags**: Evaluates responses against thresholds and creates tasks
20 | - **SurveyUtils**: Provides utility functions for survey flow management
21 | - **SurveyAPI**: Handles API requests for survey management
22 | - **CognitoValidateUser**: Validates user authentication
23 |
24 | ### Data Storage
25 | - **SurveysConfigDDBTable**: Stores survey configurations
26 | - **SurveysResultsDDBTable**: Stores survey responses
27 |
28 | ### Frontend Components
29 | - **React Application**: Admin interface for survey management
30 | - **S3 Bucket**: Hosts the static web application
31 | - **CloudFront Distribution**: Delivers the web application
32 |
33 | ### API and Authentication
34 | - **API Gateway**: Routes API requests to Lambda functions
35 | - **Cognito User Pool**: Manages user authentication
36 |
37 | ## Data Flow
38 |
39 | ### Survey Creation Flow
40 | 1. Admin authenticates through Cognito
41 | 2. Admin creates survey configuration through the web interface
42 | 3. API Gateway routes the request to the SurveyAPI Lambda
43 | 4. Lambda stores the survey configuration in DynamoDB
44 |
45 | ### Survey Execution Flow
46 | 1. Contact completes in Amazon Connect
47 | 2. Contact Flow Module is triggered
48 | 3. GetSurveyConfig Lambda retrieves survey configuration
49 | 4. Contact Flow presents questions to the customer
50 | 5. Customer responses are collected via DTMF (voice) or Lex (chat)
51 | 6. WriteSurveyResults Lambda stores responses in DynamoDB
52 | 7. ProcessSurveyFlags Lambda evaluates responses against thresholds
53 | 8. Tasks are created in Amazon Connect for flagged responses
54 |
55 | ### Survey Results Flow
56 | 1. Admin authenticates through Cognito
57 | 2. Admin views survey results through the web interface
58 | 3. API Gateway routes the request to the SurveyAPI Lambda
59 | 4. Lambda retrieves survey results from DynamoDB
60 |
61 | ## Security Architecture
62 |
63 | ### Authentication and Authorization
64 | - **Cognito User Pool**: Manages user authentication for the admin interface
65 | - **IAM Roles**: Control access to AWS resources
66 | - **API Gateway Authorizers**: Validate requests to API endpoints
67 |
68 | ### Data Protection
69 | - **S3 Bucket Encryption**: Protects static web assets
70 | - **CloudFront Distribution**: Secures content delivery
71 | - **IAM Policies**: Implement least privilege access
72 |
73 | ## Scalability Considerations
74 |
75 | The serverless architecture allows the solution to scale automatically based on demand:
76 |
77 | - **Lambda Functions**: Scale automatically with request volume
78 | - **DynamoDB Tables**: Provisioned with appropriate capacity
79 | - **CloudFront Distribution**: Handles global content delivery
80 |
81 | ## Resilience and Availability
82 |
83 | - **Multi-AZ Deployment**: AWS services operate across multiple Availability Zones
84 | - **DynamoDB**: Provides high availability and durability
85 | - **CloudFront**: Ensures global availability of the web application
86 |
87 | ## Integration Points
88 |
89 | - **Amazon Connect**: Integration through Contact Flow Module and Lambda functions
90 | - **API Gateway**: Provides RESTful API endpoints for the web application
91 | - **Cognito**: Handles user authentication and authorization
92 |
--------------------------------------------------------------------------------
/docs/architecture/component-diagram.md:
--------------------------------------------------------------------------------
1 | # Component Diagram
2 |
3 | ```
4 | ┌───────────────────────────────────────────────────────────────────────────────────────────────────────┐
5 | │ │
6 | │ Amazon Connect Instance │
7 | │ │
8 | │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │
9 | │ │ │ │ │ │ │ │ │ │
10 | │ │ Contact Flow │ │ Contact Flow │ │ Contact Flow │ │ Contact Flow Module │ │
11 | │ │ │ │ │ │ │ │ (Survey Flow) │ │
12 | │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ └───────────┬───────────┘ │
13 | │ │ │ │ │ │
14 | └───────────┼──────────────────────┼──────────────────────┼──────────────────────────┼────────────────┘
15 | │ │ │ │
16 | │ │ │ │
17 | │ │ │ │
18 | ┌───────────┼──────────────────────┼──────────────────────┼──────────────────────────┼────────────────┐
19 | │ │ │ │ │ │
20 | │ │ │ │ ▼ │
21 | │ │ │ │ ┌─────────────────────────┐ │
22 | │ │ │ │ │ │ │
23 | │ │ │ │ │ Amazon Lex Bot │ │
24 | │ │ │ │ │ (Survey Responses) │ │
25 | │ │ │ │ │ │ │
26 | │ │ │ │ └─────────────────────────┘ │
27 | │ │ │ │ │
28 | └───────────┼──────────────────────┼──────────────────────┼───────────────────────────────────────────┘
29 | │ │ │
30 | │ │ │
31 | ▼ ▼ ▼
32 | ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
33 | │ │
34 | │ AWS Lambda Functions │
35 | │ │
36 | │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
37 | │ │ │ │ │ │ │ │ │ │
38 | │ │ GetSurveyConfig │ │ WriteSurvey │ │ ProcessSurvey │ │ SurveyUtils │ │
39 | │ │ │ │ Results │ │ Flags │ │ │ │
40 | │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
41 | │ │ │ │ │ │
42 | │ │ │ │ │ │
43 | │ ▼ ▼ ▼ │ │
44 | │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │
45 | │ │ │ │ │
46 | │ │ DynamoDB Tables │ │ │
47 | │ │ │ │ │
48 | │ │ ┌─────────────────────┐ ┌─────────────────────────┐ │ │ │
49 | │ │ │ │ │ │ │ │ │
50 | │ │ │ SurveysConfigTable │◄───────────┤ SurveysResultsTable │ │ │ │
51 | │ │ │ │ │ │ │ │ │
52 | │ │ └─────────────────────┘ └─────────────────────────┘ │ │ │
53 | │ │ │ │ │
54 | │ └─────────────────────────────────────────────────────────────────────────┘ │ │
55 | │ │ │
56 | └─────────────────────────────────────────────────────────────────────────────────┼───────────────────┘
57 | │
58 | │
59 | ┌─────────────────────────────────────────────────────────────────────────────────┼───────────────────┐
60 | │ │ │
61 | │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
62 | │ │ │ │ │
63 | │ │ API Gateway │ │ │
64 | │ │ │ │ │
65 | │ │ ┌─────────────────────┐ ┌─────────────────────────┐ │ │ │
66 | │ │ │ │ │ │ │ │ │
67 | │ │ │ /surveys endpoint │ │ /results endpoint │ │ │ │
68 | │ │ │ │ │ │ │ │ │
69 | │ │ └──────────┬──────────┘ └────────────┬────────────┘ │ │ │
70 | │ │ │ │ │ │ │
71 | │ └─────────────┼────────────────────────────────────┼──────────────────┘ │ │
72 | │ │ │ │ │
73 | │ │ │ │ │
74 | │ │ │ │ │
75 | │ ▼ ▼ │ │
76 | │ ┌─────────────────────────────────────────────────────────────────┐ │ │
77 | │ │ │ │ │
78 | │ │ Lambda API Function │ │ │
79 | │ │ │ │ │
80 | │ └─────────────────────────────────────────────────────────────────┘ │ │
81 | │ │ │
82 | └─────────────────────────────────────────────────────────────────────────────────┼───────────────────┘
83 | │
84 | │
85 | ┌─────────────────────────────────────────────────────────────────────────────────┼───────────────────┐
86 | │ │ │
87 | │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
88 | │ │ │ │ │
89 | │ │ CloudFront Distribution │◄───────┘ │
90 | │ │ │ │
91 | │ └────────────────────────────────┬────────────────────────────────────┘ │
92 | │ │ │
93 | │ │ │
94 | │ ▼ │
95 | │ ┌─────────────────────────────────────────────────────────────────────┐ │
96 | │ │ │ │
97 | │ │ S3 Frontend Bucket │ │
98 | │ │ │ │
99 | │ └─────────────────────────────────────────────────────────────────────┘ │
100 | │ │
101 | └─────────────────────────────────────────────────────────────────────────────────────────────────────┘
102 |
103 | ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
104 | │ │
105 | │ Amazon Cognito │
106 | │ │
107 | │ ┌─────────────────────┐ ┌─────────────────┐ │
108 | │ │ │ │ │ │
109 | │ │ User Pool │ │ User Pool │ │
110 | │ │ │ │ Client │ │
111 | │ └─────────────────────┘ └─────────────────┘ │
112 | │ │
113 | └─────────────────────────────────────────────────────────────────────────────────────────────────────┘
114 | ```
115 |
--------------------------------------------------------------------------------
/docs/architecture/data-flow.md:
--------------------------------------------------------------------------------
1 | # Data Flow Diagrams
2 |
3 | This document provides detailed data flow diagrams for the key processes in the Amazon Connect Post-Contact Survey Solution.
4 |
5 | ## Survey Creation Flow
6 |
7 | ```
8 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
9 | │ │ │ │ │ │ │ │
10 | │ Admin │────►│ Frontend │────►│ API Gateway │────►│ Lambda API │
11 | │ │ │ │ │ │ │ │
12 | └─────────────┘ └─────────────┘ └─────────────┘ └──────┬──────┘
13 | │
14 | ▼
15 | ┌─────────────┐
16 | │ │
17 | │ DynamoDB │
18 | │ Config │
19 | │ │
20 | └─────────────┘
21 | ```
22 |
23 | 1. Admin creates or updates a survey through the frontend interface
24 | 2. Frontend sends a request to API Gateway
25 | 3. API Gateway routes the request to the Lambda API function
26 | 4. Lambda API function stores the survey configuration in DynamoDB
27 |
28 | ## Survey Execution Flow
29 |
30 | ```
31 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
32 | │ │ │ │ │ │ │ │
33 | │ Contact │────►│ Connect │────►│ Contact Flow│────►│ GetSurvey │
34 | │ Ends │ │ Instance │ │ Module │ │ Config │
35 | │ │ │ │ │ │ │ │
36 | └─────────────┘ └─────────────┘ └─────────────┘ └──────┬──────┘
37 | │
38 | ▼
39 | ┌─────────────┐
40 | │ │
41 | │ DynamoDB │
42 | │ Config │
43 | │ │
44 | └──────┬──────┘
45 | │
46 | ▼
47 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
48 | │ │ │ │ │ │ │ │
49 | │ Customer │◄────│ Survey │◄────│ Survey │◄────│ Survey │
50 | │ │ │ Questions │ │ Utils │ │ Config │
51 | │ │ │ │ │ │ │ │
52 | └──────┬──────┘ └─────────────┘ └─────────────┘ └─────────────┘
53 | │
54 | ▼
55 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
56 | │ │ │ │ │ │
57 | │ Customer │────►│ Write Survey│────►│ DynamoDB │
58 | │ Responses │ │ Results │ │ Results │
59 | │ │ │ │ │ │
60 | └─────────────┘ └──────┬──────┘ └─────────────┘
61 | │
62 | ▼
63 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
64 | │ │ │ │ │ │
65 | │ Process │────►│ Create │────►│ Connect │
66 | │ Survey Flags│ │ Task │ │ Task │
67 | │ │ │ │ │ │
68 | └─────────────┘ └─────────────┘ └─────────────┘
69 | ```
70 |
71 | 1. Contact ends in Amazon Connect
72 | 2. Contact Flow Module is triggered to start the survey
73 | 3. GetSurveyConfig Lambda retrieves survey configuration from DynamoDB
74 | 4. Survey questions are presented to the customer
75 | 5. Customer responses are collected
76 | 6. WriteSurveyResults Lambda stores responses in DynamoDB
77 | 7. ProcessSurveyFlags Lambda evaluates responses against thresholds
78 | 8. Tasks are created in Amazon Connect for flagged responses
79 |
80 | ## Survey Results Retrieval Flow
81 |
82 | ```
83 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
84 | │ │ │ │ │ │ │ │
85 | │ Admin │────►│ Frontend │────►│ API Gateway │────►│ Lambda API │
86 | │ │ │ │ │ │ │ │
87 | └─────────────┘ └─────────────┘ └─────────────┘ └──────┬──────┘
88 | │
89 | ▼
90 | ┌─────────────┐
91 | │ │
92 | │ DynamoDB │
93 | │ Results │
94 | │ │
95 | └──────┬──────┘
96 | │
97 | ▼
98 | ┌─────────────┐
99 | │ │
100 | │ Frontend │
101 | │ Display │
102 | │ │
103 | └─────────────┘
104 | ```
105 |
106 | 1. Admin requests survey results through the frontend interface
107 | 2. Frontend sends a request to API Gateway
108 | 3. API Gateway routes the request to the Lambda API function
109 | 4. Lambda API function retrieves survey results from DynamoDB
110 | 5. Results are displayed in the frontend interface
111 |
112 | ## Authentication Flow
113 |
114 | ```
115 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
116 | │ │ │ │ │ │
117 | │ User │────►│ Frontend │────►│ Cognito │
118 | │ │ │ │ │ User Pool │
119 | └─────────────┘ └─────────────┘ └──────┬──────┘
120 | │
121 | ▼
122 | ┌─────────────┐
123 | │ │
124 | │ JWT Token │
125 | │ │
126 | └──────┬──────┘
127 | │
128 | ▼
129 | ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
130 | │ │ │ │ │ │
131 | │ Protected │◄────│ API Gateway │◄────│ Token │
132 | │ Resources │ │ Authorizer │ │ Validation │
133 | │ │ │ │ │ │
134 | └─────────────┘ └─────────────┘ └─────────────┘
135 | ```
136 |
137 | 1. User logs in through the frontend interface
138 | 2. Frontend authenticates with Cognito User Pool
139 | 3. Cognito returns a JWT token
140 | 4. Token is included in API requests
141 | 5. API Gateway Authorizer validates the token
142 | 6. User accesses protected resources
143 |
--------------------------------------------------------------------------------
/docs/backend/README.md:
--------------------------------------------------------------------------------
1 | # Backend Documentation
2 |
3 | The backend of the Amazon Connect Post-Contact Survey Solution is built using AWS Lambda functions, DynamoDB tables, and other AWS services. This document provides detailed information about the backend components and their interactions.
4 |
5 | ## Lambda Functions
6 |
7 | ### API Lambda Function
8 |
9 | The API Lambda function handles API requests from the frontend application.
10 |
11 | **File:** `lambdas/api/index.js`
12 |
13 | **Purpose:**
14 | - Processes API requests for survey operations
15 | - Handles CRUD operations for surveys
16 | - Retrieves survey results
17 |
18 | **Operations:**
19 | - `list`: Retrieves all surveys
20 | - `create`: Creates a new survey
21 | - `update`: Updates an existing survey
22 | - `delete`: Deletes a survey
23 | - `results`: Retrieves survey results
24 |
25 | **Environment Variables:**
26 | - `TABLE_SURVEYS_CONFIG`: Name of the DynamoDB table for survey configurations
27 | - `TABLE_SURVEYS_RESULTS`: Name of the DynamoDB table for survey results
28 |
29 | **Example Request:**
30 | ```json
31 | {
32 | "operation": "create",
33 | "data": {
34 | "surveyName": "Customer Satisfaction",
35 | "min": 1,
36 | "max": 5,
37 | "introPrompt": "Please rate your experience",
38 | "outroPrompt": "Thank you for your feedback",
39 | "questions": [
40 | "How satisfied were you with our service?",
41 | "How likely are you to recommend us?"
42 | ],
43 | "flags": [3, 3]
44 | }
45 | }
46 | ```
47 |
48 | **Example Response:**
49 | ```json
50 | {
51 | "success": true,
52 | "data": "550e8400-e29b-41d4-a716-446655440000"
53 | }
54 | ```
55 |
56 | ### GetSurveyConfig Lambda Function
57 |
58 | Retrieves survey configuration from DynamoDB for use in Amazon Connect contact flows.
59 |
60 | **File:** `lambdas/getSurveyConfig/index.js`
61 |
62 | **Purpose:**
63 | - Retrieves survey configuration from DynamoDB
64 | - Formats survey data for use in Amazon Connect
65 |
66 | **Environment Variables:**
67 | - `TABLE`: Name of the DynamoDB table for survey configurations
68 |
69 | **Example Request:**
70 | ```json
71 | {
72 | "Details": {
73 | "Parameters": {
74 | "surveyId": "550e8400-e29b-41d4-a716-446655440000"
75 | }
76 | }
77 | }
78 | ```
79 |
80 | **Example Response:**
81 | ```json
82 | {
83 | "statusCode": 200,
84 | "message": "OK",
85 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
86 | "surveyName": "Customer Satisfaction",
87 | "min": 1,
88 | "max": 5,
89 | "introPrompt": "Please rate your experience",
90 | "outroPrompt": "Thank you for your feedback",
91 | "question_1": "How satisfied were you with our service?",
92 | "question_2": "How likely are you to recommend us?",
93 | "flag_question_1": 3,
94 | "flag_question_2": 3,
95 | "surveySize": 2
96 | }
97 | ```
98 |
99 | ### WriteSurveyResults Lambda Function
100 |
101 | Stores survey responses in DynamoDB.
102 |
103 | **File:** `lambdas/writeSurveyResults/index.js`
104 |
105 | **Purpose:**
106 | - Stores survey responses in DynamoDB
107 | - Processes survey attributes from Amazon Connect
108 |
109 | **Environment Variables:**
110 | - `TABLE`: Name of the DynamoDB table for survey results
111 |
112 | **Example Request:**
113 | ```json
114 | {
115 | "Details": {
116 | "ContactData": {
117 | "ContactId": "12345678-1234-1234-1234-123456789012",
118 | "Attributes": {
119 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
120 | "survey_result_1": "4",
121 | "survey_result_2": "5"
122 | }
123 | }
124 | }
125 | }
126 | ```
127 |
128 | **Example Response:**
129 | ```json
130 | {
131 | "statusCode": 200,
132 | "body": "OK"
133 | }
134 | ```
135 |
136 | ### ProcessSurveyFlags Lambda Function
137 |
138 | Evaluates survey responses against thresholds and creates tasks in Amazon Connect.
139 |
140 | **File:** `lambdas/processReviewFlags/index.js`
141 |
142 | **Purpose:**
143 | - Evaluates survey responses against thresholds
144 | - Creates tasks in Amazon Connect for flagged responses
145 |
146 | **Environment Variables:**
147 | - `CONTACT_FLOW_ID`: ID of the contact flow for tasks
148 | - `INSTANCE_NAME`: Name of the Amazon Connect instance
149 |
150 | **Example Request:**
151 | ```json
152 | {
153 | "Details": {
154 | "ContactData": {
155 | "ContactId": "12345678-1234-1234-1234-123456789012",
156 | "InstanceARN": "arn:aws:connect:us-west-2:123456789012:instance/12345678-1234-1234-1234-123456789012",
157 | "Attributes": {
158 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
159 | "survey_result_1": "2",
160 | "survey_result_2": "5"
161 | }
162 | },
163 | "Parameters": {
164 | "flag_question_1": "3",
165 | "flag_question_2": "3"
166 | }
167 | }
168 | }
169 | ```
170 |
171 | **Example Response:**
172 | ```json
173 | {
174 | "statusCode": 200,
175 | "body": "OK"
176 | }
177 | ```
178 |
179 | ### SurveyUtils Lambda Function
180 |
181 | Provides utility functions for survey flow management.
182 |
183 | **File:** `lambdas/surveyUtils/index.js`
184 |
185 | **Purpose:**
186 | - Manages survey flow in Amazon Connect
187 | - Validates user input
188 | - Retrieves next survey question
189 |
190 | **Operations:**
191 | - `getNextSurveyQuestion`: Gets the next question in the survey
192 | - `validateInput`: Validates user input against min/max bounds
193 |
194 | **Example Request:**
195 | ```json
196 | {
197 | "Details": {
198 | "Parameters": {
199 | "operation": "getNextSurveyQuestion",
200 | "question_1": "How satisfied were you with our service?",
201 | "question_2": "How likely are you to recommend us?"
202 | },
203 | "ContactData": {
204 | "Attributes": {
205 | "loopCounter": "1"
206 | }
207 | }
208 | }
209 | }
210 | ```
211 |
212 | **Example Response:**
213 | ```json
214 | {
215 | "operation": "getNextSurveyQuestion",
216 | "nextQuestion": "How satisfied were you with our service?",
217 | "newCounter": 2,
218 | "currentQuestionIndex": "1"
219 | }
220 | ```
221 |
222 | ### CognitoValidateUser Lambda Function
223 |
224 | Validates user authentication through Amazon Cognito.
225 |
226 | **File:** `lambdas/cognitoValidateUser/index.js`
227 |
228 | **Purpose:**
229 | - Validates user authentication
230 | - Updates user attributes in Cognito
231 |
232 | **Example Request:**
233 | ```json
234 | {
235 | "ResourceProperties": {
236 | "UserPoolId": "us-west-2_abcdefghi",
237 | "Username": "admin"
238 | }
239 | }
240 | ```
241 |
242 | **Example Response:**
243 | ```json
244 | {
245 | "statusCode": 200,
246 | "body": {}
247 | }
248 | ```
249 |
250 | ## DynamoDB Tables
251 |
252 | ### SurveysConfigDDBTable
253 |
254 | Stores survey configurations.
255 |
256 | **Schema:**
257 | - `surveyId` (String): Primary key
258 | - `surveyName` (String): Name of the survey
259 | - `min` (Number): Minimum rating value
260 | - `max` (Number): Maximum rating value
261 | - `introPrompt` (String): Introduction prompt
262 | - `outroPrompt` (String): Conclusion prompt
263 | - `question_1`, `question_2`, etc. (String): Survey questions
264 | - `flag_question_1`, `flag_question_2`, etc. (Number): Flag thresholds
265 |
266 | **Example Item:**
267 | ```json
268 | {
269 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
270 | "surveyName": "Customer Satisfaction",
271 | "min": 1,
272 | "max": 5,
273 | "introPrompt": "Please rate your experience",
274 | "outroPrompt": "Thank you for your feedback",
275 | "question_1": "How satisfied were you with our service?",
276 | "question_2": "How likely are you to recommend us?",
277 | "flag_question_1": 3,
278 | "flag_question_2": 3
279 | }
280 | ```
281 |
282 | ### SurveysResultsDDBTable
283 |
284 | Stores survey responses.
285 |
286 | **Schema:**
287 | - `contactId` (String): Primary key
288 | - `surveyId` (String): ID of the survey
289 | - `survey_result_1`, `survey_result_2`, etc. (String): Survey responses
290 | - `timestamp` (Number): Unix timestamp
291 |
292 | **Example Item:**
293 | ```json
294 | {
295 | "contactId": "12345678-1234-1234-1234-123456789012",
296 | "surveyId": "550e8400-e29b-41d4-a716-446655440000",
297 | "survey_result_1": "4",
298 | "survey_result_2": "5",
299 | "timestamp": 1647532800
300 | }
301 | ```
302 |
303 | ## Amazon Connect Integration
304 |
305 | ### Contact Flow Module
306 |
307 | The Contact Flow Module executes the survey flow after a contact ends.
308 |
309 | **Key Components:**
310 | - Invokes GetSurveyConfig Lambda to retrieve survey configuration
311 | - Presents questions to the customer
312 | - Collects responses via DTMF (voice) or Lex (chat)
313 | - Invokes WriteSurveyResults Lambda to store responses
314 | - Invokes ProcessSurveyFlags Lambda to evaluate responses
315 |
316 | **Flow Logic:**
317 | 1. Retrieve survey configuration
318 | 2. Present introduction prompt
319 | 3. Loop through survey questions
320 | 4. Collect and validate responses
321 | 5. Store responses
322 | 6. Evaluate responses against thresholds
323 | 7. Present conclusion prompt
324 |
325 | ### Amazon Lex Bot
326 |
327 | The Amazon Lex Bot processes text responses for chat-based surveys.
328 |
329 | **Intents:**
330 | - `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`: Numeric responses
331 | - `FallbackIntent`: Default intent when no other intent matches
332 |
333 | **Utterances:**
334 | - Numeric values (0-9)
335 |
336 | ## Error Handling
337 |
338 | ### Lambda Error Handling
339 |
340 | ```javascript
341 | try {
342 | // Operation code
343 | } catch (err) {
344 | console.log(err);
345 | return {
346 | statusCode: 500,
347 | body: JSON.stringify({ error: 'Internal server error' })
348 | };
349 | }
350 | ```
351 |
352 | ### DynamoDB Error Handling
353 |
354 | ```javascript
355 | try {
356 | const command = new PutCommand(params);
357 | await docClient.send(command);
358 | } catch (err) {
359 | console.log(err);
360 | throw err;
361 | }
362 | ```
363 |
364 | ### Connect Flow Error Handling
365 |
366 | The Contact Flow Module includes error handling branches for:
367 | - Lambda invocation errors
368 | - Invalid user input
369 | - Timeout errors
370 |
371 | ## Logging and Monitoring
372 |
373 | ### CloudWatch Logs
374 |
375 | All Lambda functions log to CloudWatch Logs:
376 |
377 | ```javascript
378 | console.log('Processing survey response:', event);
379 | ```
380 |
381 | ### API Gateway Logging
382 |
383 | API Gateway is configured with ERROR level logging:
384 |
385 | ```json
386 | {
387 | "MethodSettings": [
388 | {
389 | "DataTraceEnabled": true,
390 | "HttpMethod": "*",
391 | "LoggingLevel": "ERROR",
392 | "ResourcePath": "/*"
393 | }
394 | ]
395 | }
396 | ```
397 |
398 | ## Security
399 |
400 | ### IAM Roles
401 |
402 | Each Lambda function has a specific IAM role with least privilege permissions:
403 |
404 | - `LambdaSurveysApiRole`: Permissions for API operations
405 | - `LambdaGetSurveyConfigRole`: Permissions to read survey configurations
406 | - `LambdaWriteSurveyResultsRole`: Permissions to write survey results
407 | - `LambdaProcessSurveysFlagsRole`: Permissions to create tasks in Connect
408 |
409 | ### API Gateway Authorization
410 |
411 | API Gateway uses Cognito User Pools for authorization:
412 |
413 | ```json
414 | {
415 | "AuthorizationType": "COGNITO_USER_POOLS",
416 | "AuthorizerId": "CognitoAuthorizer"
417 | }
418 | ```
419 |
420 | ### DynamoDB Encryption
421 |
422 | DynamoDB tables use server-side encryption:
423 |
424 | ```json
425 | {
426 | "SSESpecification": {
427 | "Enabled": true
428 | }
429 | }
430 | ```
431 |
--------------------------------------------------------------------------------
/docs/deployment/README.md:
--------------------------------------------------------------------------------
1 | # Deployment Guide
2 |
3 | This guide provides detailed instructions for deploying the Amazon Connect Post-Contact Survey Solution.
4 |
5 | ## Prerequisites
6 |
7 | Before deploying the solution, ensure you have the following:
8 |
9 | - **AWS Account**: An AWS account with permissions to create the required resources
10 | - **Amazon Connect Instance**: An existing Amazon Connect instance
11 | - **AWS CLI**: Installed and configured with appropriate permissions
12 | - **Node.js**: Version 14.x or later
13 | - **Admin Email Address**: An email address for the initial admin user
14 |
15 | ## Required Permissions
16 |
17 | The deployment requires permissions to create and manage the following AWS resources:
18 |
19 | - Lambda functions
20 | - S3 buckets
21 | - IAM roles
22 | - Cognito user pools
23 | - DynamoDB tables
24 | - API Gateway
25 | - CloudFront distributions
26 | - Amazon Lex bots
27 |
28 | ## Deployment Steps
29 |
30 | ### 1. Clone the Repository
31 |
32 | ```bash
33 | git clone
34 | cd amazon-connect-contact-surveys
35 | ```
36 |
37 | ### 2. Install Dependencies
38 |
39 | ```bash
40 | npm install
41 | ```
42 |
43 | ### 3. Build the Frontend
44 |
45 | ```bash
46 | npm run build
47 | ```
48 |
49 | ### 4. Deploy the CloudFormation Stack
50 |
51 | ```bash
52 | aws cloudformation deploy \
53 | --template-file deployment/contact-surveys-amazon-connect.yaml \
54 | --stack-name contact-surveys \
55 | --capabilities CAPABILITY_IAM \
56 | --parameter-overrides \
57 | AmazonConnectInstanceARN= \
58 | AmazonConnectInstanceName= \
59 | ContactFlowIdForTasks= \
60 | AdminEmailAddress=
61 | ```
62 |
63 | Replace the placeholder values with your specific information:
64 |
65 | - ``: The ARN of your Amazon Connect instance
66 | - ``: The name of your Amazon Connect instance
67 | - ``: The ID of the contact flow you want generated tasks to be directed to
68 | - ``: The email address for the initial admin user
69 |
70 | ### 5. Get the CloudFormation Outputs
71 |
72 | ```bash
73 | aws cloudformation describe-stacks \
74 | --stack-name contact-surveys \
75 | --query "Stacks[0].Outputs"
76 | ```
77 |
78 | Note the following outputs:
79 | - `WebClient`: The URL for accessing the frontend application
80 | - `AdminUser`: The initial admin user for the frontend
81 |
82 | ### 6. Configure Amazon Connect
83 |
84 | #### Import the Contact Flow Module
85 |
86 | 1. Log in to the Amazon Connect admin console
87 | 2. Navigate to "Routing" > "Contact flows"
88 | 3. Click "Create contact flow" > "Import flow"
89 | 4. Upload the contact flow module from the CloudFormation outputs
90 |
91 | #### Configure Contact Flows
92 |
93 | 1. Create or edit a contact flow that will trigger the survey
94 | 2. Add a "Transfer to flow" block
95 | 3. Select the "Contact Survey" module
96 | 4. Configure the parameters:
97 | - `surveyId`: The ID of the survey to use
98 |
99 | ### 7. Verify Deployment
100 |
101 | 1. Access the frontend application using the `WebClient` URL from the CloudFormation outputs
102 | 2. Log in using the admin credentials sent to the specified email address
103 | 3. Create a test survey
104 | 4. Test the survey flow in Amazon Connect
105 |
106 | ## Post-Deployment Configuration
107 |
108 | ### Configure Survey Triggers
109 |
110 | 1. Identify the contact flows where you want to trigger surveys
111 | 2. Add a "Set contact attributes" block to set the `surveyId` attribute
112 | 3. Add a "Transfer to flow" block to transfer to the "Contact Survey" module
113 |
114 | ### Configure Task Creation
115 |
116 | 1. Create a contact flow for handling tasks created by flagged survey responses
117 | 2. Update the `ContactFlowIdForTasks` parameter in the CloudFormation stack if needed
118 |
119 | ### Configure User Access
120 |
121 | 1. Log in to the Amazon Cognito console
122 | 2. Navigate to the user pool created by the CloudFormation stack
123 | 3. Add additional users as needed
124 |
125 | ## Troubleshooting
126 |
127 | ### Common Issues
128 |
129 | #### Cognito User Not Confirmed
130 |
131 | **Error**: "User is not confirmed"
132 |
133 | **Solution**:
134 | ```bash
135 | aws cognito-idp admin-confirm-sign-up \
136 | --user-pool-id \
137 | --username
138 | ```
139 |
140 | #### Survey Creation Failures
141 |
142 | **Error**: Survey creation fails
143 |
144 | **Solution**:
145 | 1. Check Lambda CloudWatch logs: `/aws/lambda/contact-surveys-surveys-api`
146 | 2. Verify DynamoDB permissions
147 | 3. Enable debug logging:
148 | ```javascript
149 | const debugMode = true;
150 | console.debug('Survey creation payload:', surveyData);
151 | ```
152 |
153 | #### Contact Flow Module Not Working
154 |
155 | **Error**: Survey not triggered after contact
156 |
157 | **Solution**:
158 | 1. Verify the `surveyId` attribute is set correctly
159 | 2. Check Lambda CloudWatch logs for errors
160 | 3. Verify IAM permissions for Lambda functions
161 |
162 | #### Frontend Access Issues
163 |
164 | **Error**: Unable to access the frontend application
165 |
166 | **Solution**:
167 | 1. Verify the CloudFront distribution is deployed
168 | 2. Check S3 bucket permissions
169 | 3. Verify Cognito user pool configuration
170 |
171 | ## Updating the Solution
172 |
173 | To update the solution to a new version:
174 |
175 | 1. Pull the latest changes from the repository
176 | 2. Install dependencies and build the frontend
177 | 3. Update the CloudFormation stack:
178 |
179 | ```bash
180 | aws cloudformation update-stack \
181 | --stack-name contact-surveys \
182 | --template-body file://deployment/contact-surveys-amazon-connect.yaml \
183 | --capabilities CAPABILITY_IAM \
184 | --parameters \
185 | ParameterKey=AmazonConnectInstanceARN,UsePreviousValue=true \
186 | ParameterKey=AmazonConnectInstanceName,UsePreviousValue=true \
187 | ParameterKey=ContactFlowIdForTasks,UsePreviousValue=true \
188 | ParameterKey=AdminEmailAddress,UsePreviousValue=true
189 | ```
190 |
191 | ## Uninstalling the Solution
192 |
193 | To remove the solution:
194 |
195 | ```bash
196 | aws cloudformation delete-stack \
197 | --stack-name contact-surveys
198 | ```
199 |
200 | Note: This will delete all resources created by the CloudFormation stack, including the DynamoDB tables containing survey configurations and results. Make sure to back up any important data before deleting the stack.
201 |
--------------------------------------------------------------------------------
/docs/deployment/cloudformation-parameters.md:
--------------------------------------------------------------------------------
1 | # CloudFormation Parameters
2 |
3 | This document provides detailed information about the CloudFormation parameters used in the Amazon Connect Post-Contact Survey Solution.
4 |
5 | ## Required Parameters
6 |
7 | ### AmazonConnectInstanceARN
8 |
9 | - **Description**: The Amazon Connect instance ARN
10 | - **Type**: String
11 | - **Format**: `arn:aws:connect:region:account-id:instance/instance-id`
12 | - **Example**: `arn:aws:connect:us-west-2:123456789012:instance/12345678-1234-1234-1234-123456789012`
13 | - **How to find it**:
14 | 1. Log in to the AWS Console
15 | 2. Navigate to Amazon Connect
16 | 3. Select your instance
17 | 4. The ARN is displayed in the instance details
18 |
19 | ### AmazonConnectInstanceName
20 |
21 | - **Description**: The Amazon Connect instance name
22 | - **Type**: String
23 | - **Format**: The name of your Amazon Connect instance
24 | - **Example**: `my-connect-instance`
25 | - **How to find it**:
26 | 1. Log in to the AWS Console
27 | 2. Navigate to Amazon Connect
28 | 3. The instance name is displayed in the instance list
29 |
30 | ### ContactFlowIdForTasks
31 |
32 | - **Description**: The contact flow you want generated tasks to be directed to
33 | - **Type**: String
34 | - **Format**: The ID of the contact flow
35 | - **Example**: `12345678-1234-1234-1234-123456789012`
36 | - **How to find it**:
37 | 1. Log in to the Amazon Connect admin console
38 | 2. Navigate to "Routing" > "Contact flows"
39 | 3. Select the contact flow
40 | 4. The ID is in the URL: `/contact-flow/edit?id=`
41 |
42 | ### AdminEmailAddress
43 |
44 | - **Description**: The email address for the initial user of the solution
45 | - **Type**: String
46 | - **Format**: A valid email address
47 | - **Example**: `admin@example.com`
48 | - **Note**: This email address will receive the initial password for the admin user
49 |
50 | ## CloudFormation Stack Outputs
51 |
52 | ### WebClient
53 |
54 | - **Description**: The frontend access URL
55 | - **Value**: CloudFront distribution domain name
56 | - **Example**: `d1234abcdef.cloudfront.net`
57 | - **Usage**: Access the frontend application using this URL
58 |
59 | ### AdminUser
60 |
61 | - **Description**: The initial admin user for the frontend
62 | - **Value**: Username of the admin user
63 | - **Example**: `admin`
64 | - **Usage**: Use this username with the password sent to the admin email address to log in
65 |
66 | ## Advanced Configuration
67 |
68 | ### Customizing the CloudFormation Template
69 |
70 | The CloudFormation template can be customized to meet specific requirements:
71 |
72 | #### Modifying DynamoDB Capacity
73 |
74 | ```yaml
75 | SurveysConfigDDBTable:
76 | Type: AWS::DynamoDB::Table
77 | Properties:
78 | # ... other properties ...
79 | ProvisionedThroughput:
80 | ReadCapacityUnits: 5 # Modify as needed
81 | WriteCapacityUnits: 5 # Modify as needed
82 | ```
83 |
84 | #### Customizing Lambda Function Memory
85 |
86 | ```yaml
87 | LambdaSurveyApi:
88 | Type: AWS::Lambda::Function
89 | Properties:
90 | # ... other properties ...
91 | MemorySize: 256 # Modify as needed
92 | ```
93 |
94 | #### Adding Custom Domain Name
95 |
96 | ```yaml
97 | CloudFrontDistribution:
98 | Type: "AWS::CloudFront::Distribution"
99 | Properties:
100 | DistributionConfig:
101 | # ... other properties ...
102 | Aliases:
103 | - surveys.example.com
104 | ```
105 |
106 | #### Enabling DynamoDB Auto Scaling
107 |
108 | ```yaml
109 | SurveysConfigTableReadCapacityScalableTarget:
110 | Type: AWS::ApplicationAutoScaling::ScalableTarget
111 | Properties:
112 | MaxCapacity: 100
113 | MinCapacity: 1
114 | ResourceId: !Sub table/${SurveysConfigDDBTable}
115 | RoleARN: !GetAtt ScalingRole.Arn
116 | ScalableDimension: dynamodb:table:ReadCapacityUnits
117 | ServiceNamespace: dynamodb
118 | ```
119 |
120 | ## Deployment Considerations
121 |
122 | ### Resource Limits
123 |
124 | - **Lambda Functions**: The solution deploys 7 Lambda functions
125 | - **DynamoDB Tables**: The solution creates 2 DynamoDB tables
126 | - **S3 Buckets**: The solution creates 2 S3 buckets
127 | - **CloudFront Distributions**: The solution creates 1 CloudFront distribution
128 | - **Cognito User Pools**: The solution creates 1 Cognito user pool
129 |
130 | ### Regional Availability
131 |
132 | The solution can be deployed in any AWS region that supports the following services:
133 |
134 | - Amazon Connect
135 | - AWS Lambda
136 | - Amazon DynamoDB
137 | - Amazon S3
138 | - Amazon CloudFront
139 | - Amazon Cognito
140 | - Amazon API Gateway
141 | - Amazon Lex
142 |
143 | ### Cost Considerations
144 |
145 | The solution uses the following billable AWS resources:
146 |
147 | - **Lambda Functions**: Charged based on invocation count and execution time
148 | - **DynamoDB Tables**: Charged based on provisioned capacity and storage
149 | - **S3 Buckets**: Charged based on storage and requests
150 | - **CloudFront Distribution**: Charged based on data transfer and requests
151 | - **API Gateway**: Charged based on API calls
152 | - **Cognito User Pool**: Free tier available, then charged per MAU
153 | - **Amazon Lex**: Charged per request
154 |
155 | For detailed pricing information, refer to the AWS Pricing Calculator.
156 |
--------------------------------------------------------------------------------
/docs/frontend/README.md:
--------------------------------------------------------------------------------
1 | # Frontend Documentation
2 |
3 | The frontend of the Amazon Connect Post-Contact Survey Solution is built using React.js and provides a user interface for managing surveys and viewing results.
4 |
5 | ## Component Structure
6 |
7 | ```
8 | src/
9 | ├── components/
10 | │ ├── Authentication/ # Authentication components
11 | │ ├── ChangePassword/ # Password management
12 | │ ├── ForgotPassword/ # Password recovery
13 | │ ├── Home/ # Dashboard component
14 | │ ├── Logout/ # Logout handling
15 | │ ├── Survey/ # Survey management
16 | │ └── SurveysList/ # Survey listing
17 | ├── models/
18 | │ └── SurveyModel.tsx # Survey data model
19 | ├── App.tsx # Main application component
20 | └── index.tsx # Application entry point
21 | ```
22 |
23 | ## Key Components
24 |
25 | ### Authentication Components
26 | - Login form
27 | - Password management
28 | - Session handling
29 | - Protected route implementation
30 |
31 | ### Survey Management Components
32 | - Survey creation and editing
33 | - Question configuration
34 | - Response threshold settings
35 | - Results viewing
36 |
37 | ### Data Models
38 |
39 | ```typescript
40 | export interface SurveyModel {
41 | surveyId: string;
42 | surveyName: string;
43 | max: number;
44 | min: number;
45 | introPrompt: string;
46 | outroPrompt: string;
47 | questions: string[];
48 | flags: number[];
49 | }
50 | ```
51 |
52 | ## State Management
53 |
54 | The application uses React's built-in state management with hooks:
55 |
56 | ```typescript
57 | // Example state management in a component
58 | const [surveys, setSurveys] = useState([]);
59 | const [loading, setLoading] = useState(false);
60 | const [error, setError] = useState(null);
61 | ```
62 |
63 | ## API Integration
64 |
65 | ### Survey Creation
66 | ```typescript
67 | const createSurvey = async (survey: SurveyModel) => {
68 | const response = await axios.post('/api/surveys', {
69 | operation: 'create',
70 | survey: survey
71 | });
72 | return response.data;
73 | };
74 | ```
75 |
76 | ### Survey Results Processing
77 | ```typescript
78 | const processSurveyResponse = async (response) => {
79 | await axios.post('/api/surveys/results', {
80 | surveyId: response.surveyId,
81 | contactId: response.contactId,
82 | responses: response.answers
83 | });
84 | };
85 | ```
86 |
87 | ## Authentication Flow
88 |
89 | 1. User enters credentials
90 | 2. Cognito authentication
91 | 3. JWT token storage
92 | 4. Protected route access
93 |
94 | ```typescript
95 | // Example protected route
96 | const ProtectedRoute = ({ children }) => {
97 | const { isAuthenticated } = useAuth();
98 | return isAuthenticated ? children : ;
99 | };
100 | ```
101 |
102 | ## Error Handling
103 |
104 | ```typescript
105 | try {
106 | const result = await createSurvey(surveyData);
107 | // Handle success
108 | } catch (error) {
109 | if (error.response) {
110 | // Handle API error
111 | setError(error.response.data.message);
112 | } else {
113 | // Handle network error
114 | setError('Network error occurred');
115 | }
116 | }
117 | ```
118 |
119 | ## Component Examples
120 |
121 | ### Survey Form
122 | ```typescript
123 | const SurveyForm = () => {
124 | const [survey, setSurvey] = useState({
125 | surveyId: '',
126 | surveyName: '',
127 | max: 5,
128 | min: 1,
129 | introPrompt: '',
130 | outroPrompt: '',
131 | questions: [],
132 | flags: []
133 | });
134 |
135 | const handleSubmit = async (e: React.FormEvent) => {
136 | e.preventDefault();
137 | try {
138 | await createSurvey(survey);
139 | // Handle success
140 | } catch (error) {
141 | // Handle error
142 | }
143 | };
144 |
145 | return (
146 |
149 | );
150 | };
151 | ```
152 |
153 | ### Survey List
154 | ```typescript
155 | const SurveyList = () => {
156 | const [surveys, setSurveys] = useState([]);
157 |
158 | useEffect(() => {
159 | const fetchSurveys = async () => {
160 | const response = await axios.get('/api/surveys');
161 | setSurveys(response.data);
162 | };
163 | fetchSurveys();
164 | }, []);
165 |
166 | return (
167 |