Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .do/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
spec:
name: finmind
region: nyc
services:
- name: backend
dockerfile_path: packages/backend/Dockerfile
github:
repo: rohitdash08/FinMind
branch: main
deploy_on_push: true
http_port: 8000
instance_count: 1
instance_size_slug: basic-xxs
routes:
- path: /api
- path: /health
health_check:
http_path: /health
initial_delay_seconds: 10
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated
period_seconds: 10
run_command: |
sh -c "python -m flask --app wsgi:app init-db && gunicorn --workers=2 --threads=4 --bind 0.0.0.0:8000 wsgi:app"
envs:
- key: DATABASE_URL
scope: RUN_TIME
value: ${db.DATABASE_URL}
- key: REDIS_URL
scope: RUN_TIME
value: CHANGE_ME_SET_EXTERNAL_REDIS_URL
- key: JWT_SECRET
scope: RUN_TIME
type: SECRET
value: change-me
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated
- key: LOG_LEVEL
scope: RUN_TIME
value: INFO
- key: GEMINI_MODEL
scope: RUN_TIME
value: gemini-1.5-flash

- name: frontend
dockerfile_path: app/Dockerfile
github:
repo: rohitdash08/FinMind
branch: main
deploy_on_push: true
http_port: 80
instance_count: 1
instance_size_slug: basic-xxs
routes:
- path: /

databases:
- name: db
engine: PG
version: "16"
size: db-s-dev-database
num_nodes: 1

# Note: DigitalOcean App Platform doesn't have managed Redis.
# Use DigitalOcean Managed Redis or Upstash, then set REDIS_URL on the backend service.
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: sh -c "cd packages/backend && python -m flask --app wsgi:app init-db && gunicorn --workers=2 --threads=4 --bind 0.0.0.0:$PORT wsgi:app"
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated
40 changes: 40 additions & 0 deletions Tiltfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# FinMind Tiltfile — local Kubernetes development

# Build images
docker_build('ghcr.io/rohitdash08/finmind-backend', './packages/backend',
live_update=[
sync('./packages/backend/app', '/app/app'),
sync('./packages/backend/wsgi.py', '/app/wsgi.py'),
run('pip install -r requirements.txt', trigger=['./packages/backend/requirements.txt']),
]
)

docker_build('nginx', './app',
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated
# Multi-stage build: React build → nginx static serve.
# Full rebuild on source changes (live_update not viable for multi-stage).
)

# Apply K8s manifests
k8s_yaml([
'deploy/k8s/namespace.yaml',
'deploy/k8s/secrets.example.yaml',
'deploy/k8s/app-stack.yaml',
])

# Tilt automatically matches docker_build image names to K8s manifests.
# If images don't match, use k8s_image_json_path or set_image.

# Resource grouping and dependencies
k8s_resource('postgres', labels=['database'],
port_forwards='5432:5432')

k8s_resource('redis', labels=['database'],
port_forwards='6379:6379')

k8s_resource('backend', labels=['app'],
port_forwards='8000:8000',
resource_deps=['postgres', 'redis'])

k8s_resource('nginx', labels=['app'],
port_forwards='8080:80',
resource_deps=['backend'])
49 changes: 49 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "FinMind",
"description": "AI-powered personal finance manager",
"repository": "https://github.com/rohitdash08/FinMind",
"logo": "",
"keywords": ["finance", "budgeting", "flask", "react"],
"stack": "container",
"addons": [
{
"plan": "heroku-postgresql:essential-0"
},
{
"plan": "heroku-redis:mini"
}
],
"env": {
"JWT_SECRET": {
"description": "Secret key for JWT token signing",
"generator": "secret"
},
"DATABASE_URL": {
"description": "PostgreSQL connection URL (auto-set by addon)"
},
"REDIS_URL": {
"description": "Redis connection URL (auto-set by addon)"
},
"LOG_LEVEL": {
"description": "Logging level",
"value": "INFO"
},
"GEMINI_API_KEY": {
"description": "Google Gemini API key for AI features",
"required": false
},
"GEMINI_MODEL": {
"description": "Gemini model name",
"value": "gemini-1.5-flash"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "basic"
}
},
"buildpacks": [],
"scripts": {},
"environments": {}
}
30 changes: 30 additions & 0 deletions deploy/aws/apprunner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# AWS App Runner configuration
# Deploy with: aws apprunner create-service --cli-input-json file://apprunner.json
#
# This YAML is a reference. Convert to JSON for the CLI or use the console.
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated

