Skip to content

Commit

Permalink
Add updateAccountBalance
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-bach committed Jan 1, 2025
1 parent bdd701e commit be0c82a
Show file tree
Hide file tree
Showing 14 changed files with 2,167 additions and 10 deletions.
9 changes: 7 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ X Rearchitect updatePositions/updateBalances to use AppSync JS Resolvers

##### Current Task

- On PositionUpdatedEvent, update account balance with Position.marketvalue
- On BankTransactionSavedEvent, update account balance with Transaction.amount
X On PositionUpdatedEvent, update account balance with Position.marketvalue
X On BankTransactionSavedEvent, update account balance with Transaction.amount
-- Create new DLQ for updateAccountBalance

- review bookValue formula should be = price \* shares + commission
- Draw diagram

##### Future Task

- hide dropdowns after creating a new symbol, payee, category, etc
- add tests to updatePosition Lambda
- Update dashboard to pull positions and totals - requires new API getPositions(userId)
- create L3 constructs for AppSync CDK
Expand Down
45 changes: 44 additions & 1 deletion backend/lib/api-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,31 @@ export class ApiStack extends Stack {
})
);

const updateAccountBalanceFunction = new NodejsFunction(this, 'UpdateAccountBalance', {
runtime: Runtime.NODEJS_22_X,
functionName: `${props.appName}-${props.envName}-UpdateAccountBalance`,
handler: 'handler',
entry: path.resolve(__dirname, '../src/lambda/updateAccountbalance/main.ts'),
memorySize: 384,
timeout: Duration.seconds(5),
tracing: Tracing.ACTIVE,
layers: [adotJavscriptLayer],
environment: {
REGION: Stack.of(this).region,
DATA_TABLE_NAME: dataTable.tableName,
AWS_LAMBDA_EXEC_WRAPPER: '/opt/otel-handler',
},
deadLetterQueue: updatePositionDLQ,
});
// Add permissions to call DynamoDB
updateAccountBalanceFunction.addToRolePolicy(
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:UpdateItem'],
resources: [dataTable.tableArn],
})
);

/***
*** AWS EventBridge - Event Bus Rules
***/
Expand All @@ -613,12 +638,27 @@ export class ApiStack extends Stack {
});
investmentTransactionSavedRule.addTarget(
new LambdaFunction(updatePositionFunction, {
//deadLetterQueue: SqsQueue,
maxEventAge: Duration.hours(2),
retryAttempts: 2,
})
);

// EventBus Rule - PositionUpdatedEvent and BankTransactionSavedEvent
const transactionUpdatedEventRule = new Rule(this, 'PositionUpdatedEvent', {
ruleName: `${props.appName}-TransactionUpdatedEvent-${props.envName}`,
description: 'TransactionUdpatedEvent',
eventBus: eventBus,
eventPattern: {
source: ['custom.pecuniary'],
detailType: ['PositionUpdatedEvent', 'BankTransactionSavedEvent'],
},
});
transactionUpdatedEventRule.addTarget(
new LambdaFunction(updateAccountBalanceFunction, {
maxEventAge: Duration.hours(2),
retryAttempts: 2,
})
);
/***
*** Outputs
***/
Expand All @@ -640,6 +680,9 @@ export class ApiStack extends Stack {
new CfnOutput(this, 'InvestmentTransactionSavedRuleArn', {
value: investmentTransactionSavedRule.ruleArn,
});
new CfnOutput(this, 'TransactionUpdatedEventRule', {
value: transactionUpdatedEventRule.ruleArn,
});

// Lambda functions
new CfnOutput(this, 'UpdatePositionFunctionArn', {
Expand Down
46 changes: 46 additions & 0 deletions backend/src/lambda/updateAccountBalance/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { EventBridgeEvent } from 'aws-lambda';
import { UpdateItemCommandInput, UpdateItemCommand } from '@aws-sdk/client-dynamodb';
import { marshall } from '@aws-sdk/util-dynamodb';
import dynamoDbCommand from './utils/dynamoDbClient';

type EventData = {
accountId: string;
amount: number;
};

const handler = async (event: EventBridgeEvent<string, EventData>) => {
const data = parseEvent(event);

console.log(`🔔 Received event: ${JSON.stringify(data)}`);

if (!data || !data.accountId || !data.amount) {
throw new Error(`🛑 No data found in event ${data}`);
}

// update dynamodb account
const params: UpdateItemCommandInput = {
TableName: process.env.DATA_TABLE_NAME,
Key: marshall({ pk: `acc#${data.accountId}` }),
UpdateExpression: 'SET balance = balance + :amount, updatedAt = :updatedAt',
ExpressionAttributeValues: marshall({
':amount': data.amount,
':updatedAt': new Date().toISOString(),
}),
ReturnValues: 'UPDATED_NEW',
};
const result = await dynamoDbCommand(new UpdateItemCommand(params));

if (result.$metadata.httpStatusCode !== 200) {
throw new Error(`🛑 Could not update account ${data.accountId}`);
}
};

function parseEvent(event: EventBridgeEvent<string, EventData>): EventData {
const eventString: string = JSON.stringify(event);

console.debug(`🕧 Received event: ${eventString}`);

return JSON.parse(eventString).detail;
}

module.exports = { handler };
Loading

0 comments on commit be0c82a

Please sign in to comment.