Skip to content

Refactor DEA detail page to server component and add public API v1#125

Merged
vgpastor merged 16 commits intomainfrom
claude/improve-seo-sharing-Ny3QZ
Mar 15, 2026
Merged

Refactor DEA detail page to server component and add public API v1#125
vgpastor merged 16 commits intomainfrom
claude/improve-seo-sharing-Ny3QZ

Conversation

@vgpastor
Copy link
Copy Markdown
Contributor

Summary

This PR introduces significant architectural improvements and new public API endpoints to DeaMap. The main changes include converting the DEA detail page to a server component for better SEO and performance, implementing a comprehensive public REST API v1, and adding new public-facing pages for city-based AED browsing.

Key Changes

Architecture & Performance

  • Server-side rendering: Converted src/app/dea/[id]/page.tsx from a client component to a server component that fetches data server-side and generates proper metadata for SEO
  • Client component extraction: Moved all interactive UI logic to new DeaDetailClient.tsx component
  • Publication filtering: Implemented filterAedByPublicationMode() utility to respect publication settings on both server and client

Public API v1 (New)

  • Nearby AEDs endpoint (GET /api/v1/aeds/nearby): Find nearest defibrillators using PostGIS spatial queries with configurable radius and limit
  • AED detail endpoint (GET /api/v1/aeds/{id}): Retrieve full AED information with publication mode filtering
  • City search endpoint (GET /api/v1/aeds/city/{city}): Get all AEDs in a city with pagination support
  • Statistics endpoint (GET /api/v1/aeds/stats): Global statistics including total AEDs and top cities
  • OpenAPI specification (GET /api/v1/openapi.json): Full OpenAPI 3.1 spec for API documentation
  • Rate limiting: Implemented 60 requests/minute per IP for all public API endpoints

Public Pages (New)

  • City directory (/desfibriladores): Browse all cities with AED counts
  • City detail pages (/desfibriladores/[city]): View all AEDs in a specific city, grouped by district
  • API documentation (/api/docs): Comprehensive API documentation with examples and quick start guide

SEO & Metadata

  • Enhanced root layout metadata with proper Open Graph, Twitter cards, and structured data
  • Added JSON-LD structured data component for rich snippets
  • Generated dynamic metadata for DEA detail pages and city pages
  • Created sitemap generator for all public pages and AED detail pages
  • Added robots.txt configuration
  • Added manifest and AI plugin configuration files

Internationalization (New)

  • Added i18n configuration with support for 5 languages: Spanish, English, French, German, Portuguese
  • Created translation dictionaries for all supported languages
  • Implemented getDictionary() utility for loading locale-specific content

Documentation

  • Added comprehensive LLM context files (llms.txt, llms-full.txt) for AI assistant integration
  • Documented API endpoints, data structures, and usage examples

Implementation Details

  • Publication mode filtering: AEDs are filtered based on their publication_mode field to control visibility across public endpoints
  • Spatial queries: Uses PostGIS ST_DWithin for efficient geographic distance calculations
  • Pagination: City and nearby endpoints support limit/offset pagination with sensible defaults and maximums
  • Error handling: Consistent error responses with helpful messages and documentation links
  • Middleware updates: Extended public API paths to include new v1 endpoints

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9

claude added 3 commits March 15, 2026 00:23
…N-LD

- Add comprehensive metadata to layout.tsx: Open Graph tags, Twitter Cards,
  keywords, canonical URL, and Google bot directives
- Create robots.ts to control crawler access (block /admin, /api, /import, /org)
- Create sitemap.ts with all public pages and priorities
- Add JSON-LD structured data (WebApplication schema) for rich search results
- Enhance site.webmanifest with description, start_url, scope, lang, categories

The og-image.png file must be placed in public/ separately.

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
… Search Console keywords

- Split /dea/[id] into server component (generateMetadata) + client component
  for rich sharing previews (noindex, follow for SEO)
- Create /desfibriladores page listing all cities with AED counts
- Create /desfibriladores/[city] pages with per-city AED listings,
  grouped by district, with SEO-optimized content
