Remove drizzle and serverless infra. Add terraform deployment.

This commit is contained in:
Patrick Fic
2026-01-19 13:49:19 -08:00
parent fefbd45570
commit bcdc305251
30 changed files with 713 additions and 329 deletions

View File

@@ -1,10 +0,0 @@
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema/**/*.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL ?? '',
},
});

View File

@@ -1,42 +0,0 @@
CREATE TABLE
"joblines" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid () NOT NULL,
"created_at" timestamp
with
time zone DEFAULT now () NOT NULL,
"jobId" uuid NOT NULL,
"line_desc" text
);
--> statement-breakpoint
CREATE TABLE
"jobs" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid () NOT NULL,
"shopId" uuid NOT NULL,
"created_at" timestamp
with
time zone DEFAULT now () NOT NULL,
"clm_no" text,
"ciecaid" text
);
--> statement-breakpoint
CREATE TABLE
"shops" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid () NOT NULL,
"created_at" timestamp
with
time zone DEFAULT now () NOT NULL,
"es_api_key" text NOT NULL,
"active" boolean DEFAULT true NOT NULL,
CONSTRAINT "shops_es_api_key_unique" UNIQUE ("es_api_key")
);
--> statement-breakpoint
ALTER TABLE "joblines" ADD CONSTRAINT "joblines_jobId_jobs_id_fk" FOREIGN KEY ("jobId") REFERENCES "public"."jobs" ("id") ON DELETE no action ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "jobs" ADD CONSTRAINT "jobs_shopId_shops_id_fk" FOREIGN KEY ("shopId") REFERENCES "public"."shops" ("id") ON DELETE no action ON UPDATE no action;
--> statement-breakpoint
CREATE INDEX "clm_no_idx" ON "jobs" USING btree ("clm_no");

View File

@@ -1,195 +0,0 @@
{
"id": "e789ff38-2370-43ff-825a-fde4c3efca40",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.joblines": {
"name": "joblines",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"jobId": {
"name": "jobId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"line_desc": {
"name": "line_desc",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"joblines_jobId_jobs_id_fk": {
"name": "joblines_jobId_jobs_id_fk",
"tableFrom": "joblines",
"tableTo": "jobs",
"columnsFrom": [
"jobId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.jobs": {
"name": "jobs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"shopId": {
"name": "shopId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"clm_no": {
"name": "clm_no",
"type": "text",
"primaryKey": false,
"notNull": false
},
"ciecaid": {
"name": "ciecaid",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"clm_no_idx": {
"name": "clm_no_idx",
"columns": [
{
"expression": "clm_no",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"jobs_shopId_shops_id_fk": {
"name": "jobs_shopId_shops_id_fk",
"tableFrom": "jobs",
"tableTo": "shops",
"columnsFrom": [
"shopId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.shops": {
"name": "shops",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"es_api_key": {
"name": "es_api_key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shops_es_api_key_unique": {
"name": "shops_es_api_key_unique",
"nullsNotDistinct": false,
"columns": [
"es_api_key"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -1,13 +0,0 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1768419700617,
"tag": "0000_fearless_vector",
"breakpoints": true
}
]
}

View File

@@ -2,10 +2,6 @@ service: esdp-api
app: esdp-api-app
frameworkVersion: '4'
package:
patterns:
- drizzle/**
stages:
prod:
# Enables observability in the prod stage
@@ -17,8 +13,6 @@ stages:
domain: es.imex.online
es_user: Imex2
es_password: Patrick
infra_service: esdp-infra
infra_stage: shared
beta:
# Enables observability in the prod stage
observability: false
@@ -29,8 +23,6 @@ stages:
domain: beta.es.imex.online
es_user: Imex2
es_password: Patrick
infra_service: esdp-infra
infra_stage: shared
alpha:
# Enables observability in the prod stage
observability: false
@@ -40,8 +32,6 @@ stages:
domain: alpha.es.imex.online
es_user: Imex2
es_password: Patrick
infra_service: esdp-infra
infra_stage: shared
dev:
# Enables observability in the prod stage
observability: false
@@ -51,17 +41,6 @@ stages:
domain: dev.es.imex.online
es_user: Imex2
es_password: Patrick
infra_service: esdp-infra
infra_stage: shared
custom:
infra_stack: ${param:infra_service}-${param:infra_stage}
db:
host: ${cf:${self:custom.infra_stack}.DbProxyEndpoint}
port: ${cf:${self:custom.infra_stack}.DbPort}
name: ${cf:${self:custom.infra_stack}.DbName}
secretArn: ${cf:${self:custom.infra_stack}.DbSecretArn}
# params:
# dev:
@@ -81,31 +60,6 @@ provider:
httpApi: # This creates a cheaper, faster "HTTP API" Gateway
cors: true # Automatically configures CORS
# Ensure all Lambdas can reach the shared RDS Proxy in the infra VPC
vpc:
securityGroupIds:
- ${cf:${self:custom.infra_stack}.LambdaSecurityGroupId}
subnetIds:
- ${cf:${self:custom.infra_stack}.PrivateSubnetAId}
- ${cf:${self:custom.infra_stack}.PrivateSubnetBId}
# Default DB connection settings for all Lambdas (used by src/lib/db.ts)
environment:
DB_HOST: ${self:custom.db.host}
DB_PORT: ${self:custom.db.port}
DB_NAME: ${self:custom.db.name}
DB_SECRET_ARN: ${self:custom.db.secretArn}
# Allow Lambdas to fetch the DB credentials from Secrets Manager
iam:
role:
statements:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- ${self:custom.db.secretArn}
build:
esbuild:
bundle: true
@@ -151,28 +105,6 @@ functions:
path: /emsupload
method: post
dbMigrate:
handler: src/handlers/dbMigrate.handler
timeout: 30
memorySize: 512
iamRoleStatements:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- ${cf:${self:custom.infra_stack}.DbSecretArn}
dbPing:
handler: src/handlers/dbPing.handler
timeout: 15
memorySize: 256
iamRoleStatements:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- ${cf:${self:custom.infra_stack}.DbSecretArn}
resources:
Resources:
UploadBucket:

View File

@@ -0,0 +1,55 @@
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManagerClient({ region: 'ca-central-1' });
interface HasuraCredentials {
database_url: string;
admin_secret: string;
}
let cachedCredentials: HasuraCredentials | null = null;
/**
* Fetches Hasura credentials from AWS Secrets Manager
* Caches the result for subsequent invocations within the same Lambda container
*/
export async function getHasuraCredentials(): Promise<HasuraCredentials> {
if (cachedCredentials) {
return cachedCredentials;
}
const secretArn = process.env.HASURA_SECRET_ARN;
if (!secretArn) {
throw new Error('HASURA_SECRET_ARN environment variable not set');
}
try {
const response = await client.send(new GetSecretValueCommand({ SecretId: secretArn }));
if (!response.SecretString) {
throw new Error('Secret value is empty');
}
cachedCredentials = JSON.parse(response.SecretString);
return cachedCredentials!;
} catch (error) {
console.error('Failed to fetch Hasura credentials:', error);
throw error;
}
}
/**
* Example: Get just the admin secret
*/
export async function getHasuraAdminSecret(): Promise<string> {
const creds = await getHasuraCredentials();
return creds.admin_secret;
}
/**
* Example: Get just the database URL
*/
export async function getHasuraDatabaseUrl(): Promise<string> {
const creds = await getHasuraCredentials();
return creds.database_url;
}