{"id":20386950,"url":"https://github.com/cmdcolin/aws_serverless_photo_gallery","last_synced_at":"2026-04-01T19:44:40.125Z","repository":{"id":137211734,"uuid":"324216275","full_name":"cmdcolin/aws_serverless_photo_gallery","owner":"cmdcolin","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-31T20:24:19.000Z","size":21086,"stargazers_count":64,"open_issues_count":10,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2026-03-27T23:42:21.082Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmdcolin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-12-24T18:36:43.000Z","updated_at":"2025-05-31T20:24:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"c9975f26-3148-49b8-ab1b-a822e92a9afc","html_url":"https://github.com/cmdcolin/aws_serverless_photo_gallery","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cmdcolin/aws_serverless_photo_gallery","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdcolin%2Faws_serverless_photo_gallery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdcolin%2Faws_serverless_photo_gallery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdcolin%2Faws_serverless_photo_gallery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdcolin%2Faws_serverless_photo_gallery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmdcolin","download_url":"https://codeload.github.com/cmdcolin/aws_serverless_photo_gallery/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdcolin%2Faws_serverless_photo_gallery/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T02:41:43.001Z","updated_at":"2026-04-01T19:44:40.101Z","avatar_url":"https://github.com/cmdcolin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aws_serverless_photo_gallery\n\nThis is an extension of\nhttps://aws.amazon.com/blogs/compute/uploading-to-amazon-s3-directly-from-a-web-or-mobile-application/\n\nThis repo has extended the concept to include the following features\n\n- Commenting on photos\n- Uploading both videos and photos\n- Upload multiple files at a time\n- Some simple sorting and filtering\n- Client side image resize for thumbnail\n- Client side EXIF parse to read date\n\nExample site here https://myloveydove.com/ for our amazing dog dixie (RIP)\n\nYou can also see the features for posting/commenting here\nhttps://myloveydove.com/?password=nottherealpassword but this will not let you\nactually post (see #security section)\n\n## Architecture\n\n```\n\n                     +------------------------------------------------------+\n                     |                                                      |\n+--------------------+-+   +----------------------------------------+   +---v-----------------------------------+\n|                      |   |                                        |   |                                       |\n|   Client side        |   |   AWS Lambda \"postFile\"                |   |  AWS Lambda \"postComment\"             |\n|   React app (vite)   +---\u003e                                        |   |                                       |\n|                      |   |  - Generates pre-signed URL that the   |   |  - Updates the row in the \"files\"     |\n|                      |   |  client side uses to upload directly   |   |  table with a new comment (there is a |\n+---------+------------+   |  to S3                                 |   |  list of comments for each entry in   |\n          |                |  - Also inserts a row in the \"files\"   |   |  the files table)                     |\n          |                |  DynamoDB                              |   |                                       |\n          |                +----------------------------------------+   +---------------------------------------+\n          |\n+---------v-------------+  +----------------------------------------+\n|                       |  |                                        |\n|                       |  | AWS DynamoDB Table \"files\"             |\n|  AWS S3 bucket        |  | Each file has a filename that matches  |\n|  - The client talks   |  | filename in S3 bucket                  |\n|   directly to the S3  |  |                                        |\n|   bucket using the    |  | Each row in the \"files\" table also     |\n|   pre-signed URL that |  | has a list of comments (no separate    |\n|   \"postFile\" generates|  | comments table because no joins in     |\n|                       |  | DynamoDB)                              |\n+-----------------------+  +----------------------------------------+\n```\n\n## Blogposts\n\nThe process of making this was pretty involved so I made several blogposts about\nit\n\n- Part 1: Initial experimentation with serverless architecture following the AWS\n  tutorial\n  https://searchvoidstar.tumblr.com/post/638408397901987840/making-a-serverless-website-for-photo-upload-pt-1\n\n- Part 2: Converting the Vue demo code to React and demo lambda+cloudformation\n  template\n  https://searchvoidstar.tumblr.com/post/638602799897329664/making-a-serverless-website-for-photo-and-video\n\n- Part 3: registering a domain, using Route 53, and making the S3 static website\n  hooked up to CloudFront to make it https compatible\n  https://searchvoidstar.tumblr.com/post/638618421776515072/making-a-https-accessible-s3-powered-static-site\n\n### Security\n\nThe app only allows someone who visits the page with a special URL format e.g.\n`?password=yourSecretPassword` to upload files and post comments. Users without\nthe right password are not able to post comments or upload files. Having the\npassword helps prevents drive by spam that would be otherwise hard to moderate\n\nIf the password URL parameter is not supplied, the buttons for uploading are\nhidden, but if it is supplied they are shown. It still has to match the server\nside secret password to succeed posting\n\n### Deployment\n\nInstall the aws-sam CLI\n\n```\nbrew install aws/tap/aws-sam-cli\n```\n\nThen use the command\n\n```\nsam deploy --guided\n```\n\nYou can specify the SecretPassword in the guided mode\n\n### What does the deployment do\n\nThe deployment will automatically do the following\n\n- Creates lambda functions for posting/reading files and comments\n- Creates dynamodb tables for guestbook and files\n- Creates an s3 bucket that it puts the photos in. It has a coded name like\n  `sam-app-s3uploadbucket-1fyrebt7g2tr3`\n\nThen also update frontend/package.json to do `aws s3 sync` to your website\nbucket, and run `yarn deploy`. Note that your website bucket should be different\nfrom the one automatically created by the aws sam template.yaml here\n\n## Database design\n\nThis code uses a simple DynamoDB database. I considered using Amazon RDS (e.g. a\nreal database instead of dynamoDB) but the administration was too complicated,\nand so instead I updated the DynamoDB to have comments for the files directly\ninside the files table. Storing them separately would imply a join which\nDynamoDB does not have\n\nNote that there was a nice recommendation on reddit to use a specialized keys in\nDynamoDB to help avoid these problems. See\nhttps://github.com/cmdcolin/aws_serverless_photo_gallery/issues/8\n\n## Scalability\n\nThe client side currently fetches all photo JSON info and comments for all the\npages of the app in one query. Only the actual img tags on the page download at\na given time though. Unless you have a very large number of photos this is\nprobably fine. Doing pagination properly would require making a paginated\nDynamoDB query but it doesn't use standard LIMIT/OFFSET so it's a little quirky\n\n## Credits\n\nI used a ton of amazing gifs from https://gifcities.org/ and a couple other\nplaces. Thank you to the creators of all those gifs and the internet historians\npreserving them. There are many other thanks to give but I'm just grateful to\nshare :)\n\n## Note\n\nIf you are interested in using this and need help, particularly if you want to\nuse it for a memorial page, feel free to contact me\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdcolin%2Faws_serverless_photo_gallery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmdcolin%2Faws_serverless_photo_gallery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdcolin%2Faws_serverless_photo_gallery/lists"}