1+ .PHONY : build clean deploy package test load-env check-bucket deploy-info redis-up redis-down test-local-full
2+
3+ # Configuration
4+ STACK_NAME := wine-pairing-suggestions-lambda
5+ DEFAULT_S3_BUCKET := wine-pairing-suggestions-sam-deployments
6+ AWS_REGION := us-west-2
7+ LAMBDA_BIN := bootstrap
8+ WEBAPP_BIN := webapp-bin
9+
10+ # Load environment variables from .env file if it exists
11+ load-env :
12+ @if [ -f .env ]; then \
13+ echo " Loading environment variables from .env file..." ; \
14+ export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; \
15+ fi
16+
17+ # Build the Lambda function
18+ build :
19+ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=" -s -w" -o $(LAMBDA_BIN ) ./cmd/lambda
20+
21+ build-WinePairingFunction :
22+ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=" -s -w" -o $(LAMBDA_BIN ) ./cmd/lambda
23+
24+ # Build for local testing
25+ build-local :
26+ go build -o $(WEBAPP_BIN ) ./cmd/webapp
27+
28+ # Clean build artifacts
29+ clean :
30+ rm -f $(LAMBDA_BIN ) $(WEBAPP_BIN ) packaged-template.yaml
31+
32+ # Clean everything including Docker
33+ clean-all : clean
34+ @echo " 🧹 Cleaning Docker containers and volumes..."
35+ docker-compose down -v
36+ @echo " ✅ All cleaned up"
37+
38+ # Check if S3 bucket exists, create if it doesn't
39+ check-bucket :
40+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
41+ BUCKET=$$ {S3_BUCKET:-$(DEFAULT_S3_BUCKET ) }; \
42+ echo " 📦 Checking deployment bucket: $$ BUCKET" ; \
43+
44+ @if aws s3 ls "s3://$$BUCKET" >/dev/null 2>&1; then \
45+ echo "✅ S3 bucket $$BUCKET exists."; \
46+ else \
47+ echo "📦 Creating S3 bucket: $$BUCKET"; \
48+ aws s3 mb "s3://$$BUCKET" --region "$(AWS_REGION)"; \
49+ fi
50+
51+ sam-build :
52+ echo " 📦 Building application..." ; \
53+ sam build
54+
55+ # Package for SAM deployment
56+ package : check-bucket sam-build
57+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
58+ BUCKET=$$ {S3_BUCKET:-$(DEFAULT_S3_BUCKET ) }; \
59+ echo " 📦 Packaging application..." ; \
60+ sam package --template-file template.yaml --s3-bucket " $$ BUCKET" --output-template-file packaged-template.yaml --region " $( AWS_REGION) "
61+
62+ # Deploy using SAM with parameter retrieval
63+ deploy : package
64+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
65+ \
66+ echo " 🔍 Checking if stack $( STACK_NAME) exists and retrieving parameters..." ; \
67+ if aws cloudformation describe-stacks --stack-name " $( STACK_NAME) " --region " $( AWS_REGION) " > /dev/null 2>&1 ; then \
68+ echo " Stack exists, retrieving current parameters..." ; \
69+ EXISTING_GOOGLE_CLIENT_ID=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`GoogleClientID`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
70+ EXISTING_HOSTNAME=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`Hostname`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
71+ EXISTING_VALKEY_ENDPOINT=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`ValkeyEndpoint`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
72+ EXISTING_VPC_ID=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`VpcId`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
73+ EXISTING_SECURITY_GROUP_ID=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`SecurityGroupId`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
74+ EXISTING_SUBNET_IDS=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Parameters[?ParameterKey==`SubnetIds`].ParameterValue' --output text 2>/dev/null || echo "" ) ; \
75+ fi ; \
76+ \
77+ FINAL_GOOGLE_CLIENT_ID=$$ {GOOGLE_CLIENT_ID_OVERRIDE:-$$ {GOOGLE_CLIENT_ID:-$$ EXISTING_GOOGLE_CLIENT_ID}}; \
78+ FINAL_HOSTNAME=$$ {HOSTNAME_OVERRIDE:-$$ {HOSTNAME:-$$ EXISTING_HOSTNAME}}; \
79+ FINAL_VALKEY_ENDPOINT=$$ {VALKEY_ENDPOINT_OVERRIDE:-$$ {VALKEY_ENDPOINT:-$$ EXISTING_VALKEY_ENDPOINT}}; \
80+ FINAL_VPC_ID=$$ {VPC_ID_OVERRIDE:-$$ {VPC_ID:-$$ EXISTING_VPC_ID}}; \
81+ FINAL_SECURITY_GROUP_ID=$$ {SECURITY_GROUP_ID_OVERRIDE:-$$ {SECURITY_GROUP_ID:-$$ EXISTING_SECURITY_GROUP_ID}}; \
82+ FINAL_SUBNET_IDS=$$ {SUBNET_IDS_OVERRIDE:-$$ {SUBNET_IDS:-$$ EXISTING_SUBNET_IDS}}; \
83+ \
84+ if [ -z " $$ FINAL_GOOGLE_CLIENT_ID" ] || [ -z " $$ FINAL_HOSTNAME" ] || [ -z " $$ FINAL_VALKEY_ENDPOINT" ] || [ -z " $$ FINAL_VPC_ID" ] || [ -z " $$ FINAL_SECURITY_GROUP_ID" ] || [ -z " $$ FINAL_SUBNET_IDS" ]; then \
85+ echo " ❌ Missing required parameters. Please set in .env file or as environment variables:" ; \
86+ echo " - GOOGLE_CLIENT_ID" ; \
87+ echo " - HOSTNAME" ; \
88+ echo " - VALKEY_ENDPOINT" ; \
89+ echo " - VPC_ID" ; \
90+ echo " - SECURITY_GROUP_ID" ; \
91+ echo " - SUBNET_IDS" ; \
92+ exit 1; \
93+ fi ; \
94+ \
95+ ANTHROPIC_API_KEY=$$(aws secretsmanager get-secret-value --secret-id prod/Anthropic/WineSuggestions --region $(AWS_REGION ) --query SecretString --output text | jq -r .ANTHROPIC_WINESUGGESTIONS ) ; \
96+ \
97+ echo " 🚀 Deploying $( STACK_NAME) in bucket $( DEFAULT_S3_BUCKET) to AWS..." ; \
98+ sam deploy \
99+ --config-file samconfig.toml \
100+ --template-file packaged-template.yaml \
101+ --no-resolve-s3 \
102+ --s3-bucket " $( DEFAULT_S3_BUCKET) " \
103+ --stack-name " $( STACK_NAME) " \
104+ --capabilities CAPABILITY_IAM \
105+ --region " $( AWS_REGION) " \
106+ --parameter-overrides \
107+ AnthropicApiKey=" $$ ANTHROPIC_API_KEY" \
108+ GoogleClientID=" $$ FINAL_GOOGLE_CLIENT_ID" \
109+ Hostname=" $$ FINAL_HOSTNAME" \
110+ ValkeyEndpoint=" $$ FINAL_VALKEY_ENDPOINT" \
111+ VpcId=" $$ FINAL_VPC_ID" \
112+ SecurityGroupId=" $$ FINAL_SECURITY_GROUP_ID" \
113+ SubnetIds=" $$ FINAL_SUBNET_IDS"
114+ \
115+ $(MAKE ) deploy-info
116+
117+ # Get deployment info after successful deployment
118+ deploy-info :
119+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
120+ \
121+ echo " " ; \
122+ echo " ✅ Deployment successful!" ; \
123+ echo " " ; \
124+ API_URL=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Outputs[?OutputKey==`WinePairingAPI`].OutputValue' --output text 2>/dev/null || echo "N/A" ) ; \
125+ CUSTOM_DOMAIN_TARGET=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Outputs[?OutputKey==`CustomDomainEndpoint`].OutputValue' --output text 2>/dev/null || echo "N/A" ) ; \
126+ LAMBDA_ARN=$$(aws cloudformation describe-stacks --stack-name "$(STACK_NAME ) " --region "$(AWS_REGION ) " --query 'Stacks[0].Outputs[?OutputKey==`LambdaFunction`].OutputValue' --output text 2>/dev/null || echo "N/A" ) ; \
127+ \
128+ echo " 📡 API Gateway URL: $$ API_URL" ; \
129+ echo " 🌐 Custom Domain Target: $$ CUSTOM_DOMAIN_TARGET" ; \
130+ echo " ⚡ Lambda Function ARN: $$ LAMBDA_ARN" ; \
131+ echo " " ; \
132+ echo " 💡 Next steps:" ; \
133+ echo " 1. In your DNS provider, create or update a CNAME record for your custom domain to point to the 'Custom Domain Target': $$ CUSTOM_DOMAIN_TARGET" ; \
134+ echo " 2. Ensure your OAuth redirect URIs use your custom domain: https://$$ (HOSTNAME)" ; \
135+ echo " 3. Test the custom domain: curl https://$$ (HOSTNAME)/healthz" ; \
136+ echo " 4. Monitor logs: aws logs tail /aws/lambda/$$ (aws cloudformation describe-stack-resource --stack-name $( STACK_NAME) --logical-resource-id WinePairingFunction --query 'StackResourceDetail.PhysicalResourceId' --output text) --follow" ;
137+
138+ # Deploy using SAM with guided prompts
139+ deploy-guided :
140+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
141+ ANTHROPIC_API_KEY=$$(aws secretsmanager get-secret-value --secret-id prod/Anthropic/WineSuggestions --region $(AWS_REGION ) --query SecretString --output text | jq -r .ANTHROPIC_WINESUGGESTIONS ) ; \
142+ sam deploy \
143+ --stack-name $(STACK_NAME ) \
144+ --s3-bucket $(DEFAULT_S3_BUCKET ) \
145+ --no-resolve-s3 \
146+ --guided
147+
148+ # Start local Redis via docker-compose
149+ redis-up :
150+ @echo " 🚀 Starting local Redis container..."
151+ docker-compose up -d cache
152+ @echo " ✅ Redis is running at localhost:6379"
153+
154+ # Stop local Redis
155+ redis-down :
156+ @echo " 🛑 Stopping local Redis container..."
157+ docker-compose down cache
158+ @echo " ✅ Redis stopped"
159+
160+ # Test locally with SAM (using in-memory cache)
161+ test-local : sam-build
162+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
163+ echo " 🚀 Starting SAM local API (connects to localhost:6379)..." ; \
164+ VALKEY_ENDPOINT=localhost:6379 sam local start-api
165+
166+ # Test locally with SAM connected to Docker Redis network
167+ test-local-docker : build sam-build
168+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
169+ echo " 🚀 Starting SAM local API connected to Docker network..." ; \
170+ HOSTNAME=http://localhost:3000 \
171+ VALKEY_ENDPOINT=cache:6379 \
172+ sam local start-api --docker-network wine-pairing-suggestions_wine-net -t template.yaml
173+
174+ # Full local development setup (Redis + SAM)
175+ test-local-full : redis-up
176+ @echo " ⏳ Waiting for Redis to be ready..."
177+ @sleep 2
178+ @$(MAKE ) test-local-docker
179+
180+ # Run unit tests
181+ test :
182+ go test ./...
183+
184+ # Run linting
185+ lint :
186+ golangci-lint run
187+
188+ # Build and run the traditional web server locally (with host Redis)
189+ run-local : build-local
190+ @if [ -f .env ]; then export $$(grep -v '^#' .env | grep -v '^$$' | xargs ) ; fi ; \
191+ VALKEY_ENDPOINT=localhost:6379 ./webapp
192+
193+ # Run the full docker-compose stack
194+ run-docker :
195+ @echo " 🚀 Starting full Docker Compose stack..."
196+ docker-compose up
197+
198+ # Run the full docker-compose stack in background
199+ run-docker-bg :
200+ @echo " 🚀 Starting full Docker Compose stack in background..."
201+ docker-compose up -d
202+
203+ # Environment variable examples
204+ example-env :
205+ @echo " Example environment variables for deployment (.env file or environment):"
206+ @echo " S3_BUCKET=your-sam-deployment-bucket"
207+ @echo " GOOGLE_CLIENT_ID=your-google-client-id"
208+ @echo " HOSTNAME=your-custom-domain.com"
209+ @echo " VALKEY_ENDPOINT=your-valkey-endpoint:6379"
210+ @echo " VPC_ID=vpc-xxxxxxxx"
211+ @echo " SECURITY_GROUP_ID=sg-xxxxxxxx"
212+ @echo " SUBNET_IDS=subnet-xxx,subnet-yyy,subnet-zzz"
0 commit comments