Skip to content

Commit fbc3075

Browse files
committed
more aws stuff from claude
1 parent 7056058 commit fbc3075

File tree

7 files changed

+462
-4
lines changed

7 files changed

+462
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Spotify Streaming Data Parsing Website
22

33
## Running the app
4-
`docker compose -f docker/docker-compose.yml up --build`
4+
`./run.sh start`
55

66
## TODO
77
* better popup on failure

cloudformation.yaml

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: 'Spotify Data Explorer - Infrastructure as Code'
3+
4+
Parameters:
5+
ECRRepositoryName:
6+
Type: String
7+
Default: spotify-data-explorer
8+
Description: Name of the ECR repository to store Docker images
9+
10+
AppName:
11+
Type: String
12+
Default: spotify-data-explorer
13+
Description: Name of the application
14+
15+
ContainerPort:
16+
Type: Number
17+
Default: 5000
18+
Description: Port that the container exposes
19+
20+
EnvironmentName:
21+
Type: String
22+
Default: prod
23+
AllowedValues:
24+
- dev
25+
- staging
26+
- prod
27+
Description: Environment name
28+
29+
Resources:
30+
# ECR Repository
31+
ECRRepository:
32+
Type: AWS::ECR::Repository
33+
Properties:
34+
RepositoryName: !Ref ECRRepositoryName
35+
RepositoryPolicyText:
36+
Version: '2012-10-17'
37+
Statement:
38+
- Sid: AllowPull
39+
Effect: Allow
40+
Principal:
41+
Service:
42+
- ecs.amazonaws.com
43+
- ecs-tasks.amazonaws.com
44+
Action:
45+
- ecr:GetDownloadUrlForLayer
46+
- ecr:BatchGetImage
47+
- ecr:BatchCheckLayerAvailability
48+
49+
# VPC for ECS Fargate
50+
VPC:
51+
Type: AWS::EC2::VPC
52+
Properties:
53+
CidrBlock: 10.0.0.0/16
54+
EnableDnsSupport: true
55+
EnableDnsHostnames: true
56+
Tags:
57+
- Key: Name
58+
Value: !Sub ${AppName}-vpc
59+
60+
# Internet Gateway
61+
InternetGateway:
62+
Type: AWS::EC2::InternetGateway
63+
Properties:
64+
Tags:
65+
- Key: Name
66+
Value: !Sub ${AppName}-igw
67+
68+
# Attach Internet Gateway to VPC
69+
InternetGatewayAttachment:
70+
Type: AWS::EC2::VPCGatewayAttachment
71+
Properties:
72+
InternetGatewayId: !Ref InternetGateway
73+
VpcId: !Ref VPC
74+
75+
# Public Subnet 1
76+
PublicSubnet1:
77+
Type: AWS::EC2::Subnet
78+
Properties:
79+
VpcId: !Ref VPC
80+
AvailabilityZone: !Select [ 0, !GetAZs '' ]
81+
CidrBlock: 10.0.1.0/24
82+
MapPublicIpOnLaunch: true
83+
Tags:
84+
- Key: Name
85+
Value: !Sub ${AppName}-public-subnet-1
86+
87+
# Public Subnet 2
88+
PublicSubnet2:
89+
Type: AWS::EC2::Subnet
90+
Properties:
91+
VpcId: !Ref VPC
92+
AvailabilityZone: !Select [ 1, !GetAZs '' ]
93+
CidrBlock: 10.0.2.0/24
94+
MapPublicIpOnLaunch: true
95+
Tags:
96+
- Key: Name
97+
Value: !Sub ${AppName}-public-subnet-2
98+
99+
# Public Route Table
100+
PublicRouteTable:
101+
Type: AWS::EC2::RouteTable
102+
Properties:
103+
VpcId: !Ref VPC
104+
Tags:
105+
- Key: Name
106+
Value: !Sub ${AppName}-public-route-table
107+
108+
# Public Route
109+
PublicRoute:
110+
Type: AWS::EC2::Route
111+
DependsOn: InternetGatewayAttachment
112+
Properties:
113+
RouteTableId: !Ref PublicRouteTable
114+
DestinationCidrBlock: 0.0.0.0/0
115+
GatewayId: !Ref InternetGateway
116+
117+
# Public Subnet 1 Route Table Association
118+
PublicSubnet1RouteTableAssociation:
119+
Type: AWS::EC2::SubnetRouteTableAssociation
120+
Properties:
121+
RouteTableId: !Ref PublicRouteTable
122+
SubnetId: !Ref PublicSubnet1
123+
124+
# Public Subnet 2 Route Table Association
125+
PublicSubnet2RouteTableAssociation:
126+
Type: AWS::EC2::SubnetRouteTableAssociation
127+
Properties:
128+
RouteTableId: !Ref PublicRouteTable
129+
SubnetId: !Ref PublicSubnet2
130+
131+
# ECS Cluster
132+
ECSCluster:
133+
Type: AWS::ECS::Cluster
134+
Properties:
135+
ClusterName: !Sub ${AppName}-cluster
136+
CapacityProviders:
137+
- FARGATE
138+
DefaultCapacityProviderStrategy:
139+
- CapacityProvider: FARGATE
140+
Weight: 1
141+
142+
# ECS Task Execution Role
143+
ECSTaskExecutionRole:
144+
Type: AWS::IAM::Role
145+
Properties:
146+
AssumeRolePolicyDocument:
147+
Version: '2012-10-17'
148+
Statement:
149+
- Effect: Allow
150+
Principal:
151+
Service: ecs-tasks.amazonaws.com
152+
Action: sts:AssumeRole
153+
ManagedPolicyArns:
154+
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
155+
156+
# ECS Task Definition
157+
ECSTaskDefinition:
158+
Type: AWS::ECS::TaskDefinition
159+
Properties:
160+
Family: !Sub ${AppName}-task
161+
Cpu: '256'
162+
Memory: '512'
163+
NetworkMode: awsvpc
164+
RequiresCompatibilities:
165+
- FARGATE
166+
ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
167+
ContainerDefinitions:
168+
- Name: !Ref AppName
169+
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryName}:latest
170+
Essential: true
171+
PortMappings:
172+
- ContainerPort: !Ref ContainerPort
173+
HostPort: !Ref ContainerPort
174+
Protocol: tcp
175+
LogConfiguration:
176+
LogDriver: awslogs
177+
Options:
178+
awslogs-group: !Ref LogGroup
179+
awslogs-region: !Ref AWS::Region
180+
awslogs-stream-prefix: ecs
181+
182+
# Log Group for Container Logs
183+
LogGroup:
184+
Type: AWS::Logs::LogGroup
185+
Properties:
186+
LogGroupName: !Sub /ecs/${AppName}
187+
RetentionInDays: 30
188+
189+
# Security Group for ECS Service
190+
ServiceSecurityGroup:
191+
Type: AWS::EC2::SecurityGroup
192+
Properties:
193+
GroupDescription: Security group for Spotify Data Explorer service
194+
VpcId: !Ref VPC
195+
SecurityGroupIngress:
196+
- IpProtocol: tcp
197+
FromPort: !Ref ContainerPort
198+
ToPort: !Ref ContainerPort
199+
CidrIp: 0.0.0.0/0
200+
201+
# ALB Security Group
202+
ALBSecurityGroup:
203+
Type: AWS::EC2::SecurityGroup
204+
Properties:
205+
GroupDescription: Security group for the Application Load Balancer
206+
VpcId: !Ref VPC
207+
SecurityGroupIngress:
208+
- IpProtocol: tcp
209+
FromPort: 80
210+
ToPort: 80
211+
CidrIp: 0.0.0.0/0
212+
- IpProtocol: tcp
213+
FromPort: 443
214+
ToPort: 443
215+
CidrIp: 0.0.0.0/0
216+
217+
# Application Load Balancer
218+
ApplicationLoadBalancer:
219+
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
220+
Properties:
221+
Name: !Sub ${AppName}-alb
222+
Scheme: internet-facing
223+
LoadBalancerAttributes:
224+
- Key: idle_timeout.timeout_seconds
225+
Value: '60'
226+
Subnets:
227+
- !Ref PublicSubnet1
228+
- !Ref PublicSubnet2
229+
SecurityGroups:
230+
- !Ref ALBSecurityGroup
231+
Tags:
232+
- Key: Name
233+
Value: !Sub ${AppName}-alb
234+
235+
# ALB Target Group
236+
ALBTargetGroup:
237+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
238+
Properties:
239+
Name: !Sub ${AppName}-tg
240+
Port: !Ref ContainerPort
241+
Protocol: HTTP
242+
TargetType: ip
243+
VpcId: !Ref VPC
244+
HealthCheckPath: /
245+
HealthCheckIntervalSeconds: 30
246+
HealthCheckTimeoutSeconds: 5
247+
HealthyThresholdCount: 3
248+
UnhealthyThresholdCount: 3
249+
TargetGroupAttributes:
250+
- Key: deregistration_delay.timeout_seconds
251+
Value: '30'
252+
253+
# ALB Listener
254+
ALBListener:
255+
Type: AWS::ElasticLoadBalancingV2::Listener
256+
Properties:
257+
DefaultActions:
258+
- Type: forward
259+
TargetGroupArn: !Ref ALBTargetGroup
260+
LoadBalancerArn: !Ref ApplicationLoadBalancer
261+
Port: 80
262+
Protocol: HTTP
263+
264+
# ECS Service
265+
ECSService:
266+
Type: AWS::ECS::Service
267+
DependsOn: ALBListener
268+
Properties:
269+
ServiceName: !Sub ${AppName}-service
270+
Cluster: !Ref ECSCluster
271+
TaskDefinition: !Ref ECSTaskDefinition
272+
DesiredCount: 1
273+
LaunchType: FARGATE
274+
NetworkConfiguration:
275+
AwsvpcConfiguration:
276+
AssignPublicIp: ENABLED
277+
SecurityGroups:
278+
- !Ref ServiceSecurityGroup
279+
Subnets:
280+
- !Ref PublicSubnet1
281+
- !Ref PublicSubnet2
282+
LoadBalancers:
283+
- ContainerName: !Ref AppName
284+
ContainerPort: !Ref ContainerPort
285+
TargetGroupArn: !Ref ALBTargetGroup
286+
287+
Outputs:
288+
ECRRepositoryURL:
289+
Description: URL of the ECR Repository
290+
Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryName}
291+
292+
ServiceURL:
293+
Description: URL of the deployed service
294+
Value: !Sub http://${ApplicationLoadBalancer.DNSName}
295+
296+
ECSClusterName:
297+
Description: Name of the ECS Cluster
298+
Value: !Ref ECSCluster
299+
300+
ECSServiceName:
301+
Description: Name of the ECS Service
302+
Value: !Ref ECSService

