From 66a2805215e997e45317ba976d08aa13dad368b9 Mon Sep 17 00:00:00 2001 From: sajeetharan Date: Wed, 19 Aug 2026 12:21:03 +0530 Subject: [PATCH 1/3] feat: containerize frontend for Azure --- .dockerignore | 12 ++++++++++++ Dockerfile | 33 +++++++++++++++++++++++++++++++++ next.config.js | 1 + 3 files changed, 46 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a92d409 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +.github +.next +.vercel +node_modules +npm-debug.log* +temp-query.js +.env* +!.env.example +docs +docs-site +tests \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7ff5d0f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM node:22-slim AS dependencies +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm install --global npm@11.14.1 \ + && npm ci + +FROM node:22-slim AS builder +WORKDIR /app +ARG NEXT_PUBLIC_API_URL +ARG NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL +ARG NEXT_PUBLIC_SITE_URL +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL +ENV NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL=$NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL +ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL +COPY --from=dependencies /app/node_modules ./node_modules +COPY . . +RUN npm run build + +FROM node:22-slim AS runner +WORKDIR /app +ENV HOSTNAME=0.0.0.0 +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=3000 +RUN groupadd --system --gid 1001 nodejs \ + && useradd --system --uid 1001 --gid nodejs nextjs +COPY --from=builder --chown=nextjs:nodejs /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +USER nextjs +EXPOSE 3000 +CMD ["node", "server.js"] \ No newline at end of file diff --git a/next.config.js b/next.config.js index 8cad33b..5a11168 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + output: 'standalone', outputFileTracingIncludes: { '/api/card': ['./node_modules/@fontsource/manrope/files/manrope-latin-*-normal.woff'], }, From d5dcc452e1cd96ba2e1bf9c8e1f06843751695ff Mon Sep 17 00:00:00 2001 From: sajeetharan Date: Wed, 19 Aug 2026 13:11:49 +0530 Subject: [PATCH 2/3] feat: migrate web hosting to Azure --- .github/workflows/deploy.yml | 78 ++++++++++++--------------- .gitignore | 1 + README.md | 25 +++++---- app/layout.jsx | 2 - app/page.jsx | 2 +- components/AddMeModal.jsx | 2 +- components/AgentSetupPage.jsx | 2 +- components/DetailPanel.jsx | 2 +- components/DeveloperActivityPage.jsx | 2 +- components/Header.jsx | 2 +- components/UserMenu.jsx | 2 +- functions/weekly-digest/function.json | 13 +++++ functions/weekly-digest/index.js | 20 +++++++ lib/analytics.js | 1 + package-lock.json | 43 --------------- package.json | 1 - vercel.json | 10 ---- 17 files changed, 87 insertions(+), 121 deletions(-) create mode 100644 functions/weekly-digest/function.json create mode 100644 functions/weekly-digest/index.js create mode 100644 lib/analytics.js delete mode 100644 vercel.json diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2db8c58..d38ac03 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,15 +1,17 @@ -name: Deploy to Vercel +name: Deploy web app to Azure on: push: branches: [main] - pull_request: - branches: [main] + workflow_dispatch: env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} - VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + AZURE_RESOURCE_GROUP: devglobe-rg + AZURE_CONTAINER_REGISTRY: devglobewebacr + AZURE_CONTAINER_APP: devglobe-web + IMAGE_NAME: devglobe-web + NEXT_PUBLIC_API_URL: https://devglobe-public-api.azurewebsites.net + NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL: https://devglobeactivityfn.z13.web.core.windows.net/developers.json NEXT_PUBLIC_SITE_URL: https://www.devglobe.dev jobs: @@ -17,48 +19,34 @@ jobs: runs-on: ubuntu-latest permissions: contents: read - pull-requests: write + id-token: write steps: - uses: actions/checkout@v5 - - name: Setup Node.js - uses: actions/setup-node@v5 + - name: Log in to Azure + uses: azure/login@v2 with: - node-version: 22 - cache: npm - - - name: Use repository npm version - run: npm install --global npm@11.14.1 - - - name: Install dependencies - run: npm ci - - - name: Install Vercel CLI - run: npm install -g vercel - - - name: Pull Vercel Environment - if: env.VERCEL_TOKEN != '' && env.VERCEL_ORG_ID != '' && env.VERCEL_PROJECT_ID != '' - run: vercel pull --yes --environment=${{ github.event_name == 'push' && 'production' || 'preview' }} --token=${{ secrets.VERCEL_TOKEN }} + client-id: ${{ vars.AZURE_CLIENT_ID }} + tenant-id: ${{ vars.AZURE_TENANT_ID }} + subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - - name: Build - if: env.VERCEL_TOKEN != '' && env.VERCEL_ORG_ID != '' && env.VERCEL_PROJECT_ID != '' - run: vercel build ${{ github.event_name == 'push' && '--prod' || '' }} --token=${{ secrets.VERCEL_TOKEN }} - - - name: Deploy - id: deploy - if: env.VERCEL_TOKEN != '' && env.VERCEL_ORG_ID != '' && env.VERCEL_PROJECT_ID != '' + - name: Build and push image run: | - URL=$(vercel deploy --prebuilt ${{ github.event_name == 'push' && '--prod' || '' }} --token=${{ secrets.VERCEL_TOKEN }}) - echo "url=$URL" >> $GITHUB_OUTPUT - - - name: Comment PR with Preview URL - if: github.event_name == 'pull_request' && env.VERCEL_TOKEN != '' && env.VERCEL_ORG_ID != '' && env.VERCEL_PROJECT_ID != '' - uses: actions/github-script@v8 - with: - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `🚀 Preview deployed: ${{ steps.deploy.outputs.url }}` - }) + az acr build \ + --registry "$AZURE_CONTAINER_REGISTRY" \ + --image "$IMAGE_NAME:${GITHUB_SHA}" \ + --build-arg NEXT_PUBLIC_API_URL="$NEXT_PUBLIC_API_URL" \ + --build-arg NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL="$NEXT_PUBLIC_DEVELOPER_SNAPSHOT_URL" \ + --build-arg NEXT_PUBLIC_SITE_URL="$NEXT_PUBLIC_SITE_URL" \ + . + + - name: Deploy image + run: | + az containerapp update \ + --resource-group "$AZURE_RESOURCE_GROUP" \ + --name "$AZURE_CONTAINER_APP" \ + --image "$AZURE_CONTAINER_REGISTRY.azurecr.io/$IMAGE_NAME:${GITHUB_SHA}" + + - name: Log out of Azure + if: always() + run: az logout diff --git a/.gitignore b/.gitignore index 9d56059..2c42d4d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ dist/ dashboards/ docs/adx-growth-dashboard.md scripts/build-devglobe-growth-dashboard.cjs +.env*.local diff --git a/README.md b/README.md index 9844ccf..7cbe404 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **The global open-source developer discovery platform — search, compare, and connect with the people behind the code** -[![Live Demo](https://img.shields.io/badge/Live-Demo-blue?style=for-the-badge&logo=vercel)](https://devglobe.dev) +[![Live Demo](https://img.shields.io/badge/Live-Demo-blue?style=for-the-badge&logo=microsoftazure)](https://devglobe.dev) [![Documentation](https://img.shields.io/badge/Documentation-GitHub%20Pages-2ea44f?style=for-the-badge&logo=github)](https://sajeetharan.github.io/devglobe/) [![VS Code](https://img.shields.io/badge/VS%20Code-Install-007ACC?style=for-the-badge&logo=visualstudiocode)](https://marketplace.visualstudio.com/items?itemName=devglobedev.devglobe-developer-discovery) [![GitHub Stars](https://img.shields.io/github/stars/sajeetharan/devglobe?style=for-the-badge&logo=github)](https://github.com/sajeetharan/devglobe/stargazers) @@ -19,7 +19,7 @@ DevGlobe is an interactive global developer network built for engineering teams, open-source communities, and the emerging ecosystem of AI agents. It combines a 3D developer map with Azure Cosmos DB vector and hybrid search to surface relevant expertise from real contribution signals rather than popularity alone. The long-term vision is a consent-aware discovery layer where AI agents can find the right human collaborators. -The dynamic application is hosted on [Vercel](https://www.devglobe.dev). Product, API, MCP, Agent Skill, and agent-readiness documentation is published separately on [GitHub Pages](https://sajeetharan.github.io/devglobe/). +The dynamic application is hosted on [Azure Container Apps](https://www.devglobe.dev). Product, API, MCP, Agent Skill, and agent-readiness documentation is published separately on [GitHub Pages](https://sajeetharan.github.io/devglobe/). > [!IMPORTANT] > **Connect an AI agent to DevGlobe:** MCP-compatible agents can use the hosted endpoint at `https://www.devglobe.dev/mcp` to search public developer profiles without credentials. Verified agents can also request developer-approved introductions. See the [MCP setup guide](docs/mcp-server.md). @@ -111,7 +111,7 @@ AZURE_OPENAI_CHAT_DEPLOYMENT=gpt-4o-mini `AZURE_OPENAI_CHAT_DEPLOYMENT` enables generated fun facts on identity cards. Cards use factual profile copy when the chat deployment is unavailable. -Production can serve high-volume public API reads and the developer snapshot directly from Azure while Vercel hosts the frontend. See [docs/azure-backend.md](docs/azure-backend.md) for the resource layout, environment switches, and deployment checks. +Production serves the Next.js application from Azure Container Apps, high-volume public API reads from Azure Functions, and the developer snapshot from Azure Blob Storage. See [docs/azure-backend.md](docs/azure-backend.md) for the resource layout, environment switches, and deployment checks. ```bash npm run dev @@ -124,7 +124,7 @@ npm run dev | Frontend | React 19, Three.js (react-globe.gl), Next.js 15 | | Search | Azure Cosmos DB (vector + hybrid search) | | API | Next.js API Routes | -| Hosting | Vercel | +| Hosting | Azure Container Apps and Azure Functions | | Data Pipeline | Node.js scripts (GitHub GraphQL, StackOverflow API, geocoding) | ## 📊 Scoring Formula (0–100) @@ -201,11 +201,9 @@ The command preserves existing tags and is idempotent. Other credentials require └── developers-sample.json # Sample data for local dev ``` -## 🌍 Deploy to Vercel +## 🌍 Deploy to Azure Container Apps -```bash -npx vercel -``` +Pushes to `main` build the standalone Next.js image in Azure Container Registry and deploy it to Azure Container Apps through GitHub Actions OIDC. The deployment identity requires Contributor access scoped to the application resource group and these repository variables: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID`. Required environment variables: @@ -233,7 +231,7 @@ npm run setup-contacts-container See the [lifecycle email PRD](docs/prd/lifecycle-email-notifications.md). -Verified users can explicitly opt in to a Monday weekly digest from the user menu. The digest includes current global and country rankings, rank movement since the previous digest, current DevGlobe features, and an Explore DevGlobe link. Vercel invokes `/api/cron/weekly-digest` at 13:00 UTC each Monday; only verified contacts with `productUpdatesEnabled: true` are eligible. Each message uses a per-user, per-week idempotency key and includes one-click unsubscribe headers and a signed unsubscribe link. +Verified users can explicitly opt in to a Monday weekly digest from the user menu. The digest includes current global and country rankings, rank movement since the previous digest, current DevGlobe features, and an Explore DevGlobe link. The Azure Functions app invokes `/api/cron/weekly-digest` at 13:00 UTC each Monday; only verified contacts with `productUpdatesEnabled: true` are eligible. Each message uses a per-user, per-week idempotency key and includes one-click unsubscribe headers and a signed unsubscribe link. Generate a manual-review activation queue and weekly social spotlight from public, unclaimed profiles: @@ -266,10 +264,10 @@ Deploy the `functions` directory to an Azure Function App and configure these ap ```env IMPACT_HISTORY_URL=https://www.devglobe.dev/api/cron/impact-history -CRON_SECRET=the-same-secret-configured-in-vercel +CRON_SECRET=the-same-secret-configured-on-the-container-app ``` -The timer resumes the current UTC day's capture in RU-bounded batches. Keep `IMPACT_HISTORY_CONCURRENCY` and `IMPACT_HISTORY_BATCH_SIZE` on the Vercel application because the Next.js endpoint performs the Cosmos work. +The timer resumes the current UTC day's capture in RU-bounded batches. Keep `IMPACT_HISTORY_CONCURRENCY` and `IMPACT_HISTORY_BATCH_SIZE` on the Container App because the Next.js endpoint performs the Cosmos work. ### Email verification reminders @@ -279,10 +277,11 @@ Configure these application settings on the Azure Function App: ```env EMAIL_VERIFICATION_REMINDERS_URL=https://www.devglobe.dev/api/cron/email-verification-reminders -CRON_SECRET=the-same-secret-configured-in-vercel +WEEKLY_DIGEST_URL=https://www.devglobe.dev/api/cron/weekly-digest +CRON_SECRET=the-same-secret-configured-on-the-container-app ``` -Deploy the complete `functions` directory so the timer and its `function.json` are included. Do not configure the same reminder schedule in Vercel, or each due batch may be invoked twice. +Deploy the complete `functions` directory so each timer and its `function.json` are included. ## 🤝 Contributing diff --git a/app/layout.jsx b/app/layout.jsx index e725179..c962f72 100644 --- a/app/layout.jsx +++ b/app/layout.jsx @@ -1,4 +1,3 @@ -import { Analytics } from '@vercel/analytics/react'; import '../styles/main.css'; import { getSiteUrl } from '../lib/site.js'; import WebMcpProvider from '../components/WebMcpProvider.jsx'; @@ -160,7 +159,6 @@ export default function RootLayout({ children }) { dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData).replace(/ {children} - ); diff --git a/app/page.jsx b/app/page.jsx index f85414a..f85ef4e 100644 --- a/app/page.jsx +++ b/app/page.jsx @@ -1,7 +1,7 @@ 'use client'; import React, { useState, useEffect, useCallback, useRef } from 'react'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import Header from '../components/Header.jsx'; import SearchBar from '../components/SearchBar.jsx'; import Leaderboard from '../components/Leaderboard.jsx'; diff --git a/components/AddMeModal.jsx b/components/AddMeModal.jsx index 0f98105..884e3c1 100644 --- a/components/AddMeModal.jsx +++ b/components/AddMeModal.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef } from 'react'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import styles from './AddMeModal.module.css'; const PENDING_CLAIM_KEY = 'devglobe-pending-claim'; diff --git a/components/AgentSetupPage.jsx b/components/AgentSetupPage.jsx index 6327ca1..e4c4950 100644 --- a/components/AgentSetupPage.jsx +++ b/components/AgentSetupPage.jsx @@ -1,7 +1,7 @@ 'use client'; import Link from 'next/link'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import { useEffect, useState } from 'react'; import styles from './AgentSetupPage.module.css'; diff --git a/components/DetailPanel.jsx b/components/DetailPanel.jsx index 660be60..5593033 100644 --- a/components/DetailPanel.jsx +++ b/components/DetailPanel.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react'; import Link from 'next/link'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import * as d3 from 'd3'; import { formatNum, formatRelativeTime, formatUsd, isStaleData } from '../lib/format.js'; import { DIMENSIONS, SCORE_METHODOLOGY } from '../lib/scoring.js'; diff --git a/components/DeveloperActivityPage.jsx b/components/DeveloperActivityPage.jsx index 15a60a7..a84819e 100644 --- a/components/DeveloperActivityPage.jsx +++ b/components/DeveloperActivityPage.jsx @@ -2,7 +2,7 @@ import Link from 'next/link'; import { useEffect, useState } from 'react'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import { formatNum, formatRelativeTime } from '../lib/format.js'; import { publicApiUrl } from '../lib/public-api.js'; import { useActivityFeed } from './useActivityFeed.js'; diff --git a/components/Header.jsx b/components/Header.jsx index 5859eb2..87f0eb1 100644 --- a/components/Header.jsx +++ b/components/Header.jsx @@ -1,7 +1,7 @@ 'use client'; import React from 'react'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; import UserMenu from './UserMenu.jsx'; const marketplaceUrl = 'https://marketplace.visualstudio.com/items?itemName=devglobedev.devglobe-developer-discovery'; diff --git a/components/UserMenu.jsx b/components/UserMenu.jsx index a0a3699..fd18155 100644 --- a/components/UserMenu.jsx +++ b/components/UserMenu.jsx @@ -1,7 +1,7 @@ 'use client'; import React, { useState, useRef, useEffect } from 'react'; -import { track } from '@vercel/analytics'; +import { track } from '../lib/analytics.js'; export default function UserMenu({ user, onLogout, onClaim, onEditAiProfile, onOpenIntroductions, claimStatus }) { const [open, setOpen] = useState(false); diff --git a/functions/weekly-digest/function.json b/functions/weekly-digest/function.json new file mode 100644 index 0000000..ad35720 --- /dev/null +++ b/functions/weekly-digest/function.json @@ -0,0 +1,13 @@ +{ + "bindings": [ + { + "name": "timer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 13 * * 1", + "runOnStartup": false, + "useMonitor": true + } + ], + "scriptFile": "index.js" +} \ No newline at end of file diff --git a/functions/weekly-digest/index.js b/functions/weekly-digest/index.js new file mode 100644 index 0000000..6cb4fff --- /dev/null +++ b/functions/weekly-digest/index.js @@ -0,0 +1,20 @@ +module.exports = async function weeklyDigest(context) { + const endpoint = process.env.WEEKLY_DIGEST_URL; + const secret = process.env.CRON_SECRET; + if (!endpoint || !secret) { + throw new Error('WEEKLY_DIGEST_URL and CRON_SECRET are required'); + } + + const response = await fetch(endpoint, { + headers: { Authorization: `Bearer ${secret}` }, + }); + const result = await response.json(); + context.log('DevGlobe weekly digest', { + status: response.status, + eligible: result.eligible, + sent: result.sent, + skipped: result.skipped, + failed: result.failed, + }); + if (!response.ok) throw new Error(`Weekly digest returned ${response.status}`); +}; \ No newline at end of file diff --git a/lib/analytics.js b/lib/analytics.js new file mode 100644 index 0000000..bd3d48b --- /dev/null +++ b/lib/analytics.js @@ -0,0 +1 @@ +export function track() {} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5220b06..cebb2f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "@azure/cosmos": "^4.10.0", "@fontsource/manrope": "^5.3.0", "@modelcontextprotocol/sdk": "^1.30.0", - "@vercel/analytics": "^2.0.1", "@vercel/og": "^0.11.1", "d3": "^7.9.0", "dotenv": "^16.4.5", @@ -3326,48 +3325,6 @@ "win32" ] }, - "node_modules/@vercel/analytics": { - "version": "2.0.1", - "resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vercel/analytics/-/analytics-2.0.1.tgz", - "integrity": "sha1-19e9N698++6pXbXxMq5IifTSZAc=", - "license": "MIT", - "peerDependencies": { - "@remix-run/react": "^2", - "@sveltejs/kit": "^1 || ^2", - "next": ">= 13", - "nuxt": ">= 3", - "react": "^18 || ^19 || ^19.0.0-rc", - "svelte": ">= 4", - "vue": "^3", - "vue-router": "^4" - }, - "peerDependenciesMeta": { - "@remix-run/react": { - "optional": true - }, - "@sveltejs/kit": { - "optional": true - }, - "next": { - "optional": true - }, - "nuxt": { - "optional": true - }, - "react": { - "optional": true - }, - "svelte": { - "optional": true - }, - "vue": { - "optional": true - }, - "vue-router": { - "optional": true - } - } - }, "node_modules/@vercel/og": { "version": "0.11.1", "resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vercel/og/-/og-0.11.1.tgz", diff --git a/package.json b/package.json index 22652b4..3cf6b15 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@azure/cosmos": "^4.10.0", "@fontsource/manrope": "^5.3.0", "@modelcontextprotocol/sdk": "^1.30.0", - "@vercel/analytics": "^2.0.1", "@vercel/og": "^0.11.1", "d3": "^7.9.0", "dotenv": "^16.4.5", diff --git a/vercel.json b/vercel.json deleted file mode 100644 index 7daf838..0000000 --- a/vercel.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://openapi.vercel.sh/vercel.json", - "framework": "nextjs", - "crons": [ - { - "path": "/api/cron/weekly-digest", - "schedule": "0 13 * * 1" - } - ] -} From 5ac8d4ef3d5a2090e87d62000ce9eb6f61c2eadb Mon Sep 17 00:00:00 2001 From: sajeetharan Date: Wed, 19 Aug 2026 13:17:23 +0530 Subject: [PATCH 3/3] fix: validate docs against Azure frontend --- .github/workflows/docs-pages.yml | 2 ++ scripts/verify-docs-endpoints.js | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index 2da3b06..639ba3f 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -52,6 +52,8 @@ jobs: - name: Verify hosted agent resources run: npm run docs:check-live + env: + LIVE_SITE_URL: https://devglobe-web.victoriousground-cbcea081.eastus.azurecontainerapps.io - name: Run application tests run: npm test diff --git a/scripts/verify-docs-endpoints.js b/scripts/verify-docs-endpoints.js index 4435dd8..933224e 100644 --- a/scripts/verify-docs-endpoints.js +++ b/scripts/verify-docs-endpoints.js @@ -1,43 +1,45 @@ +const siteUrl = (process.env.LIVE_SITE_URL || 'https://www.devglobe.dev').replace(/\/$/, ''); + const resources = [ { name: 'API catalog', - url: 'https://www.devglobe.dev/.well-known/api-catalog', + path: '/.well-known/api-catalog', contentType: 'application/linkset+json', }, { name: 'OpenAPI description', - url: 'https://www.devglobe.dev/openapi.json', + path: '/openapi.json', contentType: 'application/openapi+json', }, { name: 'MCP server card', - url: 'https://www.devglobe.dev/.well-known/mcp/server-card.json', + path: '/.well-known/mcp/server-card.json', contentType: 'application/json', }, { name: 'Agent Skills index', - url: 'https://www.devglobe.dev/.well-known/agent-skills/index.json', + path: '/.well-known/agent-skills/index.json', contentType: 'application/json', }, { name: 'DevGlobe Agent Skill', - url: 'https://www.devglobe.dev/.well-known/agent-skills/devglobe/SKILL.md', + path: '/.well-known/agent-skills/devglobe/SKILL.md', contentType: 'text/markdown', }, { name: 'Authentication guide', - url: 'https://www.devglobe.dev/auth.md', + path: '/auth.md', contentType: 'text/markdown', }, { name: 'Agent overview', - url: 'https://www.devglobe.dev/llms.txt', + path: '/llms.txt', contentType: 'text/plain', }, ]; for (const resource of resources) { - const response = await fetch(resource.url, { + const response = await fetch(`${siteUrl}${resource.path}`, { headers: { 'User-Agent': 'DevGlobe-Docs-Check/1.0' }, signal: AbortSignal.timeout(15_000), }); @@ -57,7 +59,7 @@ for (const resource of resources) { } } -const markdownHome = await fetch('https://www.devglobe.dev', { +const markdownHome = await fetch(siteUrl, { headers: { Accept: 'text/markdown', 'User-Agent': 'DevGlobe-Docs-Check/1.0',