Skip to content

Commit 4c45e01

Browse files
authored
Merge pull request #44 from arosha-w/main
Enhance API with vehicle management and security features
2 parents f68bad4 + 38a6d48 commit 4c45e01

12 files changed

Lines changed: 214 additions & 23 deletions

File tree

.dockerignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Backend Docker ignores
2+
target
3+
.git
4+
.github
5+
.env
6+
.idea
7+
.vscode
8+
*.iml
9+
database
10+
backups

.env.example

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
# IMPORTANT: This is a template file. Copy to .env and fill in your values.
22
# DO NOT commit .env file to version control!
33

4-
# Database Configuration
5-
DB_URL=jdbc:postgresql://your-host:port/database
4+
# Database Configuration (Supabase PostgreSQL)
5+
DB_URL=jdbc:postgresql://your-host:5432/postgres
66
DB_USERNAME=your-username
77
DB_PASSWORD=your-password
88

99
# Server Configuration
1010
SERVER_PORT=8080
1111

1212
# JWT Configuration
13-
JWT_SECRET=secret_key
14-
JWT_EXPIRATION=
15-
REFRESH_TOKEN_EXPIRATION=
13+
JWT_SECRET=your-jwt-secret-key
14+
JWT_EXPIRATION=900000
15+
REFRESH_TOKEN_EXPIRATION=604800000
1616

17-
# Supabase Configurations
18-
SUPABASE_URL=
19-
SUPABASE_SERVICE_KEY=
17+
# Python Microservices URLs (internal networking in production)
18+
PYTHON_CALL_ANALYSIS_URL=http://localhost:5001
19+
PYTHON_FACIAL_RECOGNITION_URL=http://localhost:5002
20+
21+
# Supabase Configuration
22+
SUPABASE_URL=https://your-project.supabase.co
23+
SUPABASE_SERVICE_KEY=your-supabase-service-key
24+
SUPABASE_BUCKET=criminal-photos
25+
26+
# CORS Configuration (comma-separated origins, use * for all)
27+
CORS_ALLOWED_ORIGINS=*

.github/workflows/deploy.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# =============================================
2+
# CrimeLink Analyzer - Backend CI/CD
3+
# Repo: github.com/arosha-w/CrimeLinkAnalyzer_backend
4+
# Docker build → ECR → ECS Fargate
5+
# =============================================
6+
#
7+
# Required GitHub Secrets:
8+
# AWS_ACCESS_KEY_ID
9+
# AWS_SECRET_ACCESS_KEY
10+
# AWS_REGION (e.g., ap-south-1)
11+
# AWS_ACCOUNT_ID (12-digit AWS account ID)
12+
# ECS_CLUSTER_NAME (e.g., crimelink-cluster)
13+
# ECS_SERVICE_NAME (e.g., crimelink-backend-service)
14+
15+
name: Deploy Backend
16+
17+
on:
18+
push:
19+
branches: [main]
20+
workflow_dispatch:
21+
22+
env:
23+
ECR_REPOSITORY: crimelink-backend
24+
AWS_REGION: ${{ secrets.AWS_REGION }}
25+
26+
jobs:
27+
build-and-deploy:
28+
name: Build & Deploy to ECS
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Configure AWS credentials
34+
uses: aws-actions/configure-aws-credentials@v4
35+
with:
36+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
37+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
38+
aws-region: ${{ env.AWS_REGION }}
39+
40+
- name: Login to Amazon ECR
41+
id: ecr-login
42+
uses: aws-actions/amazon-ecr-login@v2
43+
44+
- name: Build, tag, and push Docker image
45+
env:
46+
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
47+
IMAGE_TAG: ${{ github.sha }}
48+
run: |
49+
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
50+
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
51+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
52+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
53+
54+
- name: Force new ECS deployment
55+
run: |
56+
aws ecs update-service \
57+
--cluster ${{ secrets.ECS_CLUSTER_NAME }} \
58+
--service ${{ secrets.ECS_SERVICE_NAME }} \
59+
--force-new-deployment

