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>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
-- ─────────────────────────────────────────────────────────────────────────
|
||||
-- ADDITIVE MIGRATION — adds the TeamMember table for the public team page.
|
||||
-- Nothing here modifies or drops existing data. Idempotent via IF NOT EXISTS.
|
||||
-- ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "TeamMember" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL,
|
||||
"bio" TEXT,
|
||||
"photoUrl" TEXT,
|
||||
"email" TEXT,
|
||||
"linkedinUrl" TEXT,
|
||||
"xUrl" TEXT,
|
||||
"websiteUrl" TEXT,
|
||||
"order" INTEGER NOT NULL DEFAULT 0,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"translationsJson" TEXT DEFAULT '{}',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "TeamMember_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "TeamMember_isActive_order_idx" ON "TeamMember" ("isActive", "order");
|
||||
@@ -380,4 +380,36 @@ model ClientUser {
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// 14. THE TEAM (Equipo de FLUX — página pública + CMS)
|
||||
// ------------------------------------------------------
|
||||
// Minimal LinkedIn-style profiles. Editable in the HQ Command Center with
|
||||
// drag-to-reorder (same pattern as HeroSlide). Name stays as written; role
|
||||
// and bio are translatable through the AI translation engine. Social links
|
||||
// are all optional — only the ones filled in render on the public card.
|
||||
model TeamMember {
|
||||
id String @id @default(cuid())
|
||||
name String // Proper name — never translated
|
||||
role String // Job title, e.g. "Founder & CEO" — translatable
|
||||
bio String? // Short biography (Markdown allowed) — translatable
|
||||
photoUrl String? // Portrait, served from /team/ bucket
|
||||
|
||||
// Optional social links — render only when present
|
||||
email String?
|
||||
linkedinUrl String?
|
||||
xUrl String? // X / Twitter
|
||||
websiteUrl String?
|
||||
|
||||
order Int @default(0) // Drag-to-reorder
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// 🌍 Translation engine — holds localized role + bio per locale
|
||||
translationsJson String? @default("{}")
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([isActive, order])
|
||||
}
|
||||
Reference in New Issue
Block a user