{"slug":"standards","title":"Technical Standards","description":"Coding standards and best practices for the platform","lastUpdated":"2026-03-06","category":"technical","content":"# Polymaths Code Standards\n\n> Engineering standards and best practices\n> Part of the Platphorm News Network\n\n---\n\n## Code Style\n\n### TypeScript\n\n```typescript\n// Use explicit return types\nfunction getPolymath(slug: string): Polymath | null {\n  // ...\n}\n\n// Prefer interfaces over types for objects\ninterface Polymath {\n  id: string;\n  name: string;\n  disciplines: string[];\n}\n\n// Use const assertions for literals\nconst ERAS = ['ancient', 'medieval', 'renaissance', 'modern'] as const;\ntype Era = typeof ERAS[number];\n\n// Prefer nullish coalescing over ||\nconst name = polymath.nickname ?? polymath.name;\n\n// Use optional chaining\nconst firstDiscipline = polymath.disciplines?.[0];\n```\n\n### React Components\n\n```tsx\n// Use functional components with TypeScript\ninterface PolymathCardProps {\n  polymath: Polymath;\n  variant?: 'default' | 'compact';\n  onSelect?: (id: string) => void;\n}\n\nexport function PolymathCard({ \n  polymath, \n  variant = 'default',\n  onSelect \n}: PolymathCardProps) {\n  // Hooks at the top\n  const [isExpanded, setIsExpanded] = useState(false);\n  \n  // Event handlers\n  const handleClick = useCallback(() => {\n    onSelect?.(polymath.id);\n  }, [onSelect, polymath.id]);\n  \n  // Early returns for edge cases\n  if (!polymath) return null;\n  \n  // Render\n  return (\n    <div className=\"...\" onClick={handleClick}>\n      {/* ... */}\n    </div>\n  );\n}\n```\n\n### File Organization\n\n```\ncomponents/\n├── polymath-card.tsx        # Component\n├── polymath-card.test.tsx   # Tests\n└── index.ts                 # Re-exports\n```\n\n---\n\n## Naming Conventions\n\n| Type | Convention | Example |\n|------|-----------|---------|\n| Files | kebab-case | `polymath-card.tsx` |\n| Components | PascalCase | `PolymathCard` |\n| Functions | camelCase | `getPolymathBySlug` |\n| Constants | SCREAMING_SNAKE | `MAX_RESULTS` |\n| Types/Interfaces | PascalCase | `PolymathProfile` |\n| CSS Classes | kebab-case | `polymath-card-header` |\n| API Routes | kebab-case | `/api/v1/polymaths` |\n| Environment Vars | SCREAMING_SNAKE | `NEXT_PUBLIC_API_URL` |\n\n---\n\n## API Standards\n\n### REST Conventions\n\n```\nGET    /api/v1/polymaths           # List\nGET    /api/v1/polymaths/:slug     # Get one\nPOST   /api/v1/polymaths           # Create (if applicable)\nPUT    /api/v1/polymaths/:slug     # Update (if applicable)\nDELETE /api/v1/polymaths/:slug     # Delete (if applicable)\n```\n\n### Response Format\n\n```typescript\n// Success\n{\n  \"success\": true,\n  \"data\": { ... },\n  \"meta\": {\n    \"version\": \"1.0.0\",\n    \"timestamp\": \"2026-03-06T12:00:00Z\",\n    \"requestId\": \"req_abc123\"\n  }\n}\n\n// Error\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Polymath not found\",\n    \"details\": { \"slug\": \"unknown-person\" }\n  },\n  \"meta\": { ... }\n}\n\n// List with pagination\n{\n  \"success\": true,\n  \"data\": [...],\n  \"meta\": { ... },\n  \"pagination\": {\n    \"page\": 1,\n    \"limit\": 20,\n    \"total\": 150,\n    \"hasMore\": true\n  }\n}\n```\n\n### HTTP Status Codes\n\n| Code | Usage |\n|------|-------|\n| 200 | Success |\n| 201 | Created |\n| 204 | No Content |\n| 400 | Bad Request |\n| 401 | Unauthorized |\n| 403 | Forbidden |\n| 404 | Not Found |\n| 429 | Rate Limited |\n| 500 | Server Error |\n\n---\n\n## SEO Standards\n\n### Meta Tags\n\nEvery page must include:\n\n```typescript\nexport const metadata: Metadata = {\n  title: 'Page Title | Polymaths',\n  description: 'Compelling 150-160 char description',\n  keywords: ['relevant', 'keywords'],\n  openGraph: {\n    title: 'Page Title',\n    description: 'Same or similar to meta description',\n    url: 'https://polymaths.platphormnews.com/page',\n    siteName: 'Polymaths',\n    images: [{ url: '/og-image.jpg', width: 1200, height: 630 }],\n    locale: 'en_US',\n    type: 'website',\n  },\n  twitter: {\n    card: 'summary_large_image',\n    title: 'Page Title',\n    description: 'Same description',\n    images: ['/og-image.jpg'],\n  },\n  alternates: {\n    canonical: 'https://polymaths.platphormnews.com/page',\n  },\n};\n```\n\n### JSON-LD\n\nRequired structured data per page type:\n\n| Page Type | Schema Types |\n|-----------|-------------|\n| All Pages | Organization, WebSite, BreadcrumbList |\n| Polymath Profile | Person |\n| Learning Path | Course |\n| FAQ | FAQPage |\n| Article | Article |\n\n---\n\n## Accessibility Standards\n\n### WCAG 2.1 AA Compliance\n\n```tsx\n// Images must have alt text\n<Image src=\"...\" alt=\"Leonardo da Vinci portrait\" />\n\n// Buttons must have accessible names\n<Button aria-label=\"Close menu\">\n  <X className=\"h-4 w-4\" />\n</Button>\n\n// Links must be distinguishable\n<Link href=\"...\" className=\"underline hover:no-underline\">\n  Learn more\n</Link>\n\n// Color contrast minimum 4.5:1 for text\n// Use sr-only for screen reader only content\n<span className=\"sr-only\">Opens in new tab</span>\n```\n\n### Keyboard Navigation\n\n- All interactive elements focusable\n- Logical tab order\n- Focus indicators visible\n- Escape closes modals\n- Arrow keys for menus\n\n---\n\n## Performance Standards\n\n### Core Web Vitals\n\n| Metric | Target |\n|--------|--------|\n| LCP | < 2.5s |\n| FID | < 100ms |\n| CLS | < 0.1 |\n\n### Image Optimization\n\n```tsx\n// Always use next/image\nimport Image from 'next/image';\n\n<Image\n  src=\"/polymath.jpg\"\n  alt=\"Description\"\n  width={400}\n  height={300}\n  placeholder=\"blur\"\n  blurDataURL=\"data:image/...\"\n  priority={isAboveTheFold}\n/>\n```\n\n### Code Splitting\n\n```tsx\n// Lazy load heavy components\nconst KnowledgeGraph = dynamic(\n  () => import('@/components/knowledge-graph'),\n  { loading: () => <Skeleton /> }\n);\n```\n\n---\n\n## Testing Standards\n\n### Unit Tests\n\n```typescript\ndescribe('getPolymathBySlug', () => {\n  it('returns polymath for valid slug', () => {\n    const result = getPolymathBySlug('leonardo-da-vinci');\n    expect(result).toMatchObject({\n      name: 'Leonardo da Vinci',\n      slug: 'leonardo-da-vinci',\n    });\n  });\n\n  it('returns null for invalid slug', () => {\n    const result = getPolymathBySlug('not-a-real-person');\n    expect(result).toBeNull();\n  });\n});\n```\n\n### API Tests\n\n```typescript\ndescribe('GET /api/v1/polymaths', () => {\n  it('returns paginated list', async () => {\n    const response = await fetch('/api/v1/polymaths');\n    const data = await response.json();\n    \n    expect(response.status).toBe(200);\n    expect(data.success).toBe(true);\n    expect(data.data).toBeInstanceOf(Array);\n    expect(data.pagination).toBeDefined();\n  });\n});\n```\n\n---\n\n## Git Standards\n\n### Branch Naming\n\n```\nfeature/add-polymath-search\nbugfix/fix-mobile-menu\nhotfix/security-patch\ndocs/update-readme\nchore/upgrade-dependencies\n```\n\n### Commit Messages\n\n```\ntype(scope): description\n\nfeat(api): add polymath search endpoint\nfix(ui): resolve mobile menu overflow\ndocs(readme): update installation steps\nchore(deps): upgrade next.js to 16.1\n```\n\nTypes: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`\n\n### Pull Requests\n\n- Descriptive title\n- Reference related issues\n- Include screenshots for UI changes\n- Ensure CI passes\n- Request review from maintainers\n\n---\n\n## Documentation Standards\n\n### Code Comments\n\n```typescript\n/**\n * Retrieves a polymath by their URL slug.\n * \n * @param slug - The URL-friendly identifier (e.g., \"leonardo-da-vinci\")\n * @returns The polymath object or null if not found\n * \n * @example\n * const leonardo = getPolymathBySlug('leonardo-da-vinci');\n */\nfunction getPolymathBySlug(slug: string): Polymath | null {\n  // ...\n}\n```\n\n### README Sections\n\n1. Overview\n2. Features\n3. Quick Start\n4. Installation\n5. Usage\n6. API Reference\n7. Contributing\n8. License\n\n---\n\n## Security Standards\n\n### Input Validation\n\n```typescript\nimport { z } from 'zod';\n\nconst querySchema = z.object({\n  page: z.coerce.number().min(1).default(1),\n  limit: z.coerce.number().min(1).max(100).default(20),\n  search: z.string().max(200).optional(),\n});\n\nexport async function GET(request: Request) {\n  const { searchParams } = new URL(request.url);\n  const params = querySchema.safeParse(Object.fromEntries(searchParams));\n  \n  if (!params.success) {\n    return Response.json({ error: 'Invalid parameters' }, { status: 400 });\n  }\n  // ...\n}\n```\n\n### Headers\n\n```typescript\n// next.config.js\nheaders: async () => [\n  {\n    source: '/:path*',\n    headers: [\n      { key: 'X-Frame-Options', value: 'DENY' },\n      { key: 'X-Content-Type-Options', value: 'nosniff' },\n      { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },\n    ],\n  },\n],\n```\n\n---\n\n*Document Version: 1.0.0*\n*Last Updated: March 2026*\n*Part of the Platphorm News Network*\n","url":"https://polymaths.platphormnews.com/docs/standards","apiUrl":"https://polymaths.platphormnews.com/api/v1/docs/standards","formats":{"json":"/api/v1/docs/standards","markdown":"/api/v1/docs/standards?format=markdown"}}