{"id":351322,"date":"2024-05-20T12:18:03","date_gmt":"2024-05-20T12:18:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=351322"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=351322","title":{"rendered":"<span>How to create sound cloud\u00a0platform \u2014 notes<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<ol>\n<li>\n<p><a href=\"#prerequisite-registe-qjeg\" rel=\"noopener noreferrer nofollow\">Prerequisite: registered domain name<\/a><\/p>\n<ol>\n<li>\n<p><a href=\"#create-route-53-a-re-yuip\" rel=\"noopener noreferrer nofollow\">Create Route 53\u00a0A record<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#configure-acm-certif-dxxn\" rel=\"noopener noreferrer nofollow\">Configure ACM certificate in N. Virginia region <em>.example.com<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p><a href=\"#create-s3-bucket-wit-tckw\" rel=\"noopener noreferrer nofollow\"><em>Create s3 bucket with website feature to host static files<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-cloudfront-di-ahjo\" rel=\"noopener noreferrer nofollow\"><em>Create Cloudfront distribution and attach ACM cert to it<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-cognito-user-faia\" rel=\"noopener noreferrer nofollow\"><em>Create Cognito User Pool<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#attach-own-domain-to-ltbo\" rel=\"noopener noreferrer nofollow\"><em>Attach own domain to Cognito User Pool<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#inside-cognito-user-ocza\" rel=\"noopener noreferrer nofollow\"><em>Inside Cognito User Pool create web app client and Configure redirect URL<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-lambda-functi-spcx\" rel=\"noopener noreferrer nofollow\"><em>Create Lambda Function for signup will fetch user image from google\/fb<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<p><a href=\"#it-may-seem-obvious-xcek\" rel=\"noopener noreferrer nofollow\"><em>It may seem obvious but lambda has to have permission to s3\/dynamodb<\/em><\/a><\/p>\n<p><a href=\"#create-api-gateway-r-qbcy\" rel=\"noopener noreferrer nofollow\"><em>Create API Gateway REST API with Lambda as handler<\/em><\/a><\/p>\n<p><a href=\"#don-t-forget-to-enab-mkde\" rel=\"noopener noreferrer nofollow\"><em>don\u2019t forget to enable CORS, attach custom domain<\/em><\/a><\/p>\n<ol>\n<li>\n<p><a href=\"#create-api-gateway-a-hyfm\" rel=\"noopener noreferrer nofollow\"><em>Create API Gateway Authorizer<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<p><em>Create Usage plan<\/em><\/p>\n<p><em>Create Stage<\/em><\/p>\n<p><em>To enable logging you must create IAM role<\/em><\/p>\n<p><em>After processing of the track is finished successfully we send message to dedicated fifo queue.<\/em><\/p>\n<p><code>Outdated tracks(now\u200a\u2014\u200acreated_at &lt; [reasonable time delta] AND status == \u2018preparing\u2019) deleted.<\/code><\/p>\n<ol>\n<li>\n<p><a href=\"#create-es-domain-att-atke\" rel=\"noopener noreferrer nofollow\"><em>Create ES domain. Attach policy to access Kibana(in our case from ext acc lambda and from local ip):<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<h3>Using AWS to create Sound sharing\u00a0platform<\/h3>\n<h3>Prerequisite: registered domain\u00a0name<\/h3>\n<h3>Create Route 53 A\u00a0record<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f67\/9b0\/06e\/f679b006ee0acc4a8b9eedf95141767a.png\" alt=\"Attachment\" width=\"800\" height=\"500\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f67\/9b0\/06e\/f679b006ee0acc4a8b9eedf95141767a.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Configure ACM certificate in N. Virginia region .example.com<\/h3>\n<h3>Create s3 bucket with website feature to host static\u00a0files<\/h3>\n<p><em>Create s3 bucket for avatars\/artworks<\/em><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/307\/99d\/c3e\/30799dc3ef259eff68a864608670e114.png\" alt=\"Attachment\" width=\"800\" height=\"500\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/307\/99d\/c3e\/30799dc3ef259eff68a864608670e114.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create Cloudfront distribution and attach ACM cert to\u00a0it<\/h3>\n<h3>Create Cognito User\u00a0Pool<\/h3>\n<h3>Attach own domain to Cognito User\u00a0Pool<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f52\/bcf\/6c6\/f52bcf6c63c6ddf3b92e6f465ffe2fed.png\" alt=\"Screenshot 2021-01-22 at 12.53.03\" width=\"800\" height=\"437\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f52\/bcf\/6c6\/f52bcf6c63c6ddf3b92e6f465ffe2fed.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-01-22 at 12.53.03<\/figcaption><\/div>\n<\/figure>\n<h3>Inside Cognito User Pool create web app client and Configure redirect\u00a0URL<\/h3>\n<h3>Create Lambda \u00a0signup post confirmation trigger Function it will fetch user image from google\/fb<\/h3>\n<h3>It may seem obvious but lambda has to have permission to s3\/dynamodb<\/h3>\n<h3>Create API Gateway REST API with Lambda as\u00a0handler<\/h3>\n<h3>don\u2019t forget to enable CORS, attach custom\u00a0domain<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/779\/488\/83d\/77948883df147df9b7acd2b46a2bf8e6.png\" alt=\"Attachment\" width=\"800\" height=\"500\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/779\/488\/83d\/77948883df147df9b7acd2b46a2bf8e6.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create dynamodb users table with sub as partition key<\/h3>\n<pre><code>export type User = {  username: string  date_joined: Date  first_name: string  last_name: string  city: string  country: string  description: string  email: string  track_count: number  avatar_url: string  permalink: string}<\/code><\/pre>\n<h3>Create API Gateway Authorizer<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/689\/a3c\/ad2\/689a3cad297cc6789072220028dbb390.png\" alt=\"Attachment\" width=\"739\" height=\"588\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/689\/a3c\/ad2\/689a3cad297cc6789072220028dbb390.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create Usage\u00a0plan<\/h3>\n<h3>Create Stage<\/h3>\n<h3>To enable logging you must create IAM\u00a0role<\/h3>\n<p><em>why did I choose DynamoDB: for example facebook users tend to read but not to post. Keep data ready to read = writing could be more complex<\/em><\/p>\n<p><strong><em>API GW\u200a\u2014\u200aUse id_token, assign api key, usage plan, custom domain path mapping<\/em><\/strong><\/p>\n<p><em>Attach authorizer to appropriate endpoints<\/em><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c7\/f9e\/b75\/6c7f9eb75153d020217da58ef10c1f2d.png\" alt=\"Attachment\" width=\"800\" height=\"473\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6c7\/f9e\/b75\/6c7f9eb75153d020217da58ef10c1f2d.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4f1\/0ce\/72c\/4f10ce72cabc4056b44b5e104e9b37a1.png\" alt=\"Attachment\" width=\"800\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4f1\/0ce\/72c\/4f10ce72cabc4056b44b5e104e9b37a1.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<p><em>Create user pool trigger on Post confirmation event to store user in db\u00a0<\/em><strong><em>!!!<\/em><\/strong><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ec3\/38e\/293\/ec338e293a33de189521972614860dd0.png\" alt=\"Attachment\" width=\"800\" height=\"500\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ec3\/38e\/293\/ec338e293a33de189521972614860dd0.png\"\/><\/p>\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<p><em>Build FFmpeg with dumpwave-filter patch applied or use prepared lambda package humeniukd\/ffmpeg-lambda.<\/em><\/p>\n<p><em>Create two s3 buckets first for incoming audio and second for storing processed mp3 along with json.<\/em><\/p>\n<p><em>For incoming bucket setup trigger for PUT event to execute wf-lambda function.<\/em><\/p>\n<p><em>Upload policy endpoint for generating presigned s3 url to PUT\/POST new uploads<\/em><\/p>\n<h3>After processing of the track is finished successfully we send message to dedicated fifo queue. Outdated tracks(now\u200a\u2014\u200acreated_at &lt; [reasonable time delta] AND status == \u2018preparing\u2019) deleted.<\/h3>\n<h3>Create ES domain. Attach policy to access Kibana(in our case from ext acc lambda and from local\u00a0ip):<\/h3>\n<pre><code>{  \"Version\": \"2012\u201310\u201317\",  \"Statement\": [    {      \"Effect\": \"Allow\",      \"Principal\": {        \"AWS\": \"arn:aws:iam::HIDDEN:role\/yes\"      },      \"Action\": \"es:\",      \"Resource\": \"arn:aws:es:eu-central-1: HIDDEN:domain\/ohyo\/\"    },    {      \"Effect\": \"Allow\",      \"Principal\": {        \"AWS\": \"\"      },      \"Action\": \"es:\",      \"Resource\": \"arn:aws:es:eu-central-1: HIDDEN:domain\/ohyo\/*\",      \"Condition\": {        \"IpAddress\": {          \"aws:SourceIp\": \"AA.BB.CC.DD\"        }      }    }  ]}<\/code><\/pre>\n<p>Create mapping for tags autocomplete suggested<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2b8\/811\/9ee\/2b88119ee7b8d194ba564d7826e99422.png\" alt=\"Screenshot 2021-01-22 at 10.52.53\" width=\"800\" height=\"395\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2b8\/811\/9ee\/2b88119ee7b8d194ba564d7826e99422.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-01-22 at 10.52.53<\/figcaption><\/div>\n<\/figure>\n<p>Put tags to new index<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6aa\/a9d\/4f4\/6aaa9d4f4f46411691fd0def1101f3a6.png\" alt=\"Screenshot 2021-01-22 at 10.54.06\" width=\"789\" height=\"369\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6aa\/a9d\/4f4\/6aaa9d4f4f46411691fd0def1101f3a6.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-01-22 at 10.54.06<\/figcaption><\/div>\n<\/figure>\n<p>Create endpoint to retrieve tags for autocompletion<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3c8\/157\/fd9\/3c8157fd91d6c06cadda9f962e274915.png\" alt=\"Screenshot 2021-01-22 at 22.30.45\" width=\"800\" height=\"408\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3c8\/157\/fd9\/3c8157fd91d6c06cadda9f962e274915.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-01-22 at 22.30.45<\/figcaption><\/div>\n<\/figure>\n<p>Create endpoint to save track metadata<\/p>\n<p>Create endpoint to resolve track\/user by permalink<\/p>\n<p>To respond with status 404 lambda should throw Error with message text recognised by API Gateway:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/26b\/036\/0c3\/26b0360c35e92aa4045c48b613d92b40.png\" alt=\"Screenshot 2021-01-31 at 15.39.25\" width=\"800\" height=\"407\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/26b\/036\/0c3\/26b0360c35e92aa4045c48b613d92b40.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-01-31 at 15.39.25<\/figcaption><\/div>\n<\/figure>\n<p>-Put item to dynamodb(update user)<\/p>\n<p>Export API as swagger JSON<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/424\/7aa\/f0b\/4247aaf0b1673d7ba2dc630a2396e150.png\" alt=\"Screenshot 2021-02-09 at 22.06.20\" width=\"800\" height=\"451\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/424\/7aa\/f0b\/4247aaf0b1673d7ba2dc630a2396e150.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-02-09 at 22.06.20<\/figcaption><\/div>\n<\/figure>\n<p>Generate types on the FE side using yarn generate:types<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/300\/702\/3bd\/3007023bd2f496e3e299979623c7f569.png\" alt=\"Screenshot 2021-02-09 at 22.10.05\" width=\"800\" height=\"221\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/300\/702\/3bd\/3007023bd2f496e3e299979623c7f569.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-02-09 at 22.10.05<\/figcaption><\/div>\n<\/figure>\n<p>-Refresh ES index for search<\/p>\n<p>Configure api gateway template mapping for skipping empty fields<\/p>\n<p>Create user stream pagination using user_id as partition key and created_at as sort key<\/p>\n<p>If LastEvaluatedKey is present use it for next url query params<\/p>\n<p>Set up dynamodb stream to process newly created comments<\/p>\n<p>To POST artwork img configure api to accept encodings such as<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/494\/eb1\/6d6\/494eb16d662a2c20004736cc855ca34f.png\" alt=\"Screenshot 2021-02-25 at 15.15.17\" width=\"800\" height=\"405\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/494\/eb1\/6d6\/494eb16d662a2c20004736cc855ca34f.png\"\/><\/p>\n<div><figcaption>Screenshot 2021-02-25 at 15.15.17<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>Go to the API Gateway settings tab for your API and add multipart\/form-data, image\/jpeg to the\u00a0<em>binary media types<\/em>section.<\/p>\n<\/li>\n<li>\n<p>Add Content-Type and Accept to the request headers for your proxy method<\/p>\n<\/li>\n<li>\n<p>Add Access-Control-Allow-Methods to Method Response headers<\/p>\n<\/li>\n<li>\n<p>Re-deploy the API<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/752650\/\"> https:\/\/habr.com\/ru\/articles\/752650\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<ol>\n<li>\n<p><a href=\"#prerequisite-registe-qjeg\" rel=\"noopener noreferrer nofollow\">Prerequisite: registered domain name<\/a><\/p>\n<ol>\n<li>\n<p><a href=\"#create-route-53-a-re-yuip\" rel=\"noopener noreferrer nofollow\">Create Route 53\u00a0A record<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#configure-acm-certif-dxxn\" rel=\"noopener noreferrer nofollow\">Configure ACM certificate in N. Virginia region <em>.example.com<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p><a href=\"#create-s3-bucket-wit-tckw\" rel=\"noopener noreferrer nofollow\"><em>Create s3 bucket with website feature to host static files<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-cloudfront-di-ahjo\" rel=\"noopener noreferrer nofollow\"><em>Create Cloudfront distribution and attach ACM cert to it<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-cognito-user-faia\" rel=\"noopener noreferrer nofollow\"><em>Create Cognito User Pool<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#attach-own-domain-to-ltbo\" rel=\"noopener noreferrer nofollow\"><em>Attach own domain to Cognito User Pool<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#inside-cognito-user-ocza\" rel=\"noopener noreferrer nofollow\"><em>Inside Cognito User Pool create web app client and Configure redirect URL<\/em><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#create-lambda-functi-spcx\" rel=\"noopener noreferrer nofollow\"><em>Create Lambda Function for signup will fetch user image from google\/fb<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<p><a href=\"#it-may-seem-obvious-xcek\" rel=\"noopener noreferrer nofollow\"><em>It may seem obvious but lambda has to have permission to s3\/dynamodb<\/em><\/a><\/p>\n<p><a href=\"#create-api-gateway-r-qbcy\" rel=\"noopener noreferrer nofollow\"><em>Create API Gateway REST API with Lambda as handler<\/em><\/a><\/p>\n<p><a href=\"#don-t-forget-to-enab-mkde\" rel=\"noopener noreferrer nofollow\"><em>don\u2019t forget to enable CORS, attach custom domain<\/em><\/a><\/p>\n<ol>\n<li>\n<p><a href=\"#create-api-gateway-a-hyfm\" rel=\"noopener noreferrer nofollow\"><em>Create API Gateway Authorizer<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<p><em>Create Usage plan<\/em><\/p>\n<p><em>Create Stage<\/em><\/p>\n<p><em>To enable logging you must create IAM role<\/em><\/p>\n<p><em>After processing of the track is finished successfully we send message to dedicated fifo queue.<\/em><\/p>\n<p><code>Outdated tracks(now\u200a\u2014\u200acreated_at &lt; [reasonable time delta] AND status == \u2018preparing\u2019) deleted.<\/code><\/p>\n<ol>\n<li>\n<p><a href=\"#create-es-domain-att-atke\" rel=\"noopener noreferrer nofollow\"><em>Create ES domain. Attach policy to access Kibana(in our case from ext acc lambda and from local ip):<\/em><\/a><\/p>\n<\/li>\n<\/ol>\n<h3>Using AWS to create Sound sharing\u00a0platform<\/h3>\n<h3>Prerequisite: registered domain\u00a0name<\/h3>\n<h3>Create Route 53 A\u00a0record<\/h3>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Configure ACM certificate in N. Virginia region .example.com<\/h3>\n<h3>Create s3 bucket with website feature to host static\u00a0files<\/h3>\n<p><em>Create s3 bucket for avatars\/artworks<\/em><\/p>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create Cloudfront distribution and attach ACM cert to\u00a0it<\/h3>\n<h3>Create Cognito User\u00a0Pool<\/h3>\n<h3>Attach own domain to Cognito User\u00a0Pool<\/h3>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-01-22 at 12.53.03<\/figcaption><\/div>\n<\/figure>\n<h3>Inside Cognito User Pool create web app client and Configure redirect\u00a0URL<\/h3>\n<h3>Create Lambda \u00a0signup post confirmation trigger Function it will fetch user image from google\/fb<\/h3>\n<h3>It may seem obvious but lambda has to have permission to s3\/dynamodb<\/h3>\n<h3>Create API Gateway REST API with Lambda as\u00a0handler<\/h3>\n<h3>don\u2019t forget to enable CORS, attach custom\u00a0domain<\/h3>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create dynamodb users table with sub as partition key<\/h3>\n<pre><code>export type User = {  username: string  date_joined: Date  first_name: string  last_name: string  city: string  country: string  description: string  email: string  track_count: number  avatar_url: string  permalink: string}<\/code><\/pre>\n<h3>Create API Gateway Authorizer<\/h3>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<h3>Create Usage\u00a0plan<\/h3>\n<h3>Create Stage<\/h3>\n<h3>To enable logging you must create IAM\u00a0role<\/h3>\n<p><em>why did I choose DynamoDB: for example facebook users tend to read but not to post. Keep data ready to read = writing could be more complex<\/em><\/p>\n<p><strong><em>API GW\u200a\u2014\u200aUse id_token, assign api key, usage plan, custom domain path mapping<\/em><\/strong><\/p>\n<p><em>Attach authorizer to appropriate endpoints<\/em><\/p>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<p><em>Create user pool trigger on Post confirmation event to store user in db\u00a0<\/em><strong><em>!!!<\/em><\/strong><\/p>\n<figure class=\"full-width\">\n<div><figcaption>Attachment<\/figcaption><\/div>\n<\/figure>\n<p><em>Build FFmpeg with dumpwave-filter patch applied or use prepared lambda package humeniukd\/ffmpeg-lambda.<\/em><\/p>\n<p><em>Create two s3 buckets first for incoming audio and second for storing processed mp3 along with json.<\/em><\/p>\n<p><em>For incoming bucket setup trigger for PUT event to execute wf-lambda function.<\/em><\/p>\n<p><em>Upload policy endpoint for generating presigned s3 url to PUT\/POST new uploads<\/em><\/p>\n<h3>After processing of the track is finished successfully we send message to dedicated fifo queue. Outdated tracks(now\u200a\u2014\u200acreated_at &lt; [reasonable time delta] AND status == \u2018preparing\u2019) deleted.<\/h3>\n<h3>Create ES domain. Attach policy to access Kibana(in our case from ext acc lambda and from local\u00a0ip):<\/h3>\n<pre><code>{  \"Version\": \"2012\u201310\u201317\",  \"Statement\": [    {      \"Effect\": \"Allow\",      \"Principal\": {        \"AWS\": \"arn:aws:iam::HIDDEN:role\/yes\"      },      \"Action\": \"es:\",      \"Resource\": \"arn:aws:es:eu-central-1: HIDDEN:domain\/ohyo\/\"    },    {      \"Effect\": \"Allow\",      \"Principal\": {        \"AWS\": \"\"      },      \"Action\": \"es:\",      \"Resource\": \"arn:aws:es:eu-central-1: HIDDEN:domain\/ohyo\/*\",      \"Condition\": {        \"IpAddress\": {          \"aws:SourceIp\": \"AA.BB.CC.DD\"        }      }    }  ]}<\/code><\/pre>\n<p>Create mapping for tags autocomplete suggested<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-01-22 at 10.52.53<\/figcaption><\/div>\n<\/figure>\n<p>Put tags to new index<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-01-22 at 10.54.06<\/figcaption><\/div>\n<\/figure>\n<p>Create endpoint to retrieve tags for autocompletion<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-01-22 at 22.30.45<\/figcaption><\/div>\n<\/figure>\n<p>Create endpoint to save track metadata<\/p>\n<p>Create endpoint to resolve track\/user by permalink<\/p>\n<p>To respond with status 404 lambda should throw Error with message text recognised by API Gateway:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-01-31 at 15.39.25<\/figcaption><\/div>\n<\/figure>\n<p>-Put item to dynamodb(update user)<\/p>\n<p>Export API as swagger JSON<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-02-09 at 22.06.20<\/figcaption><\/div>\n<\/figure>\n<p>Generate types on the FE side using yarn generate:types<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-02-09 at 22.10.05<\/figcaption><\/div>\n<\/figure>\n<p>-Refresh ES index for search<\/p>\n<p>Configure api gateway template mapping for skipping empty fields<\/p>\n<p>Create user stream pagination using user_id as partition key and created_at as sort key<\/p>\n<p>If LastEvaluatedKey is present use it for next url query params<\/p>\n<p>Set up dynamodb stream to process newly created comments<\/p>\n<p>To POST artwork img configure api to accept encodings such as<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Screenshot 2021-02-25 at 15.15.17<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>Go to the API Gateway settings tab for your API and add multipart\/form-data, image\/jpeg to the\u00a0<em>binary media types<\/em>section.<\/p>\n<\/li>\n<li>\n<p>Add Content-Type and Accept to the request headers for your proxy method<\/p>\n<\/li>\n<li>\n<p>Add Access-Control-Allow-Methods to Method Response headers<\/p>\n<\/li>\n<li>\n<p>Re-deploy the API<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/752650\/\"> https:\/\/habr.com\/ru\/articles\/752650\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-351322","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/351322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=351322"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/351322\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=351322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=351322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=351322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}