From 605e46b1b03036feb4dae8c75de10113061ead43 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 24 Feb 2026 12:04:13 -0800 Subject: [PATCH] Remove serverless, add graphql relationships. --- .../default/tables/public_joblines.yaml | 11 + .../databases/default/tables/public_jobs.yaml | 15 + .../default/tables/public_shops.yaml | 8 + serverless/package-lock.json | 32 ++ serverless/package.json | 2 + serverless/serverless.infra.yml | 397 ------------------ serverless/serverless.yml | 1 - serverless/src/handlers/scrub.ts | 78 +--- 8 files changed, 74 insertions(+), 470 deletions(-) delete mode 100644 serverless/serverless.infra.yml diff --git a/hasura/metadata/databases/default/tables/public_joblines.yaml b/hasura/metadata/databases/default/tables/public_joblines.yaml index f7c5a87..6a2a5a7 100644 --- a/hasura/metadata/databases/default/tables/public_joblines.yaml +++ b/hasura/metadata/databases/default/tables/public_joblines.yaml @@ -1,3 +1,14 @@ table: name: joblines schema: public +object_relationships: + - name: job + using: + manual_configuration: + column_mapping: + jobid: id + version: version + insertion_order: null + remote_table: + name: jobs + schema: public diff --git a/hasura/metadata/databases/default/tables/public_jobs.yaml b/hasura/metadata/databases/default/tables/public_jobs.yaml index 3729741..0454e9b 100644 --- a/hasura/metadata/databases/default/tables/public_jobs.yaml +++ b/hasura/metadata/databases/default/tables/public_jobs.yaml @@ -1,3 +1,18 @@ table: name: jobs schema: public +object_relationships: + - name: shop + using: + foreign_key_constraint_on: shopid +array_relationships: + - name: joblines + using: + manual_configuration: + column_mapping: + id: jobid + version: version + insertion_order: null + remote_table: + name: joblines + schema: public diff --git a/hasura/metadata/databases/default/tables/public_shops.yaml b/hasura/metadata/databases/default/tables/public_shops.yaml index 10d6138..cddb88b 100644 --- a/hasura/metadata/databases/default/tables/public_shops.yaml +++ b/hasura/metadata/databases/default/tables/public_shops.yaml @@ -1,3 +1,11 @@ table: name: shops schema: public +array_relationships: + - name: jobs + using: + foreign_key_constraint_on: + column: shopid + table: + name: jobs + schema: public diff --git a/serverless/package-lock.json b/serverless/package-lock.json index bdc4f5f..aa594b5 100644 --- a/serverless/package-lock.json +++ b/serverless/package-lock.json @@ -14,6 +14,8 @@ "@aws-sdk/s3-request-presigner": "^3.971.0", "axios": "^1.13.2", "form-data": "^4.0.5", + "graphql": "^16.12.0", + "graphql-request": "^7.4.0", "lodash": "^4.17.21" }, "devDependencies": { @@ -1720,6 +1722,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -4761,6 +4772,27 @@ "dev": true, "license": "ISC" }, + "node_modules/graphql": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", + "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-request": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-7.4.0.tgz", + "integrity": "sha512-xfr+zFb/QYbs4l4ty0dltqiXIp07U6sl+tOKAb0t50/EnQek6CVVBLjETXi+FghElytvgaAWtIOt3EV7zLzIAQ==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", diff --git a/serverless/package.json b/serverless/package.json index 00019d1..4efd2d8 100644 --- a/serverless/package.json +++ b/serverless/package.json @@ -24,6 +24,8 @@ "@aws-sdk/s3-request-presigner": "^3.971.0", "axios": "^1.13.2", "form-data": "^4.0.5", + "graphql": "^16.12.0", + "graphql-request": "^7.4.0", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/serverless/serverless.infra.yml b/serverless/serverless.infra.yml deleted file mode 100644 index ffa9f51..0000000 --- a/serverless/serverless.infra.yml +++ /dev/null @@ -1,397 +0,0 @@ -service: esdp-infra -app: esdp-api-app -frameworkVersion: '4' - -stages: - shared: - observability: false - params: - # Single shared database name for all app stages (dev/alpha/beta/prod) - db_name: esdp - # Your public IP in CIDR form for direct DB access (lock this down). - admin_cidr: 70.36.57.88/32 - -provider: - name: aws - runtime: nodejs22.x - region: ca-central-1 - -resources: - Resources: - EsdpVpc: - Type: AWS::EC2::VPC - Properties: - CidrBlock: 10.0.0.0/16 - EnableDnsSupport: true - EnableDnsHostnames: true - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-vpc - - InternetGateway: - Type: AWS::EC2::InternetGateway - Properties: - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-igw - - VpcGatewayAttachment: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - VpcId: - Ref: EsdpVpc - InternetGatewayId: - Ref: InternetGateway - - PublicSubnetA: - Type: AWS::EC2::Subnet - Properties: - VpcId: - Ref: EsdpVpc - AvailabilityZone: - Fn::Select: - - 0 - - Fn::GetAZs: '' - CidrBlock: 10.0.0.0/24 - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-public-a - - PublicSubnetB: - Type: AWS::EC2::Subnet - Properties: - VpcId: - Ref: EsdpVpc - AvailabilityZone: - Fn::Select: - - 1 - - Fn::GetAZs: '' - CidrBlock: 10.0.1.0/24 - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-public-b - - PrivateSubnetA: - Type: AWS::EC2::Subnet - Properties: - VpcId: - Ref: EsdpVpc - AvailabilityZone: - Fn::Select: - - 0 - - Fn::GetAZs: '' - CidrBlock: 10.0.10.0/24 - MapPublicIpOnLaunch: false - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-private-a - - PrivateSubnetB: - Type: AWS::EC2::Subnet - Properties: - VpcId: - Ref: EsdpVpc - AvailabilityZone: - Fn::Select: - - 1 - - Fn::GetAZs: '' - CidrBlock: 10.0.11.0/24 - MapPublicIpOnLaunch: false - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-private-b - - PublicRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: - Ref: EsdpVpc - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-public-rt - - PublicRoute: - Type: AWS::EC2::Route - DependsOn: VpcGatewayAttachment - Properties: - RouteTableId: - Ref: PublicRouteTable - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: - Ref: InternetGateway - - PublicSubnetARouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: - Ref: PublicSubnetA - RouteTableId: - Ref: PublicRouteTable - - PublicSubnetBRouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: - Ref: PublicSubnetB - RouteTableId: - Ref: PublicRouteTable - - NatEip: - Type: AWS::EC2::EIP - Properties: - Domain: vpc - - NatGateway: - Type: AWS::EC2::NatGateway - Properties: - AllocationId: - Fn::GetAtt: - - NatEip - - AllocationId - SubnetId: - Ref: PublicSubnetA - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-nat - - PrivateRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: - Ref: EsdpVpc - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-private-rt - - PrivateRoute: - Type: AWS::EC2::Route - Properties: - RouteTableId: - Ref: PrivateRouteTable - DestinationCidrBlock: 0.0.0.0/0 - NatGatewayId: - Ref: NatGateway - - PrivateSubnetARouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: - Ref: PrivateSubnetA - RouteTableId: - Ref: PrivateRouteTable - - PrivateSubnetBRouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: - Ref: PrivateSubnetB - RouteTableId: - Ref: PrivateRouteTable - - LambdaSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: ${self:service}-${sls:stage} Lambda security group - VpcId: - Ref: EsdpVpc - SecurityGroupEgress: - - IpProtocol: -1 - CidrIp: 0.0.0.0/0 - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-lambda-sg - - ProxySecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: ${self:service}-${sls:stage} RDS proxy security group - VpcId: - Ref: EsdpVpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - SourceSecurityGroupId: - Ref: LambdaSecurityGroup - - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - CidrIp: ${param:admin_cidr} - SecurityGroupEgress: - - IpProtocol: -1 - CidrIp: 0.0.0.0/0 - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-proxy-sg - - RdsSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: ${self:service}-${sls:stage} RDS security group - VpcId: - Ref: EsdpVpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - SourceSecurityGroupId: - Ref: ProxySecurityGroup - - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - CidrIp: ${param:admin_cidr} - Tags: - - Key: Name - Value: ${self:service}-${sls:stage}-rds-sg - - DbSubnetGroup: - Type: AWS::RDS::DBSubnetGroup - Properties: - DBSubnetGroupDescription: ${self:service}-${sls:stage} DB subnet group - SubnetIds: - - Ref: PublicSubnetA - - Ref: PublicSubnetB - - DbSecret: - Type: AWS::SecretsManager::Secret - Properties: - Description: ${self:service}-${sls:stage} RDS master credentials - GenerateSecretString: - SecretStringTemplate: '{"username":"esdp_admin"}' - GenerateStringKey: password - PasswordLength: 32 - ExcludeCharacters: '"@/\\' - - DbProxyRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: - - rds.amazonaws.com - Action: - - sts:AssumeRole - Policies: - - PolicyName: ${self:service}-${sls:stage}-db-proxy-secrets - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - secretsmanager:GetSecretValue - Resource: - - Ref: DbSecret - - DbProxy: - Type: AWS::RDS::DBProxy - Properties: - DBProxyName: ${self:service}-${sls:stage}-proxy - EngineFamily: POSTGRESQL - IdleClientTimeout: 1800 - RequireTLS: true - RoleArn: - Fn::GetAtt: - - DbProxyRole - - Arn - VpcSubnetIds: - - Ref: PrivateSubnetA - - Ref: PrivateSubnetB - VpcSecurityGroupIds: - - Ref: ProxySecurityGroup - Auth: - - AuthScheme: SECRETS - SecretArn: - Ref: DbSecret - IAMAuth: DISABLED - - DbProxyTargetGroup: - Type: AWS::RDS::DBProxyTargetGroup - Properties: - DBProxyName: - Ref: DbProxy - TargetGroupName: default - DBInstanceIdentifiers: - - Ref: PostgresDb - ConnectionPoolConfigurationInfo: - MaxConnectionsPercent: 75 - MaxIdleConnectionsPercent: 50 - ConnectionBorrowTimeout: 120 - - PostgresDb: - Type: AWS::RDS::DBInstance - DeletionPolicy: Snapshot - UpdateReplacePolicy: Snapshot - Properties: - DBInstanceIdentifier: ${self:service}-${sls:stage}-postgres - Engine: postgres - # EngineVersion intentionally omitted so AWS uses the current default/latest for RDS Postgres. - AutoMinorVersionUpgrade: true - DBInstanceClass: db.t4g.micro - AllocatedStorage: 20 - StorageType: gp3 - StorageEncrypted: true - PubliclyAccessible: true - MultiAZ: false - DBName: ${param:db_name} - BackupRetentionPeriod: 7 - CopyTagsToSnapshot: true - DeletionProtection: true - VPCSecurityGroups: - - Ref: RdsSecurityGroup - DBSubnetGroupName: - Ref: DbSubnetGroup - MasterUsername: - Fn::Sub: '{{resolve:secretsmanager:${DbSecret}::username}}' - MasterUserPassword: - Fn::Sub: '{{resolve:secretsmanager:${DbSecret}::password}}' - - Outputs: - VpcId: - Value: - Ref: EsdpVpc - PrivateSubnetAId: - Value: - Ref: PrivateSubnetA - PrivateSubnetBId: - Value: - Ref: PrivateSubnetB - - LambdaSecurityGroupId: - Value: - Ref: LambdaSecurityGroup - ProxySecurityGroupId: - Value: - Ref: ProxySecurityGroup - RdsSecurityGroupId: - Value: - Ref: RdsSecurityGroup - - DbName: - Value: ${param:db_name} - DbPort: - Value: 5432 - - DbEndpointAddress: - Value: - Fn::GetAtt: - - PostgresDb - - Endpoint.Address - DbEndpointPort: - Value: - Fn::GetAtt: - - PostgresDb - - Endpoint.Port - DbSecretArn: - Value: - Ref: DbSecret - - DbProxyEndpoint: - Value: - Fn::GetAtt: - - DbProxy - - Endpoint diff --git a/serverless/serverless.yml b/serverless/serverless.yml index 96ff850..6bbf5af 100644 --- a/serverless/serverless.yml +++ b/serverless/serverless.yml @@ -1,6 +1,5 @@ service: esdp-api app: esdp-api-app -frameworkVersion: '4' stages: prod: diff --git a/serverless/src/handlers/scrub.ts b/serverless/src/handlers/scrub.ts index dfdb3f4..e51ffbd 100644 --- a/serverless/src/handlers/scrub.ts +++ b/serverless/src/handlers/scrub.ts @@ -1,76 +1,10 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; -import axios, { AxiosError } from 'axios'; -import FormData from 'form-data'; - -import { ESJobObject, RawJobDataObject } from '../../../shared/types'; -import { transformJobForEstimateScrubber } from '../lib/transformEstimate'; -import { getVehicleType } from '../lib/vehicleTypes/vehicleType'; - -const ES_USER = process.env.ES_USER || ''; -const ES_PASSWORD = process.env.ES_PASSWORD || ''; -const ES_ENDPOINT = process.env.ES_ENDPOINT || ''; - -interface ScrubRequest { - esApiKey: string; - rawJob: RawJobDataObject; -} - -interface ScrubResponse { - report_link?: string; - identified_item?: unknown; -} export const handler = async (event: APIGatewayProxyEvent): Promise => { - try { - const { esApiKey, rawJob } = JSON.parse(event.body || '{}') as ScrubRequest; - - // Transform the raw job object to ES format - const estimate: ESJobObject = await transformJobForEstimateScrubber(rawJob); - - // Set vehicle type and sending entity ID - estimate.v_type = getVehicleType(estimate.v_model || '').type; - estimate.sending_entity_id = '87330f61-412b-4251-baaa-d026565b23c5'; - - const fileName = `${esApiKey}-${rawJob.clm_no}-${Date.now()}`; - const formData = new FormData(); - const jsonString = JSON.stringify(estimate); - - formData.append('file', Buffer.from(jsonString), { - filename: `${fileName}.json`, - contentType: 'application/json', - }); - - const result = await axios.post(`${ES_ENDPOINT}/api/sendems`, formData, { - auth: { - username: ES_USER, - password: ES_PASSWORD, - }, - headers: { - APIkey: esApiKey, - }, - }); - - const resultPDFUrl = result?.data?.report_link; - const reportIssueUrl = `https://insurtechtoolkit.com/pcontactUs.aspx?apiKey=${esApiKey}&file=${fileName}.json`; - - return { - statusCode: 200, - body: JSON.stringify({ - resultPDFUrl, - reportIssueUrl, - identified_item: result.data?.identified_item, - }), - }; - } catch (error) { - const axiosError = error as AxiosError; - const errorMessage = axiosError.response?.data || axiosError.message || 'Unknown error'; - - return { - statusCode: 400, - body: JSON.stringify({ - message: 'Error scrubbing estimate.', - error: errorMessage, - }), - }; - } + return { + statusCode: 200, + body: JSON.stringify({ + message: 'Scrub handler is under construction', + }), + }; };