Login or ask the community administrator for access to impact data.
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ }
+ >
+
+ This dashboard reflects recent activity based on edge data and is designed for
+ quick, transient insight. It does not provide historical reporting or long-term
+ retention. For comprehensive analytics, we strongly recommend connecting a dedicated
+ analytics tool in Settings.
+
+
+ Legacy analytics remain available here. We plan to
+ wind down legacy analytics at the end of 2026. If you need historical legacy data,
+ please export it from there.
+
+
+ {loading && (
+
+ * Totals adjusted to exclude known bot/spam routes. Sessions estimated
+ proportionally. Raw totals: {fmt(data.rawTotals.visits)} sessions /{' '}
+ {fmt(data.rawTotals.pageViews)} page views.
+
+
+ All web analytics capture unavoidable noise. While we apply filtering
+ and normalization, some non-human or ambiguous traffic almost surely
+ persists. Treat these numbers as directional indicators, not exact
+ measurements.
+
+
+ Analytics sourced from Cloudflare edge traffic data. Today's data is
+ refreshed at most every hour.
+
+
+ >
+ )}
+
+ );
+};
+
+export default DashboardImpact2;
diff --git a/client/containers/DashboardImpact2/dashboardImpact2.scss b/client/containers/DashboardImpact2/dashboardImpact2.scss
new file mode 100644
index 0000000000..d682634a04
--- /dev/null
+++ b/client/containers/DashboardImpact2/dashboardImpact2.scss
@@ -0,0 +1,304 @@
+.dashboard-impact2-container {
+ // ── Skeleton loading ────────────────────────────────────────────────
+ @keyframes skeleton-pulse {
+ 0% { opacity: 0.15; }
+ 50% { opacity: 0.25; }
+ 100% { opacity: 0.15; }
+ }
+
+ .skeleton-line {
+ background: #1c2127;
+ border-radius: 3px;
+ animation: skeleton-pulse 1.5s ease-in-out infinite;
+ }
+
+ .skeleton-stat {
+ border-left-color: #d3d8de !important;
+ }
+
+ .skeleton-value {
+ width: 80px;
+ height: 28px;
+ margin-bottom: 6px;
+ }
+
+ .skeleton-label {
+ width: 100px;
+ height: 10px;
+ }
+
+ .skeleton-heading {
+ width: 100px;
+ height: 10px;
+ margin-bottom: 10px;
+ }
+
+ .skeleton-chart {
+ width: 100%;
+ height: 180px;
+ background: #1c2127;
+ border-radius: 4px;
+ animation: skeleton-pulse 1.5s ease-in-out infinite;
+ }
+
+ .skeleton-table-row {
+ display: flex;
+ justify-content: space-between;
+ padding: 5px 4px;
+ }
+
+ .skeleton-cell {
+ width: 65%;
+ height: 12px;
+ }
+
+ .skeleton-cell-short {
+ width: 30px;
+ height: 12px;
+ }
+
+ .analytics-callout {
+ margin-bottom: 24px;
+ font-size: 13px;
+ line-height: 1.5;
+ }
+
+ // ── Top row: stats + chart ──────────────────────────────────────────
+ .top-row {
+ display: grid;
+ grid-template-columns: 200px 1fr;
+ gap: 20px;
+ margin-bottom: 32px;
+
+ @media (max-width: 768px) {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .stats-column {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ padding-top: 4px;
+ }
+
+ .stat-card {
+ background: none;
+ border-left: 3px solid #2b95d6;
+ border-radius: 0;
+ padding: 4px 0 4px 12px;
+
+ .stat-value {
+ font-size: 28px;
+ font-weight: 700;
+ line-height: 1.1;
+ color: #1c2127;
+ font-variant-numeric: tabular-nums;
+ }
+
+ .stat-label {
+ font-size: 11px;
+ color: #5c7080;
+ margin-top: 1px;
+ text-transform: uppercase;
+ letter-spacing: 0.6px;
+ font-weight: 600;
+ }
+
+ .stat-subtext {
+ font-size: 10px;
+ color: #8a9ba8;
+ margin-top: 1px;
+ }
+ }
+
+ .chart-column {
+ min-height: 0;
+
+ h3 {
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ color: #5c7080;
+ margin: 0 0 6px;
+ }
+ }
+
+ .fine-print {
+ font-size: 11px;
+ color: #777;
+ margin: 4px 0 0;
+ }
+
+ // ── Data grid: breakdown panels ─────────────────────────────────────
+ .data-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 16px;
+ margin-bottom: 36px;
+
+ @media (max-width: 1100px) {
+ grid-template-columns: 1fr 1fr;
+ }
+ @media (max-width: 600px) {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .data-panel {
+ h3 {
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ color: #5c7080;
+ margin: 0 0 6px;
+ padding: 0 4px;
+ }
+ }
+
+
+
+ // ── Compact table ───────────────────────────────────────────────────
+ .compact-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 13px;
+
+ th {
+ text-align: left;
+ padding: 4px;
+ border-bottom: 1px solid #e1e8ed;
+ font-weight: 600;
+ color: #8a9ba8;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.4px;
+ }
+
+ td {
+ padding: 3px 4px;
+ color: #1c2127;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 0;
+ }
+
+ td:last-child {
+ text-align: right;
+ font-variant-numeric: tabular-nums;
+ width: 60px;
+ max-width: none;
+ color: #5c7080;
+ font-weight: 500;
+ }
+
+ tr:hover td {
+ background: rgba(0, 0, 0, 0.02);
+ }
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ &:hover {
+ color: #2b95d6;
+ text-decoration: underline;
+ }
+ }
+ }
+
+ // ── Footer ──────────────────────────────────────────────────────────
+ .analytics-footer {
+ margin-top: 20px;
+ padding-top: 12px;
+ border-top: 1px solid #e1e8ed;
+
+ p {
+ font-size: 11px;
+ color: #777;
+ line-height: 1.5;
+ margin: 0 0 8px;
+
+ code {
+ font-size: 10px;
+ background: rgba(0, 0, 0, 0.04);
+ padding: 1px 3px;
+ border-radius: 2px;
+ }
+ }
+ }
+
+ .stale-callout {
+ margin-bottom: 12px;
+ font-size: 11px;
+ padding: 5px 10px;
+ background: rgba(217, 130, 43, 0.08);
+ color: #946638;
+ border-radius: 4px;
+ }
+}
+
+/* ── Dark mode ─────────────────────────────────────────────────────────── */
+.bp5-dark,
+.bp3-dark {
+ .dashboard-impact2-container {
+ .skeleton-line,
+ .skeleton-chart {
+ background: #f5f8fa;
+ }
+
+ .skeleton-stat {
+ border-left-color: #5c7080 !important;
+ }
+
+ .stat-card {
+ background: none;
+ .stat-value {
+ color: #f5f8fa;
+ }
+ .stat-label {
+ color: #a7b6c2;
+ }
+ }
+
+ .fine-print {
+ color: #738694;
+ }
+
+ .data-panel h3,
+ .chart-column h3 {
+ color: #a7b6c2;
+ }
+
+ .analytics-footer {
+ border-top-color: #30404d;
+ p {
+ color: #738694;
+ code {
+ background: rgba(255, 255, 255, 0.06);
+ }
+ }
+ }
+
+ .compact-table {
+ th {
+ border-bottom-color: #30404d;
+ color: #738694;
+ }
+ td {
+ color: #f5f8fa;
+ }
+ td:last-child {
+ color: #a7b6c2;
+ }
+ tr:hover td {
+ background: rgba(255, 255, 255, 0.04);
+ }
+ a:hover {
+ color: #48aff0;
+ }
+ }
+ }
+}
diff --git a/client/containers/index.ts b/client/containers/index.ts
index 83442f6d9c..c52e22c247 100644
--- a/client/containers/index.ts
+++ b/client/containers/index.ts
@@ -10,6 +10,7 @@ export { default as DashboardDiscussions } from './DashboardDiscussions/Dashboar
export { default as DashboardEdges } from './DashboardEdges/DashboardEdges';
export { default as DashboardFacets } from './DashboardFacets/DashboardFacets';
export { default as DashboardImpact } from './DashboardImpact/DashboardImpact';
+export { default as DashboardImpact2 } from './DashboardImpact2/DashboardImpact2';
export { default as DashboardMembers } from './DashboardMembers/DashboardMembers';
export {
DashboardCollectionOverview,
diff --git a/infra/.env.dev.enc b/infra/.env.dev.enc
index 3ed84c1eed..edfc9c2fe9 100644
--- a/infra/.env.dev.enc
+++ b/infra/.env.dev.enc
@@ -1,52 +1,54 @@
-AES_ENCRYPTION_KEY=ENC[AES256_GCM,data:Kz4/KiHal4JIP5kmXBSVg+VI/nvNGfPtRv8Rrf9mUdY7bDuc5k1In1oSPHsjjNQLDN8bs6YuzCSBzWyyouDUAg==,iv:QC65R/DVjioNsTb6EnChdSaugtlOqvEx+m4C57eZStM=,tag:kc9NcW6faLAdJIy17wcjtQ==,type:str]
-ALGOLIA_ID=ENC[AES256_GCM,data:Pu/lBy/Vo/9p1g==,iv:4HhG6IjEyheW+Ug1mI9m+6xzxRuVf2xvJ+dPtONp130=,tag:9LNs+U1klSpxqVgAnQJaug==,type:str]
-ALGOLIA_KEY=ENC[AES256_GCM,data:bY2wVEofNkVMlvwhEhGr4punAQ/JMShYYPpKfR/kyK8=,iv:NIrux9ntBLGphMQ0yem+puX9gjnvlGb3jUiDupiyths=,tag:8DkKbPwvQtPPWHGmH0zRWw==,type:str]
-ALGOLIA_SEARCH_KEY=ENC[AES256_GCM,data:MWIU9p3KmmsDjdxk+IRUJgzB7SQw479ZUG9WdlXLXk8=,iv:ujK8AHJPvvbCi7HxhL7cGvxQ/HYFJRriCFbsNkCAHXk=,tag:KaU7v4CrQJRKmH+QfJwGlA==,type:str]
-AWS_ACCESS_KEY_ID=ENC[AES256_GCM,data:nnIlGdEBlwi268NlCFi8d5Ugjmg=,iv:uP5wFBOWZJrSH50uYNzJ4kJdv3jYUcEFlMRVrDMlTng=,tag:Uv0D0mKNKebrNwuySxIM7g==,type:str]
-AWS_BACKUP_ACCESS_KEY_ID=ENC[AES256_GCM,data:aWJiiVfgnam1My2J/J3k1p/8j4g=,iv:XD+OHujRRMUyyZ8cMGJ2mw1TCtwELrR16txekGpwMi8=,tag:HEsGvUYMNEiv1mk2mb4GYw==,type:str]
-AWS_BACKUP_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:fYAtsyYDbTp3EBvm6vtabfmBupk9ryfpcu4P3ROoyTEOBnZyPrhPnQ==,iv:L/VZB/DccoB55GFWPfsVbQ9uzdIk3nwadkKZ15YzFGE=,tag:WEbCfpCYN0jHrfzWsc5TNg==,type:str]
-AWS_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:DGbljDUXr1ehACzOOWFFN2fCIrzq5aChbZg++7IXzLwBxWNldm1vqQ==,iv:G4lKHMPP4BL0kaZz4oH1CulYBiRh7SyZAu3pKhGoUys=,tag:LIVhg5BYgGuH7B7Eyk82Dw==,type:str]
-BACKUPS_SECRET=ENC[AES256_GCM,data:eQLNXNHy2Uv6TJt0nn2aZFCa/cyUFQFp490E+sv4+oMY2c0zZ1VpYSuIQCg=,iv:oFQ6xrc6v0z9K0t9m9EU3nXCwsW0lYQNoRbXclnAIFU=,tag:nO+JnRZKD5wBlIoMtyqnuw==,type:str]
-DATABASE_URL=ENC[AES256_GCM,data:+uZ8Kkhyxa6KersbX7p6hnqSpp9KcjCEttWRnxDWatf8jr3h+MhyP1SW/6c=,iv:3HQ97+1Gj+7+UjE798q3B4tF9CH7Oi8T4217dgiSygE=,tag:SXFgzJRgDXECYqx1yW6h1w==,type:str]
-DATACITE_DEPOSIT_URL=ENC[AES256_GCM,data:Q+H2KthVe4xO5RChejW0YU1TgGtJqXW4I7kc+5WXpM40GQ==,iv:jZjvyIZf3p/a4hC2LhqW6eo4wDGPLFgTn4YTWPVSrxI=,tag:WVguZkbwTPQ5kot//hkSew==,type:str]
-DOI_LOGIN_ID=ENC[AES256_GCM,data:MnV5UPz2,iv:WILeu6evYxrmctdiCKU9xuuW1E4u7RdFSjG5abdBZZs=,tag:u5gWtVGfeuXrJeqRREMPBg==,type:str]
-DOI_LOGIN_PASSWORD=ENC[AES256_GCM,data:gNfWFreLj6v6dXP/hxKvD7M7jr0=,iv:VAVh9dBRQP/ggQmKHOLepqDN8+pCmN5kIm+Xe7fpYis=,tag:w4dAIBjRMKUBnoX3FqjtXw==,type:str]
-DOI_SUBMISSION_URL=ENC[AES256_GCM,data:BjI1Ebz5t00X3n8PSmjPUk6IaIFgWOqEDDA+SheOHLDNotjabDjUE2k=,iv:FB5IXGUm4c/rdVfzD6S8WnmA7CW8y91YsvDr+EUf1NA=,tag:Q+OwRyQPNaBfNLb21AQVfg==,type:str]
-FASTLY_PURGE_TOKEN_DUQDUQ=ENC[AES256_GCM,data:MN2kB/F4ztrOXpuDVV3qDBotky/1suF4NsZbtTmE9gY=,iv:VzvRIdYjX4Tw2op5qTsdLg2l3ABeGQnTRp2EOf4F1S0=,tag:3Ua3WcAWJHVHxyRIfNTDCw==,type:str]
-FASTLY_SERVICE_ID_DUQDUQ=ENC[AES256_GCM,data:BpF94SQhZj9+gwlWtGT23VFFQaZBMw==,iv:HRVbeeO7QCYi9wO841TCwS8BZYTvb//3diy9u07RL7c=,tag:EqtpAL5cWLYNulhMupkYOw==,type:str]
-FIREBASE_SERVICE_ACCOUNT_BASE64=ENC[AES256_GCM,data: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,iv:gApN9Y2dF+3z6KbQcR5TmRIBO0DK5B907WaPhD9LIuE=,tag:Hl5fty+5t8g221MjMyfCqA==,type:str]
-IS_DUQDUQ=ENC[AES256_GCM,data:NQOkmw==,iv:0tqLjo3HE/XZnR6UgZZBFZtn2vq6mj01XgO9j5B0r9s=,tag:dX45cwa5tWLgIzjxVe1Log==,type:str]
-JWT_SIGNING_SECRET=ENC[AES256_GCM,data:PjgE+THClW+wcA1gvnT5Ej4sOmIjYJCXtSw7//wpxOaeuKs5Ic9Jt45qFErknu4lL6RtHEHXvQuuxgYEKkVqzpYuH2ckxFXRW/UChWMj/xw1ye8ZHjca1CqY8kHyN5wMGgxAAaNZAuK9IvRGV8DEWdepRR9JKM8f3RwsZSE4mw0/U/ClBbc9NywFFAGotouVPxexqWZgb8K1qA7i59FXYMP8HqBu0Z9XZzSPJ1Jj9lWe0HbRyE5IC5DX4sqCDuC2UdboDRfp5RwpJhMYWkKMf3q+3xccTm/jMuMX1BgybG26r4xgmko13g7aTcznLj0qzzY3OWilk0jZWJ5zIXp7C8282BxnFZmWfE224zi+TEaJBu8aAn/WsZznqp6dHv1PqqhXEKf109/fHKOlxFjQKx4qL4/AwS9rUBWWQZ34Ldm9Y/7F17/Hmo+DMztL9xfRyu3NkzwjOCWKXL+PX5A9AszKELOPkaJxT4MIdtNZp1CLKl3RQtpZ33l7gqb3kJuYA9+WGgya7HN0QX9IbkX9D1YdAV/cA2V9dMd7tb3pvnxybbEODig2eDwxEp0fVAsULwxTF72PRgczGTiza13zCE31NEwqEYEBRE6Nq1UIJSus2aiBocrETDtfvELzvGSTOtlJUOM+ARoZiGyUvg/BpTuNoqEkCB2lYmSiX4b1jrxiE70qgMdbG85Bi+POqcfrg68cI5rk/zIbj08mBw5QTteELNI0EFeTzd013nxYXWkAlpC+OtlaZk/Pi1n8qhqHmkPfSlZVjxL/hqTwSviybwIJDh/cZCPanSpZ+Sn7fgEG8KzaQQHXRVqxXJp/2FRt80dY2v+nX54K664DPMFWgMHlqVQYIDoWn8Yv8NVVlP2lAxAajuOAC0sRRVgbZ6IOM6Gw/MD/u7mG+cxm/cvNZZfhT2kjzotEPqsGOGJk1tBbNuxcosi1sCmFlhZsFm1gjy09kwbRTVF68U/dpfjC+bl2+e7uMWeFcJOOJfI+AczUNu8MI+Perzs1C+P8bCne+27yvNAnPnerXUdpnJyfaRsbD4kOqm89681iMEhJNA2XToK7DTBslgXlLa2YS+Cp2jQAttsoTDKsEfqZIDN11JxXYgRoBjb3usglxGZRSp3pqGv3rrqXyqx4umL77mreb2xdil4kOBySFSKG4l1hHaK/NRJqsiaHX36F1ELFy3P0V+z0hW9QujyWDlt13gymBZalCgiLfawSDplhgULcFFoEQGc/NvFQvuvlo8ZvFycsBlZaam52WXM0BsoDvfGGyunTg27KCjx0+eB2hqsIABTU4qKNIxFFdWCeT325NAO82oO65TgfSglkXRDujjAh/nj3VgSeLU+SGGobM30+Bg==,iv:JHBkoIafd0nzqnzZNYhBx5Y12q94fDdQktC6iW43cyc=,tag:wV01DXrn1ypimNFrzzJLcQ==,type:str]
-MAILCHIMP_API_KEY=ENC[AES256_GCM,data:6Co8J9KOFq1Q4qIVk3h8gayLsmP/kJ8Unczd56XjT/lC4Hkl,iv:2sNxyJmFZMigRKzqsaiDM09N/Dank783OE9SxvpUZfU=,tag:n8AzKw/BKoXciipBZkb6VA==,type:str]
-MAILGUN_API_KEY=ENC[AES256_GCM,data:+JBNQ4LxSOkZWtB2AQPSDA4juXF5jUKZrTAQo8xGB0boQEW7,iv:AxtIwHYoNnSN9QjgRQNDK85WK+sCyYB+Rlzks106eyg=,tag:G70UlOuspR+BDsx/5r697w==,type:str]
-METABASE_SECRET_KEY=ENC[AES256_GCM,data:GW/O7+RQWlC+rBb2A/xIHKyYyrEcmUMy7dxqDC5nQ/UpkzOHK1SOpRvandIa62YivcNNvxwEzAFHu7BASjZK6A==,iv:GPPmRbHHys6I5FGddg/AZsnysFQ3PVqPquupbhiAtng=,tag:XoN4puLeTMwVB4zQ72Qpqw==,type:str]
-NODE_ENV=ENC[AES256_GCM,data:7zwIoxkdMtNzBg==,iv:b8n1uKjI71k1dc1kMYJphEQnnefqS6+C8VzGgOldUm0=,tag:rN6nFQjBY4cghk/n0aeBuw==,type:str]
-#ENC[AES256_GCM,data:AQh6rlnCeWROveEJsICN/veNdoKD22C++/M=,iv:Sw5zGhSVxTzs0m5aRWoGiPRARwNnCujwdlEN1i9ZMQg=,tag:oSE0CuDZoN3hJNhykICfbA==,type:comment]
-#ENC[AES256_GCM,data:189wvfDMP4Wv/4CUSOi/ls4jIZpU7PBTa8mcDYxqnU5N9NhSjq8=,iv:ohTmqGFpcn4cbIos8TTemUwNGzTXFRZHAEo3qf8TqEc=,tag:NrWA7r7wP4MVSwJU8A42Dg==,type:comment]
-S3_BACKUP_ENDPOINT=ENC[AES256_GCM,data:kinsYfgL36qIqGou0TaalR1HGiWvX/6nCcNe/gYPp9ypSGo=,iv:Nz5Bub7iBiXlo5S5vpiv1v7OrX/2dx3VOcXNSNtigaY=,tag:rpAu5dDTZnveOMMjWCBI+A==,type:str]
-S3_BACKUP_ACCESS_KEY=ENC[AES256_GCM,data:4/yI1dtcnuRx+wzb3F+ygBDsKxs=,iv:ybu3IGbI8K98byov4TR9iy3FcG59Yr7EZC5oVHbUpUk=,tag:+pDV21jYmde6KlGa9HfV1w==,type:str]
-S3_BACKUP_SECRET_KEY=ENC[AES256_GCM,data:wEFLWIh6UL+eI9eMsgqad5lI5dppWIzac/E7B8Fa3PUSLQejPQgpeA==,iv:1r3DFRl7i0QPZ7ITr0jhKV08b1ZbnDmnmIw7FCpOkzo=,tag:rIeDFnAM4M4VaoagzalxOQ==,type:str]
-S3_BACKUP_BUCKET=ENC[AES256_GCM,data:aJ9K549KzJSlgNs=,iv:Ca9+3SxNXvyd7pvX9ShtGnjPUn8LARnMhOfSaauUAEg=,tag:0sRvNSahQTOsw3Xk9YrOPw==,type:str]
-SENTRY_AUTH_TOKEN=ENC[AES256_GCM,data:OTK6lJ6IK46n8wXKVLTH5WwKXn47iLIZjEPQasLPW29RfBjOfihuZN2kEf4T8pBwDQh0fGaY6crs1dewF4ama4hXvmg13kWqO9MwSU+NHiuroX4gUZ+Fg8xkBOjnarEe7NMiRMP0BrlntD1LwwcTDV3p/Df6SphgyYfqeXDiJP1O4AosPuv+4egBKqqY2KCy3czc47PcMWapSxWJfMU7KlWggYoSiU3BR3EhbP8cRVZ1tYUttrb0brI28A==,iv:c+h68p57wTshNPaAzd0EiEBVXcAPvBUvgozWJEpZ7n4=,tag:aV3vlkzWJCAp1n6kLXCFNA==,type:str]
-SENTRY_ORG=ENC[AES256_GCM,data:m8Qr,iv:RdVMbGg1oRNC6t+Ly27+wbjR7oI6uGYmPgGagNFE3cs=,tag:/xqPyr8e2SZgMw4dM9eRrQ==,type:str]
-SEQUELIZE_MAX_CONNECTIONS=ENC[AES256_GCM,data:ius=,iv:SgH1AcWawWQRDHcB0E5aWCfp3UXDSOvCXocgsV1eeKo=,tag:1QfV5Jl9bQvV64Ty+IcNwA==,type:str]
-SLACK_WEBHOOK_URL=ENC[AES256_GCM,data:eLJUhmgQ+zOYRHnYKJrp60DQpKR6Li3iOCeJ1VaHWv9IwItuakAEIRbVrC8hp8Q0c02M76a6nlObomuRFSqK/zOMc3aqomg9mCpObYsgQw==,iv:vCCjOU36LdEwEHaA1Rqzqfs0Po3uodY4qJSbbih2BlQ=,tag:er56v92xiIMel1MjqRL/cQ==,type:str]
-STITCH_WEBHOOK_URL=ENC[AES256_GCM,data:FFBgY/8j+ZkVDJlx20UsSc7OiR7V4yg38AC6jJWKZXZ/KnRhCjMgsqwgGHwxUBbZ1YgB/ZKLscAyhlGWeF9An9BsFueUJk1v9W+w8IOBpiczjftfC4VEqVWTqpiWT09iGbiiHYZTJKUvdxeNnsStoNAmcN7R,iv:GUY0HRWcMHKlYhVDo/LsXrS0UXMdIuak8bn0gdtAVFs=,tag:Vo5Qvjt9JHpRVbG01s01kw==,type:str]
-ZOTERO_CLIENT_KEY=ENC[AES256_GCM,data:whlgZOo3vAFqntlSdO+vvrBIws8=,iv:yiBuRlqWtTD7VZuylXFs8c+rDCZbce3N0c3kG8i50Ss=,tag:V7mbPzU7QGJcv98IUc/Mig==,type:str]
-ZOTERO_CLIENT_SECRET=ENC[AES256_GCM,data:oFi5Jd45an5EUeIfbNL2cmcMa2U=,iv:Qda3XG/A/3ilj4Ak0AL2LBSq+N5TClAtIZ15w6//U1I=,tag:5tx1ESB4JOQNGM18L4Y0xA==,type:str]
-sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzZWZlN0NjRG9aZHlKWHVR\nOElRZlVscVFseGRORHZoSEpHS1ViUHpnWFVNCkR5NUU0ZUJlR2VOZHV5aHRJTi9G\nK29CVHhvOUt6OUs2aWNOSG1RNHdzMlUKLS0tIDVHcUF3Z3dzKzhXeHNERUlUb0Na\nUXBaS1doRkx0aVdFWGJVUGFpNlN4aG8K0cjHGDgqdu4DnvrU1QIZAkaMIoZA02aE\nVlURBU9Y4MInhk3xs/9MSxNLaqlOPDu5sCXRI9ATO02fkiWNDIiDRg==\n-----END AGE ENCRYPTED FILE-----\n
+AES_ENCRYPTION_KEY=ENC[AES256_GCM,data:QwIZX8X4prK25PkL71h7QgSfTzxi6jrOPrmPZriM1HS+mARLkZS+CsH0L0bCVWU0/RnY9Ul0mtT6W8JrMiENmw==,iv:VZDXJXHEK15m2Aga6qWKw1r9X0/HejZmFD/hySKV9eU=,tag:YtJWe6RgC27XEN1R2Pmt3Q==,type:str]
+ALGOLIA_ID=ENC[AES256_GCM,data:LFdkdnTJBkJ6lw==,iv:O18JPjnSZeBlU8ZPbQUz/lz0e46MCeBtRtzvfUf0SFQ=,tag:YB1AML9eiLqUbuBhtPDG5Q==,type:str]
+ALGOLIA_KEY=ENC[AES256_GCM,data:9LgXsH/OXSg+8gwTGjwhvikHqWa00Kz7sOSZgBYgZ54=,iv:Puv8Uas8aj/oHl3kEVAfoi1SO73nQqq3BfU7YjPXxPM=,tag:OnFllRwJZdVT8qBl9XhR4w==,type:str]
+ALGOLIA_SEARCH_KEY=ENC[AES256_GCM,data:etwRyHHPvUcPAirfMBFl4/RcPNMAHoTj35HG3RZRZXQ=,iv:mV8xbHxdZvqKznqnOTnApd2eu2j3FVnvhR0CkO/rTrs=,tag:iuEM8tkQZ8S8r5JH44iHvA==,type:str]
+AWS_ACCESS_KEY_ID=ENC[AES256_GCM,data:ojDBZhAQ+y27AqpYacJtWxFrU3s=,iv:uWRxeAM83iwkVR2hiRoGKs7gFXJqoHAjUOgwH58gTQo=,tag:Eh22ZHk6PxoFAOMRwAEZBw==,type:str]
+AWS_BACKUP_ACCESS_KEY_ID=ENC[AES256_GCM,data:Q5o3MLWBhafVt8N0qv4j5qAod5w=,iv:CUa4NoqfCI9UI6G9rqF7rLvZ48O2n2Yy9VmIzN08pGc=,tag:J4LoI56Ak4M+KPSDLn0iAQ==,type:str]
+AWS_BACKUP_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:+u2Nwl9ycTYvA75Qd/UxeT0Ve0JU2BAbpO9GrZy2iwkV+/rNw3T1TA==,iv:EkyKV2vy/SzNaGQ5Oisfywz0dnF6Vrt14RINFs1Rewc=,tag:QpPRGK/1/fzhTEPS0ZipLA==,type:str]
+AWS_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:QnDJMxc2tEaQJSgNIY8D4moZ38o3oZLSxJHMuQgvu1kMO+AgrWKUjw==,iv:HCoq5iDtFfwttcUQI1iyUOSopozZpjeLlbXvBr8aYAo=,tag:b8grQVQ4NHG/zvSkTeE8Ug==,type:str]
+BACKUPS_SECRET=ENC[AES256_GCM,data:shNTuKUSpUr3PgbvLUgqqd/yANmz8UcsiS3dhrB5BSYVJ4SuWnzzOS863+k=,iv:dn2UsBtL22BolPl7y9cg+mVHiQiR24PnT1giPBM0bZI=,tag:jmC2ATslqzV3geLRXNdFXQ==,type:str]
+CLOUDFLARE_ANALYTICS_API_TOKEN=ENC[AES256_GCM,data:SGsNasbiVnbBhDlHQW53q00lPSYidNK9/FfYorR7BJmqRcSWCYoZpKmuem++LCLtfbQ95g8=,iv:hl7lgEobh/WPp0XqI09dp3E4GEjjPDt91g0JK6Qm7Qo=,tag:+pIX5QGfSQJpl1Yj7aZx7Q==,type:str]
+CLOUDFLARE_ZONE_TAG=ENC[AES256_GCM,data:Vy6jGSJX2QMVWg71RD6dzREpTLWXnKlGeP0CT9K2KB4=,iv:anwDOF0sl+plFJefNm7swlmHpPFfPkQDBDysEX/55w0=,tag:KJrzy4VHx96jETzyx1pw7Q==,type:str]
+DATABASE_URL=ENC[AES256_GCM,data:d9IYhTltxN6k4EuVP9hfvJhYqBcsRW04XoJDpPSYLGtcMGNvqKwL7whD6jA=,iv:0XJOEdBAsrBmCkElxPbOX/kzWCzLxQRwAOezVKHUB+A=,tag:ZbwKfyIdCf39LMb1Vkt58Q==,type:str]
+DATACITE_DEPOSIT_URL=ENC[AES256_GCM,data:poD5QWfdh/kPOiNMzZdJWWaJ8w1p/aG9xA4zu7Xm2ofEsQ==,iv:NanbyvJ7IpSO5JjJbEaQvgVkiKt5GU8w4knZS7sn5fc=,tag:WLGMLnT9dUWun8IJQG1Sew==,type:str]
+DOI_LOGIN_ID=ENC[AES256_GCM,data:/TScbpSP,iv:MWZ1nCD43O2lFpWj2w0MJkkkX/WcwywaYwGaA66pppo=,tag:Kbf8dccofZhTooD6jU0lYA==,type:str]
+DOI_LOGIN_PASSWORD=ENC[AES256_GCM,data:FMCoA4s1709MnRWGpjaIyNhxYhw=,iv:WRLN4pC2DlRPWk2wHQN1jkWWSDR63TBlLoIOWQkQotI=,tag:VdecgaxWBNEKa4BXneP0Eg==,type:str]
+DOI_SUBMISSION_URL=ENC[AES256_GCM,data:EB9oz9jb96SwiCcH/m0va9lFQ/LEJs155K3thqCrDEfCmdahjwzfrzg=,iv:WZDN3jxWyy/AO/BA0jZq/0xWX5e8XLnyB+xHqHFSrlU=,tag:yOpHh4pfkSoJrQ050GCMYw==,type:str]
+FASTLY_PURGE_TOKEN_DUQDUQ=ENC[AES256_GCM,data:2vSXaeqJKThevWutefRuLf6HEsAca2UMVirzkEjLZcQ=,iv:lyZruIZvw6870bdtb5uYyZZWPaxGeahWLKznBXM4+y0=,tag:SaJ7gYPIIoLeO97K56V2Rg==,type:str]
+FASTLY_SERVICE_ID_DUQDUQ=ENC[AES256_GCM,data:OtLTPCYI/Nni11+bYgxF9G+oIY1auQ==,iv:fyhp7pFod3PY59lqhBccAkt0NuAE5ZyMCiyBiSbTAdE=,tag:N5LObQVbbw94BuWi1cR2rg==,type:str]
+FIREBASE_SERVICE_ACCOUNT_BASE64=ENC[AES256_GCM,data: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,iv:lECKfIfdMikTO1b98fqJz28G4CHJjYwKvaEZ4h2bcEw=,tag:DjScRvE8w7XbW46nZZT3gw==,type:str]
+IS_DUQDUQ=ENC[AES256_GCM,data:YjPwEA==,iv:zsSPad1f5sbg73RRjhT81GGMNUr2Ua/NFdME65i2rIE=,tag:ooJrJwbpgSyvc4fAZBunDA==,type:str]
+JWT_SIGNING_SECRET=ENC[AES256_GCM,data:Wv+bQx9NgAqlX/pJKvs5LeDirgYkdKZmHWZBxzxK7aisYEkOngJmK0ktMfEwqdY85/AcQROXaoytiihmNZFvzxaXHv1rpXcjsupUsdfGzrn705XxZUsq58r/AvQlKNNCvsvgQpVF8cT2gYnPp1PCtV5o1phd+b45qmX95g66im+7SZFWbnay02bTEl2Cnb+upnbCUOog0GcGfiqnu2FT7tAKBNFIefpV66ajcVH3+cPzDtNuKKbF/Kq0VS61uLHEEXYYDMspwmQpnCgyKUmOuRa6rcosbXPVCnWEjmYrZlnsKdaNfN07Kx2KzrhiJAi08a6cFV9qxzTeaOBvuQx5abZ5yjTARKFQ5Wt3smy9AjJNnYl1uqnJU87ueFfX7br+7bza4LOe+5DytI9MdCmi9kq2/JNPrEHd7hYljbsNYJmCAN1nKypxdtc7UEZOvAl4asqtW3KZkHNpKK9hZKswrCg6YdyICvEndQlxFe7lM5FSMMYLS0kTJCOicng6LVb2J0EaNaTPYG3G7w6XKXk19Jzec6RoQkOHLbNJ1E0MTRAd66S0jQZnYjF0Kw3OgidX1E4ZTFPeMrYwvH7kGdsPT9aSA02ANgV711Yfb1kz3BxlxZQgWAdKsqpukavDPMsx7OrcQjUw/bq6LWdaQ0IBrcSgdlK43hvpUEANIzEta9D6H3zCBZSw+4woI6a+ZWL4TmrT1MUjdWQMb+h7n8huBFBYkYPShKcu40mCSmB9lxJFsfeEE4h0KwRz8Wky0ldjxqCtgcVvCRgFkYuMN4Q8DFLoGUmzfUDfzFmlGcW399av9B4fR2uQeSbY49uYAkOHiOQgyW9rn7YM0K/cu4+/kTxXiPIx7Gd9zxBbFsgYFUuYP5C9m/8Q8gKyrNFOavbALppzuHnIq7Ol4aheHwRO9qOdsUIq78WAwtg9vlPEBgzh3IV59VahGT7vK2lzvSwn3aO/pP5WaS4+X5tg/mzKey6W55BrGk4nHhj+Qyn5G9ZoDCuAO/806k+MEzDM+1UnPk14lvm8stMIYRw7uGn7b3gNwoTCqZEtkO5I2kw7+4AwAFsVLOzQjzeXu5thquLrlKpKY9YUTYUwoje1D2vFm3SaA+AvSvmyfqZn8WfKQfC3TIkmENrAY9PMBx9FbFFrSrjRpSADvDF9sMgiVs64/9SB/jnJlR1uq8lnOJoVR4gd1UV3sYljULfLE8QWkIx9U1mOW/4T+kmurvEwxBgAFNSFdPdi/AzIBqFRDFtx/tsTT3PQ9xwCCOK1HWWKZzMAijJpInJe4+Zv031Ef0jisifF3jLefH19nAF776eVhXdZbRJgnr8OsX9E33bhkacsSI63STJDak4PiBVpyfTa4A==,iv:4AB+Gy3o2YjSzpcWf4NlYb+hVzEBJkHVkIEe9AkEnTY=,tag:YY7l8sVvMWvzoG6tt7m8KA==,type:str]
+MAILCHIMP_API_KEY=ENC[AES256_GCM,data:Hni3CZSMCAw1Ko3L0QAxmTdyxE2fyGjz6uPf2MDO3p134SZb,iv:eg34UYvFQ6GikDk/3/HDIU7KP6agV1CK5sq9y3yz78M=,tag:Fh+nd2Op5Cq/p/nb+ow9zA==,type:str]
+MAILGUN_API_KEY=ENC[AES256_GCM,data:SyyJoOncFXFF2aKmfV827hDCdv5Zr2sSXJiSszSGIW784lQ9,iv:corJ7R8AbJXk8ipaI7O/q5LnsDZfT/erIIPgJsWehNA=,tag:X/fBZgjnDvLKJ4/7TSvy0g==,type:str]
+METABASE_SECRET_KEY=ENC[AES256_GCM,data:rrtTqdChIjTs4lrCrV7IwaZaCLG6AoJvglNZWiLAKmo4xrwlohAlNV4hBp1tloq0Mpyw5m2xl4Dd3h8A7hxzew==,iv:FVBVNeTJbhF+E+rpbgXDBS0CCniam24qzr3CKY7pz10=,tag:R7PbxajT0uIJJ/r6ZeOfbw==,type:str]
+NODE_ENV=ENC[AES256_GCM,data:+eUy9Aj12c95lg==,iv:ccaeTWNgHUjVPdWBGut4XC6XAVYypqT2EhEU1f3LiK0=,tag:nJcq9H/CcKiRHB93s+ixGw==,type:str]
+#ENC[AES256_GCM,data:x86kxjwXzrjAoX9V+4AIRIk+QbAO5UPGpZc=,iv:S2aq8qkVD9VnWyZpfYq+lVoxjFgcWm0AngLj3Nxbf58=,tag:mxS3SBeP8RqFZ3GP+KLv6g==,type:comment]
+#ENC[AES256_GCM,data:zJiGD91h0y8+SSRtayvj655B4/opVIFNlKS3fxTVrmVt3ptcYHE=,iv:IJcRp3bvZA3cmdO50jdl7D4RGQXRubnVBf+70cm/Re0=,tag:nS46w09X4ANQQGpCKag7PQ==,type:comment]
+S3_BACKUP_ENDPOINT=ENC[AES256_GCM,data:bS20RsEE6SXJ/gD0UYRb1tLFzvTc7oc+VUB+rYGeKyMSLvY=,iv:bGDPWDsvphCwax/vwwrmrpeWOZet3o8RmaoX3KFxfbw=,tag:gyoTaOAr+z9IhkWhvmSTew==,type:str]
+S3_BACKUP_ACCESS_KEY=ENC[AES256_GCM,data:HMAq2zxdbPKwCifMpnqt0xCTKiU=,iv:vfx8Gzf/5KfFUqMeNDNRxdIZSi+Rxxqm5397ziVmhVI=,tag:mWg2KveS+HKpPh+LhcEVBw==,type:str]
+S3_BACKUP_SECRET_KEY=ENC[AES256_GCM,data:OYeD5BX6pVGOT2L8u7r8Z8dbv3AYqS2mvZ7B6NqJld2f9mMTpTmZGQ==,iv:MrViCuxr7VDn89zeigwWzyhJZ0hWUd2Q/VB56t5/9B4=,tag:lUrJxATW+PWeeeAC7Po+1g==,type:str]
+S3_BACKUP_BUCKET=ENC[AES256_GCM,data:AlixUPNBxfAovcg=,iv:KuOXNH8ixFIinRWsHZKHqvyq/TuLRUC8Fc2SWCDxFxY=,tag:SDjLkobA0aqKp0DS/jJUQQ==,type:str]
+SENTRY_AUTH_TOKEN=ENC[AES256_GCM,data:N1hLCzeQjMbPzn0SSAo0vT+4FA6BihKM7x6uPJDVkK1SvnKcwdjKXH0Y4GxKPI7U39EWK8cbx9PGmk1GeCDgSzkq83tNRD21e88veFnEKP02F8efLnfR0j4NM3Kbg9J8g4DT4Yp1fOvaQ6Twli6+stWFYxde5ziIzrnbUOrMvdAUZPHvbFOvZiJJtYR77pyAR9/dbYMDrVHnCydt9oRmYRsJJbbNiNbrC2ATTQru1kmI1oMcdqLY6iQx7Q==,iv:A1nqc4legVPc+0Gl9RWCaWGMm5/R5yUucrUawEDWTNQ=,tag:GGgNa22SIxa4AcBKFv/89w==,type:str]
+SENTRY_ORG=ENC[AES256_GCM,data:GFdm,iv:/ewODHXse8BOGqSumC8ZGIC0chmiyu2b7UfzRBduc7k=,tag:/MRFSdMJDanUqWO+hKxZng==,type:str]
+SEQUELIZE_MAX_CONNECTIONS=ENC[AES256_GCM,data:61s=,iv:mr3svYNDAD60QHqUvps165FUbJoU7reh8AvERwRIzDw=,tag:zwOLOx7JrVe3YoYa8FJ8ow==,type:str]
+SLACK_WEBHOOK_URL=ENC[AES256_GCM,data:IZGLpb0MwS2hIKiiSNW6zGYPkSXqxRmrBVWOZCMhK81prXVy6Xa43zHZnkFgPw8euE0tOnwPl/Qwqt+7It3UQXJLKfV8Xo8rSmoPG9w/RA==,iv:3YvSRMDG6REfBeKNFYQWtYLk89S9ewUtkWVzRsJa4Q4=,tag:Nj9UWPdP/r+/RZgAwpbK3Q==,type:str]
+STITCH_WEBHOOK_URL=ENC[AES256_GCM,data:lsLU8jzBMTLt/UawVWgUjal1YQJWYACXrNCc1vrhqiLgHFzfoGNgttWP8lVK6kBoAloJBcYg8eUxdoMQM5+tq+WNk/iZ8DEri8yIewZSt+NL64/3VvHSsPBw0nbY8HUR1Fm+iYE7sujNx6mA1E6nDhdzIcHl,iv:w6pmAV0gvjX8saQHlEPgk572gPJ6xnPwVnazijFjccE=,tag:1KKKipxmDv7+sKSTco7S2Q==,type:str]
+ZOTERO_CLIENT_KEY=ENC[AES256_GCM,data:Y9mSpaxJbrISeMNMsUOqVBLOn78=,iv:pGwjaAaeaaQL99edzjt4XvSfP2GrbsVOF1U4zsU8lI0=,tag:lwbndzd9SQvJ1Uw/TqVVog==,type:str]
+ZOTERO_CLIENT_SECRET=ENC[AES256_GCM,data:twNvhGqTnp1uLflUUPsWyFeXEE4=,iv:t6x/BvikRLoG3YJwZtQ2WDmmO5A7SSmRSj+bNeNjFCA=,tag:6O0XkKaPepDarB1bkxZBNw==,type:str]
+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4R0tWbGk0WGJOZnRSYW44\ncmdGc2xlWmJnblY1dE9kR3Y2cTJjNlhrN2dBCmpSZzBiTUlGMnVnVWlTYUM2MkRu\nZEM5SWV2emVHb04venMvd1owTDNnbncKLS0tIC94SGNOY2NOYm9ha0d0YlVRb3dw\nanhEUTNuZ01vcjRBUHNyZFhYdGhJSmsKPUlgyLqiDrSKJ5LivHiHeoIlr43G5LTA\n1ca/d6ifM95xgULFcB7sZkwoHbeoxxJW9/AdrQB5pee01OnLSB0Xrg==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1wravpjmed26772xfjhawmnsnc4933htapg6y5xseqml0jdv8z9hqemzhcr
-sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvT3RxWDBqTS9LZ2NDWnND\nZ0p1dkxTNHZ3S1dLaTNPK0Jsd3h3L2xmcDFjCmpoNlgzWU50Tk5DWDc5NWtnTW5X\nZ0VMVzEremEwdWFDL1FDUjBKeUdnRjgKLS0tIFJEeXFqMnlMNzk4cjN3bHBiVm8z\nbVgzdmtaVTdzelRJWXRWQ3VnUllvVEkK7+wFnHcWlQ578ZBdYdEfbstSSUHyftzm\no6E9oYEqwH+oxftQN5E2nVQ2QxwdsXKlnThkMJgVxH3ncgfMSUt5zg==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCQ3VENHdqNmVZVkd1Nnl3\nZ0tvUndoSmZXWVloTHJVRjNYT1htKzcyRWx3CmovV3g1MktwQUI0OTA4aUdmL2JL\nZFd2bmZpcFd5d0MyRjdZUmhZTko0a2cKLS0tIGN6bmhqOWhkM0sxSXlweWpPMUhY\nbXV4RGU4NWRzRGV1eGxaODc1SGVYNzQKK5nbnkgNTGcS6pkrIxydTeuLlmD4pbdo\nKHfVnYvOh2mCzwWaNbRitgvpBE+xFcl2iB98rBR2YeV3K9kCmA56og==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_1__map_recipient=age1vhftscteyrwphx0jpp0yl60xxrjs77jq05mkzv88js7ckc926vcqepp2cj
-sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4eFhnQkJVaVFiWmdzYTd6\ncXduWCtZdG42dTU3VVJ4cEhlOEhpRndSN0JBCkdTWWhFQnFCTzBOalM1S3RTbDFo\naHBGdDdUcFB2M3o1R25VcTJ5YzZ1YnMKLS0tIDFnVnhzcVRtZmJZSmdxSE5JSGFK\nVkRRZWRPMi92VFpUNldYZ0MxU0lTSlEKh6gcbf04oOIrmLzfoK/0wagfzxDh/DSb\nQCRvyhkY4cFQgO1fn6fU4UXdOq8Lp0rXPEuaK15L7hq3q3hEo74O3A==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMTUozS290K2NLdGNFQ2ZV\nL1A3OURkWkkvZzdLR2dwZCtNMkwxSENCb3lNCkFwVlEwZWNSeis2dDlzUUpseDhq\nSWtwT3owMXFaTVRiM0FwOXZ4SktBYWMKLS0tIGlKeEpKakJTNEtFZDR4U1hSc0I3\nWXg2UFJIRVRJeU1BaUNHaXV3aWVIVVEK/8vGKWaoOz0Tabq1KS3PZiAaBbdHdfJX\nKDm4iUpXqBFd7xALNKbRDDNY0AbsgTHebS+8QQQM01o/Lf36AFZSoQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_2__map_recipient=age1slx6e48k7fre0ddyu7dtm2wwcqaywn5ke2mkngym3rpazxwvvuyq9qjknk
-sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2T1gvVzZKQkx0NkJmek9i\nUmtWUXN6bGt0WVM4V0NIN0pZdzMxNXpUZGtjCk4zRVNRMzlraFNyQjU4Qkl5WkpQ\nbDcxQ3c4cXFtYnBFd3hmM2owNVZaVjgKLS0tIHpVbGlLbDFzZFhHVGlFRU12c2tC\nYktGSm9JRVlCUmxFOURHeENVU1UzMDAKbUeckn/3XgXyPFn/W4Ha0ayo2v5wVMQb\nNrsjhYQFn9cdG8H8hqeGh/yE1KLfIwzI8U/HSXlYs/NtsvH3h5qUPQ==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlOHJNWVRDb1FqMTh0ZU1W\nN1pkRDhBZTJpTE5kazRBU0RMMW14aEgvTGljCjZVUllGN1VXUit6d0t4Nm1jRU9G\nMkF0ckxhVCtrb1BjeTBiUFJzWHBwaDQKLS0tIHcrVmZ4VlRGNkhYc2k1MVUzenQ2\nRjBIQzYzOGxXZmxwMGtJNnlxd1o3dzQK+QHtZU6x6U74tFWysjjRwFYGZvUjAB7I\nzRHc6qH4zJ7T5H7AyA6IJlauoY9ChQT9lRughZRgcpq5nHvPfjf25A==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_3__map_recipient=age1vfhyk6wmt993dezz5wjf6n3ynkd6xptv2dr0qdl6kmttev9lh5dsfjfs3h
-sops_age__list_4__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQWkY5YkJiTUVxQXFES1Q4\nYkY5UXp6N0YxaVZILzFkZGMvaEZ3TU1XVkVBCmV1dVhCQU4yZU10MnFhUGxVTEQ3\nNjFOeGlHdGRBQ003WHZGMHJzbk9zZU0KLS0tIFBCb0NRY3UrazRzM3g0TEw3MUhn\nTThUbzdFZkJONGNYVTF5QitLaTV6cW8KR/S0wl3+auYy9Ag0tLckJ2Xhy92e+s47\nm0lLrUGvjLYSGdA9Ox3KS2nmem+RQp0RCjTzErDlsY7X5Ai7duCJRA==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_4__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwR2xvUlFyckxYVjk0alFF\nVnRuUFg1aG5zVHNUWmc2N3VkQkxDeVhtK1hZCjdZQ2xKVzlnMjV5V0Rka1ZlSTZx\nWFlrMTM1bmVURTBKeEl3Z2pacGE4S00KLS0tIERxYUpzZEtJSkVYTlpPR0cvQ1d4\naTUreDNsWGNyNWhZSkNOcWpnd0FOYTQK69rYFQ7g/cFPUQf+4sIbKTkE6UKG5t8N\nbQwQ7C7yqBd/JGq4bUd95n6tUACvWZJZb6PjkdpDnA5Z5z04LOCI5w==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_4__map_recipient=age1jwuvzyghfer7rx3qtqa4vs0gxyff0sg6pqgmqvp5zlhnpmvrkdlsdha4kx
-sops_age__list_5__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1RWdBT2pqd0w3UHhtMzU3\nYlU2Z2ZsWUlCd3lIZkNMQmV3aElYTHBLNURVCkloRmZHRTM5T0MxVWxjQklRVDJx\ncDN3SnM3ZFBYWk9LdXFEQmQ2ZGFTd3cKLS0tIEs0SHhEQTdRdWp3MkdNa25mK1Zz\ncEU4ME9sMFVXT0NtMFNoVnZnOURmd3cKii8ocexy9c0xfxPaV5FtBWlWy9KsaIEh\nMpH3eJTuAK0ElMjFrrI2AvjuW3OYp3WQU7ZnqI6ubZvi8mW7iZH51Q==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_5__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvL1FJMTN3VDZKakhiY05U\nSjB5ZnR3d2hjNWR2MC9VZTFrbWNCbTVEdUFFCnNxWXFVYmtkNjFxWm54YXJOWnR0\nQVFhN2JGRmlFdVlEajRJdWVhZFk4RDgKLS0tIGNXc1ZYZnFQMFZTV21lQkZreHUz\naGpSTlJRdWE0aXNJV21wTG5Uakp5Mk0KnLJe5q2TO+JOaoqKBqMiDsZfZJiGQv4+\n9T1XiTPId/FbEPW7ClBTy4IsOLcxH16JPxg2h5bxHnip9+eMJhO4yQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_5__map_recipient=age1pgxk292zq30wafwg03gge7hu5dlu3h7yfldp2y8kqekfaljjky7s752uwy
-sops_lastmodified=2026-03-31T02:48:03Z
-sops_mac=ENC[AES256_GCM,data:PtfB+K2c3gueL/a8MnWPsaO5XL/+uk9vgilMCAGHRW53R0ilHzWujyuNTtjsFGbReRP+SXbU0hllj3RkxCQtwZKouci2Qn9PmAKEonhRLjdYl5owSJsgSaXTL97wUS0hAZrCeYYAlLLPNYgP3XE7DqtFx9mY41vcn0ViyK0MPx8=,iv:F09inZuqJ1oRn8IUQE1noenfjdsyMNBkqtW37Z4qogs=,tag:M4Tc4+MD3zl/YZ+VcUxP2w==,type:str]
+sops_lastmodified=2026-04-02T03:37:47Z
+sops_mac=ENC[AES256_GCM,data:Hk0oh/ZzGjkcf5vBV9s98p09rzF3r7jTj0UjpYPDYOKjN9zuSTPx36RziF339emo112xUEPCAvpudUgLYpV7VxkuKYXl0UeghYNpKw3NyBYGrE6SMWwYBJNJXHCdl4nFAZD7fbc0bD42nzq7HpEKOmqLzl6P/V0kWItk9+diiHc=,iv:onY4fMd1xxlF4IUQ73ONawi4/MAuRmN43EsDtjgEA5k=,tag:UKplSAOZre74TMLl1x7UBg==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.11.0
diff --git a/infra/.env.enc b/infra/.env.enc
index 1be76f8416..9c3a86747b 100644
--- a/infra/.env.enc
+++ b/infra/.env.enc
@@ -1,55 +1,57 @@
-AES_ENCRYPTION_KEY=ENC[AES256_GCM,data:vbymPb9pIX3Ar73KrjW62lYM/8A8fWoh7MnJA3IUAusQ6+MpOXNpL5k8eTu7ieGwiV7gY90MnQAra5upymG3Jg==,iv:xY8Lh00p9lcIT9B9LCARxQihN+GrivS7C2QlVKt1J2w=,tag:RDwybIdDYRk7Ecx/5L5vDA==,type:str]
-ALGOLIA_ID=ENC[AES256_GCM,data:T9BnAyvLkom50Q==,iv:hntMtsqHiA+1V6D26KA756wRBm1BkFl5AuopGhLhUT8=,tag:GblUMhdJJG+VrGCniCq3zQ==,type:str]
-ALGOLIA_KEY=ENC[AES256_GCM,data:72FxZOZkqzMIdbvYpO1yEZFyG0YZY7rVxJjuDPgcGD4=,iv:v5QGHSSljTYWL0/7djTGtPDP/VPGQeq0zPzDHrIfE7k=,tag:QmtvW6czoCHf0QuqZzyOug==,type:str]
-ALGOLIA_SEARCH_KEY=ENC[AES256_GCM,data:PhxMicSMXQSqsFVb1K2Z3ByLwpZROrob50lICyVokto=,iv:+BjJtiUur6YEiP3BxNi34wyPw7D5hVZoXYZVs6CtL8g=,tag:78je9z1AKBKwbJbEs7aKbQ==,type:str]
-ALTCHA_HMAC_KEY=ENC[AES256_GCM,data:T+llsxSjDyEyDPzQ5ocRshwFLTeqmG/BsQd1P/aTYxd+3IsWbKuDJzuyikAAQozpahKkJZefeN2nmdFhNJlrPPE7xXXvTn2Mm+gnMRJFb5X2H6/OGua+4Ds/wcREkKhCXJJ8PrUgwR6UNagqfvfa5id34ULX3Q4ZyIUCUnE3EtQ=,iv:/Zt+E7wtlGwiMqwIVOgNT8AH74JciranTzaaPi+5esY=,tag:E6LPkAGz+odAlMMsmRbHIg==,type:str]
-AWS_ACCESS_KEY_ID=ENC[AES256_GCM,data:lZO5lg0B0KwZZqcNsVkLYkQN+xc=,iv:gZiZvft7AAcfl1NEXbrkB0FSvb7ncYZ9BQ7TWK2IyLw=,tag:XdtmjbCznNYvh1UfJrgbdg==,type:str]
-AWS_BACKUP_ACCESS_KEY_ID=ENC[AES256_GCM,data:4VovW11aEAmALfR0GJzQTUqhPoM=,iv:alQBBxvedCD10OPIf8/J/VRriY38LCQDtHkkzHfdxvc=,tag:RK5YxQOPb0A1MVbLK3ho/g==,type:str]
-AWS_BACKUP_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:FZn5un+lcsDlePnkGlMTH6lUjncFMYjzl7aV4xyJMtCHhGHx9OOrMg==,iv:zQR6Z1HxiNJAv/sN3/A3UjRr33wbdNZtCIB6EWj0yNM=,tag:Uk7gvphLvDeXACoCzmryjQ==,type:str]
-AWS_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:YZb27G49IssZyhiQJIc596Obf2H1g96Nyh4mXr5rNhHypTUSMYCH8w==,iv:r7aMjD/RZBUjTP5q2rsNOlSt6+ncKgfDuBL4OX39Q7A=,tag:t0Q+Wb9Zq8aDiXRTFdS+SQ==,type:str]
-BACKUPS_SECRET=ENC[AES256_GCM,data:4BDHdFZ4+N1bdc2Ae/BO8gUIqcBozcAAW8btH6zbkcTViLq0FVa7jqdfK48=,iv:3f9W35UnnR8KDxTQ1nZAuhMX+9ByCIKJctjjsJ5HvDg=,tag:1xWFZOBVZnK1RQxK3BQ4zA==,type:str]
-BLOCKLIST_IP_ADDRESSES=ENC[AES256_GCM,data:hyphmo+BecobINiBmCOtn1uiM91/,iv:5Mz9NiC3siH/ne5a0oomvFdJKsXODXuP9C6gx4kyHIs=,tag:oGRKbNCP+/8S6mEzyccF6Q==,type:str]
-DATABASE_URL=ENC[AES256_GCM,data:VlGdDtXbuz4Z03la2CGzYPgaWd9jNjbnZL0Hp7nntg/wsThrxsI5gJcxjNw=,iv:1neCIDqq0sdaaP/5YGi9CDh5bppHCqMeTtMcUwbQ8kg=,tag:8oNLRkD2QccR8a2EBNntjQ==,type:str]
-DATACITE_DEPOSIT_URL=ENC[AES256_GCM,data:Ffm/UaNqtwglqDY4pJbrVSvbxoV8AS2hpL5/0NI=,iv:rnCV7miKSbOwpDlKpOr076gMhnas/MhZz+YqOSNrzls=,tag:UR3UiN3wZDv3dKyE/A8sig==,type:str]
-NEW_ACCOUNT_LINK_COMMENT_WINDOW_MINUTES=ENC[AES256_GCM,data:KiA=,iv:JyFPxlkDeW6mbwFKmIb1V1RmQ79L1NrvJwg8F+ZoDjc=,tag:X7a/MrnxM6Rx41Gj0fxaQg==,type:str]
-DOI_LOGIN_ID=ENC[AES256_GCM,data:rnyWq5KO,iv:ES5zyrlIYq+YiM76fbQkQWOkRlHCfCJfvJKFkkvbe6k=,tag:SbakzlP6bPGata6MxQPN6Q==,type:str]
-DOI_LOGIN_PASSWORD=ENC[AES256_GCM,data:LQKtRZYGCzbIYHTXou+Ajpk8VMk=,iv:GgF8FClckpq+ZzfzxQKxTz9LXXblxIie5JeBM3d9kk0=,tag:I1gRtcQevT63dUQrWeCtUg==,type:str]
-DOI_SUBMISSION_URL=ENC[AES256_GCM,data:FIeG9pi8ABy0OOS15akayMmbyVDu5yS0WHZk18Zf/QQ2In5bsC52nQ==,iv:XPADr6CQ4Wq1SOlDoGgrbVxrVM941/jtS49uNW7rQfs=,tag:amR+BxRepiiTrjPxIvpZFQ==,type:str]
-FASTLY_PURGE_TOKEN_PROD=ENC[AES256_GCM,data:tEeV4a6MslOGAHCO8O9exE2OR+FWI7/P/DEZr1JQEtI=,iv:rs2G/2JHcjYej7XubvvazBuysfGvcR3JqIT1KHYdaqo=,tag:i5vbABs45IDWLZA6stIZKw==,type:str]
-FASTLY_SERVICE_ID_PROD=ENC[AES256_GCM,data:r7i2ROh2K0SPmvjdg7S9fRLewlZmiw==,iv:tyvLY7zHaHM7g/7RJt0WP/k/iNeFIu8wCaZeGkWDFak=,tag:+S9pjgNt1xhmxujbKIEOUA==,type:str]
-FIREBASE_SERVICE_ACCOUNT_BASE64=ENC[AES256_GCM,data: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,iv:hscfsdG8NtRkfYYmGDxtiAlkbac2RTyBsKTkl2jr/m8=,tag:bcuZAcwY7JRrysMC9uFu/A==,type:str]
-JWT_SIGNING_SECRET=ENC[AES256_GCM,data:7IwVrNGrGdp2uECsH3QOtZ/OvskoO/LGCs/XHVbwMRVtPPo4ydbHxvmxbQiDzk+Q0GHv0sKMSbsd8B3ybYYzEU5jWp4qL8uQnqYqT8UaPVoPqgfXiaugUYLlWN+GVqTyfgOKQFTdyfcr4EGJ3e6njmaZ1rMF66AJyhJPAKHSqi7bgNWqOECjNISV1SZL9vVgo7L3xuwu9t2tUqTE95y5wWlz7XQvOjDCBJB0nuLd3ztfzI6qwMkzkg2nb18tHDTcPDItrA4t+rEcpC7ZeAhjE38536k3WcU60kCXeXnlzn4AP/2boGLGPfYC/qxVJ4fAXVf9WFmmjuhjGNMP4NqcsqufgpwgmxEVJpLC6ZFb0QFNjtPZK+SnLd/qJUzyJVpuIRUdCjK/V587dVBMh53V0Kuc2q88fZKA2cWQtjihJUUyyGayFoBIkgEi5aVmYX04w7szcaEFaCPDphKbV57UZstfrO8oYXAIDLVH4pGBSD97RiIvJkM7u0gItYzk/n3C/8L28g8/Fm1MVTvF+PsEnpb3F1q49fch9/y7ffyqb+i1JdlGdlDKUyVKScs9Ead8BuVe6VyDHxSEUJnNhmEAftTPyLXf/VLUlEtAxNAfsLDZ3tsb8/kZhp27elwvpCLmYZez+zCBnF6m2iCfqDWrextk+Iu4yghzt86g6Qkimqo=,iv:YcUxqeIcGA1lk45lVLThieXDtcfL71tJnmxfGUyut2k=,tag:1sxWXaALcISDV6zhXfafzA==,type:str]
-MAILCHIMP_API_KEY=ENC[AES256_GCM,data:KQhcMqowStnITI9nwlMYy4tdRb4HfyEOf429vgMCvh4DNtza,iv:ANcTeRiOVQRPWYADhSuSr4Iec0wD7LPmR2uJkfSaEV4=,tag:Ys18nnsHrPzeFmXirt4/QQ==,type:str]
-MAILGUN_API_KEY=ENC[AES256_GCM,data:qZ/mvlCYsb09CUd6oAxausNEYiWsrxvQgFyAWuqmuvnHDZHn,iv:1n4ndvLhR/ZsZG5id4Zc8rThI87gN8NpK+zdguLJ2Pw=,tag:Q5gZsNDyMqjclOv+xWfP9A==,type:str]
-METABASE_SECRET_KEY=ENC[AES256_GCM,data:NYstQY07BV9I8vS7bNQ/Cc0MKh0IasFWGldiG+PIzLpg1sicBORDLZlJjD2/9d8v+pZl7d9f8ETjMSJDK2JTQg==,iv:V665xBdAyDoJISCKCGlr3fHz0ukkGPeIFciu4l0/ykI=,tag:10lk2XHC502P2zmOhIMzqw==,type:str]
-NODE_ENV=ENC[AES256_GCM,data:d8aLeE89dNwCcw==,iv:O0Hiqq/LRysBJpT5a598UJq4VW37OHf4OBcB7vYWga8=,tag:nlRerWMVGSrBO6ir8SxD5w==,type:str]
-PUBPUB_PRODUCTION=ENC[AES256_GCM,data:+YMqvw==,iv:8BX5vv/f5+joMxH5IbRmps+jy1a/PGlWhdocif+LACU=,tag:jPQwqLcBtVrzxgtuX7KZFQ==,type:str]
-#ENC[AES256_GCM,data:a1UATWoyeGcPNbqZDI/5t4ZeGHJ4lQGxIw==,iv:gfIL58YSIUuJ2Dd35HWTKqdKHDWlHFxb22etNoqbXzE=,tag:eQeJq8FzglAtgcxTw6GJHw==,type:comment]
-#ENC[AES256_GCM,data:2xM1MTnAs4v2RlHq5XcEe1UNIIhV+JCTvdBAGDzH6EUvZEIh0w==,iv:sr9KzmZsbhzXZ2VEA6jeP9LP23JVxv+EwrQQcwtG7Wc=,tag:hB8YG7IuE/syrIylMkDq+Q==,type:comment]
-S3_BACKUP_ENDPOINT=ENC[AES256_GCM,data:vtIbmGq13DPp6xmmPnoLZ9yNa08X4mGaa+10yG8xfvXzgKc=,iv:8AG4A52LWFlJ0ENL/iusIM5I6kBBTnYQjpPZrvKWPQY=,tag:tw0Fm3VItc0SduiVfZS2OQ==,type:str]
-S3_BACKUP_ACCESS_KEY=ENC[AES256_GCM,data:2Th8rzoPAvzCYE9Wuqb8dT7x8Uk=,iv:bBspSn1lZyl9fXwni8kHBXF3HNqT4N24Q0qWCJJrfkI=,tag:aL3JNfqt3z9EtS4e7a6Kuw==,type:str]
-S3_BACKUP_SECRET_KEY=ENC[AES256_GCM,data:Kn+bvOY060HrZ5iKt8LX9FAxUTqE3lsmFQhlX0CV9HOHL1h8JN+i+A==,iv:1EBNgDsy/kAvUJqxFwTVmH3YLlVWb9yyVwhNqaIYpBM=,tag:d1+up1HVO2YbM5UhFRtn3w==,type:str]
-S3_BACKUP_BUCKET=ENC[AES256_GCM,data:Q6+2yr3yNTDohG8=,iv:HO7haOuCSn6wqL2n9PZd+wV+yGue1GtZZlu32zvIzKc=,tag:XgrLlDcIfENqw4ILP9pSbQ==,type:str]
-SENTRY_AUTH_TOKEN=ENC[AES256_GCM,data:foNoUlRH4NSmcZb8wcJQWLGFYT+M4WhBOxcuKrMO3yk3M9ffyXASYEfcQuMX0JtyUHODCjIcZBEenxAjorXLPxRRA/86BvxrmUaQW3Ytzyr1oG7MMbx7C/0eomzahMONHFLqUitEiv+IzAm28/qwEvT7C0JoVjX5Inq1MXVJBlXNtn4eIvFVwFoIZD0DjhDPhNAbb9J/pZ7QP7/kXLd7O0ekWZAuyUeor0xSkvHu3RusGhkZp5E9k2idkw==,iv:P4dLkW6qYWo3V7Z828gjA5c/2HDO6g2ACA5QDY0YsdQ=,tag:PVzxgpN9V8nrvlsT2OWVRg==,type:str]
-SENTRY_ORG=ENC[AES256_GCM,data:uD4Y,iv:xCwzDtvUsME6rkXD9ZjnWEpWlkkQeCHBTWO/KQ3d1tk=,tag:arH2UqCWDEnx63u0hYfGrA==,type:str]
-SEQUELIZE_MAX_CONNECTIONS=ENC[AES256_GCM,data:xZc=,iv:+VnTLa4E9ebKgzkL6ZXmJ77/z1Wg4IPchiLomjucoKw=,tag:FxcZKE2WP24MtmMqysZcaQ==,type:str]
-SLACK_WEBHOOK_URL=ENC[AES256_GCM,data:14eklwo2DK7XzFCl4B0zKorH2mjDJRPdLOQGlILCrrnEf9R7lNE9tAg6Jcw27UrNArwmHA4OoEUKEV2dyCVO8b3MPjsUNtm4X4lhFeQQKA==,iv:GMQNtmbaZf3fr9Lz1lhOyx3WQpEGt7HY0NhFqogT2Ys=,tag:P7Cmgkz8Fp797vDIIz3oDw==,type:str]
-STITCH_WEBHOOK_URL=ENC[AES256_GCM,data:0DTdF0yYSzaR7kjhJlKAUI69vlizcQvVNKutdsgkJXEM7j7r7+Aa//kxWzs2RC4iybgqh0cd9SYNyMGgvcP/5ilOoV01LGhMEV4BpEzbC/y71U4PVpzJCRPrUDNbnW6tHcqsMA5neXXZUK9a0iae5NHV4PST,iv:kDMMDSMSYs2f+vd+rzEhAUYWhtO0ihNIF7W7eJWh4Z4=,tag:r7B+miNzxPb2MrANLj9GSQ==,type:str]
-ZOTERO_CLIENT_KEY=ENC[AES256_GCM,data:3qkmTVWiUpP1D7vYahpLdQh1sG4=,iv:trEME/o+ZXXizoRX3zgRm7d00GGDuhIhPXWO/Ck/5WQ=,tag:WsIG8PSLsA5LIOeOZkTCfA==,type:str]
-ZOTERO_CLIENT_SECRET=ENC[AES256_GCM,data:tVHxu0XEMCKOai0fZcCiddozBKw=,iv:WALv9GYJDI5eDo4YiOZhkhGt+I6RFN7V7GpF/P3MVFk=,tag:0XG3bv9CpS72tC07qDYeyg==,type:str]
-sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1dmQrZ1ZWZ1ozdU96RWs3\nRDU3MEhPbDNXLzRJZ1pKbUl2Y1E4U2Qyd1c4CkQ4TlBCNHM5L28yRDJIZ1N2ZE5D\ndWJQQ3RXQmJjcnZhc0hxYnFhYXpua00KLS0tIEZyeTJMT243cnliVW1TWEFPTVlh\nZS9wTjUybzJ2cFh5YVdsbE1TUmE2K0kK1k8ivaJttK0pzp5UijicG/NT9BaQ8Xog\n0TQpR54x4vtLBgfEMi8vy/V6jBYtCFHoefIUfKw9psNxrYx6NhJz8A==\n-----END AGE ENCRYPTED FILE-----\n
+AES_ENCRYPTION_KEY=ENC[AES256_GCM,data:wwndqSv2MyIjmKwq9JqjxKFsUqvg/hBDbDibDDahffBYswCv87Db8XknpyqNGfsSHWbcyltDCZVIBeSuCsyyyA==,iv:Z3c+5UqWqd3/mk42iTM7zXB+7Be7FFKX0ZC9ScO6PuM=,tag:p7QSKjd7FkarIcUn4naqsw==,type:str]
+ALGOLIA_ID=ENC[AES256_GCM,data:4JzulnozFmPZLA==,iv:tfrffJmRI5MTP4vK7XFYBPY21TYzUlYvcoEfYGsmtjs=,tag:MtO3Hy0/zBN/mqRSNbLYaA==,type:str]
+ALGOLIA_KEY=ENC[AES256_GCM,data:mqwXWlYIl9KTjvG4l1kaiBe3ZBNOncdY9Y1wIgU4lck=,iv:mhYEoF6MpyqYEL6P2j6fnsbfnKIfHTdes0+erVx9DVc=,tag:cuWXTOcX2pRbYaAV0ThbUg==,type:str]
+ALGOLIA_SEARCH_KEY=ENC[AES256_GCM,data:jc8dIUKYUodnCWBoCrDHV9y1lMVtc+BspV97xU0sJMQ=,iv:NV0M+aRp7MRxtO0pOb644Ef3d7Sca3/ytEIE662nLGY=,tag:iauwsjDU60rlpxhk+laJew==,type:str]
+ALTCHA_HMAC_KEY=ENC[AES256_GCM,data:8Arh/hBVuNDElqQKYp3kXpVlEvtEgAHn/pMwFDh40yPEb0Dt7jbLas8vtDNY+V65cOe7V4kKRSzHXKilt1psz7i30WjwMs9+m7DLsZA79T6zrd//QA3Je8rmnR4wR2boLhzC3qk8a1u7QkCAW9bgLkuIjvT+QyC1IjjZlH2jjs8=,iv:p4oSMyE9nWOjMSvxJRpJhD7T171uqe0HUqgQ5y0lLY0=,tag:73UZAjsF7OfCn6QgqvyhTA==,type:str]
+AWS_ACCESS_KEY_ID=ENC[AES256_GCM,data:9m10wQNGx5pC2SlheVnqB+fePnc=,iv:1AQbyF8z4EgBXEpXukh9tkVw7PiiPlgoY3/4eo+30cg=,tag:uhZtDF2RI1q8He6g+93JZQ==,type:str]
+AWS_BACKUP_ACCESS_KEY_ID=ENC[AES256_GCM,data:fGTOKI7qvPVHyiqlvgQoyOpAAf0=,iv:mAzaf/YL+KNRVFIDHhK1qpxl7kAJTWA12F9eZACFbaM=,tag:CwEtd88OeL1+6rPKkWDg4A==,type:str]
+AWS_BACKUP_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:ug166i5Al6l8Fu+8CeN1S3S6TVsnIVZmCgP1R9OyWEB+g7lvT8sA9Q==,iv:HLpf24PeVoOIUiwpTZXA9EEqBcbgi3TGVT1iHlfYUmw=,tag:oEPPgqrTvH15F/Eh3olP0A==,type:str]
+AWS_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:E/n5h9ghjmTVF5h5hAxF+43N/y2D1z2JyzcTZqYjD7XXNglR7mKK4A==,iv:4FGDZPE8zI1gDHugHl6ybENx5G3pPuDgk8hJvIj3qfU=,tag:AdJ2Foz7YwtaFnje6x9gkQ==,type:str]
+BACKUPS_SECRET=ENC[AES256_GCM,data:EHaQxEk4tSDiXTEgPNyZUivr38e4Sgk6140YIboJrq3p+beDeD+RLenM/H8=,iv:tboegTeauTew1SKL35KqdQxIrg0Eya2p70BvzfEkpqY=,tag:aCBl0Fy2IUO5AryIDxQtJw==,type:str]
+BLOCKLIST_IP_ADDRESSES=ENC[AES256_GCM,data:1BfJtijgn55OVPAdM5F/3FYwNjfC,iv:RqIcEzrWbYKBEBhOvGm8VH9fHaVlcPdZMjdrQB19Pq8=,tag:uIb/WXMhdYvCz9styt3s5g==,type:str]
+CLOUDFLARE_ANALYTICS_API_TOKEN=ENC[AES256_GCM,data:VS8Q4NChEnWSQmuk8l4lb9yWLwyP0cUKsGANIIu6dImkacumOtWyHqenAECNla1cbECzoyU=,iv:A7IWdFAYZp6rtGZvihVnbZvP7yVtPkWNWwHbo8VtaEg=,tag:oRPSqS4u3HmMDXmFCXqY9A==,type:str]
+CLOUDFLARE_ZONE_TAG=ENC[AES256_GCM,data:fywQzuQEn9pdNIimV9GuhmfY4xLL2ELP6Ksq7MWFPck=,iv:nXIZDugREgzlNJPABnBmWIdPVp0gb0q30d0yDRtetx8=,tag:GKCKCwltl31qWMBuDuaN1g==,type:str]
+DATABASE_URL=ENC[AES256_GCM,data:9BTb4c8rWijnB4ky24X3o5+45IUUKaKOQZ8NAa3DcvpqFbimRwjkgPRaZeg=,iv:8NwXuFcTsN02rz3GnARXJQ4r3kbQZ8i6Hcp5woipi90=,tag:1xq+bqeUBZZ7rzw21nysmQ==,type:str]
+DATACITE_DEPOSIT_URL=ENC[AES256_GCM,data:ccb1p55D6HVnZMhjI/JOA3W1fQr2iCQUe4YdX9w=,iv:hc3xKVZ64ceE0X70Ma3DSQhpdTC9G74IF9at5u9zgCU=,tag:g6vci/24Hyuu4+uyvr3Kmg==,type:str]
+NEW_ACCOUNT_LINK_COMMENT_WINDOW_MINUTES=ENC[AES256_GCM,data:9Js=,iv:aqV/ihhmshyl+AitBR/3ht2lcZfAlbUN1aWv4ykqcZ0=,tag:soRsQ79JSp2dS23z+wJNIQ==,type:str]
+DOI_LOGIN_ID=ENC[AES256_GCM,data:7G7CJCl8,iv:Yx7O3m/9ogWC+MC7ELskHY0ds0nd5DhEkCDs9DoUkoo=,tag:lBsZKxlWmeKRXwXq1ZwNPA==,type:str]
+DOI_LOGIN_PASSWORD=ENC[AES256_GCM,data:d+HERBAHsB/Jgcv1Y1lLZ7SDxbw=,iv:Y/yHx6njcVHspagOVmwml1AF+wiO/xFk9hWNAGXg2gc=,tag:nvMDR6RQs7tqPK+JAJjp4A==,type:str]
+DOI_SUBMISSION_URL=ENC[AES256_GCM,data:/yBd5dBnbnT7Wwngak2wetscOFlIk3LdVJIeI5yaOGqSnmnspQ9PLg==,iv:3I22HNo6q+B42PVY7xX9WkhnwhPCkMUFi4nlQEk3EYo=,tag:PwyZbykobCdtFxsbogoo0w==,type:str]
+FASTLY_PURGE_TOKEN_PROD=ENC[AES256_GCM,data:quujm0S9LXd15BrFu3Qr2ZG0wXSPl+VV75xWJHELMUY=,iv:KqZ4/pVs3QNP/Lnuqsy0lChxHCKfB1cv6lpr3k9JbLE=,tag:oXfTC8sJfiLmdW2oJT4EOA==,type:str]
+FASTLY_SERVICE_ID_PROD=ENC[AES256_GCM,data:5mwHBBxnWSIjgFnL9tvSxhV6z5yiaw==,iv:Oxrpy+indTLVWQIAEguDRMRo3KXrIFEtWwC+5qzns9M=,tag:/16gsvBgWjd02SKEGc98ug==,type:str]
+FIREBASE_SERVICE_ACCOUNT_BASE64=ENC[AES256_GCM,data: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,iv:KhxfkNZ8u6Tb0MYevW55/6JA68DJtQuiBdFZj/0K/ek=,tag:Ef6tcnyMlRRxz1papcrbcA==,type:str]
+JWT_SIGNING_SECRET=ENC[AES256_GCM,data:CfBlcHV441Ql64es2Ryb5xD7fp2Jlk4H7TTZAGYfH8++NNxlwQx1gBqAYfe95u43hZEZJVSUGlDdFGX+uwsM7sw/mGr3OxzLscNGq+4ZdauFHZmmT2hjGa0G/uHjtXDgHgOT/HTf2/nUTJhegWYHUjSzLN7/ObbT9wfYb5iKAKraAsF1okWw+/OPFfKv8I508qCp5foEN7eFvTMLE6waMW1EVvNrX59UQJRNvlqKPHiRfel6F0GK4OEs+eE+3g6kWoBNyPHADpLufTfG3eyaN1SwwbMnHzBn/DC5H/zjGkPUwubwjAhZkcbvZpHjvDblufJfUz23jQ7CDIupjwrBqCtiK2lV2VbDYKdboQdpCKlFu+bMhYQI0CmG1Znnr9dvbiuXSHLIGj2oX7BuDZ92+AGzKXmHEgZIlKOgILFj6IS+mbYY9eyVS8AhxVj1vMsQ9NGfM1eeP6gV2hl0P9EFvRps102fc9GWWKp5Qrl03xhj9irjglNcUHywYBnI0Su3fmwXf3LqOerWo4iDFaaiRvUbY0Rx6ZXqNsSx+d3HDTHr5y2Kj2N8MW6Oo4ShoB6CygVuaoaChTH+gf+1FsiZj43R/mOkcW3jnzQLG/cRzZkIGAiDMA/rqcSHfScQoI9RMCxdtD0XGwibb8nalqYvP2TBdupRc6+HkMvIERDwgmg=,iv:n/ADcQsr2NPEsyu9HqXtW5UL1HmkT2J02X4q5QU9cdU=,tag:MepIH6qtyy1xfNb48vQXaQ==,type:str]
+MAILCHIMP_API_KEY=ENC[AES256_GCM,data:oK6a7gaUFbVOHc8oZ5Hbbbwh0pgm2B9FwYuYETLkdUrDvRGx,iv:o/BGp68U+kT+aohKavkbxD7vSRFU23BjyeTUycPQGAg=,tag:uPq8Xe9SXvt9bpTgdDVOcQ==,type:str]
+MAILGUN_API_KEY=ENC[AES256_GCM,data:Kl1xxcaV1Bxk3yR/wlXrEPuREZ9wisXC2wMUGuMa80Q/wSLu,iv:CSi+GdAJdwkxiX0xjMR4nkVecAHxWpy3DLtc/lsi8do=,tag:XOGaaYuI3orhgW2c0Vfa7A==,type:str]
+METABASE_SECRET_KEY=ENC[AES256_GCM,data:Z+bYXP/Pr+uIukXhkHRzjDo62+xxEX1rUwkJr7xhVj0bQ/oCBfUvboT+yPf2QzloTak9mFanqinJV+aO+KvXdQ==,iv:t5qBdfiR+39tNTbTOfZZWwrHZltXGoF1hv/GOoZhjhg=,tag:eT5raUeWsHyLIb8Jswn0xQ==,type:str]
+NODE_ENV=ENC[AES256_GCM,data:3G1tICQGSXh0Tw==,iv:hrDUTIj06vuIo5slHfCLbjnIGH19bQPfqSiy50zgj6s=,tag:CHuz/X8cY1P+XIriMVVK1w==,type:str]
+PUBPUB_PRODUCTION=ENC[AES256_GCM,data:7xMNvQ==,iv:t55FWrYc9cqXQWuwFNS/dxcpFeQxyyELLcIQDAhl1uw=,tag:FjKAUIck/D9TsmR+Rt5oSg==,type:str]
+#ENC[AES256_GCM,data:aQAu1OBmTBnIl5Tr7+v/rxGklFf1I2mFkQ==,iv:VMII2xT6vkeYcV4ec5CRYxmQtXZyMlVXjPR60dQenpg=,tag:FZTW69WLfSAmMsexlUzedg==,type:comment]
+#ENC[AES256_GCM,data:+oQ7KAt8wey3IXZ+MKbdzFA/lWVm4uLjDez/QHdjn39fLzPz3Q==,iv:shnQ6gjhjeTSd8W+l7xcBFg6+s4x4R3752liFFsix60=,tag:2ed0Kf4sSAUf+9Aatbb5Zg==,type:comment]
+S3_BACKUP_ENDPOINT=ENC[AES256_GCM,data:90qdmqeJ/i67Uz1m5H/Zuogmm/inKQpoVuatEhOgU1RYLjU=,iv:35YyOqCA+20LzQnVVHoeOeafY4NOA8XhFwyJ/hr+5A8=,tag:BTKfA/aLEzv+q9geSSjEFg==,type:str]
+S3_BACKUP_ACCESS_KEY=ENC[AES256_GCM,data:bXG4zuMIweU8MXtZ15iONM1YbDs=,iv:ZpHEbcFctnM8hgHlBNfioAOrnCAqDJdaadK6qbDiTps=,tag:MOZbmMIG3mIPkWL3WaFDKQ==,type:str]
+S3_BACKUP_SECRET_KEY=ENC[AES256_GCM,data:nyM9m9CKTfnFW06d5ddQmvAbTddeJakR7ahCxBa8s+Rf1WsIeJzfEg==,iv:LdLPa0kjBUmSw2o8njxdJD9+e+B0JnV2cm5+DxYm61E=,tag:bKwfaqVbY+NitmKVnCaUfg==,type:str]
+S3_BACKUP_BUCKET=ENC[AES256_GCM,data:RAjKU/MeRci7Au8=,iv:XsvfLEBlVFohMkXgdrFioVzrliD9aIMxDjSIFCZLnVo=,tag:/S+CWzhHxlS7aaURuBev9g==,type:str]
+SENTRY_AUTH_TOKEN=ENC[AES256_GCM,data:AHroshPbxk84wXNJBv7AzufUd8cAyrU+9KgI8zSDRqWaKamsYNzvX4fNTcWB+19Vjq3KhCR6I5h4IF2+GF5Z/dtGC611g+/NdFnlNQN4zreNhmvQJnWrIkYmXcvID81llWCcDvNaMrUVJIirG4nwxMz0jCH6bIFuQIhcEZdqy6oIxEW8J2XU/myyEfIk3WaivR0J16oQ8MhIKyicJUIEtzP+/oc8dxuAsI3ZUYayn7CLSgPtWbUJffPi1w==,iv:UlKd/SkdIG74swZQD/eTgMVgmGEMH+2h2IqXIy9L2UI=,tag:9DcnwXQvXcIBtRovpEMx4g==,type:str]
+SENTRY_ORG=ENC[AES256_GCM,data:+tA9,iv:RmHgSpZE2uWtWvTvz+AJB/wlcNIGy8LcMImuDxEsQMQ=,tag:bJcv29ozdpkF5Dd6trm35g==,type:str]
+SEQUELIZE_MAX_CONNECTIONS=ENC[AES256_GCM,data:Rx0=,iv:b/Ho1bVGN2KM9t4cZhB/yQ/w74mYo78nr7G9zIfeR/Q=,tag:xJRaQ+AqB4M8RA0S0EKqsg==,type:str]
+SLACK_WEBHOOK_URL=ENC[AES256_GCM,data:1AbX/MCuiCfda3ppkqd41qolQepZZ3KAgWk1TiC7fQbs2AUFg4D1F8DDssD9LcJ//nvnkje7gcoeud518YH6UvNSt+ATPGVPGQahSM6RbQ==,iv:ecAE+HXyz6To1a4kxLq54HcDzMiT6dv1VqpmhfandT8=,tag:QqEjlJ8hCPwvnBetvN+Jbg==,type:str]
+STITCH_WEBHOOK_URL=ENC[AES256_GCM,data:wT6Wo4wqeAQYS5L5HcIplFlQkFD2RMj+0PZq5jolVCsFOaPNY9DfeiRtW9hLYzshOBNRtAV2bzvppXqcmHPhZAx3oioFpypmV2IZB2YmmWqW/UwQAdg2OkcMUBfDeR/nWrcEaxuxYskevApuWaZ/YLuYInCh,iv:YC8ooLHoBLJeNYyA/qAB6kg/E0UzFCXo9CfkJ/mrtmA=,tag:yUHYcv4ZX7E622EqnOIaCg==,type:str]
+ZOTERO_CLIENT_KEY=ENC[AES256_GCM,data:c5BnrGOM/vrtSNWacJvF6ueuv74=,iv:1pD4U5qb9bTTIfDjro+Wu/W7Zfv9P0AsSGkD8JvOELU=,tag:TYMDMriv1RF+Sojanx7b3A==,type:str]
+ZOTERO_CLIENT_SECRET=ENC[AES256_GCM,data:YeT5B4h74UW78q9bvonDSwWQKUU=,iv:xBvsrk6HPKR/XBltyOgogARcX/+18nihlHeYOXcYTUE=,tag:5y26F8nCo/ZLXAFncolWOQ==,type:str]
+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNdDEyaGRqY2ltSjRNSjJz\nWjR2NGdsNDZzeGdWNEV0ckVIRE5kdTBWTFc4CnZiTno3NkdVY0t5VVNuN0o2d1pJ\nVUF6am9NalNReEtDcEF2cVlIT3d5ZWsKLS0tIDBoS3ZnUzB4dStWUXBzMFRrZHFl\nMTVkeEpFdmxRSW9Xenp2eGJ0em9jaEEK0KJEmAMNOu04+3BXpzXHxjK1w8yuPHPm\nWmuWU84VM6hflDfi0w+z4nyB6gfiBnehA61hEwvrzgUF7s+B8DNNug==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1wravpjmed26772xfjhawmnsnc4933htapg6y5xseqml0jdv8z9hqemzhcr
-sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqMGFITjNJazkzNGtwQUF2\ndURyRktTTE9VY3l4TWVlam9zc2psQzBSMUNBClpIcU81VitObWtnM2U2TVhGaHo5\nK25Cb01CQjdwSlRjVGNmdGlUY2xHa1kKLS0tIFMwOUtuVTB6WmNrTDhXd09tRGU0\nLzM1bi8wVmpnazMyLzhvOFYxVmNtUmsKSjl6gGc/oBnkd7rGz5HsXVlRtSY6PopE\nOoGXRVElkLdhBzC9LY6HbgkWSJyu+v56mIbYro7euczYX+6dzrrerw==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyNndlNnl0Q2ppYzQ4eHhQ\na3JmL2hhTWF2NTdRVjQxM2RmaXUrM3hqM3hVCmV4ZXF0T0VJMTJDVTU4TmZzdFlm\ncXdEYWtkUzNrc1IraWhlZW80N3hqcmsKLS0tIEU0MkRoRFFrWjZtaWJOb0RtWkth\nSkZpYVJYekhtVFR4RW9GN0hiK1N5bHcKUpaRALmGXcbE/dAlx/ijWgccaghfRIcy\naYtpnP5H/CRvuG095RNXit3LN/MV3JiRYKe3QUjks+mDQHrKnUQ49Q==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_1__map_recipient=age1vhftscteyrwphx0jpp0yl60xxrjs77jq05mkzv88js7ckc926vcqepp2cj
-sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2V2c3dkxMQnZwTDRrZWZI\nL3A0ck9CaEo1WGx3UE96bEZnWmVBUXJaazJRCkRLYVN4aFMwN3gvaThkUUE2dGpn\nS3ZGMjlTUW1NL1Radk4xOXIvYm42dHcKLS0tIEJxbHRIQUo3ZlU4QUR5K1RCL2RK\nNmc0bllPUmNDUkVuRFdUaGJYZU5yVmcKZKktxJzujZ/C8VogEoRE4l6RrYEUf41q\nObBXtOgawAax/R0gdCfoTkoC5yfNT27yu5ngIz0wlDpusNF4L+fMpQ==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1TW1YYkxrWm1sbTJkaUQw\nbzFwbmlsTXJBSkJvalBXam1vQkV0WnZURkV3CkxBYVVpR3BkL0RUOWN1alMzV0lM\nUWI3cmk3b2pHSE0zZjh6bWt2SDNMUVkKLS0tIFpvL05pNW11aGlMTmtLT3lIZy85\ndkJiZHlnVCtSc0hEN1lKRzhvQ0Fxdk0K6bJZXUueiyg1T8fZK3yM/knasxHmR7jn\nNLhaJsdVatDOoBqRFx7SFk4ETQy/eC1hK10K8wfqIuuqICrC/mhVcA==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_2__map_recipient=age1slx6e48k7fre0ddyu7dtm2wwcqaywn5ke2mkngym3rpazxwvvuyq9qjknk
-sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHc2RSV0trMW1qZ2dRaFlS\ndjZ6ZHliM3hVS2FKa2R2R3FiYklwQllrQTFFCjJwNk1ZZEo1UkNDMTBPQy9vcVM2\nbE1MSHg0WXZ3NGd0MmUzY0pmTWRkSlEKLS0tIGxKTThVR016enMvZi8rSjBHNC9V\nL2MwNWhBdlplYnJ2Q3lLMzNDZGJQZVEKkNanfMXN+vxtDXaUSK/w4q4/bc0NwVQw\nVyKvEmwT2IagUVqD7ey+4upLgiGdRuhkooAGfiBtJHyPVsKvCPeMgg==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKc1NaSzlFdUZYYUZXcGV5\nQVJJUmZYUkp4K3pVTkNQNEZmam9YZGJQb3hBCjRSc0NaNkVubHhuc3VvVURKdU5R\nM0xQUmdFTG9TWFdoYm5NWXhJQzlBaUEKLS0tIFpwcVNVN1dWTHNRSWJVaVUyV0pT\nend6T084WkJ1NG5ldmZ1dXF4akI4MGsKQVC/chR6Spkp4z2RIvERs3OgOF7vam2J\nm3wAsUo23LNhtD2AlohPLmrLMNnMl4rhkkVEJUazJwa4vO7vSpATyg==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_3__map_recipient=age1vfhyk6wmt993dezz5wjf6n3ynkd6xptv2dr0qdl6kmttev9lh5dsfjfs3h
-sops_age__list_4__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1N0JjWkt1cGxwbzhPVUVk\nVE9MS1R3MHRIL1VLRHlGNGxpSUdGZWNVc21NCnhMamUyd0RwYWw1SHhQQXBzbzh1\nRVlvMXpaUTNId1BwYU1LZFVONExhNzQKLS0tIEZpZ3dhVHJtRHBidU1OZ1NyZFUw\nT04reTVzR0tuK3QxZ1ZzdTJqUThCTzQK3vTB9CQLDcOJShwvYOkmOcLQfJ9QCkZF\n9SNn1wPd1MNGSfxdSOYWl9t1o0z3gz65YSL71KJC8xZ90TaV3Esthw==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_4__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCbjBHemdCdUFtS2RjNHFa\nY3gvbmVXMEI0S0tkOFFya3NFOEtsbUlsR3cwCndEMWxJMlI5bFFZbFFGMnBUZ3hq\neWJYQUxoTEdmRGlUdko4TjN4aG1ZelUKLS0tIDZ0a0wyTGk1Q1d6cWJveC85Y1dt\nclVHUEhkbDNOUFBGcmJTNkpQQ0RFNXMKXaJaLRGZ5Iof5UcRpal/4mgk7JU3xvZ6\nUz3fK/5c9nPT3Q4m90QBpF2yC/dglKkUoyxSJo2tYEByWhVOw4382g==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_4__map_recipient=age1jwuvzyghfer7rx3qtqa4vs0gxyff0sg6pqgmqvp5zlhnpmvrkdlsdha4kx
-sops_age__list_5__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyeXlpa0xmWkMzSGVNQ2V1\nOXMwWi9ibitBeXk1b0lsdUVYVlZieEVZS25nCkVUcHdkTlpuUjdkTTlwV3BmOW5i\nbEQ0cEY4TEJubGV1YjlnQjdjckRKbjgKLS0tIHRHa252aXVxT3Bwd1JaWW5Ld0xr\nTW84ZHlWNXF0K2dDMEJ2NmxWWndYckUKEsCbco1+C6mhFUxFj9zGQuo1Xs5U2HMb\nFq/OLyclKqJryJbkNRPQTfD0J/vzLKk1TLjiyn6fE74vvHVp0qUOCQ==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_5__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDYUtwNEowcE1yT1pwaWl2\nOHlSdmhNSWkxOUVuWU9ydGI1RlBOc21zcmxNCllSR3pDNzk2VXlRZ2JQSDE0Y0VD\nU2hTUlRwMGp0M2dLVjJxM1RQYWFYSUUKLS0tIFFab1pxUVlXL0RwVUI0U3phTVRW\nQXFtaDVXckdocXN6Q1VzWkxEUHNINlEKMJ8AA0gdiKV8XNytk7eof0W49iUlzr2g\n1et7FiDDzpQdPBD3IB9PkbwmVjBJADm2LkQ0x1DWuInNU+nDpsowZQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_5__map_recipient=age1pgxk292zq30wafwg03gge7hu5dlu3h7yfldp2y8kqekfaljjky7s752uwy
-sops_lastmodified=2026-04-01T03:03:08Z
-sops_mac=ENC[AES256_GCM,data:hQlfCmb8jk2U5+U1cRI0W662mzTMEfaHXhmX2nHLnTSn/n3I3rVnl/tl16XikJjrO6LQpoELhs0Espu+1PYF7VRknDI0vmoP4XYciV/W2LiXZ8Q9au7NSfNrOmkvNEGdXgOedzxO5cCl96ARmmXsz1Yi5SzWWaxDW3mFb6RPSm4=,iv:TLr9e4RhdNm6Yc/YKPXBxQRzb9Q1RqYeW+0dQodcKDo=,tag:Z2TIN79C44dWJWmgzfdd8g==,type:str]
+sops_lastmodified=2026-04-02T03:37:53Z
+sops_mac=ENC[AES256_GCM,data:Ip76fcVfHTtyP3DS9DGF2L9tSBWhrZ/8HzvzRPfXP4sOfdoq9tUNiJButvgKxhjtleUSaNv23LWD3EsTSyTLGbNx0eluFqSbvSIlhyPG5rUGXSGQuE7fQnKgqqJH4f5Vfs2iXuHY98uK6mfqICS2f++EeVqulQPnDMObTDnVVSg=,iv:Nl2L6K+UPMrBFX5hQagazdKIgj31uPgUCyHUs/pXzko=,tag:jr+t2DlSrCbHWdl0sKLdDg==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.11.0
diff --git a/server/analyticsDailyCache/model.ts b/server/analyticsDailyCache/model.ts
new file mode 100644
index 0000000000..c7b5cfcd3f
--- /dev/null
+++ b/server/analyticsDailyCache/model.ts
@@ -0,0 +1,52 @@
+import type { CreationOptional, InferAttributes, InferCreationAttributes } from 'sequelize';
+
+import { AllowNull, Column, DataType, Model, PrimaryKey, Table } from 'sequelize-typescript';
+
+/**
+ * Caches per-day Cloudflare analytics for a community hostname + scope.
+ *
+ * Composite primary key: (hostname, date, scope).
+ * scope = 'community' for community-wide data,
+ * 'pub:' for per-pub data,
+ * etc.
+ * Past days are cached permanently (expiresAt = null).
+ * Today's partial data is cached with a short TTL (expiresAt = now + 1h).
+ */
+@Table({ tableName: 'AnalyticsDailyCaches', timestamps: false })
+export class AnalyticsDailyCache extends Model<
+ InferAttributes,
+ InferCreationAttributes
+> {
+ /** Community hostname, e.g. "demo.pubpub.org" or "journal.example.com" */
+ @PrimaryKey
+ @AllowNull(false)
+ @Column(DataType.TEXT)
+ declare hostname: string;
+
+ /** Calendar date (ISO format, e.g. "2026-04-01") */
+ @PrimaryKey
+ @AllowNull(false)
+ @Column(DataType.DATEONLY)
+ declare date: string;
+
+ /** Scope identifier: 'community', 'pub:my-slug', etc. */
+ @PrimaryKey
+ @AllowNull(false)
+ @Column({ type: DataType.TEXT, defaultValue: 'community' })
+ declare scope: CreationOptional;
+
+ /**
+ * Pre-aggregated analytics payload for this day.
+ * Shape: { visits, pageViews, topPaths[], countries[], devices[], referrers[] }
+ */
+ @AllowNull(false)
+ @Column(DataType.JSONB)
+ declare data: object;
+
+ /**
+ * When this cache entry expires. NULL = permanent (completed past days).
+ * For today's partial data, set to ~1 hour from write time.
+ */
+ @Column(DataType.DATE)
+ declare expiresAt: CreationOptional;
+}
diff --git a/server/apiRoutes.ts b/server/apiRoutes.ts
index 772b4cec09..b6ab10446e 100644
--- a/server/apiRoutes.ts
+++ b/server/apiRoutes.ts
@@ -13,6 +13,7 @@ import { router as devApiRouter } from './dev/api';
import { router as discussionRouter } from './discussion/api';
import { router as doiRouter } from './doi/api';
import { router as editorRouter } from './editor/api';
+import { router as impact2Router } from './impact2/api';
import { router as integrationDataOAuth1Router } from './integrationDataOAuth1/api';
import { router as landingPageFeatureRouter } from './landingPageFeature/api';
import { router as layoutRouter } from './layout/api';
@@ -72,6 +73,7 @@ const apiRouter = Router()
.use(userNotificationPreferencesRouter)
.use(userSubscriptionRouter)
.use(zoteroIntegrationRouter)
+ .use(impact2Router)
.use(apiDocsRouter);
if (!isProd() && process.env.NODE_ENV !== 'test') {
diff --git a/server/impact2/api.ts b/server/impact2/api.ts
new file mode 100644
index 0000000000..6b6df9d10c
--- /dev/null
+++ b/server/impact2/api.ts
@@ -0,0 +1,184 @@
+import { Router } from 'express';
+
+import { Collection } from 'server/collection/model';
+import { CollectionPub } from 'server/collectionPub/model';
+import { Community } from 'server/community/model';
+import { Pub } from 'server/pub/model';
+import {
+ debugCommunityAnalytics,
+ fetchCollectionAnalytics,
+ fetchCommunityAnalytics,
+ fetchPubAnalytics,
+ testCloudflareConnection,
+} from 'server/utils/cloudflareAnalytics';
+import { ForbiddenError, handleErrors } from 'server/utils/errors';
+import { getInitialData } from 'server/utils/initData';
+import { hostIsValid } from 'server/utils/routes';
+
+export const router = Router();
+
+/**
+ * Resolve the hostname Cloudflare actually sees for a community.
+ *
+ * We query the Community model directly because getInitialData overwrites
+ * communityData.domain with the localhost proxy header in dev mode.
+ *
+ * Priority:
+ * 1. Raw `domain` column from the DB (if it's a real domain, not localhost).
+ * 2. Fallback to {subdomain}.pubpub.org.
+ */
+async function resolveCloudflareHostname(communityId: string): Promise {
+ const row = await Community.findByPk(communityId, {
+ attributes: ['subdomain', 'domain'],
+ });
+ if (!row) {
+ throw new Error(`Community not found: ${communityId}`);
+ }
+ const { domain, subdomain } = row;
+ if (domain && !domain.includes('localhost') && !domain.includes('127.0.0.1')) {
+ // Strip port if present (shouldn't be in prod, but just in case)
+ return domain.replace(/:\d+$/, '');
+ }
+ return `${subdomain}.pubpub.org`;
+}
+
+/**
+ * GET /api/impact2/test
+ *
+ * Quick diagnostic to verify Cloudflare env vars are set and working.
+ * Returns JSON with { ok, error?, zoneTag?, tokenPrefix? }.
+ */
+router.get('/api/impact2/test', async (_req, res) => {
+ const result = await testCloudflareConnection();
+ const status = result.ok ? 200 : 503;
+ return res.status(status).json(result);
+});
+
+/**
+ * GET /api/impact2/debug
+ *
+ * Shows the exact hostname being used, the filter sent to Cloudflare,
+ * raw CF responses, and which hostnames actually have data in the zone.
+ * Accepts optional ?hostname=override&startDate=...&endDate=...
+ *
+ * Only available in non-production environments.
+ */
+router.get('/api/impact2/debug', async (req, res, next) => {
+ if (process.env.NODE_ENV === 'production') {
+ return res.status(404).json({ error: 'Not available in production' });
+ }
+ try {
+ if (!hostIsValid(req, 'community')) {
+ return next();
+ }
+ const initialData = await getInitialData(req, { isDashboard: true });
+ const { canView } = initialData.scopeData.activePermissions;
+ if (!canView) {
+ throw new ForbiddenError();
+ }
+
+ const communityData = initialData.communityData;
+ const defaultHostname = await resolveCloudflareHostname(communityData.id);
+ const hostname = (req.query.hostname as string) || defaultHostname;
+
+ const now = new Date();
+ const defaultStart = new Date(now);
+ defaultStart.setDate(defaultStart.getDate() - 7);
+
+ const startDate =
+ (req.query.startDate as string) || defaultStart.toISOString().slice(0, 10);
+ const endDate = (req.query.endDate as string) || now.toISOString().slice(0, 10);
+
+ const result = await debugCommunityAnalytics(hostname, startDate, endDate);
+ return res.json({
+ communityFromDb: {
+ subdomain: communityData.subdomain,
+ domainRaw: communityData.domain,
+ resolvedHostname: defaultHostname,
+ },
+ overrideHostname: req.query.hostname || null,
+ ...result,
+ });
+ } catch (err) {
+ return handleErrors(req, res, next)(err);
+ }
+});
+
+/**
+ * GET /api/impact2
+ *
+ * Returns Cloudflare-sourced analytics for the current scope.
+ * Query params:
+ * startDate – ISO date (e.g. "2026-03-01"). Defaults to 30 days ago.
+ * endDate – ISO date (e.g. "2026-03-31"). Defaults to today.
+ * pubSlug – if set, returns pub-scoped analytics (CF path filter).
+ * collectionId – if set, returns collection-scoped analytics (merged).
+ */
+router.get('/api/impact2', async (req, res, next) => {
+ try {
+ if (!hostIsValid(req, 'community')) {
+ return next();
+ }
+ const initialData = await getInitialData(req, { isDashboard: true });
+ const { canView } = initialData.scopeData.activePermissions;
+ if (!canView) {
+ throw new ForbiddenError();
+ }
+
+ const communityData = initialData.communityData;
+ const hostname = await resolveCloudflareHostname(communityData.id);
+
+ const now = new Date();
+ const defaultStart = new Date(now);
+ defaultStart.setDate(defaultStart.getDate() - 30);
+
+ const startDate =
+ (req.query.startDate as string) || defaultStart.toISOString().slice(0, 10);
+ const endDate = (req.query.endDate as string) || now.toISOString().slice(0, 10);
+
+ const pubSlug = req.query.pubSlug as string | undefined;
+ const collectionId = req.query.collectionId as string | undefined;
+
+ let result;
+
+ if (pubSlug) {
+ // Pub scope: CF query filtered by path prefix
+ result = await fetchPubAnalytics(hostname, pubSlug, startDate, endDate);
+ } else if (collectionId) {
+ // Collection scope: community data + pub cache enrichment
+ const collection = await Collection.findByPk(collectionId, {
+ attributes: ['slug'],
+ });
+ if (!collection) {
+ return res.status(404).json({ error: 'Collection not found' });
+ }
+ const collectionPubs = await CollectionPub.findAll({
+ where: { collectionId },
+ include: [{ model: Pub, as: 'pub', attributes: ['slug'] }],
+ });
+ const pubSlugs = collectionPubs
+ .map((cp) => cp.pub?.slug)
+ .filter((s): s is string => !!s);
+
+ result = await fetchCollectionAnalytics(
+ hostname,
+ collection.slug,
+ pubSlugs,
+ startDate,
+ endDate,
+ );
+ } else {
+ // Community scope (default)
+ result = await fetchCommunityAnalytics(hostname, startDate, endDate);
+ }
+
+ if (!result) {
+ return res.status(503).json({
+ error: 'Cloudflare analytics not configured. Set CLOUDFLARE_ANALYTICS_API_TOKEN and CLOUDFLARE_ZONE_TAG environment variables.',
+ });
+ }
+ return res.json(result);
+ } catch (err) {
+ return handleErrors(req, res, next)(err);
+ }
+});
diff --git a/server/models.ts b/server/models.ts
index 925e1b1b75..f1cdafdee2 100644
--- a/server/models.ts
+++ b/server/models.ts
@@ -3,6 +3,7 @@ import passportLocalSequelize from 'passport-local-sequelize';
/* Import and create all models. */
/* Also import them to make them available to other modules */
import { ActivityItem } from './activityItem/model';
+import { AnalyticsDailyCache } from './analyticsDailyCache/model';
import { AuthToken } from './authToken/model';
import { Collection } from './collection/model';
import { CollectionAttribution } from './collectionAttribution/model';
@@ -64,6 +65,7 @@ import { ZoteroIntegration } from './zoteroIntegration/model';
sequelize.addModels([
ActivityItem,
+ AnalyticsDailyCache,
AuthToken,
Collection,
CollectionAttribution,
@@ -159,6 +161,7 @@ export const includeUserModel = (() => {
export {
ActivityItem,
+ AnalyticsDailyCache,
AuthToken,
Collection,
CollectionAttribution,
diff --git a/server/routes/dashboardImpact.tsx b/server/routes/dashboardImpact.tsx
index d082304f21..b2f99906a2 100644
--- a/server/routes/dashboardImpact.tsx
+++ b/server/routes/dashboardImpact.tsx
@@ -12,7 +12,11 @@ import { generateMetaComponents, renderToNodeStream } from 'server/utils/ssr';
export const router = Router();
router.get(
- ['/dash/impact', '/dash/collection/:collectionSlug/impact', '/dash/pub/:pubSlug/impact'],
+ [
+ '/dash/impact-v1',
+ '/dash/collection/:collectionSlug/impact-v1',
+ '/dash/pub/:pubSlug/impact-v1',
+ ],
async (req, res, next) => {
try {
if (!hostIsValid(req, 'community')) {
diff --git a/server/routes/dashboardImpact2.tsx b/server/routes/dashboardImpact2.tsx
new file mode 100644
index 0000000000..615c5e8660
--- /dev/null
+++ b/server/routes/dashboardImpact2.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+
+import { Router } from 'express';
+
+import Html from 'server/Html';
+import { handleErrors, NotFoundError } from 'server/utils/errors';
+import { getInitialData } from 'server/utils/initData';
+import { hostIsValid } from 'server/utils/routes';
+import { generateMetaComponents, renderToNodeStream } from 'server/utils/ssr';
+
+export const router = Router();
+
+router.get(
+ ['/dash/impact', '/dash/collection/:collectionSlug/impact', '/dash/pub/:pubSlug/impact'],
+ async (req, res, next) => {
+ try {
+ if (!hostIsValid(req, 'community')) {
+ return next();
+ }
+ const initialData = await getInitialData(req, { isDashboard: true });
+ if (!initialData.scopeData.elements.activeTarget) {
+ throw new NotFoundError();
+ }
+ return renderToNodeStream(
+ res,
+ ,
+ );
+ } catch (err) {
+ return handleErrors(req, res, next)(err);
+ }
+ },
+);
diff --git a/server/routes/index.ts b/server/routes/index.ts
index b5b2f9afd5..3357c47d45 100644
--- a/server/routes/index.ts
+++ b/server/routes/index.ts
@@ -12,6 +12,7 @@ import { router as dashboardDiscussionsRouter } from './dashboardDiscussions';
import { router as dashboardEdgesRouter } from './dashboardEdges';
import { router as dashboardFacetsRouter } from './dashboardFacets';
import { router as dashboardImpactRouter } from './dashboardImpact';
+import { router as dashboardImpact2Router } from './dashboardImpact2';
import { router as dashboardMembersRouter } from './dashboardMembers';
import { router as dashboardPageRouter } from './dashboardPage';
import { router as dashboardPagesRouter } from './dashboardPages';
@@ -64,6 +65,7 @@ rootRouter
.use(dashboardEdgesRouter)
.use(dashboardFacetsRouter)
.use(dashboardImpactRouter)
+ .use(dashboardImpact2Router)
.use(dashboardMembersRouter)
.use(dashboardCommunityOverviewRouter)
.use(dashboardCollectionOverviewRouter)
diff --git a/server/utils/cloudflareAnalytics.ts b/server/utils/cloudflareAnalytics.ts
new file mode 100644
index 0000000000..9a3b5c0355
--- /dev/null
+++ b/server/utils/cloudflareAnalytics.ts
@@ -0,0 +1,1350 @@
+/**
+ * Cloudflare GraphQL Analytics API client.
+ *
+ * Uses the httpRequestsAdaptiveGroups dataset, filtered by clientRequestHTTPHost,
+ * to get per-community (per-domain) analytics sourced from Cloudflare's edge.
+ *
+ * Required env vars:
+ * CLOUDFLARE_ANALYTICS_API_TOKEN – a Cloudflare API token with Analytics:Read
+ * CLOUDFLARE_ZONE_TAG – the zone ID that fronts PubPub traffic
+ */
+
+const CF_GRAPHQL_ENDPOINT = 'https://api.cloudflare.com/client/v4/graphql';
+
+function getConfig() {
+ const apiToken = process.env.CLOUDFLARE_ANALYTICS_API_TOKEN;
+ const zoneTag = process.env.CLOUDFLARE_ZONE_TAG;
+ if (!apiToken || !zoneTag) {
+ const missing = [
+ !apiToken && 'CLOUDFLARE_ANALYTICS_API_TOKEN',
+ !zoneTag && 'CLOUDFLARE_ZONE_TAG',
+ ].filter(Boolean);
+ console.warn(
+ `[Impact2] Cloudflare analytics disabled — missing env var(s): ${missing.join(', ')}. ` +
+ 'Set these to enable the Impact dashboard.',
+ );
+ return null;
+ }
+ return { apiToken, zoneTag };
+}
+
+export { getConfig as getCloudflareConfig };
+
+/**
+ * Run a minimal introspection query to verify the API token + zone tag work.
+ * Returns { ok: true } or { ok: false, error: string }.
+ */
+export async function testCloudflareConnection(): Promise<{
+ ok: boolean;
+ error?: string;
+ zoneTag?: string;
+ tokenPrefix?: string;
+}> {
+ const config = getConfig();
+ if (!config) {
+ return {
+ ok: false,
+ error: 'Missing env vars. Set CLOUDFLARE_ANALYTICS_API_TOKEN and CLOUDFLARE_ZONE_TAG.',
+ };
+ }
+ const { apiToken, zoneTag } = config;
+ try {
+ const yesterday = new Date();
+ yesterday.setDate(yesterday.getDate() - 1);
+ const dateStr = yesterday.toISOString().slice(0, 10);
+ const result = await cfGraphQL(
+ `query Test($zoneTag: string, $date: Date!) {
+ viewer {
+ zones(filter: { zoneTag: $zoneTag }) {
+ httpRequests1dGroups(limit: 1, filter: { date_gt: $date }) {
+ dimensions { date }
+ }
+ }
+ }
+ }`,
+ { zoneTag, date: dateStr },
+ apiToken,
+ );
+ const zones = result?.data?.viewer?.zones;
+ if (!zones || zones.length === 0) {
+ return {
+ ok: false,
+ error: `No zone found for zoneTag "${zoneTag}". Check CLOUDFLARE_ZONE_TAG.`,
+ zoneTag,
+ tokenPrefix: apiToken.slice(0, 6) + '…',
+ };
+ }
+ return { ok: true, zoneTag, tokenPrefix: apiToken.slice(0, 6) + '…' };
+ } catch (err: any) {
+ return {
+ ok: false,
+ error: err.message ?? String(err),
+ zoneTag,
+ tokenPrefix: apiToken.slice(0, 6) + '…',
+ };
+ }
+}
+
+async function cfGraphQL(query: string, variables: Record, apiToken: string) {
+ const res = await fetch(CF_GRAPHQL_ENDPOINT, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${apiToken}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ query, variables }),
+ });
+ const body = await res.json();
+ if (!res.ok) {
+ const detail = JSON.stringify(body?.errors ?? body);
+ throw new Error(
+ `Cloudflare GraphQL request failed: ${res.status} ${res.statusText} – ${detail}`,
+ );
+ }
+ if (body.errors?.length) {
+ throw new Error(`Cloudflare GraphQL errors: ${JSON.stringify(body.errors)}`);
+ }
+ return body;
+}
+
+// ---------------------------------------------------------------------------
+// Public types
+// ---------------------------------------------------------------------------
+
+export type DailyAnalytics = {
+ date: string;
+ visits: number;
+ pageViews: number;
+};
+
+export type TopPath = {
+ path: string;
+ count: number;
+};
+
+export type CountryBreakdown = {
+ country: string;
+ count: number;
+};
+
+export type DeviceBreakdown = {
+ device: string;
+ count: number;
+};
+
+export type ReferrerBreakdown = {
+ referrer: string;
+ count: number;
+};
+
+export type CloudflareAnalyticsResult = {
+ daily: DailyAnalytics[];
+ topPaths: TopPath[];
+ countries: CountryBreakdown[];
+ devices: DeviceBreakdown[];
+ referrers: ReferrerBreakdown[];
+ totals: {
+ visits: number;
+ pageViews: number;
+ };
+ /** Pre-adjustment totals (before noise/bot filtering). */
+ rawTotals: {
+ visits: number;
+ pageViews: number;
+ };
+ /** True when CF returned an error (e.g. rate limit) and we fell back to cache. */
+ stale?: boolean;
+};
+
+// ---------------------------------------------------------------------------
+// Noise path filter — strip bot probes / infrastructure routes
+// ---------------------------------------------------------------------------
+
+const NOISE_PATH_PREFIXES = [
+ '/cdn-cgi/',
+ '/wp-',
+ '/.env',
+ '/.git',
+ '/xmlrpc.php',
+ '/wp-login',
+ '/wp-admin',
+ '/wp-content',
+ '/wp-includes',
+ '/api/',
+ '/dist/',
+ '/static/',
+ '/login',
+];
+const NOISE_EXACT_PATHS = new Set([
+ '/robots.txt',
+ '/favicon.ico',
+ '/sitemap.xml',
+ '/sitemap_index.xml',
+ '/.well-known/security.txt',
+]);
+
+function isNoisePath(path: string): boolean {
+ if (NOISE_EXACT_PATHS.has(path)) return true;
+ if (path.endsWith('.xml')) return true;
+ return NOISE_PATH_PREFIXES.some((prefix) => path.startsWith(prefix));
+}
+
+// ---------------------------------------------------------------------------
+// Postgres-backed daily cache
+// ---------------------------------------------------------------------------
+//
+// Each row stores a full day's pre-aggregated analytics JSON for one hostname.
+// Uses the AnalyticsDailyCache Sequelize model (shared Postgres → works across swarm).
+//
+// Past days: expiresAt = NULL → permanent cache.
+// Today: expiresAt = now + 3h → cached, but refreshed periodically.
+//
+// Effect:
+// • First load for a community: 1 CF API call, all days stored.
+// • Repeat load within 3h: 0 CF calls, pure Postgres.
+// • After 3h: 1 CF call for just today (past days still cached permanently).
+
+import { Op } from 'sequelize';
+
+import { AnalyticsDailyCache } from 'server/analyticsDailyCache/model';
+
+/** 1 hour in milliseconds. */
+const TODAY_CACHE_TTL_MS = 1 * 60 * 60 * 1000;
+
+/**
+ * Delete cache rows older than 45 days.
+ * We only display up to 30 days, so 45 gives a comfortable buffer.
+ * Throttled to run at most once per hour — the Date.now() check is ~free,
+ * so we skip the DB round-trip on 99.9% of calls. Triggered from the
+ * analytics fetch path (not a background job).
+ */
+const CACHE_MAX_AGE_DAYS = 45;
+const CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
+let lastCleanup = 0;
+
+function pruneOldCacheRows(): Promise {
+ const now = Date.now();
+ if (now - lastCleanup < CLEANUP_INTERVAL_MS) return Promise.resolve();
+ lastCleanup = now;
+ const cutoff = new Date();
+ cutoff.setDate(cutoff.getDate() - CACHE_MAX_AGE_DAYS);
+ return AnalyticsDailyCache.destroy({
+ where: { date: { [Op.lt]: cutoff.toISOString().slice(0, 10) } },
+ })
+ .then(() => undefined)
+ .catch((err) => {
+ console.error('Analytics cache cleanup failed:', err);
+ });
+}
+
+/** What we store per cached day. */
+type DayCachePayload = {
+ visits: number;
+ pageViews: number;
+ topPaths: Array<{ path: string; count: number }>;
+ countries: Array<{ country: string; count: number }>;
+ devices: Array<{ device: string; count: number }>;
+ referrers: Array<{ referrer: string; count: number }>;
+};
+
+async function getCachedDays(
+ hostname: string,
+ dates: string[],
+ scope = 'community',
+): Promise