{"id":28549159,"url":"https://github.com/hoangsonww/petswipe-match-app","last_synced_at":"2026-03-02T22:14:13.453Z","repository":{"id":295454793,"uuid":"990131577","full_name":"hoangsonww/PetSwipe-Match-App","owner":"hoangsonww","description":"🐻 A Tinder-inspired pet adoption app where you swipe to navigate, “adopt”, or “pass” on shelter animals. Built \u0026 deployed with PostgreSQL, Express, Node.js, TypeORM, Next.js, AWS and many other modern technologies for a fun, real-time experience 🐱🐶","archived":false,"fork":false,"pushed_at":"2025-08-17T10:29:08.000Z","size":19342,"stargazers_count":25,"open_issues_count":4,"forks_count":21,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-08-17T12:21:54.905Z","etag":null,"topics":["amazon-web-services","ansible","aws","aws-ecr","aws-ecs","aws-elastic-beanstalk","aws-rds","aws-s3","docker","express","javascript","nextjs","nodejs","postgresql","react","shadcn-ui","supabase","typeorm","typescript","vercel"],"latest_commit_sha":null,"homepage":"https://petswipe.vercel.app","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/hoangsonww.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-25T15:11:06.000Z","updated_at":"2025-08-17T11:09:47.000Z","dependencies_parsed_at":"2025-07-12T05:26:16.227Z","dependency_job_id":"a5d3aa6b-500e-41ac-b21f-a7f3d189ec51","html_url":"https://github.com/hoangsonww/PetSwipe-Match-App","commit_stats":null,"previous_names":["hoangsonww/petswipe-match-app"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/hoangsonww/PetSwipe-Match-App","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangsonww%2FPetSwipe-Match-App","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangsonww%2FPetSwipe-Match-App/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangsonww%2FPetSwipe-Match-App/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangsonww%2FPetSwipe-Match-App/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hoangsonww","download_url":"https://codeload.github.com/hoangsonww/PetSwipe-Match-App/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangsonww%2FPetSwipe-Match-App/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271745678,"owners_count":24813521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["amazon-web-services","ansible","aws","aws-ecr","aws-ecs","aws-elastic-beanstalk","aws-rds","aws-s3","docker","express","javascript","nextjs","nodejs","postgresql","react","shadcn-ui","supabase","typeorm","typescript","vercel"],"created_at":"2025-06-10T02:00:50.657Z","updated_at":"2026-03-02T22:14:13.434Z","avatar_url":"https://github.com/hoangsonww.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🐾 PetSwipe - Swipe to Adopt\n\n**PetSwipe** is on a mission to help shelter animals find loving homes. This swipe-to-adopt platform connects prospective pet parents with adoptable animals in need. With PetSwipe, users can effortlessly browse pets, swipe right to adopt or left to pass, and manage their profiles with ease. They can also view their matches and keep track of their swipe history — making the journey to adoption simpler, faster, and more heartwarming 🐰.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://petswipe.vercel.app\" target=\"_blank\"\u003e\n    \u003cimg src=\"docs/img/logo.jpeg\" alt=\"PetSwipe Logo\" width=\"45%\" style=\"border-radius: 8px\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e [!NOTE]\n\u003e Inspired by Tinder UX, but for pets to find their loving humans! 🐶🐱\n\n![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat-square\u0026logo=typescript\u0026logoColor=white) ![Node.js](https://img.shields.io/badge/Node.js-339933?style=flat-square\u0026logo=nodedotjs\u0026logoColor=white) ![Express](https://img.shields.io/badge/Express-000000?style=flat-square\u0026logo=express\u0026logoColor=white) ![Next.js](https://img.shields.io/badge/Next.js-000000?style=flat-square\u0026logo=nextdotjs\u0026logoColor=white) ![Shell](https://img.shields.io/badge/Shell-4EAA25?style=flat-square\u0026logo=gnubash\u0026logoColor=white) ![Docker](https://img.shields.io/badge/Docker-2496ED?style=flat-square\u0026logo=docker\u0026logoColor=white) ![Shadcn UI](https://img.shields.io/badge/Shadcn/UI-889889?style=flat-square\u0026logo=shadcnui\u0026logoColor=white) ![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-38B2AC?style=flat-square\u0026logo=tailwindcss\u0026logoColor=white) ![Framer Motion](https://img.shields.io/badge/Framer_Motion-000000?style=flat-square\u0026logo=framer\u0026logoColor=white) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=flat-square\u0026logo=postgresql\u0026logoColor=white) ![TypeORM](https://img.shields.io/badge/TypeORM-336791?style=flat-square\u0026logo=typeorm\u0026logoColor=white) ![Supabase](https://img.shields.io/badge/Supabase-3ECF8E?style=flat-square\u0026logo=supabase\u0026logoColor=white) ![Redis](https://img.shields.io/badge/Redis-DC382D?style=flat-square\u0026logo=redis\u0026logoColor=white) ![RabbitMQ](https://img.shields.io/badge/RabbitMQ-FF6600?style=flat-square\u0026logo=rabbitmq\u0026logoColor=white) ![Swagger](https://img.shields.io/badge/Swagger-85EA2D?style=flat-square\u0026logo=swagger\u0026logoColor=black) ![JWT](https://img.shields.io/badge/JWT-000000?style=flat-square\u0026logo=jsonwebtokens\u0026logoColor=white) ![Google AI](https://img.shields.io/badge/Google_AI-4285F4?style=flat-square\u0026logo=google\u0026logoColor=white) ![Google Cloud](https://img.shields.io/badge/Google_Cloud-4242F4?style=flat-square\u0026logo=googlecloud\u0026logoColor=white) ![AWS](https://img.shields.io/badge/AWS-232F3E?style=flat-square\u0026logo=amazonwebservices\u0026logoColor=white) ![AWS S3](https://img.shields.io/badge/AWS_S3-569A31?style=flat-square\u0026logo=amazons3\u0026logoColor=white) ![AWS RDS](https://img.shields.io/badge/AWS_RDS-527FFF?style=flat-square\u0026logo=amazonrds\u0026logoColor=white) ![AWS ECS](https://img.shields.io/badge/AWS_ECS-FF0022?style=flat-square\u0026logo=amazonecs\u0026logoColor=white) ![AWS ECR](https://img.shields.io/badge/AWS_ECR-456789?style=flat-square\u0026logo=amazonec2\u0026logoColor=white) ![AWS ALB](https://img.shields.io/badge/AWS_ALB-FF9900?style=flat-square\u0026logoColor=white) ![AWS IAM](https://img.shields.io/badge/AWS_IAM-F05900?style=flat-square\u0026logo=amazoniam\u0026logoColor=white) ![AWS KMS](https://img.shields.io/badge/AWS_KMS-FF9900?style=flat-square\u0026logo=amazon\u0026logoColor=white) ![AWS CloudWatch](https://img.shields.io/badge/AWS_CloudWatch-232F3E?style=flat-square\u0026logo=amazoncloudwatch\u0026logoColor=white) ![Vercel](https://img.shields.io/badge/Vercel-000000?style=flat-square\u0026logo=vercel\u0026logoColor=white) ![Terraform](https://img.shields.io/badge/Terraform-7B42BC?style=flat-square\u0026logo=terraform\u0026logoColor=white) ![Consul](https://img.shields.io/badge/Consul-DC322F?style=flat-square\u0026logo=consul\u0026logoColor=white) ![Nomad](https://img.shields.io/badge/Nomad-00A8E8?style=flat-square\u0026logo=nomad\u0026logoColor=white) ![Vault](https://img.shields.io/badge/Vault-121F31?style=flat-square\u0026logo=vault\u0026logoColor=white) ![Ansible](https://img.shields.io/badge/Ansible-EE0000?style=flat-square\u0026logo=ansible\u0026logoColor=white) ![Make](https://img.shields.io/badge/Make-777777?style=flat-square\u0026logo=gnu\u0026logoColor=white) ![Playwright](https://img.shields.io/badge/Playwright-2B2D42?style=flat-square\u0026logo=nestjs\u0026logoColor=white) ![Jest](https://img.shields.io/badge/Jest-C21325?style=flat-square\u0026logo=jest\u0026logoColor=white) ![Chai](https://img.shields.io/badge/Chai-A30701?style=flat-square\u0026logo=chai\u0026logoColor=white) ![Mocha](https://img.shields.io/badge/Mocha-8D6748?style=flat-square\u0026logo=mocha\u0026logoColor=white) ![Commitlint](https://img.shields.io/badge/Commitlint-000000?style=flat-square\u0026logo=commitlint\u0026logoColor=white) ![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-2088FF?style=flat-square\u0026logo=githubactions\u0026logoColor=white) ![Prettier](https://img.shields.io/badge/Prettier-F7B93E?style=flat-square\u0026logo=prettier\u0026logoColor=black) ![ESLint](https://img.shields.io/badge/ESLint-4B3263?style=flat-square\u0026logo=eslint\u0026logoColor=white) ![Yelp](https://img.shields.io/badge/Yelp-FF0000?style=flat-square\u0026logo=yelp\u0026logoColor=white) ![GitHub](https://img.shields.io/badge/GitHub-181717?style=flat-square\u0026logo=github\u0026logoColor=white) ![Prometheus](https://img.shields.io/badge/Prometheus-FF0000?style=flat-square\u0026logo=prometheus\u0026logoColor=white) ![Grafana](https://img.shields.io/badge/Grafana-F46800?style=flat-square\u0026logo=grafana\u0026logoColor=white)\n![React](https://img.shields.io/badge/React-20232A?style=flat-square\u0026logo=react\u0026logoColor=61DAFB) ![Radix UI](https://img.shields.io/badge/Radix_UI-161618?style=flat-square\u0026logo=radixui\u0026logoColor=white) ![SWR](https://img.shields.io/badge/SWR-000000?style=flat-square\u0026logoColor=white) ![Recharts](https://img.shields.io/badge/Recharts-FF6384?style=flat-square\u0026logoColor=white) ![Axios](https://img.shields.io/badge/Axios-5A29E4?style=flat-square\u0026logo=axios\u0026logoColor=white) ![React Hook Form](https://img.shields.io/badge/React_Hook_Form-EC5990?style=flat-square\u0026logo=reacthookform\u0026logoColor=white) ![Zod](https://img.shields.io/badge/Zod-3E67B1?style=flat-square\u0026logoColor=white) ![Lucide](https://img.shields.io/badge/Lucide-18181B?style=flat-square\u0026logoColor=white) ![date-fns](https://img.shields.io/badge/date--fns-770C56?style=flat-square\u0026logoColor=white) ![React Markdown](https://img.shields.io/badge/React_Markdown-000000?style=flat-square\u0026logo=markdown\u0026logoColor=white) ![KaTeX](https://img.shields.io/badge/KaTeX-008080?style=flat-square\u0026logoColor=white) ![next-themes](https://img.shields.io/badge/next--themes-000000?style=flat-square\u0026logo=nextdotjs\u0026logoColor=white) ![Embla Carousel](https://img.shields.io/badge/Embla_Carousel-1F1F1F?style=flat-square\u0026logoColor=white) ![Sonner](https://img.shields.io/badge/Sonner-FF6B6B?style=flat-square\u0026logoColor=white) ![Vaul](https://img.shields.io/badge/Vaul-111111?style=flat-square\u0026logoColor=white) ![Vercel Analytics](https://img.shields.io/badge/Vercel_Analytics-000000?style=flat-square\u0026logo=vercel\u0026logoColor=white)\n![Firebase](https://img.shields.io/badge/Firebase-FFCA28?style=flat-square\u0026logo=firebase\u0026logoColor=black) ![bcryptjs](https://img.shields.io/badge/bcryptjs-4C8BF5?style=flat-square\u0026logoColor=white) ![cookie-parser](https://img.shields.io/badge/cookie--parser-D2691E?style=flat-square\u0026logoColor=white) ![CORS](https://img.shields.io/badge/CORS-005571?style=flat-square\u0026logoColor=white) ![Morgan](https://img.shields.io/badge/Morgan-4B5563?style=flat-square\u0026logoColor=white) ![Multer](https://img.shields.io/badge/Multer-FFB020?style=flat-square\u0026logoColor=black) ![Sharp](https://img.shields.io/badge/Sharp-99CC00?style=flat-square\u0026logoColor=black) ![UUID](https://img.shields.io/badge/UUID-3B82F6?style=flat-square\u0026logoColor=white) ![CSV](https://img.shields.io/badge/CSV-217346?style=flat-square\u0026logoColor=white) ![serverless-http](https://img.shields.io/badge/serverless--http-FD5750?style=flat-square\u0026logo=serverless\u0026logoColor=white) ![Kubernetes](https://img.shields.io/badge/Kubernetes-326CE5?style=flat-square\u0026logo=kubernetes\u0026logoColor=white) ![NGINX](https://img.shields.io/badge/NGINX-009639?style=flat-square\u0026logo=nginx\u0026logoColor=white) ![Jenkins](https://img.shields.io/badge/Jenkins-D24939?style=flat-square\u0026logo=jenkins\u0026logoColor=white) ![GHCR](https://img.shields.io/badge/GHCR-181717?style=flat-square\u0026logo=github\u0026logoColor=white) ![AWS CloudFront](https://img.shields.io/badge/AWS_CloudFront-FF9900?style=flat-square\u0026logo=amazoncloudwatch\u0026logoColor=white) ![AWS CodeDeploy](https://img.shields.io/badge/AWS_CodeDeploy-232F3E?style=flat-square\u0026logo=amazonwebservices\u0026logoColor=white) ![AWS WAF](https://img.shields.io/badge/AWS_WAF-232F3E?style=flat-square\u0026logo=amazonwebservices\u0026logoColor=white) ![AWS Shield](https://img.shields.io/badge/AWS_Shield-232F3E?style=flat-square\u0026logo=amazonwebservices\u0026logoColor=white)\n![Trivy](https://img.shields.io/badge/Trivy-1904DA?style=flat-square\u0026logoColor=white) ![tfsec](https://img.shields.io/badge/tfsec-3D5AFE?style=flat-square\u0026logoColor=white) ![Checkov](https://img.shields.io/badge/Checkov-FCC624?style=flat-square\u0026logoColor=black) ![Infracost](https://img.shields.io/badge/Infracost-DB44B8?style=flat-square\u0026logoColor=white) ![OpenAPI](https://img.shields.io/badge/OpenAPI-6BA539?style=flat-square\u0026logo=openapiinitiative\u0026logoColor=white) ![GitHub Container Registry](https://img.shields.io/badge/GitHub_Container_Registry-181717?style=flat-square\u0026logo=github\u0026logoColor=white)\n---\n\n## 📋 Table of Contents\n\n1. [About PetSwipe](#-about-petswipe)\n2. [Live App](#-live-app)\n3. [Features](#-features)\n4. [Tech Stack \u0026 Architecture](#-tech-stack--architecture)\n5. [User Interface](#-user-interface)\n6. [Database Schema](#-database-schema-typeorm-entities)\n7. [Getting Started](#-getting-started)\n   - [Backend Setup](#-backend-setup)\n   - [Frontend Setup](#-frontend-setup)\n8. [API Reference](#-api-reference)\n   - [Authentication](#authentication)\n   - [Matches](#matches)\n   - [Pets](#pets)\n   - [Swipes](#swipes)\n   - [Users](#users)\n   - [Swagger UI](#swagger-ui)\n9. [AWS Deployment](#-aws-deployment)\n   - [Production-Ready Deployment Strategies](#production-ready-deployment-strategies)\n   - [Infrastructure Stack](#infrastructure-stack)\n   - [Terraform](#terraform)\n   - [Vault, Consul, Nomad](#vault-consul-nomad)\n   - [Ansible](#ansible)\n10. [Agentic AI Integration](#-agentic-ai-integration)\n11. [Scripts \u0026 Utilities](#-scripts--utilities)\n    - [Docker](#docker)\n12. [Testing](#-testing)\n    - [Playwright](#playwright)\n    - [Jest](#jest)\n    - [Chai \u0026 Mocha](#chai--mocha)\n13. [GitHub Actions CI/CD](#-github-actions)\n14. [Command Line Interface](#-command-line-interface)\n15. [Monitoring \u0026 Observability](#-monitoring--observability)\n16. [Contributing](#-contributing)\n17. [License](#-license)\n18. [Author](#-author)\n\n---\n\n## 🐾 About PetSwipe\n\nPetSwipe is a full-stack application that allows users to swipe through pets available for adoption. The app is designed to be user-friendly and visually appealing, with a focus on providing a seamless experience for both users and shelter staff.\n\nThe app is built using modern technologies, including **TypeScript**, **Next.js**, **Express**, and **PostgreSQL**. It leverages the power of **AWS** for storage and deployment, ensuring scalability and reliability.\n\nThe app is also designed to be modular and easy to extend, with a focus on clean code and best practices. It includes features such as user authentication, a swipe interface, personalized pet decks, and admin tools for managing pets and users.\n\nAnd most importantly, it is built with the goal of helping shelter animals find their forever homes. By providing a fun and engaging way for users to browse pets, PetSwipe aims to increase adoption rates and raise awareness about the importance of pet adoption. 🐾\n\nI hope you enjoy using PetSwipe as much as I enjoyed building it! 🐱\n\n\u003e [!TIP]\n\u003e Please spread the word about PetSwipe to your friends and family, and help us find loving homes for as many pets as possible! 🏠❤️\n\n---\n\n## 🌐 Live App\n\n**[PetSwipe](https://petswipe.vercel.app)** is live on Vercel! You can now try it out and see how it works.\n\n\u003e [!TIP]\n\u003e Link not working? Copy and paste this URL into your browser: [https://petswipe.vercel.app](https://petswipe.vercel.app).\n\nAlso, checkout the backend API at **[PetSwipe API](https://petswipe-backend-api.vercel.app/)**. You can use tools like Postman or Swagger UI to explore the API endpoints.\n\n\u003e [!IMPORTANT] \u003e **Note**: Currently, most of the data is seeded with dummy data. We hope the app will be used by more real users and pet adoption shelters in the future. If you are a shelter or a pet adoption organization, please reach out to us to get **all** your data integrated into the app in seconds! Or you can also use the in-app manual add pet features to further enrich our pets database (only works for authenticated users).\n\n---\n\n## 🚀 Features\n\nPetSwipe is a full-stack application with the following features:\n\n- **User Authentication**:\n  - Login, signup, password reset functionalities are all implemented\n  - **JWT-based authentication**, where tokens are stored in **HTTP-only cookies** for security\n- **Swipe Interface**:\n  - Swipe left/right or press arrow keys/buttons to navigate through the deck of pets cards\n  - For each card, users can view pet details, photos, and decide to adopt or pass\n  - Each user is randomly assigned a sample selection of pet cards (around 90-110 cards) to review. As the app gathers more real, user-added pet data, it will improve in matching users with the most relevant pets.\n- **Personalized Deck**:\n  - Deck is generated based on user preferences and past swipes\n  - Users will only see pets that they haven't swiped on before, and pets that are most relevant to them\n- **History**: View all swipes \u0026 liked (adopted) pets\n- **Adoption Planner**:\n  - Dedicated shortlist decision page with compatibility and readiness scoring for liked pets\n  - Includes paginated pet comparison, home-fit guidance, budget/time estimates, checklist-driven prep, shelter questions, and suggested outreach notes\n- **Preference Insights**:\n  - Dedicated analytics page based on real swipe history\n  - Includes swipe activity charts, decision split, pet-type affinity, shelter momentum, and recommendation blocks that feed back into the planner flow\n- **Pets Map**:\n  - Map page for shelter discovery and geographic browsing\n  - Geocoding now runs through a same-origin proxy with normalized queries, hit/miss caching, in-flight deduplication, lower concurrency, and client-side cache reuse to reduce slow repeated lookups\n- **Chatbot**:\n  - A simple chatbot to answer common questions about the app and pets (e.g. breeds, adoption process, pet care tips, etc.)\n  - Powered by **Google AI** and **Retrieval-Augmented Generation (RAG)** for personalized responses\n- **Admin Tools**:\n  - Bulk upload pets via CSV\n  - Export pets data\n  - Photo uploads to S3\n  - Manual match assignment\n  - and more!\n- **Responsive UI**: Built with **Tailwind CSS** and **shadcn/ui**\n  - Fully responsive design for mobile and desktop\n  - Light and dark mode support\n  - Accessible design for all users\n  - Mobile-specific navbar layout with compact quick actions and a dedicated menu panel instead of a squeezed desktop toolbar\n- **Real-time Animations**:\n  - Framer Motion for smooth transitions and animations\n  - Swipe animations for a more engaging experience\n  - Loading spinners and skeleton screens for better UX\n- **Analytics**: Countups of swipes, matches, adoptions, etc. all are available to admins\n\n---\n\n## 🏛 Tech Stack \u0026 Architecture\n\nPetSwipe is built using a modern tech stack, ensuring scalability, maintainability, and performance. The architecture is designed to be modular and easy to extend.\n\n| Layer                   | Technology                                                                                |\n| ----------------------- | ----------------------------------------------------------------------------------------- |\n| **Frontend**            | Next.js, React, TypeScript, Tailwind CSS, shadcn/ui, Framer Motion, SWR                   |\n| **Backend \u0026 API**       | Node.js, Express, TypeScript, TypeORM, PostgreSQL, OpenAPI (via Swagger), RabbitMQ, Redis |\n| **Data \u0026 Storage**      | AWS RDS (PostgreSQL), AWS S3                                                              |\n| **Security \u0026 Auth**     | JSON Web Tokens, bcryptjs, cookie-parser                                                  |\n| **DevOps \u0026 Deployment** | Docker, Kubernetes, AWS ECR \u0026 ECS (Fargate), Vercel, GitHub Actions                       |\n| **Infrastructure**      | Terraform, Kubernetes manifests, Consul, Vault, Nomad, AWS IAM, AWS CloudWatch, AWS ALB   |\n| **AI**                  | Google AI, Retrieval-Augmented Generation (RAG)                                           |\n| **Testing**             | Playwright (frontend), Jest (backend)                                                     |\n\n### High-Level System Architecture\n\n```mermaid\nflowchart TB\n    subgraph Client[\"🖥️ Client Layer\"]\n        Browser[\"Web Browser\"]\n        Mobile[\"Mobile Browser\"]\n    end\n\n    subgraph CDN[\"🌐 CDN \u0026 Edge\"]\n        Vercel[\"Vercel Edge Network\"]\n        CloudFront[\"AWS CloudFront\"]\n    end\n\n    subgraph Frontend[\"⚛️ Frontend (Next.js)\"]\n        NextApp[\"Next.js Application\"]\n        SWR[\"SWR Data Fetching\"]\n        Framer[\"Framer Motion\"]\n        Shadcn[\"shadcn/ui Components\"]\n    end\n\n    subgraph LoadBalancing[\"⚖️ Load Balancing\"]\n        ALB[\"AWS Application Load Balancer\"]\n        TG[\"Target Group\"]\n    end\n\n    subgraph Backend[\"🔧 Backend Services\"]\n        ECS[\"AWS ECS Fargate\"]\n        Express[\"Express.js API\"]\n        TypeORM[\"TypeORM\"]\n        Redis[\"Redis Cache\"]\n        RabbitMQ[\"RabbitMQ\"]\n    end\n\n    subgraph Data[\"💾 Data Layer\"]\n        RDS[\"AWS RDS PostgreSQL\"]\n        S3[\"AWS S3 Storage\"]\n        Supabase[\"Supabase (Backup)\"]\n    end\n\n    subgraph AI[\"🤖 AI Services\"]\n        GoogleAI[\"Google AI / Gemini\"]\n        RAG[\"RAG System\"]\n    end\n\n    subgraph Monitoring[\"📊 Monitoring \u0026 Observability\"]\n        Prometheus[\"Prometheus\"]\n        Grafana[\"Grafana\"]\n        CloudWatch[\"AWS CloudWatch\"]\n    end\n\n    subgraph Infrastructure[\"🏗️ Infrastructure as Code\"]\n        Terraform[\"Terraform\"]\n        Consul[\"HashiCorp Consul\"]\n        Vault[\"HashiCorp Vault\"]\n        Nomad[\"HashiCorp Nomad\"]\n        Ansible[\"Ansible\"]\n    end\n\n    subgraph CICD[\"🚀 CI/CD Pipeline\"]\n        GHA[\"GitHub Actions\"]\n        Jenkins[\"Jenkins\"]\n        ECR[\"AWS ECR\"]\n        GHCR[\"GitHub Container Registry\"]\n    end\n\n    Browser --\u003e Vercel\n    Mobile --\u003e Vercel\n    Vercel --\u003e NextApp\n    NextApp --\u003e SWR\n    SWR --\u003e ALB\n    ALB --\u003e TG\n    TG --\u003e ECS\n    ECS --\u003e Express\n    Express --\u003e TypeORM\n    Express --\u003e Redis\n    Express --\u003e RabbitMQ\n    TypeORM --\u003e RDS\n    Express --\u003e S3\n    Express --\u003e GoogleAI\n    GoogleAI --\u003e RAG\n\n    Express --\u003e Prometheus\n    Prometheus --\u003e Grafana\n    ECS --\u003e CloudWatch\n\n    GHA --\u003e ECR\n    GHA --\u003e GHCR\n    GHA --\u003e Vercel\n    Jenkins --\u003e ECR\n    ECR --\u003e ECS\n\n    Terraform --\u003e Backend\n    Terraform --\u003e Data\n    Consul --\u003e Backend\n    Vault --\u003e Backend\n    Nomad --\u003e Backend\n    Ansible --\u003e Infrastructure\n\n    S3 -.Backup.-\u003e Supabase\n```\n\n### Infrastructure \u0026 Deployment Flow\n\n```mermaid\nflowchart LR\n    subgraph Development[\"👨‍💻 Development\"]\n        Dev[\"Developer\"]\n        Git[\"Git Repository\"]\n    end\n\n    subgraph CI[\"🔄 Continuous Integration\"]\n        GHA[\"GitHub Actions\"]\n        Jenkins[\"Jenkins Pipeline\"]\n        Lint[\"Linting \u0026 Format\"]\n        Test[\"Testing Suite\"]\n        Build[\"Build Process\"]\n        Security[\"Security Scan\"]\n    end\n\n    subgraph Registry[\"📦 Container Registry\"]\n        ECR[\"AWS ECR\"]\n        GHCR[\"GitHub CR\"]\n    end\n\n    subgraph IaC[\"🏗️ Infrastructure\"]\n        TF[\"Terraform Apply\"]\n        Ansible[\"Ansible Playbooks\"]\n    end\n\n    subgraph AWS[\"☁️ AWS Cloud\"]\n        ECS[\"ECS Fargate\"]\n        RDS[\"RDS PostgreSQL\"]\n        S3[\"S3 Buckets\"]\n        ALB[\"Load Balancer\"]\n        CW[\"CloudWatch\"]\n    end\n\n    subgraph HashiStack[\"🔐 HashiCorp Stack\"]\n        Consul[\"Service Discovery\"]\n        Vault[\"Secrets Management\"]\n        Nomad[\"Orchestration\"]\n    end\n\n    Dev --\u003e|Push Code| Git\n    Git --\u003e|Trigger| GHA\n    Git --\u003e|Trigger| Jenkins\n    GHA --\u003e Lint\n    Lint --\u003e Test\n    Test --\u003e Security\n    Security --\u003e Build\n    Build --\u003e ECR\n    Build --\u003e GHCR\n\n    Jenkins --\u003e Lint\n\n    ECR --\u003e ECS\n    TF --\u003e|Provision| AWS\n    TF --\u003e|Configure| HashiStack\n    Ansible --\u003e|Deploy| AWS\n\n    Consul --\u003e ECS\n    Vault --\u003e ECS\n    Nomad --\u003e ECS\n\n    ECS --\u003e ALB\n    ECS --\u003e RDS\n    ECS --\u003e S3\n    ECS --\u003e CW\n```\n\n### Data Flow \u0026 Entity Relationships\n\n```mermaid\nerDiagram\n    AppUser ||--o{ Swipe : makes\n    AppUser ||--o{ Match : receives\n    AppUser {\n        uuid id PK\n        string email UK\n        string password\n        string name\n        date dob\n        text bio\n        text avatarUrl\n        timestamp createdAt\n        timestamp updatedAt\n    }\n\n    Pet ||--o{ Swipe : receives\n    Pet ||--o{ Match : appears_in\n    Pet {\n        uuid id PK\n        string name\n        string type\n        text description\n        text photoUrl\n        string shelterName\n        text shelterContact\n        text shelterAddress\n        timestamp createdAt\n        timestamp updatedAt\n    }\n\n    Swipe {\n        uuid id PK\n        uuid userId FK\n        uuid petId FK\n        boolean liked\n        timestamp swipedAt\n    }\n\n    Match {\n        uuid id PK\n        uuid userId FK\n        uuid petId FK\n        timestamp matchedAt\n    }\n```\n\n### Authentication \u0026 Security Flow\n\n```mermaid\nsequenceDiagram\n    participant User as 👤 User\n    participant Frontend as ⚛️ Next.js\n    participant ALB as ⚖️ ALB\n    participant Backend as 🔧 Express API\n    participant Vault as 🔐 Vault\n    participant DB as 💾 PostgreSQL\n    participant S3 as 📦 S3\n\n    User-\u003e\u003eFrontend: Visit App\n    Frontend-\u003e\u003eUser: Show Login Page\n    User-\u003e\u003eFrontend: Submit Credentials\n    Frontend-\u003e\u003eALB: POST /api/auth/login\n    ALB-\u003e\u003eBackend: Forward Request\n    Backend-\u003e\u003eVault: Retrieve Secrets\n    Vault--\u003e\u003eBackend: Return Secrets\n    Backend-\u003e\u003eDB: Verify Credentials\n    DB--\u003e\u003eBackend: User Data\n    Backend-\u003e\u003eBackend: Generate JWT\n    Backend-\u003e\u003eALB: Set HTTP-Only Cookie\n    ALB--\u003e\u003eFrontend: 200 OK + Token\n    Frontend-\u003e\u003eFrontend: Store Auth State\n\n    User-\u003e\u003eFrontend: Upload Avatar\n    Frontend-\u003e\u003eALB: POST /api/users/me/avatar\n    ALB-\u003e\u003eBackend: Forward with JWT\n    Backend-\u003e\u003eBackend: Verify JWT\n    Backend-\u003e\u003eS3: Upload Image\n    S3--\u003e\u003eBackend: S3 URL\n    Backend-\u003e\u003eDB: Update User Record\n    Backend-\u003e\u003eALB: Return Success\n    ALB--\u003e\u003eFrontend: 200 OK\n    Frontend--\u003e\u003eUser: Show Updated Profile\n```\n\n---\n\n## 🏗 User Interface\n\n### Current UX Highlights\n\n- **Navigation**:\n  - Desktop navigation uses icon-first actions for map, pets, insights, and planner with tooltips\n  - Mobile navigation uses a dedicated compact header and a full action panel instead of squeezing the desktop toolbar into small widths\n- **Adoption Planner**:\n  - Compare liked pets in paginated groups of four\n  - Compatibility and readiness gauges, home-fit guidance, transition planning, checklist-driven prep, and action-oriented outreach support\n- **Preference Insights**:\n  - Responsive chart-based analytics with swipe trends, decision split, type affinity, and shelter momentum\n  - Shared chart styling now uses solid tooltips, dark-mode-safe text colors, and mobile-safe sizing\n- **Pets Map**:\n  - Cache-first shelter geocoding pipeline with deduped requests and safer fallbacks for better performance\n  - Query, pet, and miss caches reduce repeated address lookups when users paginate around the map\n\n### Landing Page\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/landing.png\" alt=\"Landing Page\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Home Page\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/home-1.png\" alt=\"Home Page\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/home-2.png\" alt=\"Home Page\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n#### Home Page Overview\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/record.gif\" alt=\"Home Page Record\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### All Swipes\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/all-swipes.png\" alt=\"All Swipes\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Adopted Pets\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/adopted.png\" alt=\"Adopted Pets\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Pet Details\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/pet-details.png\" alt=\"Pet Details\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### My Pets\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/my-pets.png\" alt=\"My Pets\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Pets Map\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/pets-map.png\" alt=\"Pets Map\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Preference Insights\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/preference-insights.png\" alt=\"Preference Insights\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Adoption Planner\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/adoption-planner.png\" alt=\"Adoption Planner\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Bulk Upload Pets\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/bulk-upload.png\" alt=\"Bulk Upload Pets\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Chatbot\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/chatbot.png\" alt=\"Chatbot\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Profile\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/profile.png\" alt=\"Profile\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Login \u0026 Signup\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/login.png\" alt=\"Login\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/signup.png\" alt=\"Signup\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Reset Password\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/reset-password.png\" alt=\"Reset Password\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### FAQ\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/faq.png\" alt=\"FAQ\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n_and so many more..._\n\n---\n\n## 🗄 Database Schema (TypeORM Entities)\n\n| Entity      | Column           | Type                  | Nullable | Description                     | Notes / Relations                              |\n| ----------- | ---------------- | --------------------- | -------- | ------------------------------- | ---------------------------------------------- |\n| **Match**   | `id`             | `uuid`                | No       | Primary key                     | `@PrimaryGeneratedColumn(\"uuid\")`              |\n|             | `user`           | `ManyToOne → AppUser` | No       | Who is swiping                  | FK → `AppUser.id`, cascade on delete           |\n|             | `pet`            | `ManyToOne → Pet`     | No       | Which pet was presented         | FK → `Pet.id`, cascade on delete               |\n|             | `matchedAt`      | `timestamp`           | No       | When it was shown               | `@CreateDateColumn()`                          |\n| **Pet**     | `id`             | `uuid`                | No       | Primary key                     | `@PrimaryGeneratedColumn(\"uuid\")`              |\n|             | `name`           | `varchar`             | No       | e.g. “Buddy” or “Whiskers”      | `@Column()`                                    |\n|             | `type`           | `varchar`             | No       | e.g. “Dog”, “Cat”               | `@Column()`                                    |\n|             | `description`    | `text`                | Yes      | Breed, color, age etc.          | `@Column({ type: \"text\", nullable: true })`    |\n|             | `photoUrl`       | `text`                | Yes      | URL to photo(s)                 | `@Column({ type: \"text\", nullable: true })`    |\n|             | `shelterName`    | `varchar`             | Yes      | The shelter this pet is from    | `@Column({ type: \"varchar\", nullable: true })` |\n|             | `shelterContact` | `text`                | Yes      | Contact info for the shelter    | `@Column({ type: \"text\", nullable: true })`    |\n|             | `shelterAddress` | `text`                | Yes      | Physical address of the shelter | `@Column({ type: \"text\", nullable: true })`    |\n|             | `matches`        | `OneToMany → Match[]` | —        | All Match records for this pet  | inverse of `Match.pet`                         |\n|             | `swipes`         | `OneToMany → Swipe[]` | —        | All Swipe records for this pet  | inverse of `Swipe.pet`                         |\n|             | `createdAt`      | `timestamp`           | No       | When record was created         | `@CreateDateColumn()`                          |\n|             | `updatedAt`      | `timestamp`           | No       | When record was last updated    | `@UpdateDateColumn()`                          |\n| **Swipe**   | `id`             | `uuid`                | No       | Primary key                     | `@PrimaryGeneratedColumn(\"uuid\")`              |\n|             | `user`           | `ManyToOne → AppUser` | No       | Who swiped                      | FK → `AppUser.id`, cascade on delete           |\n|             | `pet`            | `ManyToOne → Pet`     | No       | Which pet was swiped on         | FK → `Pet.id`, cascade on delete               |\n|             | `liked`          | `boolean`             | No       | `true` = adopt, `false` = pass  | `@Column()`                                    |\n|             | `swipedAt`       | `timestamp`           | No       | When the swipe occurred         | `@CreateDateColumn()`                          |\n|             | **unique index** | `(user, pet)`         | —        | Prevent duplicate swipes        | `@Index([\"user\",\"pet\"],{unique:true})`         |\n| **AppUser** | `id`             | `uuid`                | No       | Primary key                     | `@PrimaryGeneratedColumn(\"uuid\")`              |\n|             | `email`          | `varchar`             | No       | Unique user email               | `@Column({ unique: true })`                    |\n|             | `password`       | `varchar`             | Yes      | Hashed password                 | `@Column({ nullable: true })`                  |\n|             | `name`           | `varchar`             | Yes      | User’s full name                | `@Column({ nullable: true })`                  |\n|             | `dob`            | `date`                | Yes      | Date of birth                   | `@Column({ type: \"date\", nullable: true })`    |\n|             | `bio`            | `text`                | Yes      | User biography                  | `@Column({ type: \"text\", nullable: true })`    |\n|             | `avatarUrl`      | `text`                | Yes      | URL to avatar image             | `@Column({ type: \"text\", nullable: true })`    |\n|             | `matches`        | `OneToMany → Match[]` | —        | All Match records by this user  | inverse of `Match.user`                        |\n|             | `swipes`         | `OneToMany → Swipe[]` | —        | All Swipe records by this user  | inverse of `Swipe.user`                        |\n|             | `createdAt`      | `timestamp`           | No       | When user was created           | `@CreateDateColumn()`                          |\n|             | `updatedAt`      | `timestamp`           | No       | When user was last updated      | `@UpdateDateColumn()`                          |\n\n\u003e [!NOTE]\n\u003e This table may not be up-to-date, as more entities and relationships could be introduced in the near future to support additional features and enhancements!\n\n---\n\n## 🏁 Getting Started\n\n### Prerequisites\n\n- **Node.js** ≥ v18\n- **npm** ≥ v8 or **Yarn**\n- **PostgreSQL** (AWS RDS recommended)\n- **AWS CLI** \u0026 IAM credentials for S3, RDS\n- **Docker** (optional, for local Postgres container)\n- **Google AI** API key (for chatbot feature)\n\n\u003e [!CAUTION]\n\u003e ⚠️ **Note**: Due to `shadcn/ui` peerDeps, install frontend dependencies with:\n\u003e\n\u003e ```bash\n\u003e npm install --legacy-peer-deps\n\u003e # or\n\u003e yarn install --ignore-engines\n\u003e ```\n\n---\n\n### 🛠 Backend Setup\n\n1. **Clone \u0026 Install**\n\n   ```bash\n   git clone https://github.com/hoangsonww/PetSwipe-Match-App.git\n   cd PetSwipe-Match-App/backend\n   npm install\n   ```\n\n2. **Environment**\n   Copy and configure:\n\n   ```bash\n   cp .env.example .env\n   ```\n\n   - `DATABASE_URL`: your AWS RDS Postgres connection string\n   - `JWT_SECRET`, `COOKIE_SECRET`\n   - AWS: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_BUCKET_NAME`\n   - More in `.env.example`. Be sure that you have all required environment variables set up before running the app!\n\n3. **Seed Sample Pets** (optional)\n\n   ```bash\n   npm run seed:pets\n   ```\n\n4. **Run in Development**\n\n   ```bash\n   npm run dev\n   ```\n\n   The backend API is now available at `http://localhost:5001/api`.\n\n---\n\n### 🖥 Frontend Setup\n\n1. **Clone \u0026 Install**\n\n   ```bash\n   cd frontend\n   npm install --legacy-peer-deps\n   ```\n\n2. **Environment**\n   Create `.env.local`: (replace `http://localhost:5001` with your backend URL)\n\n   ```bash\n   NEXT_PUBLIC_API_URL=http://localhost:5001/api\n   ```\n\n3. **Run in Development**\n\n   ```bash\n   npm run dev\n   ```\n\n   Frontend available at `http://localhost:3000`\n\n4. **Build \u0026 Production**\n\n   ```bash\n   npm run build\n   npm run start\n   ```\n\n---\n\n## 📚 API Reference\n\nSwagger docs are served locally at `http://localhost:5001/api-docs.json`. You can also access the live API documentation at **[PetSwipe API](https://petswipe-backend-api.vercel.app/)**, and the JSON format at **[PetSwipe API JSON](https://petswipe-backend-api.vercel.app/api-docs.json)**.\n\n### Authentication\n\n- **POST** `/api/auth/signup`\n- **POST** `/api/auth/login`\n- **POST** `/api/auth/logout`\n- **POST** `/api/auth/verify-email`\n- **POST** `/api/auth/reset-password`\n\n### Matches\n\n- **POST** `/api/matches`\n- **GET** `/api/matches`\n- **GET** `/api/matches/me`\n\n### Pets\n\n- **GET** `/api/pets`\n- **POST** `/api/pets`\n- **GET** `/api/pets/export`\n- **POST** `/api/pets/:petId/photo`\n- **POST** `/api/pets/upload`\n- **GET** `/api/pets/mine`\n- **PUT** `/api/pets/:petId`\n- **GET** `/api/pets/:petId`\n\n### Swipes\n\n- **POST** `/api/swipes`\n- **GET** `/api/swipes/me`\n- **GET** `/api/swipes/me/liked`\n- **GET** `/api/swipes` (Admins only)\n\n### Users\n\n- **GET** `/api/users/me`\n- **PUT** `/api/users/me`\n- **POST** `/api/users/me/avatar`\n- **DELETE** `/api/users/me/avatar`\n\n### Chatbot\n\n- **POST** `/api/chat`\n\nMore endpoints may be added as the app evolves. Refer to the Swagger docs for the most up-to-date information!\n\n### Swagger UI\n\nSwagger UI is available at `https://petswipe-backend-api.vercel.app/`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/swagger.png\" alt=\"Swagger UI\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n---\n\n## ☁️ Deployment\n\n### Kubernetes Stack\n\nPetSwipe now ships with a first-class Kubernetes deployment stack under [`k8s/`](k8s/README.md).\n\n- `k8s/base` contains production-oriented manifests for frontend and backend deployments\n- readiness and liveness probes target `/ready`, `/health`, and `/`\n- horizontal autoscaling and PodDisruptionBudgets are included for both workloads\n- ingress is split across `petswipe.example.com` and `api.petswipe.example.com`\n- containers run as non-root users and are ready for EKS, GKE, AKS, or any conformant cluster\n\nQuick start:\n\n```bash\nkubectl apply -k k8s/base\n```\n\nBefore applying, replace the placeholder image names, hostnames, database endpoints, and secrets in [`k8s/base`](k8s/base).\n\n### AWS Deployment\n\n### Production-Ready Deployment Strategies\n\nPetSwipe features **enterprise-grade deployment strategies** for zero-downtime releases:\n\n#### 🔵🟢 Blue-Green Deployment\n- **Zero-downtime** deployments with instant rollback\n- Two identical environments (Blue \u0026 Green)\n- Perfect for major releases and database migrations\n- Rollback time: \u003c 30 seconds\n\n#### 🐤 Canary Deployment\n- **Gradual traffic shifting** (5% → 10% → 25% → 50% → 100%)\n- Automated rollback on errors or high latency\n- Real-time health monitoring during rollout\n- Progressive validation with production traffic\n\n#### ⚖️ Predicted Scaling \u0026 Auto-Scaling\n\n- Scale based on CPU, memory, and request metrics\n- Scheduled scaling for predictable traffic patterns\n- Load testing prior to deployment for capacity planning\n\n📖 **[Full Deployment Guide](docs/DEPLOYMENT.md)** | 🚀 **[Quick Reference](docs/DEPLOYMENT_QUICK_REFERENCE.md)**\n\n### Infrastructure Stack\n\nOur production infrastructure can run either on Kubernetes or on AWS-native container services. The repository currently includes Terraform-based AWS infrastructure plus a portable Kubernetes manifest set.\n\n**Compute \u0026 Orchestration:**\n- **Kubernetes**: Portable orchestration for EKS, GKE, AKS, or self-managed clusters\n  - Frontend and backend `Deployment` resources\n  - HPAs, PDBs, rolling updates, readiness/liveness probes\n  - TLS ingress with separate web and API hosts\n- **AWS ECS Fargate**: Serverless container orchestration\n  - Blue, Green, and Canary environments\n  - Auto-scaling based on CPU/memory metrics\n  - Circuit breaker deployment with automated rollback\n- **AWS ECR**: Private Docker registry with vulnerability scanning\n  - Backup: **GitHub Container Registry (GHCR)**\n\n**Networking \u0026 Load Balancing:**\n- **Application Load Balancer**: Traffic routing and health checks\n  - Weighted routing for canary deployments\n  - SSL/TLS termination with ACM certificates\n  - HTTP/2 and WebSocket support\n- **Route 53**: DNS management\n- **CloudFront**: CDN for static assets (optional)\n\n**Data \u0026 Storage:**\n- **AWS RDS PostgreSQL**: Multi-AZ database with automated backups\n  - Read replicas for scaling\n  - Performance Insights enabled\n  - Point-in-time recovery\n- **AWS S3**: Object storage\n  - Static assets bucket (public)\n  - Uploads bucket (private)\n  - ALB access logs\n  - Lifecycle policies for cost optimization\n  - Backup: **Supabase Storage**\n\n**Monitoring \u0026 Observability:**\n- **CloudWatch**: Comprehensive monitoring\n  - Custom dashboards (main + canary-specific)\n  - Metric alarms with SNS notifications\n  - Log aggregation and Insights queries\n  - X-Ray distributed tracing\n- **CloudWatch Alarms**: Proactive alerts\n  - Service health (CPU, memory, errors)\n  - Deployment health (canary metrics)\n  - Database performance\n  - Composite alarms for deployment quality\n\n**Security \u0026 Compliance:**\n- **AWS KMS**: Encryption for all resources\n- **AWS WAF**: Web application firewall\n- **AWS Shield**: DDoS protection (Standard)\n- **IAM**: Least-privilege access policies\n- **Security Groups**: Network-level access control\n- **Secrets Manager**: Sensitive configuration management\n\n**CI/CD \u0026 Deployment:**\n- **Jenkins**: Automated build and deployment pipelines\n  - Blue-Green pipeline: `Jenkinsfile.bluegreen`\n  - Canary pipeline: `Jenkinsfile.canary`\n  - Main CI pipeline with strategy selection\n- **AWS CodeDeploy**: ECS blue-green deployments\n- **Lambda**: Automated canary rollback function\n- **GitHub Actions**: Backup CI/CD\n- **Terraform**: Infrastructure as Code (100+ resources)\n\n**HashiCorp Stack (Optional):**\n- **Vault**: Secrets management and encryption-as-a-service\n- **Consul**: Service discovery and distributed configuration\n- **Nomad**: Alternative workload orchestration\n\n**Frontend Hosting:**\n- **Vercel**: Next.js application hosting with edge functions\n  - Automatic deployments from Git\n  - Preview deployments for PRs\n  - Global CDN distribution\n\n\u003e [!NOTE]\n\u003e Our infrastructure is designed for **production-grade reliability, security, and scalability**. The use of blue-green and canary deployments ensures zero-downtime releases with instant rollback capabilities. All infrastructure is version-controlled and reproducible via Terraform.\n\n### Terraform\n\nTo deploy the app to AWS, we use **Terraform** for Infrastructure as Code (IaC). This allows us to define our AWS resources in code and deploy them easily.\n\nTo get started with Terraform:\n\n1. Install Terraform on your machine.\n2. Navigate to the `infrastructure` directory:\n\n   ```bash\n   cd terraform\n   ```\n\n3. Initialize Terraform:\n\n   ```bash\n    terraform init\n   ```\n\n4. Configure your AWS credentials in `~/.aws/credentials` or set them as environment variables.\n5. Run the following commands to deploy:\n\n   ```bash\n   terraform plan    # Preview the changes\n   terraform apply   # Apply the changes\n   ```\n\nThis will create the necessary AWS resources for the AWS-native deployment path, including RDS, S3, ECS, ECR, IAM roles, and more.\n\n\u003e [!CAUTION]\n\u003e Make sure you have the necessary permissions to create and manage AWS resources. Review the Terraform scripts before applying them to avoid any unintended changes. For more details on how to configure and use Terraform with AWS, check out the [Terraform AWS Provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs).\n\n### Vault, Consul, Nomad\n\nFor managing secrets and service discovery, we use **HashiCorp Vault**, **Consul**, and **Nomad**. These tools help us securely store sensitive information, manage configurations, and orchestrate our services.\n\nThese tools provide:\n\n- **Secure secret storage \u0026 dynamic secret issuance** (Vault)\n- **Encryption-as-a-Service \u0026 audit logging** (Vault)\n- **Distributed service discovery \u0026 health checking** (Consul)\n- **Centralized key/value configuration store** (Consul)\n- **Identity-based service mesh (mTLS) for secure service-to-service communication** (Consul)\n- **Flexible, multi-region workload orchestration \u0026 scheduling** (Nomad)\n- **Rolling upgrades, canary deployments \u0026 autoscaling** (Nomad)\n- **Support for containers, VMs \u0026 standalone binaries** (Nomad)\n\nThese tools are optional but recommended for larger, more complex deployments. They can be set up using Terraform as well. For more information, refer to the [terraform/README.md](terraform/README.md) file in the `terraform` directory to see how to configure and deploy these tools.\n\n\u003e [!NOTE]\n\u003e If you are not familiar with these tools, you can skip this section for now. The app can run without them, but they provide additional security and flexibility for production deployments.\n\n### Ansible\n\nFor managing the deployment and configuration of the app, we also use **Ansible**. Ansible playbooks are used to automate tasks such as:\n\n- **Provisioning AWS infrastructure**\n  Create or update RDS instances, S3 buckets (static + uploads), ECR repositories, Application Load Balancer \u0026 Target Group, ECS clusters and services.\n\n- **Building \u0026 deploying containers**\n  Build, tag and push backend and frontend Docker images to ECR, then trigger zero-downtime rolling updates of your Fargate service.\n\n- **Configuring frontend hosting**\n  Sync Next.js static build to S3 and invalidate CloudFront distributions for instant cache busting.\n\n- **Managing application configuration**\n  Template out and distribute environment variables, secrets (via AWS Secrets Manager or HashiCorp Vault), and config files to running services.\n\n- **Database migrations \u0026 backups**\n  Run schema migrations on PostgreSQL (via TypeORM) and schedule or trigger automated backups and snapshots.\n\n- **Lifecycle \u0026 housekeeping**\n  Apply S3 lifecycle rules (e.g. purge old uploads), rotate credentials, and clean up unused resources.\n\n- **Service discovery \u0026 secrets bootstrap**\n  (If using HashiCorp stack) Bootstrap or update Consul/Nomad clusters, deploy Vault auto-unseal configuration, and distribute ACL tokens.\n\n- **OS \u0026 user management**\n  Install OS packages, manage system users, SSH keys, and security hardening on any EC2 hosts you might run.\n\n- **CI/CD integration**\n  Hook into GitHub Actions workflows to run Ansible playbooks on push or merge, ensuring every change is tested and deployed automatically.\n\n\u003e [!CAUTION]\n\u003e Remember to set up your AWS credentials and permissions correctly before running any Ansible playbooks. Ensure that the IAM user/role has the necessary permissions to create and manage the resources defined in your playbooks.\n\n\u003e [!TIP]\n\u003e For more information on how to use Ansible with AWS, check out the [ansible/README.md](ansible/README.md) file and the [Ansible AWS documentation](https://docs.ansible.com/ansible/latest/collections/amazon/aws/index.html).\n\n#### Important Notes\n\n\u003e [!WARNING]\n\u003e NEVER store sensitive information (like AWS credentials, database passwords, etc.) directly in your Ansible playbooks or inventory files. Use Ansible Vault or environment variables to securely manage secrets. Also, NEVER commit your `.env` files or any sensitive configuration files to version control!\n\n---\n\n## 🤖 Agentic AI Integration\n\nPetSwipe features a sophisticated **multi-agent AI system** built with **LangGraph** and **LangChain** that provides intelligent pet matching, personalized recommendations, and natural language conversations. The system uses an assembly line architecture where specialized agents work together to deliver the best possible pet-to-human matches.\n\n### Key Features\n\n- 🤖 **6 Specialized AI Agents** - User profiler, pet analyzer, matcher, recommender, conversation, and monitoring agents\n- ⚡ **Assembly Line Processing** - Sequential, observable agent execution with workflow timeouts\n- 🎯 **Intelligent Matching** - AI-powered compatibility scoring between users and pets\n- 💬 **Natural Conversations** - Context-aware chat with profile + recommendation grounding\n- 🌐 **REST + MCP WebSocket API** - `/v1/*` endpoints and MCP bridge for integrations\n- 📊 **Cost + Metrics Tracking** - Token/cost reporting, Prometheus metrics, Grafana dashboards\n- 🔐 **Production Controls** - API key auth, rate limiting, caching, and structured logging\n\n### Architecture\n\nThe agentic AI pipeline processes user requests through multiple stages:\n\n1. **User Profiling** - Analyzes user preferences and swipe history\n2. **Pet Analysis** - Extracts personality traits and compatibility factors from pet profiles\n3. **Matching** - Calculates compatibility scores using semantic matching\n4. **Recommendations** - Generates personalized pet recommendations\n5. **Conversation** - Handles natural language interactions\n6. **Monitoring** - Tracks performance metrics and system health\n\nFor detailed information about the AI system, including installation, configuration, REST/MCP API reference, cost tracking, and deployment guides, see the **[Agentic AI README](agentic_ai/README.md)**.\n\n---\n\n## 🛠 Scripts \u0026 Utilities\n\nThe app also comes with several scripts and utilities to help with development and deployment:\n\n- **Seed Pets**: `npm run seed:pets`\n- **Assign Pets**: `npm run assign:user`\n- **TypeORM CLI**: `npm run typeorm \u003ccommand\u003e`\n- **Swagger**: Auto-generated OpenAPI spec\n\nAdditionally, a `Makefile` is included for common tasks:\n\n```bash\nmake install        # Install dependencies\nmake start          # Start the backend server\nmake dev            # Start the backend server in development mode\nmake up             # Start the backend server with Docker\nmake test           # Run tests\nmake lint           # Lint the codebase\nmake deploy         # Deploy to AWS\nmake clean          # Clean up Docker containers\n\n# and more...\n```\n\n### Docker\n\nTo start the entire app with Docker, run:\n\n```bash\ndocker-compose up --build\n```\n\nThis will pull the images from ECR and start the backend and database containers locally on your machine.\n\nAdditionally, there are also Shell scripts that help you run Docker commands easily:\n\n1. `pull_and_run.sh`: Pulls the latest Docker image from ECR and runs it.\n2. `upload_to_ghcr.sh`: Builds the Docker image and uploads it to GitHub Container Registry (remember to set up your GitHub PAT and username in the script/export them in your shell).\n\n#### Docker Compute Terminal\n\nPetSwipe also includes a Docker Compute Terminal for running commands inside the Docker container. You can use it to run database migrations, seed data, or any other commands you need.\n\nTo hop into the Docker Compute Terminal, run:\n\n```bash\ndocker-compose exec compute /bin/zsh\n```\n\nThis will give you a shell inside the Docker container where you can run commands as if you were on a regular terminal, plus you can access all the installed dependencies and tools of the application.\n\n---\n\n## ⚛️ Testing\n\nPetSwipe includes a comprehensive testing suite to ensure the application works as expected. The tests are organized into three main categories:\n\n- **Playwright**: End-to-end tests for the frontend UI.\n- **Jest**: Unit and integration tests for the backend API and frontend API helper functions.\n- **Chai \u0026 Mocha**: Additional tests for specific features and functionalities.\n- **Commitlint**: Ensures commit messages follow the conventional commit format.\n\n### Playwright\n\nPlaywright is used for end-to-end testing of the frontend application. It simulates user interactions and verifies that the UI behaves as expected.\n\nTo run Playwright tests, navigate to the `frontend` directory and run:\n\n```bash\ncd frontend\nnpm run test:e2e\n```\n\n### Jest\n\nJest is used for unit and integration tests in the backend API and some frontend components. It provides a fast and reliable testing framework.\n\nTo run Jest tests in the backend, navigate to the `backend` directory and run:\n\n```bash\ncd backend\nnpm run test\n```\n\nThis will run all tests in the backend API, including unit tests for controllers, services, and integration tests for the database.\n\nTo run Jest tests in the frontend, navigate to the `frontend` directory and run:\n\n```bash\ncd frontend\nnpm run test\n```\n\n### Chai \u0026 Mocha\n\nChai and Mocha are used for additional tests in the frontend. To run Chai \u0026 Mocha tests, navigate to the `frontend` directory and run:\n\n```bash\ncd frontend\nnpm run test:mocha\n```\n\n---\n\n## 📝 GitHub Actions\n\nPetSwipe uses GitHub Actions for Continuous Integration and Continuous Deployment (CI/CD). The workflow is defined in `.github/workflows/workflow.yml`.\n\nThe CI/CD pipeline includes the following steps:\n\n- **Checkout Code**: Pulls the latest code from the repository.\n- **Set Up Node.js**: Installs the specified Node.js version.\n- **Install Dependencies**: Installs the necessary dependencies for both backend and frontend.\n- **Run Linting**: Runs ESLint and Prettier to ensure code quality and formatting.\n- **Run Tests**: Executes Jest tests for the backend and Playwright tests for the frontend.\n- **Build Frontend**: Builds the Next.js frontend application.\n- **Build Docker Images**: Builds Docker images for both backend and frontend.\n- **Push Docker Images**: Pushes the built images to GitHub Container Registry (GHCR).\n- **Deploy to AWS**: Deploys the backend API to AWS ECS and the frontend to Vercel.\n- **Notify on Failure**: Sends notifications via email if any step fails.\n- **Commitlint**: Ensures commit messages follow the conventional commit format.\n\nThis setup ensures that every change pushed to the repository is automatically tested, built, and deployed, providing a robust and reliable development workflow.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/gh.png\" alt=\"GitHub Actions Workflow\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n---\n\n## 🧪 Command Line Interface\n\nThe app also includes a CLI for managing pets and users. You can run the CLI commands from the root directory:\n\n```bash\npetswipe \u003ccommand\u003e [options]\n```\n\n### Available Commands\n\n- `petswipe dev`: Start backend \u0026 frontend in development mode.\n- `petswipe build`: Build both backend \u0026 frontend applications.\n- `petswipe docker:build`: Build \u0026 push Docker images to GitHub Container Registry.\n- `petswipe up`: Pull Docker images and start the stack.\n- `petswipe down`: Stop the Docker Compose stack.\n- `petswipe clean`: Remove build artifacts.\n- `petswipe lint`: Run linters in both projects.\n- `petswipe test`: Run tests in both projects.\n\nThis CLI is designed to make it easier to manage the application and perform common tasks without having to navigate through multiple directories or run multiple commands.\n\n---\n\n## 📊 Monitoring \u0026 Observability\n\nPetSwipe includes comprehensive monitoring and observability using Prometheus and Grafana to track application performance, health, and metrics.\n\n### Quick Access\n\n- **Prometheus**: http://localhost:9090 - Metrics collection and querying\n- **Grafana**: http://localhost:3001 - Dashboards and visualization (admin/admin)\n\n### Getting Started\n\nThe monitoring stack is automatically included when you run:\n\n```bash\ndocker-compose up -d\n```\n\nThis starts Prometheus, Grafana, and configures them to monitor your application services including the backend API, frontend, and database.\n\n### What's Monitored\n\n- Service uptime and health checks\n- Backend API performance metrics\n- Frontend application metrics\n- Database connection status\n- System resource usage\n\nFor detailed configuration and customization options, see [monitoring/Monitoring.md](monitoring/Monitoring.md).\n\n---\n\n## 🤝 Contributing\n\n1. Fork the repo \u0026 clone\n2. Create a feature branch\n3. Code, lint, test\n   - **IMPORTANT:** Run `npm run format` in the root directory to format all files before committing!\n4. Open a Pull Request. We'll review and merge it if it is meaningful and useful!\n\n**Please** follow the existing code style (ESLint, Prettier, TypeScript). This helps maintain a clean and consistent codebase!\n\n---\n\n## 📝 License\n\n© 2025 **[Son Nguyen](https://sonnguyenhoang.com)**. I hope this code is useful for you and your projects. Feel free to use it, modify it, and share it with others.\n\nLicensed under the **MIT License**. See [LICENSE](LICENSE) for details.\n\n\u003e [!IMPORTANT]\n\u003e In short, you may use this code for personal or educational purposes, but please do not use it for commercial purposes without permission. If you do use this code, please give proper credit to the original author.\n\n---\n\n## 💁🏻‍♂️ Author\n\nThis application is built with ❤️ by **[Son Nguyen](https://sonnguyenhoang.com)** in 2025:\n\n- [My GitHub](https://github.com/hoangsonww)\n- [My LinkedIn](https://www.linkedin.com/in/hoangsonw/)\n- [Email Me](mailto:hoangson091104@gmail.com)\n\nFeel free to reach out for any questions, suggestions, or even collaborations!\n\n---\n\n❤️ _Thank you for helping pets find their forever homes!_ 🐶🐱\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoangsonww%2Fpetswipe-match-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoangsonww%2Fpetswipe-match-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoangsonww%2Fpetswipe-match-app/lists"}