7 Commits

Author SHA1 Message Date
davidherran bf8b2aa631 feat(map): connect Global Map cases to their full application case pages
Closes the disconnect where a case study opened from the 3D globe had no
path to its full write-up — you had to leave the globe, open the right
application, and hunt for it.

- CaseStudyModal: new "View full case study" CTA for real installations
  (not events / HQ). It deep-links via the locale-aware next-intl Link to
  /applications/{application}#case-{nodeId}, closes the modal, and fires a
  case_study_viewed GA event.
- ApplicationClient: on mount it reads a "#case-<id>" hash, auto-expands the
  matching case in the "Proven Solutions" wall, and smooth-scrolls to it.
  Each case row now carries id="case-<id>" + scroll-mt for correct offset.
- viewFullCase string added to the CaseStudyModal namespace in all 5 locales.

The GlobalNode.application field (already equal to the Application slug) is
the join key — no schema change needed.

Verified: production build compiles, TypeScript clean, 5 message files valid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 12:17:08 -05:00
davidherran 148aefc68f feat(team): public Team page + HQ CMS panel
New "Team" section — a LinkedIn-style minimal profile page for the FLUX
team, fully editable from the HQ Command Center.

Data model:
- New TeamMember model (name, role, bio, photoUrl, optional social links:
  email/linkedin/x/website, order, isActive, translationsJson).
- Additive migration 20260602120000_add_team_member (IF NOT EXISTS guards).
- Name stays as written; role + bio are translatable via the AI engine.

HQ panel (/hq-command/dashboard/team):
- Drag-to-reorder (same HTML5 pattern as the Hero panel).
- Inline auto-save for name/role/visibility; expandable editor for photo
  upload, bio, social links, and AI auto-translate to IT/VEC/ES/DE.
- Photo upload reuses /api/assets with a new flat "team" scope -> /public/team/.
- Dashboard tile added.

Public page (/[locale]/team):
- Responsive card grid (framer-motion stagger), portrait + name + role +
  bio + social icons (only the links that exist render).
- Per-member Person JSON-LD + breadcrumb for SEO.
- Localized via getLocalizedData; new TeamPage namespace in all 5 locales.
- NavBar item "Team" inserted before "Spare Parts" (translated 5 locales).
- Added to sitemap.

Infra:
- "team" scope registered in /api/assets (SCOPE_ROOTS + FLAT_SCOPES +
  buildPublicUrl) and revalidate.ts (RevalidateScope + path).
- Nginx serves /team/ from disk; docker-compose mounts public/team in both
  app and nginx (rw + ro).

Verified: production build compiles, all 5 /[locale]/team routes + the HQ
panel render; TypeScript clean; 5 message files valid JSON.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 07:17:09 -05:00
davidherran 1ee8288c7e feat(analytics): GA4 with GDPR Consent Mode v2
Google Analytics integration, off by default and GDPR-compliant for EU:

- src/lib/analytics/gtag.ts: typed event helpers + consent control. Every
  function is a safe no-op when NEXT_PUBLIC_GA_ID is unset.
- GoogleAnalytics.tsx: loads gtag.js with Consent Mode v2, all storage
  defaulting to "denied". anonymize_ip on, send_page_view off.
- ConsentBanner.tsx: on-brand cookie banner, localized to all 5 locales,
  persists choice for one year, flips analytics_storage to granted on accept.
- PageViewTracker.tsx: fires page_view on App Router client navigation
  (inside Suspense for useSearchParams).
- Key conversion events wired: ai_consultation_submitted (primary funnel
  goal) and ai_chat_opened.
- Consent strings added to messages/{en,it,vec,es,de}.json.

Build plumbing:
- NEXT_PUBLIC_GA_ID inlined at build time via Dockerfile ARG +
  docker-compose build.args (NEXT_PUBLIC_* must exist during next build,
  not just runtime).
- Nginx CSP extended to allow googletagmanager.com + google-analytics.com.
- env template documents NEXT_PUBLIC_GA_ID (empty = analytics disabled).

Verified: production build inlines the Measurement ID into the client
bundle; site builds cleanly both with and without the ID set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 06:53:04 -05:00
davidherran c45a5be99e feat(i18n): translate hardcoded article page strings to 5 locales
Deploy to VPS / deploy (push) Has been cancelled
- Add ArticlePage namespace (backToNewsHub, backToNews, mediaGallery,
  joinLinkedIn, internalRelease) to all 5 locale message files
  (en, it, es, de, vec)
- Replace 5 hardcoded English strings in news/[slug]/page.tsx with
  getTranslations() calls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-06 18:14:46 -05:00
davidherran f931ae281c i18n: preserve technical industry terms across all locales
Deploy to VPS / deploy (push) Has been cancelled
Some technical terms were being translated literally and reading awkwardly
to industrial buyers — fixed across IT, ES, VEC, DE so they match the
English source and industry convention.

PRESERVED IN ENGLISH (industry-standard, never translate)
- "Solid-State RF" — was "RF a Stato Solido" / "RF de Estado Sólido" /
  "RF a Stato Sołido" / "Solid-State-RF"
- "Microwave Systems" — was "Sistemi a Microonde" / "Sistemas de
  Microondas" / "Mikrowellensysteme" / "Sistemi Microwave"
- "Radio Frequency (RF)" — was "Radiofrequenza" / "Radiofrecuencia" /
  "Radiofrequensa" / "Hochfrequenztechnologie" (kept as the technical
  proper noun, with the RF acronym in parentheses for first reference)
- "Pulse Wave" — was "onde pulsate" / "ondas pulsadas" / "onde pulsà" /
  "Pulswellen-Technologie"

Files: messages/it.json, messages/es.json, messages/vec.json,
messages/de.json. messages/en.json unchanged. JSON syntax validated.
2026-05-04 13:14:20 -05:00
davidherran 86ef0e2d75 agregar idiomas a parts
Deploy to VPS / deploy (push) Has been cancelled
2026-04-08 12:47:26 -05:00
davidherran fc24313f15 production: docker + nginx config for rf-flux.com
Deploy to VPS / deploy (push) Has been cancelled
2026-03-20 13:46:05 -05:00