├── .nvmrc ├── frontend ├── .nvmrc ├── .env.example ├── .mocharc.json ├── public │ ├── OIP.jpg │ ├── logo.png │ ├── favicon.ico │ ├── favicon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── Dockerfile │ └── manifest.json ├── hooks │ ├── useUser.ts │ └── use-mobile.tsx ├── postcss.config.mjs ├── components │ ├── ui │ │ ├── aspect-ratio.tsx │ │ ├── skeleton.tsx │ │ ├── collapsible.tsx │ │ ├── textarea.tsx │ │ ├── label.tsx │ │ ├── input.tsx │ │ ├── separator.tsx │ │ ├── progress.tsx │ │ ├── sonner.tsx │ │ ├── checkbox.tsx │ │ ├── slider.tsx │ │ ├── switch.tsx │ │ ├── badge.tsx │ │ ├── hover-card.tsx │ │ ├── tooltip.tsx │ │ ├── popover.tsx │ │ ├── radio-group.tsx │ │ ├── avatar.tsx │ │ ├── toggle.tsx │ │ ├── scroll-area.tsx │ │ ├── alert.tsx │ │ ├── resizable.tsx │ │ ├── toggle-group.tsx │ │ ├── tabs.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── accordion.tsx │ │ └── input-otp.tsx │ ├── theme-provider.tsx │ ├── Layout.tsx │ └── Footer.tsx ├── lib │ └── utils.ts ├── next.config.ts ├── playwright.config.js ├── eslint.config.mjs ├── jest.config.js ├── components.json ├── tsconfig.json ├── .gitignore ├── Dockerfile ├── pages │ ├── api │ │ ├── chat-proxy.ts │ │ ├── pets │ │ │ └── [id].ts │ │ └── geocode.ts │ └── _app.tsx └── tests │ ├── helpers │ └── local-storage.js │ ├── mocha │ ├── chat-proxy.spec.js │ └── api.spec.js │ └── e2e │ └── basic.spec.js ├── backend ├── .gitignore ├── src │ ├── types │ │ └── express │ │ │ └── index.d.ts │ ├── bin │ │ └── runImageProcessor.ts │ ├── data-source.ts │ ├── routes │ │ ├── chat.ts │ │ ├── matches.ts │ │ ├── swipes.ts │ │ ├── auth.ts │ │ ├── users.ts │ │ └── pets.ts │ ├── middlewares │ │ ├── errorHandler.ts │ │ └── auth.ts │ ├── utils │ │ ├── csv.ts │ │ ├── jwt.ts │ │ ├── s3.ts │ │ ├── assignmentHelper.ts │ │ └── supabase.ts │ ├── config │ │ ├── redis.config.ts │ │ ├── index.ts │ │ ├── rabbitmq.config.ts │ │ └── ormconfig.ts │ ├── cache │ │ ├── redisClient.ts │ │ └── cacheService.ts │ ├── entities │ │ ├── Match.ts │ │ ├── Swipe.ts │ │ ├── User.ts │ │ └── Pet.ts │ ├── migrations │ │ └── 1710000000000-AddCreatedByToPet.ts │ ├── messaging │ │ ├── producers │ │ │ └── imageProducer.ts │ │ ├── rabbitmq.ts │ │ └── consumers │ │ │ └── imageProcessor.ts │ ├── index.ts │ └── services │ │ ├── imageService.ts │ │ └── userService.ts ├── vercel.json ├── jest.config.js ├── tsconfig.json ├── .env.example ├── Dockerfile ├── scripts │ └── assignPetsToUser.ts └── jest.setup.js ├── .prettierignore ├── agentic_ai ├── api │ ├── __init__.py │ ├── server.py │ └── schemas.py ├── tests │ ├── __init__.py │ ├── test_utils.py │ ├── test_workflow.py │ └── test_costs.py ├── service │ └── __init__.py ├── config │ ├── prometheus.yml │ ├── grafana │ │ ├── datasources │ │ │ └── datasource.yml │ │ └── dashboards │ │ │ └── dashboard.yml │ └── .env.example ├── workflows │ └── __init__.py ├── mcp_server │ └── __init__.py ├── __init__.py ├── agents │ └── __init__.py ├── utils │ ├── __init__.py │ ├── context.py │ ├── llm.py │ ├── security.py │ ├── logger.py │ └── cache.py ├── .gitignore ├── requirements.txt ├── aws │ └── README.md ├── Dockerfile ├── azure │ └── README.md ├── Makefile └── docker-compose.yml ├── lambda ├── predictive-scaling │ └── requirements.txt └── gitops-sync │ └── package.json ├── ansible ├── inventory.ini ├── ansible.cfg ├── playbook.yml ├── roles │ ├── s3 │ │ └── tasks │ │ │ └── main.yml │ ├── frontend │ │ └── tasks │ │ │ └── main.yml │ ├── rds │ │ └── tasks │ │ │ └── main.yml │ ├── ecr │ │ └── tasks │ │ │ └── main.yml │ ├── alb │ │ └── tasks │ │ │ └── main.yml │ └── ecs │ │ └── tasks │ │ └── main.yml └── group_vars │ └── all.yml ├── docs ├── img │ ├── faq.png │ ├── gh.png │ ├── home-1.png │ ├── home-2.png │ ├── login.png │ ├── logo.jpeg │ ├── logo.png │ ├── record.gif │ ├── signup.png │ ├── adopted.png │ ├── chatbot.png │ ├── landing.png │ ├── mermaid.png │ ├── my-pets.png │ ├── pets-map.png │ ├── profile.png │ ├── register.png │ ├── swagger.png │ ├── all-swipes.png │ ├── bulk-upload.png │ ├── pet-details.png │ └── reset-password.png └── SECURITY_SCANNING.md ├── .githooks └── commit-msg ├── tox.ini ├── Jenkinsfile ├── .gitattributes ├── .claude └── settings.local.json ├── terraform ├── vault │ ├── outputs.tf │ └── variables.tf ├── nomad │ ├── outputs.tf │ └── variables.tf ├── consul │ ├── outputs.tf │ ├── variables.tf │ └── main.tf ├── outputs.tf ├── provider.tf └── Dockerfile ├── tests └── terraform │ └── go.mod ├── .pre-commit-config.yaml ├── .idea ├── misc.xml ├── vcs.xml ├── compiler.xml ├── .gitignore ├── jsLibraryMappings.xml ├── copilot.data.migration.agent.xml ├── copilot.data.migration.ask.xml ├── copilot.data.migration.edit.xml ├── copilot.data.migration.ask2agent.xml ├── modules.xml ├── Dockerfile ├── PawSwipe-Fullstack-App.iml └── dataSources.xml ├── .gitignore ├── monitoring ├── grafana │ └── provisioning │ │ ├── datasources │ │ └── prometheus.yml │ │ └── dashboards │ │ └── dashboard.yml └── prometheus │ └── prometheus.yml ├── .editorconfig ├── tsconfig.json ├── pull_and_run.sh ├── pyproject.toml ├── .github ├── Dockerfile ├── workflows │ ├── Dockerfile │ └── deploy.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── pull_request_template.md ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── docker-compose.override.yml ├── scripts ├── canary-rollback-lambda │ └── package.json └── secret-scan.sh ├── bin ├── Dockerfile └── cli.js ├── aws ├── Dockerfile ├── ecs-utils.sh ├── s3-lifecycle.sh ├── rds-ops.sh ├── aws-messaging.js └── ecr-tools.sh ├── upload_to_ghcr.sh ├── LICENSE ├── jenkins └── Jenkinsfile.deploy ├── package.json ├── Dockerfile.compute └── docker-compose.yml /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.9.0 2 | -------------------------------------------------------------------------------- /frontend/.nvmrc: -------------------------------------------------------------------------------- 1 | 20.9.0 2 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | frontend/.next 2 | *.md 3 | -------------------------------------------------------------------------------- /agentic_ai/api/__init__.py: -------------------------------------------------------------------------------- 1 | """Agentic AI API package.""" 2 | -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_URL= 2 | -------------------------------------------------------------------------------- /lambda/predictive-scaling/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3>=1.28.0 2 | -------------------------------------------------------------------------------- /agentic_ai/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Test suite for Agentic AI.""" 2 | -------------------------------------------------------------------------------- /agentic_ai/service/__init__.py: -------------------------------------------------------------------------------- 1 | """Service layer for Agentic AI.""" 2 | -------------------------------------------------------------------------------- /ansible/inventory.ini: -------------------------------------------------------------------------------- 1 | [local] 2 | localhost ansible_connection=local 3 | -------------------------------------------------------------------------------- /docs/img/faq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/faq.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/gh.png -------------------------------------------------------------------------------- /frontend/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec": ["tests/mocha/**/*.spec.js"], 3 | "exit": true 4 | } 5 | -------------------------------------------------------------------------------- /docs/img/home-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/home-1.png -------------------------------------------------------------------------------- /docs/img/home-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/home-2.png -------------------------------------------------------------------------------- /docs/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/login.png -------------------------------------------------------------------------------- /docs/img/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/logo.jpeg -------------------------------------------------------------------------------- /docs/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/logo.png -------------------------------------------------------------------------------- /docs/img/record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/record.gif -------------------------------------------------------------------------------- /docs/img/signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/signup.png -------------------------------------------------------------------------------- /docs/img/adopted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/adopted.png -------------------------------------------------------------------------------- /docs/img/chatbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/chatbot.png -------------------------------------------------------------------------------- /docs/img/landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/landing.png -------------------------------------------------------------------------------- /docs/img/mermaid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/mermaid.png -------------------------------------------------------------------------------- /docs/img/my-pets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/my-pets.png -------------------------------------------------------------------------------- /docs/img/pets-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/pets-map.png -------------------------------------------------------------------------------- /docs/img/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/profile.png -------------------------------------------------------------------------------- /docs/img/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/register.png -------------------------------------------------------------------------------- /docs/img/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/swagger.png -------------------------------------------------------------------------------- /docs/img/all-swipes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/all-swipes.png -------------------------------------------------------------------------------- /docs/img/bulk-upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/bulk-upload.png -------------------------------------------------------------------------------- /docs/img/pet-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/pet-details.png -------------------------------------------------------------------------------- /frontend/public/OIP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/OIP.jpg -------------------------------------------------------------------------------- /frontend/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/logo.png -------------------------------------------------------------------------------- /docs/img/reset-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/docs/img/reset-password.png -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/favicon.png -------------------------------------------------------------------------------- /.githooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # commit-msg hook – runs Commitlint 3 | npx --no-install commitlint --edit "$1" 4 | -------------------------------------------------------------------------------- /frontend/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/favicon-32x32.png -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [testenv:secrets] 2 | deps = detect-secrets 3 | commands = detect-secrets scan --baseline .secrets.baseline --all-files 4 | -------------------------------------------------------------------------------- /frontend/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/PetSwipe-Match-App/HEAD/frontend/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | // Wrapper Jenkinsfile to delegate to the main CI pipeline under jenkins/Jenkinsfile.ci 3 | load 'jenkins/Jenkinsfile.ci' 4 | -------------------------------------------------------------------------------- /ansible/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = inventory.ini 3 | host_key_checking = False 4 | collections = 5 | - community.aws 6 | - community.docker 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.png binary 4 | *.jpg binary 5 | *.jpeg binary 6 | *.gif binary 7 | *.webp binary 8 | *.ico binary 9 | *.pdf binary 10 | -------------------------------------------------------------------------------- /.claude/settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "allow": ["Bash(tree:*)", "Bash(chmod:*)", "Bash(test:*)"], 4 | "deny": [], 5 | "ask": [] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /terraform/vault/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vault_servers_ips" { 2 | value = module.vault.servers_private_ips 3 | description = "Vault server private IP addresses" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/hooks/useUser.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { AuthContext } from "@/context/AuthContext"; 3 | 4 | export const useUser = () => useContext(AuthContext); 5 | -------------------------------------------------------------------------------- /frontend/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /frontend/components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; 2 | 3 | const AspectRatio = AspectRatioPrimitive.Root; 4 | 5 | export { AspectRatio }; 6 | -------------------------------------------------------------------------------- /tests/terraform/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/petswipe/infrastructure-tests 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/gruntwork-io/terratest v0.46.7 7 | github.com/stretchr/testify v1.8.4 8 | ) 9 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/Yelp/detect-secrets 3 | rev: v1.5.0 4 | hooks: 5 | - id: detect-secrets 6 | args: ["--baseline", ".secrets.baseline"] 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | /out-tsc 3 | 4 | /node_modules 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | /.pnp 9 | .pnp.js 10 | 11 | .vscode/* 12 | /backend/node_modules/ 13 | /backend/.env 14 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /frontend/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /agentic_ai/config/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: "agentic-ai" 6 | metrics_path: /metrics 7 | static_configs: 8 | - targets: ["agentic-ai:8765"] 9 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /agentic_ai/config/grafana/datasources/datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 8 | isDefault: true 9 | -------------------------------------------------------------------------------- /backend/src/types/express/index.d.ts: -------------------------------------------------------------------------------- 1 | import { AppUser } from "../../entities/User"; 2 | 3 | declare global { 4 | namespace Express { 5 | interface Request { 6 | user?: AppUser; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/copilot.data.migration.agent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/copilot.data.migration.ask.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/copilot.data.migration.edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/datasources/prometheus.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 8 | isDefault: true 9 | editable: true -------------------------------------------------------------------------------- /.idea/copilot.data.migration.ask2agent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /ansible/playbook.yml: -------------------------------------------------------------------------------- 1 | - name: Deploy petSwipe infrastructure & app 2 | hosts: local 3 | connection: local 4 | gather_facts: no 5 | 6 | roles: 7 | - rds 8 | - s3 9 | - ecr 10 | - alb 11 | - ecs 12 | - frontend 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /backend/src/bin/runImageProcessor.ts: -------------------------------------------------------------------------------- 1 | import "reflect-metadata"; 2 | import { startImageProcessor } from "../messaging/consumers/imageProcessor"; 3 | 4 | startImageProcessor().catch((err) => { 5 | console.error("Fatal error in image processor:", err); 6 | process.exit(1); 7 | }); 8 | -------------------------------------------------------------------------------- /backend/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "src/index.ts", 6 | "use": "@vercel/node" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "/(.*)", 12 | "dest": "src/index.ts" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /backend/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | preset: "ts-jest", // transpile the *.ts controllers on-the-fly 4 | testEnvironment: "node", 5 | verbose: true, 6 | setupFiles: ["/jest.setup.js"], 7 | roots: ["/tests"], 8 | }; 9 | -------------------------------------------------------------------------------- /backend/src/data-source.ts: -------------------------------------------------------------------------------- 1 | import "reflect-metadata"; 2 | import { DataSource } from "typeorm"; 3 | import ormconfig from "./config/ormconfig"; 4 | 5 | export const AppDataSource = new DataSource({ 6 | ...ormconfig, 7 | synchronize: false, 8 | migrations: ["src/migrations/*.{ts,js}"], 9 | }); 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "outDir": "dist" 10 | }, 11 | "include": ["src"] 12 | } 13 | -------------------------------------------------------------------------------- /agentic_ai/config/grafana/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: "agentic-ai" 5 | orgId: 1 6 | folder: "Agentic AI" 7 | type: file 8 | disableDeletion: false 9 | updateIntervalSeconds: 30 10 | options: 11 | path: /etc/grafana/provisioning/dashboards 12 | -------------------------------------------------------------------------------- /terraform/nomad/outputs.tf: -------------------------------------------------------------------------------- 1 | output "nomad_servers" { 2 | value = module.nomad.server_private_ips 3 | description = "Nomad server private IP addresses" 4 | } 5 | 6 | output "nomad_clients" { 7 | value = module.nomad.client_private_ips 8 | description = "Nomad client private IP addresses" 9 | } 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /backend/src/routes/chat.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { chatHandler } from "../controllers/chatController"; 3 | import { authMiddleware } from "../middlewares/auth"; 4 | 5 | export const router = Router(); 6 | 7 | router.use(authMiddleware); 8 | router.post("/", chatHandler); 9 | 10 | export default router; 11 | -------------------------------------------------------------------------------- /frontend/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | reactStrictMode: true, 6 | eslint: { 7 | ignoreDuringBuilds: true, 8 | }, 9 | typescript: { 10 | ignoreBuildErrors: true, 11 | }, 12 | }; 13 | 14 | export default nextConfig; 15 | -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'default' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | updateIntervalSeconds: 10 11 | allowUiUpdates: true 12 | options: 13 | path: /etc/grafana/provisioning/dashboards -------------------------------------------------------------------------------- /terraform/consul/outputs.tf: -------------------------------------------------------------------------------- 1 | output "consul_servers" { 2 | value = module.consul.server_private_ips 3 | description = "Consul server private IP addresses" 4 | } 5 | 6 | output "consul_acl_token" { 7 | value = module.consul.acl_bootstrap_token 8 | description = "Consul ACL bootstrap token (sensitive)" 9 | sensitive = true 10 | } 11 | -------------------------------------------------------------------------------- /frontend/playwright.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@playwright/test').PlaywrightTestConfig} */ 2 | module.exports = { 3 | testDir: "./tests/e2e", 4 | testMatch: "**/*.spec.@(js|ts)", 5 | timeout: 30_000, 6 | reporter: "list", 7 | use: { 8 | baseURL: process.env.E2E_BASE_URL || "http://localhost:3000", 9 | headless: true, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /pull_and_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # pull_and_run.sh 3 | # Pull latest images from GHCR and bring up your stack 4 | 5 | set -euo pipefail 6 | 7 | echo "📥 Pulling images from GHCR..." 8 | docker-compose pull 9 | 10 | echo "🚀 Starting services..." 11 | docker-compose up -d 12 | 13 | echo "✅ Stack is up! (db → 5432, backend → 5001, frontend → 3000)" 14 | -------------------------------------------------------------------------------- /frontend/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ); 13 | } 14 | 15 | export { Skeleton }; 16 | -------------------------------------------------------------------------------- /backend/src/middlewares/errorHandler.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | 3 | export function errorHandler( 4 | err: any, 5 | req: Request, 6 | res: Response, 7 | next: NextFunction, 8 | ) { 9 | console.error(err); 10 | res 11 | .status(err.status || 500) 12 | .json({ message: err.message || "Internal Server Error" }); 13 | } 14 | -------------------------------------------------------------------------------- /frontend/components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 5 | 6 | export function ThemeProvider({ 7 | children, 8 | ...props 9 | }: React.ComponentProps) { 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"; 4 | 5 | const Collapsible = CollapsiblePrimitive.Root; 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent }; 12 | -------------------------------------------------------------------------------- /agentic_ai/workflows/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Agentic AI Workflows 3 | ==================== 4 | 5 | LangGraph-based workflow orchestration for the agent assembly line. 6 | """ 7 | 8 | from .assembly_line import AssemblyLinePipeline 9 | from .workflow_builder import WorkflowBuilder 10 | from .state_manager import StateManager 11 | 12 | __all__ = [ 13 | "AssemblyLinePipeline", 14 | "WorkflowBuilder", 15 | "StateManager", 16 | ] 17 | -------------------------------------------------------------------------------- /backend/src/utils/csv.ts: -------------------------------------------------------------------------------- 1 | import { Parser } from "json2csv"; 2 | import { Request, Response } from "express"; 3 | 4 | /** 5 | * Convert objects to CSV and send as attachment. 6 | */ 7 | export function sendCsv(res: Response, data: T[], filename: string): void { 8 | const parser = new Parser(); 9 | const csv = parser.parse(data); 10 | res.header("Content-Type", "text/csv"); 11 | res.attachment(filename); 12 | res.send(csv); 13 | } 14 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "PetSwipe" 3 | version = "0.1.0" 4 | description = "Python package for PetSwipe, an app that helps users find and adopt pets." 5 | authors = [ 6 | { name="Son Nguyen", email="hoangson091104@gmail.com" }, 7 | ] 8 | dependencies = [ 9 | "detect-secrets==1.5.0", 10 | ] 11 | 12 | [build-system] 13 | requires = ["setuptools>=42", "wheel", "tomli>=1.1.0"] 14 | build-backend = "setuptools.build_meta" 15 | 16 | -------------------------------------------------------------------------------- /ansible/roles/s3/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure static website bucket exists 3 | community.aws.s3_bucket: 4 | name: "{{ static_bucket }}" 5 | region: "{{ aws_region }}" 6 | state: present 7 | website_configuration: 8 | index_document: index.html 9 | 10 | - name: Ensure uploads bucket exists 11 | community.aws.s3_bucket: 12 | name: "{{ uploads_bucket }}" 13 | region: "{{ aws_region }}" 14 | state: present 15 | -------------------------------------------------------------------------------- /backend/src/routes/matches.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { 3 | assignPets, 4 | listMatches, 5 | listMyMatches, 6 | } from "../controllers/matchController"; 7 | import { authMiddleware } from "../middlewares/auth"; 8 | 9 | const router = Router(); 10 | router.use(authMiddleware); 11 | 12 | router.post("/", assignPets); 13 | router.get("/", listMatches); 14 | router.get("/me", listMyMatches); 15 | 16 | export default router; 17 | -------------------------------------------------------------------------------- /agentic_ai/mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Model Context Protocol (MCP) Server 3 | ==================================== 4 | 5 | MCP server implementation for exposing agentic AI functionality 6 | through a standardized protocol. 7 | """ 8 | 9 | from .server import MCPServer 10 | from .handlers import RequestHandler 11 | from .protocol import MCPProtocol 12 | 13 | __all__ = [ 14 | "MCPServer", 15 | "RequestHandler", 16 | "MCPProtocol", 17 | ] 18 | -------------------------------------------------------------------------------- /.idea/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use VS Code’s official Node.js 18 devcontainer image 2 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:18 3 | 4 | # Install Docker Compose CLI 5 | RUN apt-get update \ 6 | && apt-get install -y docker-compose \ 7 | && apt-get clean -y \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # (Optional) Install global tools you find handy 11 | RUN npm install -g typescript ts-node 12 | 13 | # Default workdir 14 | WORKDIR /workspace 15 | -------------------------------------------------------------------------------- /lambda/gitops-sync/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitops-sync-lambda", 3 | "version": "1.0.0", 4 | "description": "Lambda function to trigger ArgoCD sync on deployment events", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "zip -r ../gitops-sync.zip .", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "dependencies": { 11 | "aws-sdk": "^2.1498.0" 12 | }, 13 | "author": "", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /.github/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use VS Code’s official Node.js 18 devcontainer image 2 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:18 3 | 4 | # Install Docker Compose CLI 5 | RUN apt-get update \ 6 | && apt-get install -y docker-compose \ 7 | && apt-get clean -y \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # (Optional) Install global tools you find handy 11 | RUN npm install -g typescript ts-node 12 | 13 | # Default workdir 14 | WORKDIR /workspace 15 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use VS Code’s official Node.js 18 devcontainer image 2 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:18 3 | 4 | # Install Docker Compose CLI 5 | RUN apt-get update \ 6 | && apt-get install -y docker-compose \ 7 | && apt-get clean -y \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # (Optional) Install global tools you find handy 11 | RUN npm install -g typescript ts-node 12 | 13 | # Default workdir 14 | WORKDIR /workspace 15 | -------------------------------------------------------------------------------- /backend/src/routes/swipes.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { 3 | recordSwipe, 4 | listMySwipes, 5 | listMyLikedSwipes, 6 | } from "../controllers/swipeController"; 7 | import { authMiddleware } from "../middlewares/auth"; 8 | 9 | const router = Router(); 10 | router.use(authMiddleware); 11 | 12 | router.post("/", recordSwipe); 13 | router.get("/me", listMySwipes); 14 | router.get("/me/liked", listMyLikedSwipes); 15 | 16 | export default router; 17 | -------------------------------------------------------------------------------- /.github/workflows/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use VS Code’s official Node.js 18 devcontainer image 2 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:18 3 | 4 | # Install Docker Compose CLI 5 | RUN apt-get update \ 6 | && apt-get install -y docker-compose \ 7 | && apt-get clean -y \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # (Optional) Install global tools you find handy 11 | RUN npm install -g typescript ts-node 12 | 13 | # Default workdir 14 | WORKDIR /workspace 15 | -------------------------------------------------------------------------------- /backend/src/routes/auth.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { 3 | signup, 4 | login, 5 | logout, 6 | verifyEmail, 7 | resetPassword, 8 | } from "../controllers/authController"; 9 | 10 | const router = Router(); 11 | 12 | router.post("/signup", signup); 13 | router.post("/login", login); 14 | router.post("/logout", logout); 15 | router.post("/verify-email", verifyEmail); 16 | router.post("/reset-password", resetPassword); 17 | 18 | export default router; 19 | -------------------------------------------------------------------------------- /frontend/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | compute: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile.compute 8 | container_name: petswipe-compute 9 | volumes: 10 | - .:/workspace 11 | working_dir: /workspace 12 | tty: true # allocate a TTY so we can exec interactive shells 13 | stdin_open: true # keep STDIN open 14 | environment: 15 | - SHELL=/bin/zsh 16 | - TERM=xterm-256color 17 | - 18 | -------------------------------------------------------------------------------- /frontend/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | // jsdom gives us window, localStorage, FormData, etc. 4 | testEnvironment: "jsdom", 5 | 6 | // transpile *.ts / *.tsx on-the-fly 7 | transform: { 8 | "^.+\\.(ts|tsx)$": "ts-jest", 9 | }, 10 | 11 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"], 12 | testMatch: ["**/__tests__/**/*.spec.[jt]s?(x)"], 13 | // completely silent test run – keep the CI log clean 14 | verbose: false, 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { Navbar } from "./Navbar"; 3 | import { Footer } from "./Footer"; 4 | 5 | export function Layout({ children }: { children: ReactNode }) { 6 | return ( 7 |
8 | 9 |
{children}
10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /scripts/canary-rollback-lambda/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canary-rollback-lambda", 3 | "version": "1.0.0", 4 | "description": "Automated canary deployment rollback Lambda function", 5 | "main": "index.js", 6 | "scripts": { 7 | "package": "zip -r ../canary-rollback.zip index.js package.json node_modules/" 8 | }, 9 | "dependencies": { 10 | "aws-sdk": "^2.1000.0" 11 | }, 12 | "engines": { 13 | "node": ">=18.0.0" 14 | }, 15 | "author": "PetSwipe DevOps Team", 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /.idea/PawSwipe-Fullstack-App.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "CommonJS", 5 | "outDir": "dist", 6 | "rootDir": "src", 7 | "strict": true, 8 | "moduleResolution": "Node", 9 | "esModuleInterop": true, 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "resolveJsonModule": true, 13 | "baseUrl": "./src", 14 | "paths": { "*": ["*"] }, 15 | "typeRoots": ["src/types", "node_modules/@types"] 16 | }, 17 | "include": ["src/**/*", "src/types/**/*.d.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /frontend/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "styles/globals.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /backend/src/utils/jwt.ts: -------------------------------------------------------------------------------- 1 | import * as jwt from "jsonwebtoken"; 2 | import config from "../config"; 3 | 4 | export function generateToken(userId: string): string { 5 | const secret = config.jwt.secret as jwt.Secret; 6 | const options: jwt.SignOptions = { 7 | expiresIn: config.jwt.expiresIn as jwt.SignOptions["expiresIn"], 8 | }; 9 | return jwt.sign({ userId }, secret, options); 10 | } 11 | 12 | export function verifyToken(token: string): { userId: string } { 13 | const secret = config.jwt.secret as jwt.Secret; 14 | return jwt.verify(token, secret) as { userId: string }; 15 | } 16 | -------------------------------------------------------------------------------- /terraform/consul/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" { 2 | type = string 3 | description = "VPC ID where Consul servers should run" 4 | } 5 | 6 | variable "private_subnet_ids" { 7 | type = list(string) 8 | description = "List of Private Subnets for Consul servers" 9 | } 10 | 11 | variable "consul_cluster_size" { 12 | type = number 13 | description = "Number of Consul server nodes" 14 | default = 3 15 | } 16 | 17 | variable "instance_type" { 18 | type = string 19 | description = "EC2 instance type for Consul servers" 20 | default = "t3.medium" 21 | } 22 | -------------------------------------------------------------------------------- /backend/src/routes/users.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { 3 | uploadAvatarMiddleware, 4 | uploadAvatarHandler, 5 | getProfile, 6 | updateProfile, 7 | deleteAvatarHandler, 8 | } from "../controllers/userController"; 9 | import { authMiddleware } from "../middlewares/auth"; 10 | 11 | const router = Router(); 12 | router.use(authMiddleware); 13 | 14 | router.get("/me", getProfile); 15 | router.put("/me", updateProfile); 16 | router.post("/me/avatar", uploadAvatarMiddleware, uploadAvatarHandler); 17 | router.delete("/me/avatar", deleteAvatarHandler); 18 | 19 | export default router; 20 | -------------------------------------------------------------------------------- /backend/src/config/redis.config.ts: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | dotenv.config(); 3 | 4 | /** 5 | * Reads Redis (AWS ElastiCache) connection parameters from environment variables. 6 | * 7 | * Expected env vars: 8 | * REDIS_HOST e.g. "my-redis-cluster.xxxxxx.use1.cache.amazonaws.com" 9 | * REDIS_PORT e.g. "6379" 10 | * REDIS_PASSWORD e.g. "supersecretpassword" 11 | */ 12 | 13 | export const REDIS_HOST = process.env.REDIS_HOST || "localhost"; 14 | export const REDIS_PORT = parseInt(process.env.REDIS_PORT || "6379", 10); 15 | export const REDIS_PASSWORD = process.env.REDIS_PASSWORD || ""; 16 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "react-jsx", 15 | "incremental": true, 16 | "paths": { 17 | "@/*": ["./*"] 18 | } 19 | }, 20 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /agentic_ai/api/server.py: -------------------------------------------------------------------------------- 1 | """Uvicorn entrypoint for Agentic AI API.""" 2 | 3 | import uvicorn 4 | 5 | from ..utils.config import load_config 6 | 7 | 8 | def main() -> None: 9 | config = load_config() 10 | server_cfg = config.get("server", {}) 11 | host = server_cfg.get("host", "0.0.0.0") 12 | port = server_cfg.get("port", 8765) 13 | workers = server_cfg.get("workers", 1) 14 | 15 | uvicorn.run( 16 | "agentic_ai.api.app:app", 17 | host=host, 18 | port=port, 19 | workers=workers, 20 | log_level="info", 21 | ) 22 | 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /backend/src/cache/redisClient.ts: -------------------------------------------------------------------------------- 1 | import Redis from "ioredis"; 2 | import { REDIS_HOST, REDIS_PORT, REDIS_PASSWORD } from "../config/redis.config"; 3 | 4 | // Create a single shared Redis client 5 | export const redisClient = new Redis({ 6 | host: REDIS_HOST, 7 | port: REDIS_PORT, 8 | password: REDIS_PASSWORD || undefined, 9 | tls: REDIS_PASSWORD ? {} : undefined, // If ElastiCache is in TLS mode 10 | }); 11 | 12 | redisClient.on("connect", () => { 13 | console.log(`[Redis] Connected to ${REDIS_HOST}:${REDIS_PORT}`); 14 | }); 15 | 16 | redisClient.on("error", (err: any) => { 17 | console.error("[Redis] Error:", err); 18 | }); 19 | -------------------------------------------------------------------------------- /ansible/roles/frontend/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Build frontend static site 3 | npm: 4 | path: "{{ playbook_dir }}/../frontend" 5 | executable: npm 6 | args: run build 7 | 8 | - name: Sync built assets to S3 9 | community.aws.aws_s3: 10 | bucket: "{{ static_bucket }}" 11 | mode: sync 12 | local_path: "{{ playbook_dir }}/../frontend/out" 13 | delete: yes 14 | region: "{{ aws_region }}" 15 | 16 | - name: Invalidate CloudFront (if configured) 17 | shell: > 18 | aws cloudfront create-invalidation 19 | --distribution-id {{ cf_distribution_id }} 20 | --paths "/*" 21 | when: cf_distribution_id != '' 22 | -------------------------------------------------------------------------------- /agentic_ai/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PetSwipe Agentic AI Pipeline 3 | ============================ 4 | 5 | A sophisticated agentic AI system using LangGraph and LangChain for intelligent 6 | pet matching, recommendation, and user interaction processing. 7 | 8 | Features: 9 | - Multi-agent assembly line architecture 10 | - LangGraph workflow orchestration 11 | - Model Context Protocol (MCP) server 12 | - Production-ready deployment configurations for AWS and Azure 13 | """ 14 | 15 | __version__ = "1.0.0" 16 | __author__ = "PetSwipe Team" 17 | 18 | from .agents import * 19 | from .workflows import * 20 | from .mcp_server import * 21 | from .config import * 22 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://postgresql-db-mysql-database-proj.d.aivencloud.com:11121/defaultdb 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /backend/src/entities/Match.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Entity, 3 | PrimaryGeneratedColumn, 4 | ManyToOne, 5 | CreateDateColumn, 6 | } from "typeorm"; 7 | import { AppUser } from "./User"; 8 | import { Pet } from "./Pet"; 9 | 10 | @Entity() 11 | export class Match { 12 | @PrimaryGeneratedColumn("uuid") 13 | id!: string; 14 | 15 | /** who is swiping */ 16 | @ManyToOne(() => AppUser, (u) => u.matches, { onDelete: "CASCADE" }) 17 | user!: AppUser; 18 | 19 | /** which pet was presented */ 20 | @ManyToOne(() => Pet, (p) => p.matches, { onDelete: "CASCADE" }) 21 | pet!: Pet; 22 | 23 | /** when it was shown */ 24 | @CreateDateColumn() 25 | matchedAt!: Date; 26 | } 27 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | # Server 2 | PORT=3000 3 | NODE_ENV=development 4 | JWT_SECRET=your_jwt_secret 5 | JWT_EXPIRES=1h 6 | 7 | # Postgres 8 | DB_HOST=your_postgres_host 9 | DB_PORT=your_postgres_port 10 | DB_USER=your_postgres_user 11 | DB_PASS=your_postgres_password 12 | DB_NAME=your_postgres_db_name 13 | 14 | # AWS S3 (for avatars) 15 | AWS_REGION=us-east-1 16 | AWS_ACCESS_KEY_ID=your_access_key_id 17 | AWS_SECRET_ACCESS_KEY=your_secret_access_key 18 | S3_BUCKET=your_avatar_bucket 19 | 20 | # Supabase 21 | NEXT_PUBLIC_SUPABASE_URL=your_supabase_url 22 | NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key 23 | 24 | # Google AI API 25 | GOOGLE_AI_API_KEY=your_google_ai_api_key 26 | -------------------------------------------------------------------------------- /backend/src/migrations/1710000000000-AddCreatedByToPet.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner, TableColumn } from "typeorm"; 2 | 3 | export class AddCreatedByToPet1710000000000 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.addColumn( 6 | "pet", 7 | new TableColumn({ 8 | name: "createdBy", 9 | type: "varchar", 10 | length: "255", 11 | isNullable: false, 12 | default: "'test@unc.edu'", 13 | }), 14 | ); 15 | } 16 | 17 | public async down(queryRunner: QueryRunner): Promise { 18 | await queryRunner.dropColumn("pet", "createdBy"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bin/Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1: Install dependencies 2 | FROM node:18-alpine AS deps 3 | WORKDIR /usr/src/app 4 | 5 | # Copy package manifests and install production deps 6 | COPY package.json package-lock.json ./ 7 | RUN npm ci --production 8 | 9 | # Stage 2: Build the final image 10 | FROM node:18-alpine 11 | WORKDIR /usr/src/app 12 | 13 | # Bring in installed modules 14 | COPY --from=deps /usr/src/app/node_modules ./node_modules 15 | 16 | # Copy the CLI source (assumes bin/ and Makefile at the root) 17 | COPY bin ./bin 18 | COPY Makefile ./ 19 | 20 | # Link the CLI globally 21 | RUN npm link /usr/src/app 22 | 23 | # Set the entrypoint to your CLI 24 | ENTRYPOINT ["petswipe"] 25 | CMD ["--help"] 26 | -------------------------------------------------------------------------------- /frontend/hooks/use-mobile.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const MOBILE_BREAKPOINT = 768; 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState( 7 | undefined, 8 | ); 9 | 10 | React.useEffect(() => { 11 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); 12 | const onChange = () => { 13 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 14 | }; 15 | mql.addEventListener("change", onChange); 16 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 17 | return () => mql.removeEventListener("change", onChange); 18 | }, []); 19 | 20 | return !!isMobile; 21 | } 22 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # 1) Install deps 2 | FROM node:18-alpine AS deps 3 | WORKDIR /app 4 | COPY package*.json ./ 5 | RUN npm ci --legacy-peer-deps 6 | 7 | # 2) Build TS -> ignore TypeScript/Next errors 8 | FROM node:18-alpine AS builder 9 | WORKDIR /app 10 | COPY --from=deps /app/node_modules ./node_modules 11 | COPY . . 12 | RUN npm run build || true 13 | 14 | # 3) Runtime image 15 | FROM node:18-alpine AS runner 16 | WORKDIR /app 17 | ENV NODE_ENV=production 18 | ENV PORT=5001 19 | 20 | # Copy compiled output & deps 21 | COPY --from=builder /app/dist ./dist 22 | COPY --from=builder /app/node_modules ./node_modules 23 | COPY package*.json ./ 24 | 25 | EXPOSE 5001 26 | CMD ["node", "dist/index.js"] 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env.local 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | 43 | test-results 44 | -------------------------------------------------------------------------------- /aws/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Node.js 18 (alpine) so we have npm for the frontend build 2 | FROM node:18-alpine 3 | 4 | # Install bash, Python3 & pip, Docker CLI, and dependencies for AWS CLI v2 5 | RUN apk add --no-cache \ 6 | bash \ 7 | python3 \ 8 | py3-pip \ 9 | docker-cli \ 10 | && pip3 install --no-cache-dir awscli 11 | 12 | # Set working dir 13 | WORKDIR /aws 14 | 15 | # Copy in your deploy script and make it executable 16 | COPY deploy.sh . 17 | RUN chmod +x deploy.sh 18 | 19 | # (Optional) Copy everything if you want to mount less at runtime 20 | # COPY backend ./backend 21 | # COPY frontend ./frontend 22 | 23 | # Default entrypoint runs the deploy script 24 | ENTRYPOINT ["./deploy.sh"] 25 | -------------------------------------------------------------------------------- /agentic_ai/agents/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Agentic AI Agents 3 | ================ 4 | 5 | Collection of specialized agents for the PetSwipe assembly line architecture. 6 | """ 7 | 8 | from .base_agent import BaseAgent 9 | from .pet_analyzer_agent import PetAnalyzerAgent 10 | from .user_profiler_agent import UserProfilerAgent 11 | from .matching_agent import MatchingAgent 12 | from .recommendation_agent import RecommendationAgent 13 | from .conversation_agent import ConversationAgent 14 | from .monitoring_agent import MonitoringAgent 15 | 16 | __all__ = [ 17 | "BaseAgent", 18 | "PetAnalyzerAgent", 19 | "UserProfilerAgent", 20 | "MatchingAgent", 21 | "RecommendationAgent", 22 | "ConversationAgent", 23 | "MonitoringAgent", 24 | ] 25 | -------------------------------------------------------------------------------- /backend/src/routes/pets.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { 3 | uploadPets, 4 | listPets, 5 | exportPets, 6 | uploadPetPhoto, 7 | createPet, 8 | getPetById, 9 | updatePet, 10 | listMyCreatedPets, 11 | } from "../controllers/petController"; 12 | import { authMiddleware } from "../middlewares/auth"; 13 | 14 | const router = Router(); 15 | 16 | router.use(authMiddleware); 17 | 18 | router.post("/", createPet); 19 | router.post("/upload", ...uploadPets); 20 | router.get("/", listPets); 21 | router.get("/export", exportPets); 22 | router.get("/mine", listMyCreatedPets); 23 | router.put("/:petId", updatePet); 24 | router.post("/:petId/photo", ...uploadPetPhoto); 25 | router.get("/:petId", getPetById); 26 | 27 | export default router; 28 | -------------------------------------------------------------------------------- /frontend/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |