ㄷ목차
관련 링크: https://github.com/tstachlewski/serverless-survey/
AWS 관리 콘솔의 Lambda 함수를 만들 때 SAM(Serverless Application Model)을 이용해서 기존에 만들어진 Survey를 차용하여 사용할 수 있습니다.
https://y85teb42e2.execute-api.us-east-1.amazonaws.com/Prod/newsurvey
#-*- coding: utf-8 -*- import yaml import sys import json from yattag import Doc def lambda_handler(event, context): # print(event['requestContext']['queryStringParameters']['email']) print(json.dumps(event)) if event['queryStringParameters'] is not None: if event['queryStringParameters'].has_key('email'): email = event['queryStringParameters']['email'] else: email = 'anonymous' else: email = 'anonymous' sourceIp = event['requestContext']['identity']['sourceIp'] requesTime = event['requestContext']['requestTimeEpoch'] configuration = yaml.load(open("config.yaml").read()) questions = configuration['Questions']; title = configuration['Title']; author = configuration['Author']; image1 = configuration['Image1']; image2 = configuration['Image2']; theme = configuration['Theme']; questionsNames = list() for questionIterator in questions: questionsNames.append(questionIterator) questionsNames.sort() doc, tag, text = Doc().tagtext() with tag('html'): with tag('body'): doc.stag('br') with tag('div', align='center'): with doc.tag('div', style="font-size: medium;font-weight: bold; font-family: verdana; color:#" + str(theme) + ";"): text(title) doc.stag('br') with doc.tag('div', style="font-size: small; font-weight: bold; font-family: verdana;"): text("by " + author) doc.stag('br') doc.stag('img', src=image1, width="300") doc.stag('br') doc.stag('br') with tag('form', action = "submitsurvey", style="margin-left: auto; margin-right: auto; width: 70%;"): doc.input(name = 'title', type = 'hidden', value = title) doc.input(name = 'email', type = 'hidden', value = email) doc.input(name = 'sourceIp', type = 'hidden', value = sourceIp) doc.input(name = 'requesTime', type = 'hidden', value = requesTime) for questionName in questionsNames: with tag('div'): questionLabel = questions[questionName]['Label'] questionType = questions[questionName]['Type'] questionNumber = questions[questionName]['Qnumber'] #doc.stag('font', size="4", style="font-weight: bold; font-family: verdana; color:#" + str(theme) + ";") with doc.tag('div',style="font-size: medium;font-weight: bold; font-family: verdana; color:#" + str(theme) + ";"): with doc.tag('p'): with doc.tag('span', style="font-family: arial, helvetica, sans-serif;padding: 3px 10px 3px 10px;border-radius: 25px;text-align: center;width: 50px;background-color: #377F9F;color: white;font-size : 14px;"): doc.asis("Q " + questionNumber) with doc.tag('span'): doc.asis(" " + questionLabel) if (questionType == "Label"): value = questions[questionName]['Value'] with doc.tag('a', href=value, target="_blank",): doc.asis(value) doc.stag('br') pass if (questionType == "Text"): with doc.textarea(name = questionNumber, style="width: 100%; border-color: #" + str(theme) + "; " , rows="5", placeholder="최대 한글 300자까지 가능합니다."): pass if (questionType == "ShortText"): with doc.textarea(name = questionNumber, style="width: 100%; border-color: #" + str(theme) + "; " , rows="1"): pass if (questionType == "Radio"): values = questions[questionName]['Values'] with doc.tag('table', style="table-layout: fixed;width: 100%;border-collapse: collapse;border: 1px solid gray;"): with doc.tag('tr'): for valueIterator in values: value = questions[questionName]['Values'][valueIterator] with doc.tag('td', style="font-family: arial, helvetica, sans-serif;text-align: center;width:20%;border: 1px solid gray;padding:10;"): doc.asis(value); with doc.tag('tr'): for valueIterator in values: value = questions[questionName]['Values'][valueIterator] with doc.tag('td', style="font-family: arial, helvetica, sans-serif;text-align: center;width:20%;border: 1px solid gray;padding:10;"): doc.input(name = questionNumber, type = 'radio', value = value, style="border-color: #" + str(theme) + "; ") # for valueIterator in values: # value = questions[questionName]['Values'][valueIterator] # with doc.tag('div', style="font-size: small; font-weight: normal; font-family: verdana; color:black;"): # doc.input(name = questionName, type = 'radio', value = value, style="border-color: #" + str(theme) + "; ") # text(" "+str(value)) # doc.stag('br') if (questionType == "CheckBox"): with tag('fieldset',style="border: 0px; padding: 0px; font-size: small; font-weight: normal; font-family: verdana; color:black;"): values = list(questions[questionName]['Values']) for valueIterator in values: value = questions[questionName]['Values'][valueIterator] field_name = questionName + "_" + "".join([ c if c.isalnum() else "_" for c in value.lower() ]) doc.input(name = questionNumber, type = 'hidden', value = "0",style="border-color: #" + str(theme) + "; ") doc.input(name = questionNumber, id = field_name , type = 'checkbox', value = "1", style="border-color: #" + str(theme) + "; ") text(" "+str(value)) doc.stag('br') doc.stag('br') doc.stag('br') with doc.tag('div', style="text-align: center;"): doc.stag('input', type = "submit", value = "설문 완료", style="background-color:#50AEEB;border:none;color:white;padding:10px 30px;text-align: center; text-decoration: none; display: inline-block;font-size: 16px;margin: 4px 2px;border-radius: 12px;cursor: pointer;") htmlResult = doc.getvalue() return { 'statusCode': "200", 'body': htmlResult, 'headers': { 'Content-Type': 'text/html; charset=utf-8', } } |
Title: AWS 2020년 2월 19일 미팅 설문조사 Author: Solutions Architect 김현수 Image1: https://a0.awsstatic.com/libra-css/images/logos/aws_logo_smile_1200x630.png Image2: https://a0.awsstatic.com/libra-css/images/logos/aws_logo_smile_1200x630.png Theme: 282828 Questions: q1: Type: Radio Qnumber: 1-1 Label: AWS와의 금일 미팅에 대해서 만족하십니까? Values: Value5: 매우 만족 Value4: 만족 Value3: 중립 Value2: 불만족 Value1: 매우 불만족 q2: Type: Text Qnumber: 1-2 Label: AWS와의 미팅에서 만족한 이유 또는 개선해야 할 점이 있다면 적어주세요. q3: Type: Radio Qnumber: 2-1 Label: 미팅 시간은 적절하였나요? Values: Value5: 매우 적절 Value4: 적절 Value3: 중립 Value2: 시간 부족 q4: Type: CheckBox Qnumber: 3-1 Label: 현재 프로젝트와 관련하여 어떤 서비스가 도움이 될 것이라고 생각하십니까? Values: Value8: "잘 모르겠다" Value7: "Amazon Pinpoint" Value6: "Amazon API Gateway" Value5: "AWS Lambda" Value4: "Amazon DynamoDB" Value3: "Amazon QuickSight" Value2: "Amazon Comprehend" Value1: "기타" q5: Type: Radio Qnumber: 4-1 Label: AWS의 Solutions Architect와의 미팅을 다른 고객들에게 추천하시겠습니까? Values: Value5: 적극 추천 Value4: 추천 Value3: 중립 Value2: 비추천 Value1: 절대 비추천 q6: Type: Text Qnumber: 4-2 Label: AWS의 Solutions Architect와의 미팅을 추천하는 이유 또는 개선해야 할 점이 있다면 적어주세요. q7: Type: Text Qnumber: 5-1 Label: AWS에 요청하고 싶은 내용이 있다면 적어주세요. q8: Type: Label Qnumber: 6-1 Label: 아래 링크에서 금일 미팅 관련 정보를 제공해 드립니다. Value: http://wiki.studydev.com/pages/viewpage.action?pageId=48923317 |
동시에 여러명의 서베이 요청을 수행하기 위해서는 DynamoDB의 WCU를 고려해야 합니다.
따라서 아래와 같은 형태의 아키텍쳐를 고려할 수 있습니다.
관련 블로그: Things to Consider When You Build REST APIs with Amazon API Gateway
2.1 Segment를 만듭니다.
csv, json 포맷으로 작성하고 등록하면 됩니다. (아래와 같은 형태)
2.2 이메일 템플릿을 제작합니다.
<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <font face="Arial"> <table cellpadding="0" cellspacing="0" width="100%"> <tbody> <tr> <td width="100"> <img src="https://a0.awsstatic.com/libra-css/images/logos/aws_logo_smile_1200x630.png" alt="Amazon Web Services Logo" height="50"> </td> <td style="text-align:right;padding-right:10px"> <font size="2"><a href="https://aws.amazon.com/">aws.amazon.com</a> </font> </td> </tr> </tbody> </table> <hr> <br> <div style="height: 200px; overflow: hidden;text-align:center"> <img src="https://d1.awsstatic.com/product-marketing/Pinpoint/Pinpoint%20Web%20Illustrations_EngagementManagement-Editorial.08da4e3b599fbbcd18ab5a85b991b4b8077fe509.png" alt="Aamazon Pinpoint Journey" style="height:200px; margin:0px 0 0 0;"> </div> <br> <div style="padding:20px;"> <h4>AWS와의 미팅은 즐거우셨나요?</h4> <div> 고객님의 소중한 의견을 모아 더 나은 서비스로 보답하고자 설문조사를 실시하고 있습니다. 잠시만 시간을 내주시면 감사하겠습니다. </div> <br> <h4>We Hope you had a pleasant trip with Amazon Web Services.</h4> <div> Please answer this short survey to share your experience with us. Your valuable feedback will be userd to futher enhance our services. </div> </div> <br> <div style="text-align:center"> <a href="https://y85teb42e2.execute-api.us-east-1.amazonaws.com/Prod/newsurvey?email={{Address}}"> <button style="background-color:#50AEEB;border:none;color:white;padding:15px;text-align: center; text-decoration: none; display: inline-block;font-size: 16px;margin: 4px 2px;border-radius: 12px;">설문조사 바로가기 / Start Survey</button> </a> </div> <br> <font color="white"> <table bgcolor="#757F88" cellpadding="0" cellspacing="0" width="100%" style="font-size:75%"> <tbody> <tr> <th width="20"> </th> <th> </th> <th width="20"> </th> </tr> <tr> <td> </td> <td> <ul style="padding-left:20px;"> <li> <b>E-MAIL 발송 정보</b> </li> <div> 본 이메일은 금번 미팅에 참석해 주신 분들께만 발송되었습니다. 메일을 더 이상 받지 않으시려면 [<a href="https://aws.amazon.com/">수신거부</a>]를 눌러주시기 바랍니다. </div> </ul> <or> </or> </td> <td> </td> </tr> <tr> <td></td> <td> <div style="white-space:nowrap;text-align: right;"> <a href="https://www.facebook.com/amazonwebservices.ko/?brand_redir=153063591397681" target="_blank"><img src="https://www.koreanair.com/etc/clientlibs/koreanair/images/components/footer/icon-fb.png" alt="AWS 페이스북"></a> <a href="https://twitter.com/awscloud" target="_blank"><img src="https://www.koreanair.com/etc/clientlibs/koreanair/images/components/footer/icon-tw.png" alt="AWS 트위터"></a> </div> </td> <td></td> </tr> <tr> <td colspan="3"> </td> </tr> <tr> <td colspan="3"> </td> </tr> </tbody> </table> </font> </font> </body> </html> |
2.3 캠페인을 생성합니다. (채널: 이메일)
동일한 캠페인을 보냈지만, 서로 상이한 이름과 지역 미팅 목적으로 다르게 메시지가 나가는 것을 확인 할 수 있습니다.
설문 조사를 수행 합니다.
2.4 이메일 수신 여부를 확인합니다. 설문 조사 결과도 저장 되는지 확인 합니다.
결과는 DynamoDB Table에서 확인 가능합니다.
2.5 캠페인을 모니터링 합니다.
총 3개의 Endpoint 중에서 Email 주소가 담긴 2개로만 이메일이 발송 되었고, 2개의 이메일이 오픈 되었습니다.
이메일에 있는 링크도 각각 한번씩 눌러서 2개가 클릭 된 것으로 확인됩니다.
필터링 조건을 통해서 데이터를 분석하여 볼 수 있습니다.
캠페인을 진행해서 발송한 고객 중 응답하는 고객이 있을 수 있고 그렇지 않은 고객이 있을 수 있습니다.
- 문자의 경우 스팸 처리가 되거나 또는 읽지 않거나 읽더라도 설문 조사를 참여하지 않는 경우입니다.
- 이메일의 경우 스팸 처리가 되거나 또는 읽더라도 설문 조사를 참여하지 않는 경우입니다. 해당 사용자가 몇 번의 캠페인 요청에도 응답이 없다면 다음 캠페인에서도 동일한 반응이 예상될 수 있습니다. 이럴 때는 발송을 하지 않거나 다시 돌아올 수 있도록 프로모션을 하는 것이 더 좋은 방법이 될 수 있습니다.
- 100만명의 고객이 있다 하더라도 실제 Active하게 반응 하는 고객을 추려 낼 수 있으며, RAW 데이터를 보고 싶을 경우, 이메일 캠페인에 대한 분석 설정을 진행할 수 있습니다.
실습 문서:
설문 조사 결과를 분석하고 QuickSight를 통하여 시각화를 할 수 있습니다. 예시로 아래와 같은 방법을 활용할 수 있습니다.
관련 이미지
AWS Amazon Athena와 DynamoDB와 QuickSight를 활용하는 방법: https://aws.amazon.com/jp/blogs/news/athena-federated-query-dynamodb-quicksight/
https://athena-in-action.workshop.aws/40-federatedquery/402-dynamodb-connector.html