Dockerfile

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# =============================================
2+
# CrimeLink Analyzer - Spring Boot Backend
3+
# Multi-stage build: Maven → JRE 21
4+
# =============================================
5+
6+
# Stage 1: Build with Maven
7+
FROM eclipse-temurin:21-jdk-alpine AS builder
8+
9+
WORKDIR /app
10+
11+
# Copy Maven wrapper and POM first (better caching)
12+
COPY mvnw ./
13+
COPY .mvn .mvn
14+
COPY pom.xml ./
15+
16+
# Make mvnw executable and fix Windows CRLF line endings
17+
RUN chmod +x mvnw && sed -i 's/\r$//' mvnw
18+
19+
# Download dependencies (cached unless pom.xml changes)
20+
RUN ./mvnw dependency:go-offline -B
21+
22+
# Copy source code
23+
COPY src src
24+
25+
# Build the application (skip tests for faster builds)
26+
RUN ./mvnw package -DskipTests -B
27+
28+
# Stage 2: Runtime with minimal JRE
29+
FROM eclipse-temurin:21-jre-alpine
30+
31+
WORKDIR /app
32+
33+
# Create non-root user
34+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
35+
36+
# Copy the built JAR from builder
37+
COPY --from=builder /app/target/*.jar app.jar
38+
39+
# Create directories for backups and uploads
40+
RUN mkdir -p /app/backups && chown -R appuser:appgroup /app
41+
42+
# Switch to non-root user
43+
USER appuser
44+
45+
# Expose port
46+
EXPOSE 8080
47+
48+
# Health check
49+
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
50+
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/api/health || exit 1
51+
52+
# JVM tuning for containers
53+
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:+UseG1GC"
54+
55+
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

aws/ecs-task-def.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"family": "crimelink-backend",
3+
"networkMode": "awsvpc",
4+
"requiresCompatibilities": ["FARGATE"],
5+
"cpu": "512",
6+
"memory": "1024",
7+
"executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/ecsTaskExecutionRole",
8+
"taskRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/ecsTaskRole",
9+
"containerDefinitions": [
10+
{
11+
"name": "backend",
12+
"image": "YOUR_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/crimelink-backend:latest",
13+
"essential": true,
14+
"portMappings": [
15+
{
16+
"containerPort": 8080,
17+
"protocol": "tcp"
18+
}
19+
],
20+
"environment": [
21+
{ "name": "SERVER_PORT", "value": "8080" },
22+
{ "name": "SUPABASE_BUCKET", "value": "criminal-photos" },
23+
{ "name": "CORS_ALLOWED_ORIGINS", "value": "https://your-cloudfront-domain.cloudfront.net" }
24+
],
25+
"secrets": [
26+
{ "name": "DB_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-url" },
27+
{ "name": "DB_USERNAME", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-username" },
28+
{ "name": "DB_PASSWORD", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-password" },
29+
{ "name": "JWT_SECRET", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/jwt-secret" },
30+
{ "name": "SUPABASE_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/supabase-url" },
31+
{ "name": "SUPABASE_SERVICE_KEY", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/supabase-service-key" },
32+
{ "name": "PYTHON_CALL_ANALYSIS_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/call-analysis-url" },
33+
{ "name": "PYTHON_FACIAL_RECOGNITION_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/facial-recognition-url" }
34+
],
35+
"healthCheck": {
36+
"command": ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/api/health || exit 1"],
37+
"interval": 30,
38+
"timeout": 5,
39+
"retries": 3,
40+
"startPeriod": 60
41+
},
42+
"logConfiguration": {
43+
"logDriver": "awslogs",
44+
"options": {
45+
"awslogs-group": "/ecs/crimelink-backend",
46+
"awslogs-region": "YOUR_REGION",
47+
"awslogs-stream-prefix": "ecs"
48+
}
49+
}
50+
}
51+
]
52+
}

backend_logs.txt

63.6 KB
Binary file not shown.

src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public class SecurityConfig {
3737
@Autowired
3838
private UserDetailsService userDetailsService;
3939

40+
@org.springframework.beans.factory.annotation.Value("${cors.allowed-origins:*}")
41+
private String corsAllowedOrigins;
42+
4043
@Bean
4144
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
4245
http
@@ -127,15 +130,15 @@ public PasswordEncoder passwordEncoder() {
127130
@Bean
128131
public CorsConfigurationSource corsConfigurationSource() {
129132
CorsConfiguration configuration = new CorsConfiguration();
130-
// Use allowedOriginPatterns for wildcard support with credentials
131-
// For production, replace with specific origins
132-
configuration.setAllowedOriginPatterns(List.of("*"));
133-
// Or use specific origins (recommended for production):
134-
// configuration.setAllowedOrigins(Arrays.asList(
135-
// "http://localhost:5173",
136-
// "http://localhost:3000",
137-
// "https://yourdomain.com"
138-
// ));
133+
// Use env var CORS_ALLOWED_ORIGINS to configure origins
134+
// Default: * (all origins) — restrict for production
135+
if ("*".equals(corsAllowedOrigins)) {
136+
configuration.setAllowedOriginPatterns(List.of("*"));
137+
} else {
138+
configuration.setAllowedOrigins(
139+
Arrays.asList(corsAllowedOrigins.split(","))
140+
);
141+
}
139142
configuration.setAllowedMethods(Arrays.asList(
140143
"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
141144
configuration.setAllowedHeaders(List.of("*"));

src/main/java/com/crimeLink/analyzer/controller/UserController.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public UserController(UserService service) {
1616
this.service = service;
1717
}
1818

19+
@GetMapping("/field-officers")
1920
public List<User> getFieldOfficers() {
2021
return service.getFieldOfficers();
2122
}

src/main/java/com/crimeLink/analyzer/controller/VehicleController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
@RestController
1919
@RequestMapping("/api/vehicles")
20-
@CrossOrigin(origins = {"http://localhost:5173", "http://localhost:3000"})
2120
public class VehicleController {
2221

2322
@Autowired

src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class CallAnalysisService {
3131
private final RestTemplate restTemplate;
3232
private final ObjectMapper objectMapper;
3333

34-
@Value("${python.call-analysis.url:http://localhost:5001}")
34+
@Value("${python.call-analysis.url}")
3535
private String callAnalysisServiceUrl;
3636

3737
public CallAnalysisService(RestTemplate restTemplate) {

0 commit comments

Comments
 (0)