@rivascva/dt-idl 1.1.191 → 1.1.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,136 @@
1
+ # Deployment
2
+
3
+ ## Overview
4
+
5
+ The platform consists of four Go microservices deployed as AWS Lambda functions in the **us-east-2** region. The mobile app communicates directly with each Lambda's function URL. Asynchronous background flows are orchestrated via AWS EventBridge Schedules and AWS Step Functions.
6
+
7
+ ---
8
+
9
+ ## Architecture Diagram
10
+
11
+ ```
12
+ ┌─────────────┐ ┌─────────────────────────────┐
13
+ │ Mobile App │───────────▶│ AWS Lambda Function URLs │
14
+ └─────────────┘ └─────────────────────────────┘
15
+
16
+ ┌──────────────┬─────────────────────┼──────────────────┐
17
+ │ │ │ │
18
+ ▼ ▼ ▼ ▼
19
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
20
+ │ dt-market- │ │ dt-asset- │ │ dt-trade- │ │ dt-user- │
21
+ │ service │ │ service │ │ service │ │ service │
22
+ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
23
+ │ │ │ │
24
+ ▼ ▼ ▼ ▼
25
+ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
26
+ │ Upstash │ │ AWS S3 │ │ Supabase │ │ Supabase │
27
+ │ (Redis) │ │ (Images) │ │ (Postgres)│ │ (Postgres)│
28
+ └───────────┘ └───────────┘ └───────────┘ └───────────┘
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Services & Lambda Functions
34
+
35
+ All Lambda functions share these settings:
36
+
37
+ - **Runtime:** Amazon Linux 2023
38
+ - **Architecture:** ARM64
39
+ - **Role:** `lambda-execution-role`
40
+ - **Timeout:** 30 seconds
41
+ - **Function URL:** Enabled w/ no auth
42
+
43
+ | Service | Lambda Function(s) |
44
+ | ----------------- | --------------------------------------------------- |
45
+ | dt-market-service | `dt-market-service-prod` |
46
+ | | `dt-market-service-refresh-realtime-quotes-prod` |
47
+ | | `dt-market-service-refresh-performance-quotes-prod` |
48
+ | dt-trade-service | `dt-trade-service-prod` |
49
+ | | `dt-trade-service-execute-pending-orders-prod` |
50
+ | | `dt-trade-service-sync-portfolio-history-prod` |
51
+ | dt-user-service | `dt-user-service-prod` |
52
+ | dt-asset-service | `dt-asset-service-prod` |
53
+
54
+ All functions exit early if run outside of market hours (with a grace period).
55
+
56
+ > **Console:** [Lambda Functions (us-east-2)](https://us-east-2.console.aws.amazon.com/lambda/home?region=us-east-2#/functions)
57
+
58
+ ---
59
+
60
+ ## CI/CD Pipeline
61
+
62
+ Each service has a `.github/workflows/lambda-deploy.yaml` that triggers on:
63
+
64
+ - Push to `main`
65
+ - Manual dispatch (`workflow_dispatch`)
66
+
67
+ ### Build Process
68
+
69
+ 1. Checkout code
70
+ 2. Set up Go (version from `go.mod`)
71
+ 3. Configure Git for private modules via `GH_ACCESS_TOKEN`
72
+ 4. Cross-compile: `GOOS=linux GOARCH=arm64 go build -o bootstrap <path>`
73
+ 5. Zip: `zip function.zip bootstrap`
74
+ 6. Configure AWS credentials (us-east-2)
75
+ 7. Update Lambda environment variables
76
+ 8. Wait for config propagation
77
+ 9. Deploy new function code
78
+ 10. Wait for code propagation
79
+
80
+ Services with asynchronous flows use a **matrix strategy** to deploy multiple Lambda functions from a single workflow run.
81
+
82
+ ### Environment Variables
83
+
84
+ Each service's environment variables are managed via **GitHub Settings > Secrets and Variables** in its respective repository. The deployment workflow reads these secrets/variables at deploy time and pushes them to the Lambda function configuration.
85
+
86
+ ---
87
+
88
+ ## Scheduled Flows (Background Jobs)
89
+
90
+ Background jobs are triggered by **AWS EventBridge Schedules** which invoke **AWS Step Functions** state machines.
91
+
92
+ > **Console:** [EventBridge Schedules (us-east-2)](https://us-east-2.console.aws.amazon.com/scheduler/home?region=us-east-2#schedules) · [Step Functions (us-east-2)](https://us-east-2.console.aws.amazon.com/states/home?region=us-east-2#/statemachines)
93
+
94
+ ### dt-refresh-prices-schedule
95
+
96
+ | Property | Value |
97
+ | ------------ | ----------------------------------------------------- |
98
+ | **Schedule** | Every 5 minutes, 9:00 AM – 4:00 PM (America/New_York) |
99
+ | **Target** | `dt-refresh-prices-step-fn` |
100
+
101
+ **Step Function Execution (sequential):**
102
+
103
+ 1. `dt-market-service-refresh-realtime-quotes-prod`
104
+ 2. `dt-market-service-refresh-performance-quotes-prod`
105
+ 3. `dt-trade-service-execute-pending-orders-prod`
106
+
107
+ ### dt-sync-portfolios-schedule
108
+
109
+ | Property | Value |
110
+ | ------------ | ------------------------------------------------------ |
111
+ | **Schedule** | Every 15 minutes, 9:01 AM – 4:01 PM (America/New_York) |
112
+ | **Target** | `dt-sync-portfolios-step-fn` |
113
+
114
+ > The 1-minute offset (9:01 AM instead of 9:00 AM) ensures that the latest realtime quotes have already been refreshed by `dt-refresh-prices-schedule` before portfolios are synced.
115
+
116
+ **Step Function Execution:**
117
+
118
+ 1. `dt-trade-service-sync-portfolio-history-prod`
119
+
120
+ ---
121
+
122
+ ## External Services
123
+
124
+ | Service | Provider | Plan | Purpose |
125
+ | ----------------- | ----------------------------------------------------------------- | --------------------- | ----------------------------------- |
126
+ | PostgreSQL | [Supabase](https://supabase.com) | Free | Primary relational database |
127
+ | Redis | [Upstash](https://upstash.com) | Fixed 250 MB ($10/mo) | Caching (quotes, etc.) |
128
+ | Stock Market Data | [Financial Modeling Prep](https://site.financialmodelingprep.com) | $19/mo | Real-time & historical stock prices |
129
+
130
+ ---
131
+
132
+ ## Region & Networking
133
+
134
+ - **AWS Region:** `us-east-2` (Ohio)
135
+ - **Ingress:** Lambda function URLs are publicly accessible (auth type: `NONE`)
136
+ - **Inter-service communication:** Services call each other via their function URLs
@@ -40,6 +40,106 @@ const (
40
40
  MarketCloseGracePeriod = 2 * time.Minute
41
41
  )
42
42
 
43
+ var (
44
+ // MarketHolidays is a map of future market holidays.
45
+ // The key is the date of the holiday in YYYY-MM-DD format (based on the timezone specified in MarketTimezone).
46
+ // The value is the information about the holiday.
47
+ MarketHolidays = map[string]MarketHolidayInfo{
48
+ "2026-01-01": {
49
+ Name: "New Year's Day",
50
+ CloseTime: "",
51
+ },
52
+ "2026-01-19": {
53
+ Name: "Martin Luther King, Jr. Day",
54
+ CloseTime: "",
55
+ },
56
+ "2026-02-16": {
57
+ Name: "Presidents' Day",
58
+ CloseTime: "",
59
+ },
60
+ "2026-04-03": {
61
+ Name: "Good Friday",
62
+ CloseTime: "",
63
+ },
64
+ "2026-05-25": {
65
+ Name: "Memorial Day",
66
+ CloseTime: "",
67
+ },
68
+ "2026-06-19": {
69
+ Name: "Juneteenth National Independence Day",
70
+ CloseTime: "",
71
+ },
72
+ "2026-07-03": {
73
+ Name: "Independence Day (Observed)",
74
+ CloseTime: "",
75
+ },
76
+ "2026-09-07": {
77
+ Name: "Labor Day",
78
+ CloseTime: "",
79
+ },
80
+ "2026-11-26": {
81
+ Name: "Thanksgiving Day",
82
+ CloseTime: "",
83
+ },
84
+ "2026-11-27": {
85
+ Name: "Friday after Thanksgiving",
86
+ CloseTime: "13:00",
87
+ },
88
+ "2026-12-24": {
89
+ Name: "Christmas Eve",
90
+ CloseTime: "13:00",
91
+ },
92
+ "2026-12-25": {
93
+ Name: "Christmas Day",
94
+ CloseTime: "",
95
+ },
96
+ "2027-01-01": {
97
+ Name: "New Year's Day",
98
+ CloseTime: "",
99
+ },
100
+ "2027-01-18": {
101
+ Name: "Martin Luther King, Jr. Day",
102
+ CloseTime: "",
103
+ },
104
+ "2027-02-15": {
105
+ Name: "Presidents' Day",
106
+ CloseTime: "",
107
+ },
108
+ "2027-03-26": {
109
+ Name: "Good Friday",
110
+ CloseTime: "",
111
+ },
112
+ "2027-05-31": {
113
+ Name: "Memorial Day",
114
+ CloseTime: "",
115
+ },
116
+ "2027-06-18": {
117
+ Name: "Juneteenth National Independence Day (Observed)",
118
+ CloseTime: "",
119
+ },
120
+ "2027-07-05": {
121
+ Name: "Independence Day (Observed)",
122
+ CloseTime: "",
123
+ },
124
+ "2027-09-06": {
125
+ Name: "Labor Day",
126
+ CloseTime: "",
127
+ },
128
+ "2027-11-25": {
129
+ Name: "Thanksgiving Day",
130
+ CloseTime: "",
131
+ },
132
+ "2027-11-26": {
133
+ Name: "Friday after Thanksgiving",
134
+ CloseTime: "13:00",
135
+ },
136
+ "2027-12-24": {
137
+ Name: "Christmas Day (Observed)",
138
+ CloseTime: "",
139
+ },
140
+ }
141
+ )
142
+
43
143
  var (
44
144
  // PortfolioDefaultCash is the default cash for new portfolios.
45
145
  PortfolioDefaultCash = float64(50000)
@@ -0,0 +1,12 @@
1
+ package models
2
+
3
+ // MarketHolidayInfo contains information about a market holiday.
4
+ type MarketHolidayInfo struct {
5
+ // Name is the name of the holiday.
6
+ Name string
7
+ // CloseTime is the time the market closes on the holiday in a 24-hour format (HH:mm).
8
+ // Based on the timezone specified in MarketTimezone.
9
+ // For some holidays, the market may simply close early.
10
+ // The value will be empty if the market closes the entire day.
11
+ CloseTime string
12
+ }
@@ -21,6 +21,11 @@ func GetAccessTokenFromContext(ctx context.Context) *jwt.Token {
21
21
  return token
22
22
  }
23
23
 
24
+ // ContextWithAccessToken returns a new context with the given access token set.
25
+ func ContextWithAccessToken(ctx context.Context, accessToken *jwt.Token) context.Context {
26
+ return context.WithValue(ctx, models.AccessTokenKey, accessToken)
27
+ }
28
+
24
29
  // GetActorIdFromContext retrieves the actor id from the JWT access token in the given context.
25
30
  // The actor id is the subject of the JWT access token that represents the user id or service name that initiated the request.
26
31
  func GetActorIdFromContext(ctx context.Context) (string, error) {
@@ -66,6 +66,25 @@ func isMarketHoursWithOpenAndCloseOffsets(now time.Time, openOffset time.Duratio
66
66
  return false, fmt.Errorf("unable to parse the close minute: %w", err)
67
67
  }
68
68
 
69
+ // check if on a market holiday
70
+ if holidayInfo, ok := models.MarketHolidays[now.Format("2006-01-02")]; ok {
71
+ if holidayInfo.CloseTime == "" {
72
+ // the market closes the entire day
73
+ return false, nil
74
+ } else {
75
+ // the market closes early, so set the close time to the holiday close time
76
+ holidayCloseTimeParts := strings.Split(holidayInfo.CloseTime, ":")
77
+ closeHour, err = strconv.Atoi(holidayCloseTimeParts[0])
78
+ if err != nil {
79
+ return false, fmt.Errorf("unable to parse the holiday close hour: %w", err)
80
+ }
81
+ closeMinute, err = strconv.Atoi(holidayCloseTimeParts[1])
82
+ if err != nil {
83
+ return false, fmt.Errorf("unable to parse the holiday close minute: %w", err)
84
+ }
85
+ }
86
+ }
87
+
69
88
  // create the open time with the offset
70
89
  openTime := time.Date(now.Year(), now.Month(), now.Day(), openHour, openMinute, 0, 0, loc)
71
90
  openWithOffset := openTime.Add(openOffset)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivascva/dt-idl",
3
- "version": "1.1.191",
3
+ "version": "1.1.193",
4
4
  "description": "Dream Trade - Interface Definition Language",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",