@startuml
title Before: Scheme-less origin handling was split

skinparam backgroundColor #FFFFFF
skinparam shadowing false
skinparam defaultTextAlignment center
skinparam defaultFontColor #000000
skinparam ArrowColor #333333
skinparam component {
  BackgroundColor #F7F9FC
  BorderColor #334155
  FontColor #000000
}
skinparam database {
  BackgroundColor #FFF7ED
  BorderColor #9A3412
  FontColor #000000
}
skinparam note {
  BackgroundColor #FFFDEB
  BorderColor #A16207
  FontColor #000000
}

actor "Operator" as operator
database "Env/YAML\nBASE_URL\nTRUSTED_ORIGINS" as config
component "load_config" as load
component "AuthConfig" as auth
component "CSRF\nis_origin_trusted" as csrf
component "CORS middleware" as cors
component "Passkey RP id\nUrl::parse(base_url)" as passkey
component "Public URL builder\npublic_auth_url" as public_url

operator --> config : supplies runtime values
config --> load : raw strings
load --> auth : raw base_url\nraw trusted_origins
auth --> csrf : trusted origin checks
auth --> public_url : public URLs
auth --> passkey : base_url host
auth --> cors : raw CORS origins

csrf --> csrf : normalizes trusted origins
cors --> cors : duplicate origin normalizer
passkey --> passkey : strict URL parse
public_url --> public_url : string concat

note right of passkey
Scheme-less BASE_URL did not parse here.
The fallback host could become localhost.
end note

note bottom of cors
Scheme-less TRUSTED_ORIGINS worked in places,
but the rules were duplicated between CSRF/config and CORS.
end note
@enduml