frontend/next.config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ const nextConfig: NextConfig = {
66
ignoreDuringBuilds: true,
77
},
88
output: 'export', // This creates an 'out' directory
9+
10+
// Disable image optimization since we're exporting statically
11+
images: {
12+
unoptimized: true,
13+
},
14+
15+
// Disable @next/swc-* imports which aren't needed for static exports
16+
experimental: {
17+
esmExternals: true,
18+
},
19+
20+
// Other Next.js config options
21+
reactStrictMode: true,
922
};
1023

1124
export default nextConfig;

frontend/src/app/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TabNavigation } from "@/components/ui/tab-navigation";
88
import { AggregationSelector, AggregationLevel } from "@/components/ui/aggregation-selector";
99
import { SearchBar } from "@/components/ui/search-bar";
1010
import { DetailModal } from "@/components/ui/detail-modal";
11+
import { API_BASE_URL } from "@/lib/api-config";
1112

1213
// Define the type for data items
1314
interface DataItem {
@@ -170,7 +171,7 @@ export default function FileUploader() {
170171

171172
try {
172173
// Upload and process data at all levels at once
173-
const response = await fetch("http://localhost:5000/api/upload", {
174+
const response = await fetch(`${API_BASE_URL}/upload`, {
174175
method: "POST",
175176
body: formData,
176177
});
@@ -228,7 +229,7 @@ export default function FileUploader() {
228229
setLoading(true);
229230
try {
230231
const response = await fetch(
231-
`http://localhost:5000/api/data/${aggregationLevel}/sort?column=${column}&direction=${newDirection}`
232+
`${API_BASE_URL}/data/${aggregationLevel}/sort?column=${column}&direction=${newDirection}`
232233
);
233234
const result = await response.json();
234235

frontend/src/components/ui/detail-modal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// frontend/src/components/ui/detail-modal.tsx
22
import { useState, useEffect, useMemo } from "react";
33
import { SimpleTable } from "@/components/ui/simple-table";
4+
import { API_BASE_URL } from "@/lib/api-config";
45

56
interface DetailModalProps {
67
detailType: "album" | "artist";
@@ -36,7 +37,7 @@ export const DetailModal = ({ detailType, detailName, isOpen, onClose }: DetailM
3637
setError(null);
3738

3839
try {
39-
const response = await fetch(`http://localhost:5000/api/data/detail/${detailType}/${encodeURIComponent(detailName)}`);
40+
const response = await fetch(`${API_BASE_URL}/data/detail/${detailType}/${encodeURIComponent(detailName)}`);
4041

4142
if (!response.ok) {
4243
throw new Error("Failed to fetch detail data");

0 commit comments

Comments
 (0)