├── .eslintrc ├── .gitignore ├── .idea ├── .gitignore ├── aws-development-with-localstack.iml ├── aws.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml ├── sonarlint │ └── issuestore │ │ └── index.pb └── vcs.xml ├── .prettierrc ├── LICENSE ├── README.md ├── bin └── app.ts ├── cdk.json ├── jest.config.js ├── lib ├── ApplicationStack.ts ├── dynamodb │ ├── index.ts │ └── test-development.ts ├── firehose │ ├── index.ts │ └── test-firehose.ts ├── iam │ ├── firehose_skeleton.json │ ├── super-role.json │ └── super-role.ts ├── s3 │ ├── index.ts │ └── screenshot.ts └── sqs │ ├── index.ts │ └── simple-sqs-development.ts ├── localstack └── docker-compose.yml ├── package-lock.json ├── package.json ├── scripts ├── config.ts └── migrationModels │ └── migrationScript.ts ├── seed ├── config.ts └── index.ts ├── test └── app.test.ts ├── tsconfig.json ├── utils └── createGlobalSecondaryIndex.ts └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "extends": ["plugin:@typescript-eslint/recommended"], 4 | "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, 5 | "rules": {} 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # This local data 107 | localstack/.localstack/ 108 | 109 | # your stack 110 | cdk.out/ 111 | /cdk.out/ 112 | setup 113 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/aws-development-with-localstack.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/aws.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 15 | 16 | 23 | 24 | 27 | 28 | 35 | 36 | 43 | 44 | 45 | 46 |
47 | 48 | 49 | (-[a-z]+-)?font 50 | 51 | BY_NAME 52 | 53 | 54 | 55 | (-[a-z]+-)?font-family 56 | 57 | BY_NAME 58 | 59 | 60 | 61 | (-[a-z]+-)?font-size 62 | 63 | BY_NAME 64 | 65 | 66 | 67 | (-[a-z]+-)?font-weight 68 | 69 | BY_NAME 70 | 71 | 72 | 73 | (-[a-z]+-)?font-style 74 | 75 | BY_NAME 76 | 77 | 78 | 79 | (-[a-z]+-)?font-variant 80 | 81 | BY_NAME 82 | 83 | 84 | 85 | (-[a-z]+-)?font-size-adjust 86 | 87 | BY_NAME 88 | 89 | 90 | 91 | (-[a-z]+-)?font-stretch 92 | 93 | BY_NAME 94 | 95 | 96 | 97 | (-[a-z]+-)?line-height 98 | 99 | BY_NAME 100 | 101 | 102 | 103 | (-[a-z]+-)?position 104 | 105 | BY_NAME 106 | 107 | 108 | 109 | (-[a-z]+-)?z-index 110 | 111 | BY_NAME 112 | 113 | 114 | 115 | (-[a-z]+-)?top 116 | 117 | BY_NAME 118 | 119 | 120 | 121 | (-[a-z]+-)?right 122 | 123 | BY_NAME 124 | 125 | 126 | 127 | (-[a-z]+-)?bottom 128 | 129 | BY_NAME 130 | 131 | 132 | 133 | (-[a-z]+-)?left 134 | 135 | BY_NAME 136 | 137 | 138 | 139 | (-[a-z]+-)?display 140 | 141 | BY_NAME 142 | 143 | 144 | 145 | (-[a-z]+-)?visibility 146 | 147 | BY_NAME 148 | 149 | 150 | 151 | (-[a-z]+-)?float 152 | 153 | BY_NAME 154 | 155 | 156 | 157 | (-[a-z]+-)?clear 158 | 159 | BY_NAME 160 | 161 | 162 | 163 | (-[a-z]+-)?overflow 164 | 165 | BY_NAME 166 | 167 | 168 | 169 | (-[a-z]+-)?overflow-x 170 | 171 | BY_NAME 172 | 173 | 174 | 175 | (-[a-z]+-)?overflow-y 176 | 177 | BY_NAME 178 | 179 | 180 | 181 | (-[a-z]+-)?clip 182 | 183 | BY_NAME 184 | 185 | 186 | 187 | (-[a-z]+-)?zoom 188 | 189 | BY_NAME 190 | 191 | 192 | 193 | (-[a-z]+-)?align-content 194 | 195 | BY_NAME 196 | 197 | 198 | 199 | (-[a-z]+-)?align-items 200 | 201 | BY_NAME 202 | 203 | 204 | 205 | (-[a-z]+-)?align-self 206 | 207 | BY_NAME 208 | 209 | 210 | 211 | (-[a-z]+-)?flex 212 | 213 | BY_NAME 214 | 215 | 216 | 217 | (-[a-z]+-)?flex-flow 218 | 219 | BY_NAME 220 | 221 | 222 | 223 | (-[a-z]+-)?flex-basis 224 | 225 | BY_NAME 226 | 227 | 228 | 229 | (-[a-z]+-)?flex-direction 230 | 231 | BY_NAME 232 | 233 | 234 | 235 | (-[a-z]+-)?flex-grow 236 | 237 | BY_NAME 238 | 239 | 240 | 241 | (-[a-z]+-)?flex-shrink 242 | 243 | BY_NAME 244 | 245 | 246 | 247 | (-[a-z]+-)?flex-wrap 248 | 249 | BY_NAME 250 | 251 | 252 | 253 | (-[a-z]+-)?justify-content 254 | 255 | BY_NAME 256 | 257 | 258 | 259 | (-[a-z]+-)?order 260 | 261 | BY_NAME 262 | 263 | 264 | 265 | (-[a-z]+-)?box-sizing 266 | 267 | BY_NAME 268 | 269 | 270 | 271 | (-[a-z]+-)?width 272 | 273 | BY_NAME 274 | 275 | 276 | 277 | (-[a-z]+-)?min-width 278 | 279 | BY_NAME 280 | 281 | 282 | 283 | (-[a-z]+-)?max-width 284 | 285 | BY_NAME 286 | 287 | 288 | 289 | (-[a-z]+-)?height 290 | 291 | BY_NAME 292 | 293 | 294 | 295 | (-[a-z]+-)?min-height 296 | 297 | BY_NAME 298 | 299 | 300 | 301 | (-[a-z]+-)?max-height 302 | 303 | BY_NAME 304 | 305 | 306 | 307 | (-[a-z]+-)?margin 308 | 309 | BY_NAME 310 | 311 | 312 | 313 | (-[a-z]+-)?margin-top 314 | 315 | BY_NAME 316 | 317 | 318 | 319 | (-[a-z]+-)?margin-right 320 | 321 | BY_NAME 322 | 323 | 324 | 325 | (-[a-z]+-)?margin-bottom 326 | 327 | BY_NAME 328 | 329 | 330 | 331 | (-[a-z]+-)?margin-left 332 | 333 | BY_NAME 334 | 335 | 336 | 337 | (-[a-z]+-)?padding 338 | 339 | BY_NAME 340 | 341 | 342 | 343 | (-[a-z]+-)?padding-top 344 | 345 | BY_NAME 346 | 347 | 348 | 349 | (-[a-z]+-)?padding-right 350 | 351 | BY_NAME 352 | 353 | 354 | 355 | (-[a-z]+-)?padding-bottom 356 | 357 | BY_NAME 358 | 359 | 360 | 361 | (-[a-z]+-)?padding-left 362 | 363 | BY_NAME 364 | 365 | 366 | 367 | (-[a-z]+-)?table-layout 368 | 369 | BY_NAME 370 | 371 | 372 | 373 | (-[a-z]+-)?empty-cells 374 | 375 | BY_NAME 376 | 377 | 378 | 379 | (-[a-z]+-)?caption-side 380 | 381 | BY_NAME 382 | 383 | 384 | 385 | (-[a-z]+-)?border-spacing 386 | 387 | BY_NAME 388 | 389 | 390 | 391 | (-[a-z]+-)?border-collapse 392 | 393 | BY_NAME 394 | 395 | 396 | 397 | (-[a-z]+-)?list-style 398 | 399 | BY_NAME 400 | 401 | 402 | 403 | (-[a-z]+-)?list-style-position 404 | 405 | BY_NAME 406 | 407 | 408 | 409 | (-[a-z]+-)?list-style-type 410 | 411 | BY_NAME 412 | 413 | 414 | 415 | (-[a-z]+-)?list-style-image 416 | 417 | BY_NAME 418 | 419 | 420 | 421 | (-[a-z]+-)?content 422 | 423 | BY_NAME 424 | 425 | 426 | 427 | (-[a-z]+-)?quotes 428 | 429 | BY_NAME 430 | 431 | 432 | 433 | (-[a-z]+-)?counter-reset 434 | 435 | BY_NAME 436 | 437 | 438 | 439 | (-[a-z]+-)?counter-increment 440 | 441 | BY_NAME 442 | 443 | 444 | 445 | (-[a-z]+-)?resize 446 | 447 | BY_NAME 448 | 449 | 450 | 451 | (-[a-z]+-)?cursor 452 | 453 | BY_NAME 454 | 455 | 456 | 457 | (-[a-z]+-)?user-select 458 | 459 | BY_NAME 460 | 461 | 462 | 463 | (-[a-z]+-)?nav-index 464 | 465 | BY_NAME 466 | 467 | 468 | 469 | (-[a-z]+-)?nav-up 470 | 471 | BY_NAME 472 | 473 | 474 | 475 | (-[a-z]+-)?nav-right 476 | 477 | BY_NAME 478 | 479 | 480 | 481 | (-[a-z]+-)?nav-down 482 | 483 | BY_NAME 484 | 485 | 486 | 487 | (-[a-z]+-)?nav-left 488 | 489 | BY_NAME 490 | 491 | 492 | 493 | (-[a-z]+-)?transition 494 | 495 | BY_NAME 496 | 497 | 498 | 499 | (-[a-z]+-)?transition-delay 500 | 501 | BY_NAME 502 | 503 | 504 | 505 | (-[a-z]+-)?transition-timing-function 506 | 507 | BY_NAME 508 | 509 | 510 | 511 | (-[a-z]+-)?transition-duration 512 | 513 | BY_NAME 514 | 515 | 516 | 517 | (-[a-z]+-)?transition-property 518 | 519 | BY_NAME 520 | 521 | 522 | 523 | (-[a-z]+-)?transform 524 | 525 | BY_NAME 526 | 527 | 528 | 529 | (-[a-z]+-)?transform-origin 530 | 531 | BY_NAME 532 | 533 | 534 | 535 | (-[a-z]+-)?animation 536 | 537 | BY_NAME 538 | 539 | 540 | 541 | (-[a-z]+-)?animation-name 542 | 543 | BY_NAME 544 | 545 | 546 | 547 | (-[a-z]+-)?animation-duration 548 | 549 | BY_NAME 550 | 551 | 552 | 553 | (-[a-z]+-)?animation-play-state 554 | 555 | BY_NAME 556 | 557 | 558 | 559 | (-[a-z]+-)?animation-timing-function 560 | 561 | BY_NAME 562 | 563 | 564 | 565 | (-[a-z]+-)?animation-delay 566 | 567 | BY_NAME 568 | 569 | 570 | 571 | (-[a-z]+-)?animation-iteration-count 572 | 573 | BY_NAME 574 | 575 | 576 | 577 | (-[a-z]+-)?animation-direction 578 | 579 | BY_NAME 580 | 581 | 582 | 583 | (-[a-z]+-)?text-align 584 | 585 | BY_NAME 586 | 587 | 588 | 589 | (-[a-z]+-)?text-align-last 590 | 591 | BY_NAME 592 | 593 | 594 | 595 | (-[a-z]+-)?vertical-align 596 | 597 | BY_NAME 598 | 599 | 600 | 601 | (-[a-z]+-)?white-space 602 | 603 | BY_NAME 604 | 605 | 606 | 607 | (-[a-z]+-)?text-decoration 608 | 609 | BY_NAME 610 | 611 | 612 | 613 | (-[a-z]+-)?text-emphasis 614 | 615 | BY_NAME 616 | 617 | 618 | 619 | (-[a-z]+-)?text-emphasis-color 620 | 621 | BY_NAME 622 | 623 | 624 | 625 | (-[a-z]+-)?text-emphasis-style 626 | 627 | BY_NAME 628 | 629 | 630 | 631 | (-[a-z]+-)?text-emphasis-position 632 | 633 | BY_NAME 634 | 635 | 636 | 637 | (-[a-z]+-)?text-indent 638 | 639 | BY_NAME 640 | 641 | 642 | 643 | (-[a-z]+-)?text-justify 644 | 645 | BY_NAME 646 | 647 | 648 | 649 | (-[a-z]+-)?letter-spacing 650 | 651 | BY_NAME 652 | 653 | 654 | 655 | (-[a-z]+-)?word-spacing 656 | 657 | BY_NAME 658 | 659 | 660 | 661 | (-[a-z]+-)?text-outline 662 | 663 | BY_NAME 664 | 665 | 666 | 667 | (-[a-z]+-)?text-transform 668 | 669 | BY_NAME 670 | 671 | 672 | 673 | (-[a-z]+-)?text-wrap 674 | 675 | BY_NAME 676 | 677 | 678 | 679 | (-[a-z]+-)?text-overflow 680 | 681 | BY_NAME 682 | 683 | 684 | 685 | (-[a-z]+-)?text-overflow-ellipsis 686 | 687 | BY_NAME 688 | 689 | 690 | 691 | (-[a-z]+-)?text-overflow-mode 692 | 693 | BY_NAME 694 | 695 | 696 | 697 | (-[a-z]+-)?word-wrap 698 | 699 | BY_NAME 700 | 701 | 702 | 703 | (-[a-z]+-)?word-break 704 | 705 | BY_NAME 706 | 707 | 708 | 709 | (-[a-z]+-)?tab-size 710 | 711 | BY_NAME 712 | 713 | 714 | 715 | (-[a-z]+-)?hyphens 716 | 717 | BY_NAME 718 | 719 | 720 | 721 | (-[a-z]+-)?pointer-events 722 | 723 | BY_NAME 724 | 725 | 726 | 727 | (-[a-z]+-)?opacity 728 | 729 | BY_NAME 730 | 731 | 732 | 733 | (-[a-z]+-)?color 734 | 735 | BY_NAME 736 | 737 | 738 | 739 | (-[a-z]+-)?border 740 | 741 | BY_NAME 742 | 743 | 744 | 745 | (-[a-z]+-)?border-width 746 | 747 | BY_NAME 748 | 749 | 750 | 751 | (-[a-z]+-)?border-style 752 | 753 | BY_NAME 754 | 755 | 756 | 757 | (-[a-z]+-)?border-color 758 | 759 | BY_NAME 760 | 761 | 762 | 763 | (-[a-z]+-)?border-top 764 | 765 | BY_NAME 766 | 767 | 768 | 769 | (-[a-z]+-)?border-top-width 770 | 771 | BY_NAME 772 | 773 | 774 | 775 | (-[a-z]+-)?border-top-style 776 | 777 | BY_NAME 778 | 779 | 780 | 781 | (-[a-z]+-)?border-top-color 782 | 783 | BY_NAME 784 | 785 | 786 | 787 | (-[a-z]+-)?border-right 788 | 789 | BY_NAME 790 | 791 | 792 | 793 | (-[a-z]+-)?border-right-width 794 | 795 | BY_NAME 796 | 797 | 798 | 799 | (-[a-z]+-)?border-right-style 800 | 801 | BY_NAME 802 | 803 | 804 | 805 | (-[a-z]+-)?border-right-color 806 | 807 | BY_NAME 808 | 809 | 810 | 811 | (-[a-z]+-)?border-bottom 812 | 813 | BY_NAME 814 | 815 | 816 | 817 | (-[a-z]+-)?border-bottom-width 818 | 819 | BY_NAME 820 | 821 | 822 | 823 | (-[a-z]+-)?border-bottom-style 824 | 825 | BY_NAME 826 | 827 | 828 | 829 | (-[a-z]+-)?border-bottom-color 830 | 831 | BY_NAME 832 | 833 | 834 | 835 | (-[a-z]+-)?border-left 836 | 837 | BY_NAME 838 | 839 | 840 | 841 | (-[a-z]+-)?border-left-width 842 | 843 | BY_NAME 844 | 845 | 846 | 847 | (-[a-z]+-)?border-left-style 848 | 849 | BY_NAME 850 | 851 | 852 | 853 | (-[a-z]+-)?border-left-color 854 | 855 | BY_NAME 856 | 857 | 858 | 859 | (-[a-z]+-)?border-radius 860 | 861 | BY_NAME 862 | 863 | 864 | 865 | (-[a-z]+-)?border-top-left-radius 866 | 867 | BY_NAME 868 | 869 | 870 | 871 | (-[a-z]+-)?border-top-right-radius 872 | 873 | BY_NAME 874 | 875 | 876 | 877 | (-[a-z]+-)?border-bottom-right-radius 878 | 879 | BY_NAME 880 | 881 | 882 | 883 | (-[a-z]+-)?border-bottom-left-radius 884 | 885 | BY_NAME 886 | 887 | 888 | 889 | (-[a-z]+-)?border-image 890 | 891 | BY_NAME 892 | 893 | 894 | 895 | (-[a-z]+-)?border-image-source 896 | 897 | BY_NAME 898 | 899 | 900 | 901 | (-[a-z]+-)?border-image-slice 902 | 903 | BY_NAME 904 | 905 | 906 | 907 | (-[a-z]+-)?border-image-width 908 | 909 | BY_NAME 910 | 911 | 912 | 913 | (-[a-z]+-)?border-image-outset 914 | 915 | BY_NAME 916 | 917 | 918 | 919 | (-[a-z]+-)?border-image-repeat 920 | 921 | BY_NAME 922 | 923 | 924 | 925 | (-[a-z]+-)?outline 926 | 927 | BY_NAME 928 | 929 | 930 | 931 | (-[a-z]+-)?outline-width 932 | 933 | BY_NAME 934 | 935 | 936 | 937 | (-[a-z]+-)?outline-style 938 | 939 | BY_NAME 940 | 941 | 942 | 943 | (-[a-z]+-)?outline-color 944 | 945 | BY_NAME 946 | 947 | 948 | 949 | (-[a-z]+-)?outline-offset 950 | 951 | BY_NAME 952 | 953 | 954 | 955 | (-[a-z]+-)?background 956 | 957 | BY_NAME 958 | 959 | 960 | 961 | (-[a-z]+-)?background-color 962 | 963 | BY_NAME 964 | 965 | 966 | 967 | (-[a-z]+-)?background-image 968 | 969 | BY_NAME 970 | 971 | 972 | 973 | (-[a-z]+-)?background-repeat 974 | 975 | BY_NAME 976 | 977 | 978 | 979 | (-[a-z]+-)?background-attachment 980 | 981 | BY_NAME 982 | 983 | 984 | 985 | (-[a-z]+-)?background-position 986 | 987 | BY_NAME 988 | 989 | 990 | 991 | (-[a-z]+-)?background-position-x 992 | 993 | BY_NAME 994 | 995 | 996 | 997 | (-[a-z]+-)?background-position-y 998 | 999 | BY_NAME 1000 | 1001 | 1002 | 1003 | (-[a-z]+-)?background-clip 1004 | 1005 | BY_NAME 1006 | 1007 | 1008 | 1009 | (-[a-z]+-)?background-origin 1010 | 1011 | BY_NAME 1012 | 1013 | 1014 | 1015 | (-[a-z]+-)?background-size 1016 | 1017 | BY_NAME 1018 | 1019 | 1020 | 1021 | (-[a-z]+-)?box-decoration-break 1022 | 1023 | BY_NAME 1024 | 1025 | 1026 | 1027 | (-[a-z]+-)?box-shadow 1028 | 1029 | BY_NAME 1030 | 1031 | 1032 | 1033 | (-[a-z]+-)?text-shadow 1034 | 1035 | BY_NAME 1036 | 1037 |
1038 |
1039 |
1040 |
1041 | 1042 | 1049 | 1050 | 1055 |
1056 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/index.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pub-technology/aws-development-with-localstack/ffbfcb15ed4313928c10c052a2ecf8d86f063d79/.idea/sonarlint/issuestore/index.pb -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 120, 6 | "tabWidth": 2 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 haithai91 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS CDK & Localstack (Local Development) 2 | 3 | ![123](https://user-images.githubusercontent.com/18282144/146704241-769f8c06-8981-411b-a055-3e3649bbc86f.png) 4 | 5 | ## A few benefits of this approach are 6 | - You can run the lambda function locally 7 | - Don’t impact your team by sharing the same env ( update on the same buckets, same records ) 8 | - Debug & Speed up your working 9 | - Don’t need to worry about paying for AWS usage for stupid action 🥰 10 | 11 | 12 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 13 | 14 | ## Useful commands 15 | 16 | * `yarn build` compile typescript to js 17 | * `yarn lint` check code style 18 | * `yarn destroy` destroy the current stack 19 | * `yarn deploy` deploy this stack to your default AWS account/region 20 | * `yarn bootstrap` clean up env 21 | 22 | 23 | ## Install & Setup LocalStack 24 | 1. Install Docker if you haven’t already. 25 | https://docs.docker.com/get-docker/ 26 | 2. Install AWS CLI. While we won’t be working with “real” AWS 27 | we will be using it to communicate with our local docker containers. 28 | https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html 29 | 30 | ## Install AWS CDK Local 31 | 32 | Avoid the mistake when we use `cdk` command maybe it can impact to real environment 33 | This lib provides a thin wrapper script cdklocal for using the AWS CDK library against local APIs provided by LocalStack. 34 | Refer : https://github.com/localstack/aws-cdk-local 35 | 36 | ```shell 37 | npm install -g aws-cdk-local aws-cdk 38 | ``` 39 | 40 | 41 | Or yarn 42 | 43 | ```shell 44 | yarn global add aws-cdk-local aws-cdk 45 | ``` 46 | 47 | $ cdklocal --version 48 | 1.65.5 49 | 50 | 51 | 52 | # Start Localstack & Deploy our services 53 | 54 | ### Step 1. init create a fake aws credentials - use for our localstack as below ( This is required for our localstack ) 55 | ```shell 56 | cat ~/.aws/credentials 57 | 58 | [default] 59 | aws_access_key_id = test 60 | aws_secret_access_key = test 61 | region = us-west-2 62 | output = json 63 | ``` 64 | 65 | ### Step 2. `cd to localstack` folder and run the command `docker-compose up -d` 66 | 67 | #### Open browser check our service `http://localhost:4566/health` 68 | ```json 69 | { 70 | "services": { 71 | "dynamodbstreams": "running", 72 | "firehose": "running", 73 | "kinesis": "running", 74 | "s3": "running", 75 | "ses": "running", 76 | "sns": "running", 77 | "sqs": "running", 78 | "dynamodb": "running" 79 | }, "features": {"persistence": "initialized", "initScripts": "initialized"} 80 | } 81 | ``` 82 | 83 | #### Check your `memcached` was run successfully :check_mark: 84 | 85 | ``` 86 | # telnet the to port 11211 87 | telnet localhost 11211 88 | 89 | # Add a new key to memcache 90 | set Customer_Id 0 900 5 91 | # Type your value ( Enter - A message STORED will be displayed) 92 | 00-000-000 93 | STORED 94 | # Recheck by get your key stored 95 | get Customer_Id 96 | 00-000-000 97 | # exit telnet 98 | quit 99 | ``` 100 | 101 | #### Check your `Redis` was run successfully :check_mark: 102 | Install Redis Client ( Add connection ) 103 | 104 | #### Windows 105 | Download latest https://github.com/qishibo/AnotherRedisDesktopManager/releases package from https://github.com/qishibo/AnotherRedisDesktopManager/releases [or gitee in China], double click to install. 106 | 107 | Or by winget: winget install qishibo.AnotherRedisDesktopManager 108 | 109 | #### Mac 110 | Download latest https://github.com/qishibo/AnotherRedisDesktopManager/releases package from release [or gitee in China], double click to install. 111 | 112 | Or by brew: brew install --cask another-redis-desktop-manager 113 | 114 | 115 | 116 | ### Step 3. Deploy our Application Stack 117 | 118 | ```shell 119 | yarn deploy 120 | ``` 121 | 122 | ```markdown 123 | IAM Statement Changes ... 124 | ┌───┬───────────────────────┬────────┬─────────────────┬───────────────────────────┬───────────────────────────────────────────────────────┐ 125 | │ │ Resource │ Effect │ Action │ Principal │ Condition │ 126 | ├───┼───────────────────────┼────────┼─────────────────┼───────────────────────────┼───────────────────────────────────────────────────────┤ 127 | │ + │ ${SampleAppQueue.Arn} │ Allow │ sqs:SendMessage │ Service:sns.amazonaws.com │ "ArnEquals": { │ 128 | │ │ │ │ │ │ "aws:SourceArn": "${SampleAppTopic}" │ 129 | │ │ │ │ │ │ } │ 130 | └───┴───────────────────────┴────────┴─────────────────┴───────────────────────────┴───────────────────────────────────────────────────────┘ 131 | (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) 132 | 133 | Do you wish to deploy these changes (y/n)? 134 | 135 | #### Type `y` and see our stack 136 | 137 | ApplicationStack: deploying... 138 | ApplicationStack: creating CloudFormation changeset... 139 | 140 | 141 | ✅ ApplicationStack 142 | 143 | Stack ARN: 144 | arn:aws:cloudformation:us-west-2:000000000000:stack/ApplicationStack/e67d04e2 145 | ``` 146 | 147 | ### Step 4. Quick check our deployment S3 & Dynamo DB Tables 148 | #### DynamoDB 149 | ```shell 150 | aws --endpoint-url=http://localhost:4566 dynamodb list-tables 151 | 152 | { 153 | "TableNames": [ 154 | "test-development" 155 | ] 156 | } 157 | 158 | aws --endpoint-url=http://localhost:4566 dynamodb describe-table --table-name test-development 159 | ``` 160 | 161 | ## Useful Tools ( How to use it ) 162 | | Tool | Description | 163 | | ----------- | ----------- | 164 | | S3 Viewer (MAC & Win)
https://cyberduck.io/ | ![Screen Shot 2021-10-08 at 17 39 59](https://user-images.githubusercontent.com/78775708/136542800-12649534-6832-46db-84c6-d1f5b9e63d85.png) | 165 | | DynamoDB Viewer (MAC & Win)
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html | ![Screen Shot 2021-10-08 at 17 42 30](https://user-images.githubusercontent.com/78775708/136543146-5a52d1a0-a7c1-4eda-b394-83facca1d3d2.png) | 166 | | SQS Sender
https://github.com/kobee-tech-stack/sqs-viewer | 167 | | Redis Viewer (MAC & Win)
https://github.com/qishibo/AnotherRedisDesktopManager | ... | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /bin/app.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from '@aws-cdk/core'; 3 | import {ApplicationStack} from '../lib/ApplicationStack'; 4 | 5 | const app = new cdk.App(); 6 | new ApplicationStack(app, 'ApplicationStack', { 7 | env: { 8 | region: 'us-west-2' 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/app.ts", 3 | "context": { 4 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 5 | "@aws-cdk/core:enableStackNameDuplicates": "true", 6 | "aws-cdk:enableDiffNoFail": "true", 7 | "@aws-cdk/core:stackRelativeExports": "true", 8 | "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, 9 | "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, 10 | "@aws-cdk/aws-kms:defaultKeyPolicies": true, 11 | "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, 12 | "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, 13 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 14 | "@aws-cdk/aws-efs:defaultEncryptionAtRest": true, 15 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 16 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /lib/ApplicationStack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "@aws-cdk/core"; 2 | import {initDynamoDB} from "./dynamodb"; 3 | import {initS3Buckets} from "./s3"; 4 | import {initFirehose} from "./firehose"; 5 | import {initSQS} from './sqs'; 6 | 7 | /** 8 | * This is Application Stack 9 | * Create DynamoDB , S3, FireHose, SQS services support for local development. 10 | */ 11 | export class ApplicationStack extends cdk.Stack { 12 | constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 13 | super(scope, id, props); 14 | 15 | // Dynamo DB initialize 16 | initDynamoDB(this); 17 | 18 | // S3 Initialize 19 | initS3Buckets(this); 20 | 21 | // Firehose Initialize 22 | initFirehose(this); 23 | 24 | // SQS Initialize 25 | initSQS(this); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/dynamodb/index.ts: -------------------------------------------------------------------------------- 1 | import { generateTestDevelopmentTable } from './test-development'; 2 | import { Stack } from '@aws-cdk/core'; 3 | 4 | export const initDynamoDB = (root: Stack): void => { 5 | // Test Development Table 6 | generateTestDevelopmentTable(root); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/dynamodb/test-development.ts: -------------------------------------------------------------------------------- 1 | import * as dynamodb from "@aws-cdk/aws-dynamodb"; 2 | import {GlobalSecondaryIndexProps, StreamViewType} from "@aws-cdk/aws-dynamodb/lib/table"; 3 | import {createStandardGSI} from "../../utils/createGlobalSecondaryIndex"; 4 | import {Stack} from "@aws-cdk/core" 5 | 6 | export const generateTestDevelopmentTable = (root: Stack): dynamodb.Table => { 7 | const testDevelopmentTable = new dynamodb.Table(root, 'Table', { 8 | tableName: 'test-development', 9 | // partition key & sort key 10 | partitionKey: {name: 'pk', type: dynamodb.AttributeType.STRING}, 11 | sortKey: {name: 'sk', type: dynamodb.AttributeType.STRING}, 12 | // ProvisionedThroughput 13 | readCapacity: 5, 14 | writeCapacity: 5, 15 | // StreamSpecification 16 | stream: StreamViewType.NEW_AND_OLD_IMAGES, 17 | }); 18 | 19 | const pk2Sk2Index: GlobalSecondaryIndexProps = createStandardGSI('pk2-sk2-index', 'pk2', 'sk2'); 20 | const pk3Sk3Index: GlobalSecondaryIndexProps = createStandardGSI('pk3-sk3-index', 'pk3', 'sk3'); 21 | const pk4Sk4Index: GlobalSecondaryIndexProps = createStandardGSI('pk4-sk4-index', 'pk4', 'sk4'); 22 | 23 | testDevelopmentTable.addGlobalSecondaryIndex(pk2Sk2Index); 24 | testDevelopmentTable.addGlobalSecondaryIndex(pk3Sk3Index); 25 | testDevelopmentTable.addGlobalSecondaryIndex(pk4Sk4Index); 26 | 27 | return testDevelopmentTable; 28 | } 29 | -------------------------------------------------------------------------------- /lib/firehose/index.ts: -------------------------------------------------------------------------------- 1 | import {Stack} from "@aws-cdk/core"; 2 | import {generateTestFirehose} from "./test-firehose"; 3 | import * as iam from "@aws-cdk/aws-iam"; 4 | 5 | export const initFirehose = (root: Stack): void => { 6 | const safetyCheckFirehoseRole = new iam.Role(root, 'safety-check-firehose-role', { 7 | assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com') 8 | }); 9 | 10 | generateTestFirehose(root, safetyCheckFirehoseRole); 11 | } 12 | -------------------------------------------------------------------------------- /lib/firehose/test-firehose.ts: -------------------------------------------------------------------------------- 1 | import * as s3 from '@aws-cdk/aws-s3'; 2 | import {Duration, RemovalPolicy, Size, Stack} from "@aws-cdk/core"; 3 | import {CfnDeliveryStream} from "@aws-cdk/aws-kinesisfirehose"; 4 | import {Role} from '@aws-cdk/aws-iam'; 5 | 6 | export const generateTestFirehose = (root: Stack, firehoseRole: Role): CfnDeliveryStream => { 7 | // S3 bucket that will serve as the destination for our raw compressed data 8 | const auditLogBucket = new s3.Bucket(root, "test-firehose-s3-bucket", { 9 | removalPolicy: RemovalPolicy.DESTROY, // REMOVE FOR PRODUCTION 10 | autoDeleteObjects: true, // REMOVE FOR PRODUCTION, 11 | bucketName: 'test-firehose-s3', 12 | publicReadAccess: true, 13 | }); 14 | 15 | return new CfnDeliveryStream(root, "FirehoseStreamToS", { 16 | deliveryStreamName: "test-firehose-delivery-stream", 17 | deliveryStreamType: "DirectPut", 18 | s3DestinationConfiguration: { 19 | bucketArn: auditLogBucket.bucketArn, 20 | bufferingHints: { 21 | sizeInMBs: Size.mebibytes(1).toMebibytes(), 22 | intervalInSeconds: Duration.seconds(60).toSeconds() 23 | }, 24 | compressionFormat: 'UNCOMPRESSED', 25 | encryptionConfiguration: { 26 | noEncryptionConfig: "NoEncryption" 27 | }, 28 | prefix: "user-logs", 29 | errorOutputPrefix: 'user-error-logs', 30 | roleArn: firehoseRole.roleArn 31 | }, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /lib/iam/firehose_skeleton.json: -------------------------------------------------------------------------------- 1 | { 2 | "DeliveryStreamName": "s3-stream-1", 3 | "DeliveryStreamType": "DirectPut", 4 | "S3DestinationConfiguration": { 5 | "RoleARN": "arn:aws:iam::000000000000:role/super-role", 6 | "BucketARN": "arn:aws:s3:::test-firehose-s3", 7 | "Prefix": "test-log", 8 | "ErrorOutputPrefix": "test-error-log", 9 | "BufferingHints": { 10 | "SizeInMBs": 1, 11 | "IntervalInSeconds": 60 12 | }, 13 | "CompressionFormat": "UNCOMPRESSED", 14 | "CloudWatchLoggingOptions": { 15 | "Enabled": false, 16 | "LogGroupName": "", 17 | "LogStreamName": "" 18 | } 19 | }, 20 | "Tags": [ 21 | { 22 | "Key": "tagKey", 23 | "Value": "tagValue" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /lib/iam/super-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "Stmt1572416334166", 6 | "Action": "*", 7 | "Effect": "Allow", 8 | "Resource": "*" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /lib/iam/super-role.ts: -------------------------------------------------------------------------------- 1 | import {Effect, Group, ManagedPolicy, PolicyStatement, User} from '@aws-cdk/aws-iam'; 2 | import {Stack} from "@aws-cdk/core"; 3 | 4 | export const generateSuperRole = (root: Stack): User => { 5 | // 👇 Create group 6 | const group = new Group(root, 'admin-group', { 7 | managedPolicies: [ 8 | ManagedPolicy.fromAwsManagedPolicyName('*'), 9 | ], 10 | }); 11 | 12 | // 👇 Create Managed Policy 13 | const allManagedPolicy = ManagedPolicy.fromAwsManagedPolicyName( 14 | '*', 15 | ); 16 | 17 | // 👇 Create Permissions Boundary 18 | const permissionsBoundary = new ManagedPolicy( 19 | root, 20 | 'admin-role-permissions', 21 | { 22 | statements: [ 23 | new PolicyStatement({ 24 | effect: Effect.ALLOW, 25 | actions: ['*'], 26 | resources: ['*'], 27 | }), 28 | ], 29 | }, 30 | ); 31 | 32 | // 👇 Create User 33 | const user: User = new User(root, 'super-role', { 34 | userName: 'administrator', 35 | managedPolicies: [allManagedPolicy], 36 | groups: [group], 37 | permissionsBoundary, 38 | }); 39 | 40 | console.log('Super Admin : ', user.userArn); 41 | return user; 42 | } 43 | -------------------------------------------------------------------------------- /lib/s3/index.ts: -------------------------------------------------------------------------------- 1 | import {Stack} from "@aws-cdk/core"; 2 | import {generateScreenShotBucket} from "./screenshot"; 3 | 4 | export const initS3Buckets = (root: Stack): void => { 5 | generateScreenShotBucket(root); 6 | } 7 | -------------------------------------------------------------------------------- /lib/s3/screenshot.ts: -------------------------------------------------------------------------------- 1 | import * as s3 from '@aws-cdk/aws-s3'; 2 | import { Stack } from '@aws-cdk/core'; 3 | 4 | export const generateScreenShotBucket = (root: Stack): s3.Bucket => { 5 | return new s3.Bucket(root, 'screen-shot', { 6 | bucketName: 'screenshot', 7 | // https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html 8 | encryption: s3.BucketEncryption.S3_MANAGED, 9 | versioned: false, 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /lib/sqs/index.ts: -------------------------------------------------------------------------------- 1 | import {Stack} from "@aws-cdk/core"; 2 | 3 | import { generateSimpleSQS } from "./simple-sqs-development"; 4 | 5 | export const initSQS = (root: Stack): void => { 6 | generateSimpleSQS(root); 7 | } 8 | -------------------------------------------------------------------------------- /lib/sqs/simple-sqs-development.ts: -------------------------------------------------------------------------------- 1 | import * as sqs from '@aws-cdk/aws-sqs'; 2 | import {RemovalPolicy, Stack} from "@aws-cdk/core"; 3 | 4 | export const generateSimpleSQS = (root: Stack): sqs.Queue => { 5 | // 👇 create queue 6 | return new sqs.Queue(root, 'simple-sqs', { 7 | queueName: 'simple-sqs-development', 8 | encryption: sqs.QueueEncryption.UNENCRYPTED, 9 | fifo: false, 10 | removalPolicy: RemovalPolicy.DESTROY 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /localstack/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | memcached: 5 | container_name: aws_memcached 6 | image: bitnami/memcached:latest 7 | network_mode: bridge 8 | ports: 9 | - "11211:11211" 10 | environment: 11 | - MEMCACHED_CACHE_SIZE=128 12 | redis: 13 | container_name: aws_redis 14 | image: bitnami/redis:latest 15 | network_mode: bridge 16 | ports: 17 | - "6379:6379" 18 | environment: 19 | - ALLOW_EMPTY_PASSWORD=yes 20 | volumes: 21 | - './.redis-persistence:/bitnami/redis/data' 22 | localstack: 23 | container_name: AWS-DEVELOPMENT-WITH-LOCALSTACK 24 | image: localstack/localstack:latest 25 | network_mode: bridge 26 | ports: 27 | - "127.0.0.1:53:53" 28 | - "127.0.0.1:53:53/udp" 29 | - "127.0.0.1:443:443" 30 | - "127.0.0.1:4566:4566" 31 | - "127.0.0.1:4571:4571" 32 | environment: 33 | - SERVICES=apigateway,s3,dynamodb,sns,sqs,firehose,kinesis,ses,sts,cloudformation,iam,lambda 34 | - DEBUG=1 35 | - DATA_DIR=/tmp/localstack/data 36 | - PORT_WEB_UI=8080 37 | - DEFAULT_REGION=us-west-2 38 | - LAMBDA_EXECUTOR=local 39 | - KINESIS_ERROR_PROBABILITY=1.0 40 | - DOCKER_HOST=unix:///var/run/docker.sock 41 | - HOST_TMP_FOLDER=./.localstack 42 | volumes: 43 | - './.localstack:/tmp/localstack' 44 | - '/var/run/docker.sock:/var/run/docker.sock' 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-development-with-localstack", 3 | "version": "0.1.0", 4 | "bin": { 5 | "app": "bin/app.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "lint": "eslint lib/**/*.ts", 12 | "format": "eslint lib/**/*.ts --fix", 13 | "cdk": "cdklocal", 14 | "deploy": "cdklocal deploy", 15 | "bootstrap": "cdklocal bootstrap aws://unknown-account/us-west-2", 16 | "destroy": "cdklocal destroy", 17 | "seed": "npx ts-node seed/index.ts", 18 | "migrate": "npx ts-node scripts/migrationModels/migrationScript.ts" 19 | }, 20 | "devDependencies": { 21 | "@aws-cdk/assert": "1.117.0", 22 | "@types/jest": "^26.0.10", 23 | "@types/node": "10.17.27", 24 | "@typescript-eslint/eslint-plugin": "^4.31.2", 25 | "@typescript-eslint/parser": "^4.31.2", 26 | "@types/lodash": "^4.14.175", 27 | "aws-cdk": "^1.124.0", 28 | "eslint": "^7.32.0", 29 | "jest": "^26.4.2", 30 | "prettier": "^2.4.1", 31 | "ts-jest": "^26.2.0", 32 | "ts-node": "^9.0.0", 33 | "typescript": "~3.9.7", 34 | "husky": "^7.0.2" 35 | }, 36 | "dependencies": { 37 | "@aws-cdk/aws-dynamodb": "1.117.0", 38 | "@aws-cdk/aws-iam": "1.117.0", 39 | "@aws-cdk/aws-kinesis": "1.117.0", 40 | "@aws-cdk/aws-kinesisfirehose": "1.117.0", 41 | "@aws-cdk/aws-kinesisfirehose-destinations": "1.117.0", 42 | "@aws-cdk/aws-s3": "1.117.0", 43 | "@aws-cdk/aws-sns": "1.117.0", 44 | "@aws-cdk/aws-sns-subscriptions": "1.117.0", 45 | "@aws-cdk/aws-sqs": "1.117.0", 46 | "@aws-cdk/core": "1.117.0", 47 | "@aws-sdk/client-dynamodb": "^3.32.0", 48 | "@aws-sdk/util-dynamodb": "^3.32.0", 49 | "lodash": "^4.17.21", 50 | "axios": "^0.22.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /scripts/config.ts: -------------------------------------------------------------------------------- 1 | const config = { 2 | endpoint: process.env.MIGRATION_SEED_APP_CONFIG_ENDPOINT || "http://localhost:4566", 3 | region: process.env.MIGRATION_SEED_APP_CONFIG_REGION || "us-west-2", 4 | }; 5 | 6 | export default config; 7 | -------------------------------------------------------------------------------- /scripts/migrationModels/migrationScript.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; 4 | import appConfig from "../config"; 5 | 6 | const migrationScript = async () => { 7 | const client = new DynamoDBClient({ 8 | endpoint: appConfig.endpoint, 9 | region: appConfig.region 10 | }); 11 | 12 | console.log("Migrate Data : Done"); 13 | }; 14 | 15 | (async function main() { 16 | await migrationScript(); 17 | console.log(` 18 | Migrate development data to local was run successfully. 19 | `); 20 | })(); 21 | -------------------------------------------------------------------------------- /seed/config.ts: -------------------------------------------------------------------------------- 1 | const seedAppConfig = { 2 | endpoint: process.env.SEED_APP_CONFIG_ENDPOINT || 'http://localhost:4566', 3 | region: process.env.SEED_APP_CONFIG_REGION || 'us-west-2' 4 | } 5 | 6 | export default seedAppConfig; 7 | -------------------------------------------------------------------------------- /seed/index.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import {DynamoDBClient} from "@aws-sdk/client-dynamodb"; 4 | 5 | import seedAppConfig from "./config"; 6 | 7 | const seedData = async () => { 8 | const client = new DynamoDBClient({ 9 | endpoint: seedAppConfig.endpoint, 10 | region: seedAppConfig.region 11 | }); 12 | console.log('Seed Data : Done'); 13 | } 14 | 15 | (async function main() { 16 | await seedData(); 17 | console.log(` 18 | Seed global data was run successfully. 19 | `); 20 | })(); 21 | -------------------------------------------------------------------------------- /test/app.test.ts: -------------------------------------------------------------------------------- 1 | import { expect as expectCDK, haveResource } from '@aws-cdk/assert'; 2 | import * as cdk from '@aws-cdk/core'; 3 | import * as App from '../lib/ApplicationStack'; 4 | 5 | test('SQS Queue Created', () => { 6 | const app = new cdk.App(); 7 | // WHEN 8 | const stack = new App.ApplicationStack(app, 'MyTestStack'); 9 | // THEN 10 | expectCDK(stack).to(haveResource("AWS::SQS::Queue",{ 11 | VisibilityTimeout: 300 12 | })); 13 | }); 14 | 15 | test('SNS Topic Created', () => { 16 | const app = new cdk.App(); 17 | // WHEN 18 | const stack = new App.ApplicationStack(app, 'MyTestStack'); 19 | // THEN 20 | expectCDK(stack).to(haveResource("AWS::SNS::Topic")); 21 | }); 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2018" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ], 25 | "allowSyntheticDefaultImports": true, 26 | "esModuleInterop": true 27 | }, 28 | "exclude": [ 29 | "node_modules", 30 | "cdk.out" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /utils/createGlobalSecondaryIndex.ts: -------------------------------------------------------------------------------- 1 | import { AttributeType, ProjectionType, GlobalSecondaryIndexProps } from "@aws-cdk/aws-dynamodb"; 2 | 3 | /** 4 | * Default pk & sk is attr type is STRING & read/write capacity is 5. 5 | * @param indexName 6 | * @param pkName 7 | * @param skName 8 | */ 9 | export const createStandardGSI = (indexName: string, pkName: string, skName: string) : GlobalSecondaryIndexProps => { 10 | return { 11 | indexName, 12 | partitionKey: { name: pkName, type: AttributeType.STRING }, 13 | sortKey: { name: skName, type: AttributeType.STRING }, 14 | projectionType: ProjectionType.ALL, 15 | }; 16 | } 17 | --------------------------------------------------------------------------------