66 */
77import { z } from 'zod' ;
88
9+ /**
10+ * Default SAML IdP entity ID. Stable across hosts — see the SAML_ENTITY_ID
11+ * field below and specs/api/saml.md#idp-identity-and-hosts.
12+ */
13+ export const SAML_ENTITY_ID_DEFAULT = 'https://codeforphilly.org/api/saml/slack/metadata' ;
14+
915export const EnvSchema = z . object ( {
1016 /** TCP port the Fastify server listens on. */
1117 PORT : z . coerce . number ( ) . default ( 3001 ) ,
@@ -49,8 +55,17 @@ export const EnvSchema = z.object({
4955 /** SAML IdP certificate (PEM) for the Slack SAML integration. */
5056 SAML_CERTIFICATE : z . string ( ) . optional ( ) ,
5157 /**
52- * Slack workspace host. Used as the SAML `NameQualifier` per
53- * specs/api/saml.md and shared with the `/chat` redirect handler.
58+ * SAML IdP entity ID — the metadata `entityID` and the `<Issuer>` on every
59+ * assertion. A stable logical identifier Slack stores at setup time, so it
60+ * deliberately does NOT follow CFP_SITE_HOST: the pre-cutover
61+ * `next.codeforphilly.org` deploy and the post-cutover `codeforphilly.org`
62+ * deploy present the same issuer. Per specs/api/saml.md#idp-identity-and-hosts.
63+ */
64+ SAML_ENTITY_ID : z . url ( ) . default ( SAML_ENTITY_ID_DEFAULT ) ,
65+ /**
66+ * Slack workspace host. Used for the SAML ACS URL and `NameQualifier` per
67+ * specs/api/saml.md and shared with the `/chat` redirect handler. Never
68+ * used for our own IdP entity ID or endpoint URLs.
5469 */
5570 SLACK_TEAM_HOST : z . string ( ) . default ( 'codeforphilly.slack.com' ) ,
5671 /**
@@ -64,19 +79,27 @@ export const EnvSchema = z.object({
6479 * `next-v2.codeforphilly.org` in sandbox). Used by the server-side
6580 * markdown renderer to distinguish internal from external links — anchors
6681 * with a host different from this one get `target="_blank" rel="noopener
67- * nofollow"`. Per specs/behaviors/markdown-rendering.md.
82+ * nofollow"`. Per specs/behaviors/markdown-rendering.md. Also the host the
83+ * SAML IdP metadata advertises for its SSO endpoint Locations (per
84+ * specs/api/saml.md#idp-identity-and-hosts).
6885 */
6986 CFP_SITE_HOST : z . string ( ) . default ( 'codeforphilly.org' ) ,
7087 /**
71- * Resend API key for the email notifier. When unset, the services plugin
72- * falls back to LoggingNotifier so dev + test runs don't need a real key.
73- * See plans/notifier-email.md.
88+ * Postmark server token for the email notifier. When unset, the services
89+ * plugin falls back to LoggingNotifier so dev + test runs don't need a
90+ * real token. See plans/postmark-notifier.md.
91+ */
92+ POSTMARK_SERVER_TOKEN : z . string ( ) . optional ( ) ,
93+ /**
94+ * Postmark message stream outbound mail is sent on. `outbound` is the
95+ * transactional default stream every Postmark server ships with. Only
96+ * relevant when POSTMARK_SERVER_TOKEN is set.
7497 */
75- RESEND_API_KEY : z . string ( ) . optional ( ) ,
98+ POSTMARK_MESSAGE_STREAM : z . string ( ) . default ( 'outbound' ) ,
7699 /**
77100 * From-address for outbound notifications. RFC 5322 form
78101 * (e.g. `"Code for Philly <notifications@codeforphilly.org>"`). Only
79- * relevant when RESEND_API_KEY is set.
102+ * relevant when POSTMARK_SERVER_TOKEN is set.
80103 */
81104 CFP_NOTIFICATION_FROM : z
82105 . string ( )
@@ -115,10 +138,12 @@ export const envJsonSchema = {
115138 CFP_JWT_SIGNING_KEY : { type : 'string' , minLength : 1 } ,
116139 SAML_PRIVATE_KEY : { type : 'string' } ,
117140 SAML_CERTIFICATE : { type : 'string' } ,
141+ SAML_ENTITY_ID : { type : 'string' , default : SAML_ENTITY_ID_DEFAULT } ,
118142 SLACK_TEAM_HOST : { type : 'string' , default : 'codeforphilly.slack.com' } ,
119143 CFP_WEB_DIST_PATH : { type : 'string' } ,
120144 CFP_SITE_HOST : { type : 'string' , default : 'codeforphilly.org' } ,
121- RESEND_API_KEY : { type : 'string' } ,
145+ POSTMARK_SERVER_TOKEN : { type : 'string' } ,
146+ POSTMARK_MESSAGE_STREAM : { type : 'string' , default : 'outbound' } ,
122147 CFP_NOTIFICATION_FROM : {
123148 type : 'string' ,
124149 default : 'Code for Philly <notifications@codeforphilly.org>' ,
0 commit comments