From e2a41d17cec6fab93f355bcb69be1b19a840f98e Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:08:53 +0530 Subject: [PATCH 1/6] feat: add endpoint to retrieve field officers in UserController --- .../java/com/crimeLink/analyzer/controller/UserController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/crimeLink/analyzer/controller/UserController.java b/src/main/java/com/crimeLink/analyzer/controller/UserController.java index ab64e04..e618a1a 100644 --- a/src/main/java/com/crimeLink/analyzer/controller/UserController.java +++ b/src/main/java/com/crimeLink/analyzer/controller/UserController.java @@ -16,6 +16,7 @@ public UserController(UserService service) { this.service = service; } + @GetMapping("/field-officers") public List getFieldOfficers() { return service.getFieldOfficers(); } From ec0d15ee07ae9f5bb86d5b900dc15f80aa88b179 Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:09:29 +0530 Subject: [PATCH 2/6] feat: Implement comprehensive Spring Security with JWT, role-based authorization, and CORS, and introduce a new vehicle management API. --- .env.example | 24 ++++++++++++------- .../analyzer/config/SecurityConfig.java | 21 +++++++++------- .../controller/VehicleController.java | 1 - src/main/resources/application.properties | 3 +++ 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index a8e355c..a5b37e8 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,8 @@ # IMPORTANT: This is a template file. Copy to .env and fill in your values. # DO NOT commit .env file to version control! -# Database Configuration -DB_URL=jdbc:postgresql://your-host:port/database +# Database Configuration (Supabase PostgreSQL) +DB_URL=jdbc:postgresql://your-host:5432/postgres DB_USERNAME=your-username DB_PASSWORD=your-password @@ -10,10 +10,18 @@ DB_PASSWORD=your-password SERVER_PORT=8080 # JWT Configuration -JWT_SECRET=secret_key -JWT_EXPIRATION= -REFRESH_TOKEN_EXPIRATION= +JWT_SECRET=your-jwt-secret-key +JWT_EXPIRATION=900000 +REFRESH_TOKEN_EXPIRATION=604800000 -# Supabase Configurations -SUPABASE_URL= -SUPABASE_SERVICE_KEY= +# Python Microservices URLs (internal networking in production) +PYTHON_CALL_ANALYSIS_URL=http://localhost:5001 +PYTHON_FACIAL_RECOGNITION_URL=http://localhost:5002 + +# Supabase Configuration +SUPABASE_URL=https://your-project.supabase.co +SUPABASE_SERVICE_KEY=your-supabase-service-key +SUPABASE_BUCKET=criminal-photos + +# CORS Configuration (comma-separated origins, use * for all) +CORS_ALLOWED_ORIGINS=* diff --git a/src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java b/src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java index 7b84314..4d476a7 100644 --- a/src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java +++ b/src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java @@ -37,6 +37,9 @@ public class SecurityConfig { @Autowired private UserDetailsService userDetailsService; + @org.springframework.beans.factory.annotation.Value("${cors.allowed-origins:*}") + private String corsAllowedOrigins; + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http @@ -134,15 +137,15 @@ public PasswordEncoder passwordEncoder() { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - // Use allowedOriginPatterns for wildcard support with credentials - // For production, replace with specific origins - configuration.setAllowedOriginPatterns(List.of("*")); - // Or use specific origins (recommended for production): - // configuration.setAllowedOrigins(Arrays.asList( - // "http://localhost:5173", - // "http://localhost:3000", - // "https://yourdomain.com" - // )); + // Use env var CORS_ALLOWED_ORIGINS to configure origins + // Default: * (all origins) — restrict for production + if ("*".equals(corsAllowedOrigins)) { + configuration.setAllowedOriginPatterns(List.of("*")); + } else { + configuration.setAllowedOrigins( + Arrays.asList(corsAllowedOrigins.split(",")) + ); + } configuration.setAllowedMethods(Arrays.asList( "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")); configuration.setAllowedHeaders(List.of("*")); diff --git a/src/main/java/com/crimeLink/analyzer/controller/VehicleController.java b/src/main/java/com/crimeLink/analyzer/controller/VehicleController.java index a5f1139..6d0ad1e 100644 --- a/src/main/java/com/crimeLink/analyzer/controller/VehicleController.java +++ b/src/main/java/com/crimeLink/analyzer/controller/VehicleController.java @@ -17,7 +17,6 @@ @RestController @RequestMapping("/api/vehicles") -@CrossOrigin(origins = {"http://localhost:5173", "http://localhost:3000"}) public class VehicleController { @Autowired diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5ed118c..3b78610 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -50,3 +50,6 @@ spring.servlet.multipart.max-request-size=50MB # Backup Configuration backup.directory=${BACKUP_DIR:./backups} + +# CORS Configuration +cors.allowed-origins=${CORS_ALLOWED_ORIGINS:*} From 77efd030e688eaabd7c993c315d58ed8106f21e2 Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:26:18 +0530 Subject: [PATCH 3/6] build: Add Dockerfile and .dockerignore for containerizing the Spring Boot backend application. --- .dockerignore | 10 ++++++++++ Dockerfile | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fc679a5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Backend Docker ignores +target +.git +.github +.env +.idea +.vscode +*.iml +database +backups diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..971b950 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# ============================================= +# CrimeLink Analyzer - Spring Boot Backend +# Multi-stage build: Maven → JRE 21 +# ============================================= + +# Stage 1: Build with Maven +FROM eclipse-temurin:21-jdk-alpine AS builder + +WORKDIR /app + +# Copy Maven wrapper and POM first (better caching) +COPY mvnw ./ +COPY .mvn .mvn +COPY pom.xml ./ + +# Make mvnw executable +RUN chmod +x mvnw + +# Download dependencies (cached unless pom.xml changes) +RUN ./mvnw dependency:go-offline -B + +# Copy source code +COPY src src + +# Build the application (skip tests for faster builds) +RUN ./mvnw package -DskipTests -B + +# Stage 2: Runtime with minimal JRE +FROM eclipse-temurin:21-jre-alpine + +WORKDIR /app + +# Create non-root user +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# Copy the built JAR from builder +COPY --from=builder /app/target/*.jar app.jar + +# Create directories for backups and uploads +RUN mkdir -p /app/backups && chown -R appuser:appgroup /app + +# Switch to non-root user +USER appuser + +# Expose port +EXPOSE 8080 + +# Health check +HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/api/health || exit 1 + +# JVM tuning for containers +ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:+UseG1GC" + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] From cdd2e99e335bdbf3a49f20888692596fc0661bed Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:50:23 +0530 Subject: [PATCH 4/6] Make it Deploy Ready --- .github/workflows/deploy.yml | 59 +++++++++++++++++++ aws/ecs-task-def.json | 52 ++++++++++++++++ .../analyzer/service/CallAnalysisService.java | 2 +- .../service/FacialRecognitionService.java | 2 +- src/main/resources/application.properties | 6 +- 5 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 aws/ecs-task-def.json diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..9e3cf6e --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,59 @@ +# ============================================= +# CrimeLink Analyzer - Backend CI/CD +# Repo: github.com/arosha-w/CrimeLinkAnalyzer_backend +# Docker build → ECR → ECS Fargate +# ============================================= +# +# Required GitHub Secrets: +# AWS_ACCESS_KEY_ID +# AWS_SECRET_ACCESS_KEY +# AWS_REGION (e.g., ap-south-1) +# AWS_ACCOUNT_ID (12-digit AWS account ID) +# ECS_CLUSTER_NAME (e.g., crimelink-cluster) +# ECS_SERVICE_NAME (e.g., crimelink-backend-service) + +name: Deploy Backend + +on: + push: + branches: [main] + workflow_dispatch: + +env: + ECR_REPOSITORY: crimelink-backend + AWS_REGION: ${{ secrets.AWS_REGION }} + +jobs: + build-and-deploy: + name: Build & Deploy to ECS + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: ecr-login + uses: aws-actions/amazon-ecr-login@v2 + + - name: Build, tag, and push Docker image + env: + ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }} + IMAGE_TAG: ${{ github.sha }} + run: | + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . + docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest + + - name: Force new ECS deployment + run: | + aws ecs update-service \ + --cluster ${{ secrets.ECS_CLUSTER_NAME }} \ + --service ${{ secrets.ECS_SERVICE_NAME }} \ + --force-new-deployment diff --git a/aws/ecs-task-def.json b/aws/ecs-task-def.json new file mode 100644 index 0000000..5d7b9e2 --- /dev/null +++ b/aws/ecs-task-def.json @@ -0,0 +1,52 @@ +{ + "family": "crimelink-backend", + "networkMode": "awsvpc", + "requiresCompatibilities": ["FARGATE"], + "cpu": "512", + "memory": "1024", + "executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/ecsTaskExecutionRole", + "taskRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/ecsTaskRole", + "containerDefinitions": [ + { + "name": "backend", + "image": "YOUR_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/crimelink-backend:latest", + "essential": true, + "portMappings": [ + { + "containerPort": 8080, + "protocol": "tcp" + } + ], + "environment": [ + { "name": "SERVER_PORT", "value": "8080" }, + { "name": "SUPABASE_BUCKET", "value": "criminal-photos" }, + { "name": "CORS_ALLOWED_ORIGINS", "value": "https://your-cloudfront-domain.cloudfront.net" } + ], + "secrets": [ + { "name": "DB_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-url" }, + { "name": "DB_USERNAME", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-username" }, + { "name": "DB_PASSWORD", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/db-password" }, + { "name": "JWT_SECRET", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/jwt-secret" }, + { "name": "SUPABASE_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/supabase-url" }, + { "name": "SUPABASE_SERVICE_KEY", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/supabase-service-key" }, + { "name": "PYTHON_CALL_ANALYSIS_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/call-analysis-url" }, + { "name": "PYTHON_FACIAL_RECOGNITION_URL", "valueFrom": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/crimelink/facial-recognition-url" } + ], + "healthCheck": { + "command": ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/api/health || exit 1"], + "interval": 30, + "timeout": 5, + "retries": 3, + "startPeriod": 60 + }, + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "/ecs/crimelink-backend", + "awslogs-region": "YOUR_REGION", + "awslogs-stream-prefix": "ecs" + } + } + } + ] +} diff --git a/src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java b/src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java index e0897e7..3ad6656 100644 --- a/src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java +++ b/src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java @@ -31,7 +31,7 @@ public class CallAnalysisService { private final RestTemplate restTemplate; private final ObjectMapper objectMapper; - @Value("${python.call-analysis.url:http://localhost:5001}") + @Value("${python.call-analysis.url}") private String callAnalysisServiceUrl; public CallAnalysisService(RestTemplate restTemplate) { diff --git a/src/main/java/com/crimeLink/analyzer/service/FacialRecognitionService.java b/src/main/java/com/crimeLink/analyzer/service/FacialRecognitionService.java index 59883fd..f4408ba 100644 --- a/src/main/java/com/crimeLink/analyzer/service/FacialRecognitionService.java +++ b/src/main/java/com/crimeLink/analyzer/service/FacialRecognitionService.java @@ -31,7 +31,7 @@ public class FacialRecognitionService { private final RestTemplate restTemplate; private final ObjectMapper objectMapper; - @Value("${python.facial-recognition.url:http://localhost:5002}") + @Value("${python.facial-recognition.url}") private String facialRecognitionServiceUrl; public FacialRecognitionService(RestTemplate restTemplate) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3b78610..f112236 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -34,9 +34,9 @@ jwt.secret=${JWT_SECRET} jwt.expiration=${JWT_EXPIRATION:900000} jwt.refresh-expiration=${REFRESH_TOKEN_EXPIRATION:604800000} -# Python Microservices Configuration -python.call-analysis.url=${PYTHON_CALL_ANALYSIS_URL:http://localhost:5001} -python.facial-recognition.url=${PYTHON_FACIAL_RECOGNITION_URL:http://localhost:5002} +# Python Microservices Configuration (REQUIRED — no defaults) +python.call-analysis.url=${PYTHON_CALL_ANALYSIS_URL} +python.facial-recognition.url=${PYTHON_FACIAL_RECOGNITION_URL} #Supabase Configuration supabase.url=${SUPABASE_URL} From 245f2bddf237f541bd55a9e47fc520a49e802dc3 Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Sat, 14 Mar 2026 00:59:35 +0530 Subject: [PATCH 5/6] fix: Update Dockerfile to ensure mvnw is executable and adjust health check start period --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 971b950..950fcfc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,8 @@ COPY mvnw ./ COPY .mvn .mvn COPY pom.xml ./ -# Make mvnw executable -RUN chmod +x mvnw +# Make mvnw executable and fix Windows CRLF line endings +RUN chmod +x mvnw && sed -i 's/\r$//' mvnw # Download dependencies (cached unless pom.xml changes) RUN ./mvnw dependency:go-offline -B @@ -46,7 +46,7 @@ USER appuser EXPOSE 8080 # Health check -HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \ +HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/api/health || exit 1 # JVM tuning for containers From c8e3fada9883ca43599b28d512becdbd218713f9 Mon Sep 17 00:00:00 2001 From: JinethBosilu <157296244+JinethBosilu@users.noreply.github.com> Date: Sat, 14 Mar 2026 01:40:21 +0530 Subject: [PATCH 6/6] Refactor code structure for improved readability and maintainability --- backend_logs.txt | Bin 0 -> 65094 bytes src/main/resources/application.properties | 1 + 2 files changed, 1 insertion(+) create mode 100644 backend_logs.txt diff --git a/backend_logs.txt b/backend_logs.txt new file mode 100644 index 0000000000000000000000000000000000000000..589e16b98d761bd6870fdcc1955c1e229d5cea90 GIT binary patch literal 65094 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 Kp0U7kd;brw(@={5 literal 0 HcmV?d00001 diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f112236..0a0605d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -53,3 +53,4 @@ backup.directory=${BACKUP_DIR:./backups} # CORS Configuration cors.allowed-origins=${CORS_ALLOWED_ORIGINS:*} +spring.datasource.hikari.data-source-properties.prepareThreshold=0