ServiceName: finmind-backend
SourceConfiguration:
ImageRepository:
ImageIdentifier: <ECR_IMAGE_URI>
ImageRepositoryType: ECR
ImageConfiguration:
Port: "8000"
RuntimeEnvironmentVariables:
DATABASE_URL: <your-database-url>
REDIS_URL: <your-redis-url>
JWT_SECRET: <your-jwt-secret>
LOG_LEVEL: INFO
GEMINI_MODEL: gemini-1.5-flash
StartCommand: "sh -c 'python -m flask --app wsgi:app init-db && gunicorn --workers=2 --threads=4 --bind 0.0.0.0:8000 wsgi:app'"
AutoDeploymentsEnabled: true
InstanceConfiguration:
Cpu: "0.25 vCPU"
Memory: "0.5 GB"
HealthCheckConfiguration:
Protocol: HTTP
Path: /health
Interval: 10
Timeout: 5
HealthyThreshold: 1
UnhealthyThreshold: 5
178 changes: 178 additions & 0 deletions deploy/aws/cloudformation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: FinMind ECS Fargate Stack

Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
BackendImage:
Type: String
Description: Backend Docker image URI
FrontendImage:
Type: String
Description: Frontend Docker image URI
DatabaseUrl:
Type: String
NoEcho: true
RedisUrl:
Type: String
NoEcho: true
JwtSecret:
Type: String
NoEcho: true
Default: ''
Comment thread
sirrodgepodge marked this conversation as resolved.
Outdated

Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: finmind
CapacityProviders: [FARGATE]

ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: finmind-execution-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

TaskRole:
Type: AWS::IAM::Role
Properties:
RoleName: finmind-task-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole

LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /ecs/finmind
RetentionInDays: 14

SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: FinMind ECS Security Group
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 8000
ToPort: 8000
CidrIp: 0.0.0.0/0

BackendTaskDef:
Type: AWS::ECS::TaskDefinition
Properties:
Family: finmind-backend
Cpu: '256'
Memory: '512'
NetworkMode: awsvpc
RequiresCompatibilities: [FARGATE]
ExecutionRoleArn: !GetAtt ExecutionRole.Arn
TaskRoleArn: !GetAtt TaskRole.Arn
ContainerDefinitions:
- Name: backend
Image: !Ref BackendImage
Essential: true
PortMappings:
- ContainerPort: 8000
Environment:
- Name: DATABASE_URL
Value: !Ref DatabaseUrl
- Name: REDIS_URL
Value: !Ref RedisUrl
- Name: JWT_SECRET
Value: !Ref JwtSecret
- Name: LOG_LEVEL
Value: INFO
Command:
- sh
- -c
- "python -m flask --app wsgi:app init-db && gunicorn --workers=2 --threads=4 --bind 0.0.0.0:8000 wsgi:app"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: backend
HealthCheck:
Command: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
Interval: 30
Timeout: 5
Retries: 3
StartPeriod: 30

FrontendTaskDef:
Type: AWS::ECS::TaskDefinition
Properties:
Family: finmind-frontend
Cpu: '256'
Memory: '256'
NetworkMode: awsvpc
RequiresCompatibilities: [FARGATE]
ExecutionRoleArn: !GetAtt ExecutionRole.Arn
ContainerDefinitions:
- Name: frontend
Image: !Ref FrontendImage
Essential: true
PortMappings:
- ContainerPort: 80
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: frontend

BackendService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
ServiceName: finmind-backend
TaskDefinition: !Ref BackendTaskDef
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups: [!Ref SecurityGroup]
Subnets: !Ref SubnetIds

FrontendService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
ServiceName: finmind-frontend
TaskDefinition: !Ref FrontendTaskDef
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups: [!Ref SecurityGroup]
Subnets: !Ref SubnetIds

Outputs:
ClusterName:
Value: !Ref ECSCluster
BackendServiceName:
Value: !GetAtt BackendService.Name
FrontendServiceName:
Value: !GetAtt FrontendService.Name
Loading
Loading