Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
47 changes: 15 additions & 32 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -232,45 +232,28 @@ if config_env() == :prod do
#
# Check `Plug.SSL` for all available options in `force_ssl`.

# ## Configuring the mailer with AWS SES
#
# In production, emails are sent via AWS Simple Email Service (SES).
# The API client is configured at compile-time in config/prod.exs with:
# config :swoosh, :api_client, Swoosh.ApiClient.Req
#
# Required environment variables:
# - AWS_REGION or AWS_SES_REGION: AWS region (e.g., us-east-1)
# - AWS_ACCESS_KEY_ID: IAM access key with SES permissions
# - AWS_SECRET_ACCESS_KEY: IAM secret key
#
# Optional:
# - AWS_SES_CONFIGURATION_SET: SES configuration set for tracking/analytics
#
# See https://hexdocs.pm/swoosh/Swoosh.Adapters.AmazonSES.html for details.

ses_region = System.get_env("AWS_SES_REGION") || System.get_env("AWS_REGION")
ses_access_key = System.get_env("AWS_ACCESS_KEY_ID")
ses_secret_key = System.get_env("AWS_SECRET_ACCESS_KEY")

if ses_region && ses_access_key && ses_secret_key do
ses_config = [
adapter: Swoosh.Adapters.AmazonSES,
region: ses_region,
access_key: ses_access_key,
secret: ses_secret_key

if ses_region do
config :ex_aws,
http_client: ExAws.Request.Req,
access_key_id: [:instance_role],
secret_access_key: [:instance_role],
region: ses_region

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 50d6ad4 — added http_client: ExAws.Request.Req to the :ex_aws config. We already depend on :req, and ex_aws ships ExAws.Request.Req as a built-in alternative to the default Hackney client. Confirmed via deps/ex_aws/lib/ex_aws/instance_meta.ex:18 that instance-role credential resolution goes through config.http_client.request/5, so this is required for the credential lookup to work in ECS.


mailer_config = [
adapter: Swoosh.Adapters.ExAwsAmazonSES,
region: ses_region
]

# Add configuration set if provided
ses_config =
mailer_config =
case System.get_env("AWS_SES_CONFIGURATION_SET") do
nil -> ses_config
config_set -> Keyword.put(ses_config, :configuration_set_name, config_set)
nil -> mailer_config
set -> Keyword.put(mailer_config, :configuration_set_name, set)
end

config :gtfs_planner, GtfsPlanner.Mailer, ses_config
config :gtfs_planner, GtfsPlanner.Mailer, mailer_config
else
# Fallback to Logger adapter if AWS SES is not configured
# This logs emails instead of sending them - suitable for staging
config :gtfs_planner, GtfsPlanner.Mailer, adapter: Swoosh.Adapters.Logger
end
end
1 change: 1 addition & 0 deletions infra/modules/service/task.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ locals {
OTP_JAR_PATH = "/opt/otp/otp.jar"
OTP_OSM_PATH = "/opt/otp/data/philadelphia.osm.pbf"
GEOAPIFY_API_KEY = var.geoapify_api_key
AWS_REGION = data.aws_region.current.region
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ defmodule GtfsPlannerWeb.Gtfs.StationReport2Components do
id: "report2-pathway-field-completeness",
label: "Pathway Field Completeness",
desc: "Fill rates for optional pathway fields like traversal time, stair count, and slope."
},
%{
id: "report2-accessibility",
label: "Accessibility",
desc: "Wheelchair boarding and accessible pathway coverage."
}
]

Expand Down
2 changes: 2 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ defmodule GtfsPlanner.MixProject do
{:swoosh, "~> 1.16"},
{:gen_smtp, "~> 1.0"},
{:phoenix_swoosh, "~> 1.2"},
{:ex_aws, "~> 2.1"},
{:sweet_xml, "~> 0.6"},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive — ~> 0.6 in Hex means >= 0.6.0 and < 1.0.0 (see Version docs), so 0.7.5 is in range and satisfies both our constraint and ex_aws's transitive ~> 0.7 requirement. mix.exs and mix.lock agree, and mix deps.get resolves cleanly. Leaving as-is to match the constraint published in the Swoosh.Adapters.ExAwsAmazonSES docs.

{:req, "~> 0.5"},
{:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"ecto_sql": {:hex, :ecto_sql, "3.13.3", "81f7067dd1951081888529002dbc71f54e5e891b69c60195040ea44697e1104a", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5751caea36c8f5dd0d1de6f37eceffea19d10bd53f20e5bbe31c45f2efc8944a"},
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
"esbuild": {:hex, :esbuild, "0.10.0", "b0aa3388a1c23e727c5a3e7427c932d89ee791746b0081bbe56103e9ef3d291f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "468489cda427b974a7cc9f03ace55368a83e1a7be12fba7e30969af78e5f8c70"},
"ex_aws": {:hex, :ex_aws, "2.6.1", "194582c7b09455de8a5ab18a0182e6dd937d53df82be2e63c619d01bddaccdfa", [:mix], [{:configparser_ex, "~> 5.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "67842a08c90a1d9a09dbe4ac05754175c7ca253abe4912987c759395d4bd9d26"},
"ex_cldr": {:hex, :ex_cldr, "2.44.1", "0d220b175874e1ce77a0f7213bdfe700b9be11aefbf35933a0e98837803ebdc5", [:mix], [{:cldr_utils, "~> 2.28", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19 or ~> 1.0", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "3880cd6137ea21c74250cd870d3330c4a9fdec07fabd5e37d1b239547929e29b"},
"ex_cldr_plugs": {:hex, :ex_cldr_plugs, "1.3.4", "8c996a5c838f137a93610c3110d36aee81309a27d77bd2d0ab436df6bc01a085", [:mix], [{:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19 or ~> 1.0", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "30829e097eac403013101dc087e6cabf5e01a1c5e3a6b23ea4562e85521ff52a"},
"expo": {:hex, :expo, "1.1.1", "4202e1d2ca6e2b3b63e02f69cfe0a404f77702b041d02b58597c00992b601db5", [:mix], [], "hexpm", "5fb308b9cb359ae200b7e23d37c76978673aa1b06e2b3075d814ce12c5811640"},
Expand Down Expand Up @@ -50,6 +51,7 @@
"postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"},
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
"req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"},
"sweet_xml": {:hex, :sweet_xml, "0.7.5", "803a563113981aaac202a1dbd39771562d0ad31004ddbfc9b5090bdcd5605277", [:mix], [], "hexpm", "193b28a9b12891cae351d81a0cead165ffe67df1b73fe5866d10629f4faefb12"},
"swoosh": {:hex, :swoosh, "1.19.9", "4eb2c471b8cf06adbdcaa1d57a0ad53c0ed9348ce8586a06cc491f9f0dbcb553", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "516898263a64925c31723c56bc7999a26e97b04e869707f681f4c9bca7ee1688"},
"tailwind": {:hex, :tailwind, "0.4.1", "e7bcc222fe96a1e55f948e76d13dd84a1a7653fb051d2a167135db3b4b08d3e9", [:mix], [], "hexpm", "6249d4f9819052911120dbdbe9e532e6bd64ea23476056adb7f730aa25c220d1"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
Expand Down