- Add metadata layout for /dea/new-simple
- Update keywords based on Search Console data (mapa dea, desfibriladores
  cerca de mi, dea near me, AED locator, etc.)
- Set up i18n foundation: config, dictionary loader, and translation
  files for ES, EN, FR, DE, PT
- Add hreflang alternate links in root layout metadata
- Make sitemap.ts dynamic: fetches city pages from database
- Remove Google verification env var (already verified via DNS)

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
…in manifest

Public API endpoints (rate limited 60 req/min, no auth required):
- GET /api/v1/aeds/nearby - Find nearest AEDs by coordinates (PostGIS)
- GET /api/v1/aeds/:id - Get AED details by ID
- GET /api/v1/aeds/city/:city - List AEDs by city (paginated)
- GET /api/v1/aeds/stats - Global statistics (totals, top cities)
- GET /api/v1/openapi.json - OpenAPI 3.1 specification

Supporting files for LLM/AI discoverability:
- /llms.txt - Summary for LLM consumption
- /llms-full.txt - Full API context with examples
- /.well-known/ai-plugin.json - AI plugin manifest (ChatGPT/etc.)
- /api/docs - Human-readable API documentation page

Infrastructure:
- Rate limiter for public API (60/min per IP) in rate-limit-public-api.ts
- Middleware updated to allow /api/v1/ as public path
- robots.txt updated to allow /api/docs and /api/v1/openapi.json
- Sitemap updated to include /api/docs page
- All responses include CORS headers and cache control

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Mar 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dea-map Ready Ready Preview Mar 15, 2026 1:59am

Request Review

Structured issue for creating iframe-embeddable maps for third parties:
installers, maintenance companies, municipalities, and organizations.

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
…tions)

Raw SQL queries were using Prisma model names ("Aed", "AedLocation") instead
of the actual PostgreSQL table names (aeds, aed_locations) mapped via @@Map().
This caused P2010 errors during build: 'relation "Aed" does not exist'.

Also removes the .github/ISSUES file that was committed by mistake.

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
- Add FAQPage JSON-LD to homepage with 5 Q&As (DeaMap, how it works,
  why AEDs matter, how to add one, public API) for Google rich snippets
- Add BreadcrumbList JSON-LD to city pages (DeaMap > Desfibriladores > City)
- Add internal links in footer: "Desfibriladores por ciudad" and "API pública"
- Improve 404 page with useful links: map, city search, add AED
- Update copyright year to 2024-2026

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
- Extract footer from homepage into reusable Footer component in layout
- All pages now consistently show navigation + footer
- City pages load 50 AEDs per page instead of all at once (fixes
  performance for cities like Madrid with 5000+ entries)
- Use COUNT queries for metadata instead of loading all records
- Add district overview section for large cities
- Show pagination controls with page numbers

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
…temap

- Fix pagination canonicals: page 2+ now self-referential instead of
  pointing to page 1
- Remove hreflang declarations (app is Spanish-only, was confusing
  search engines)
- Add noindex robots to auth pages (login, register, forgot/reset
  password) and 404
- Remove auth and legal pages from sitemap
- Add paginated city URLs to sitemap with proper priorities
- Add Place + GeoCoordinates JSON-LD structured data to individual
  DEA pages for better sharing and AI understanding

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
- Pre-render top 100 cities by AED count at build time
- dynamicParams=true allows unlisted cities on-demand
- Revalidate every hour (ISR) so pages stay fresh
- Also add revalidate to /desfibriladores index page

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
- Rename route folder from desfibriladores/ to locations/
- Update all internal links, sitemap, breadcrumbs, and footer
- Add permanent 301 redirects in next.config.ts for old URLs
- Neutral English path works better for future internationalization

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
Wrap query in try/catch so build succeeds without a database
connection (CI). ISR will populate data on first request.

https://claude.ai/code/session_01XR9dGVxVAS4D3XutEUnhk9
@vgpastor vgpastor merged commit d013b5f into main Mar 15, 2026
9 checks passed
@vgpastor vgpastor deleted the claude/improve-seo-sharing-Ny3QZ branch March 15, 2026 02:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants