Client Portal System Overhaul: Lowercase URL Standardization and Portfolio Magazine Integration

Summary

Implemented comprehensive client portal system improvements including lowercase URL standardization across all client routes, added portfolio magazine functionality, and fixed stealth client card navigation to ensure consistent URL structure throughout the application.

Why Care

This update resolves critical inconsistencies in client portal navigation that were causing 404 errors and poor user experience. The standardization to lowercase URLs ensures reliable access to all client content, while the portfolio magazine integration provides a unified content browsing experience. These changes eliminate case-sensitivity issues that were breaking client portal functionality and establish a scalable foundation for future client content additions.

Implementation

Changes Made

Core Client Portal Routing Updates

File: site/src/pages/client/[client].astro
  • Updated getStaticPaths() to generate lowercase URL parameters while preserving actual client directory names
  • Added actualClientName prop to maintain correct file system access
  • Changed from { params: { client: entry.name } } to { params: { client: entry.name.toLowerCase() }, props: { actualClientName: entry.name } }
File: site/src/pages/client/[client]/thread/[magazine].astro
  • Added portfolio magazine support to collection map: 'portfolio': { collection: 'client-portfolios', urlPrefix: '/client/' }
  • Updated client discovery logic to include client-portfolios collection
  • Implemented case-insensitive client mapping with clientsMap to preserve original directory names for file system access
  • Modified path generation to use lowercase URLs: params: { client: lowercaseClient, magazine: magazineKey }
File: site/src/pages/client/[client]/read/[...slug].astro
  • Updated client parameter generation to use lowercase URLs
  • Added actualClientName prop for proper file system access
  • Modified both main reader and individual essay path generation
File: site/src/pages/client/[client]/portfolio/[...slug].astro
  • Updated portfolio route to generate lowercase client URLs
  • Added actualClientName prop to maintain proper file system access

Client Portal Layout Improvements

File: site/src/layouts/ClientPortalLayout.astro
  • Fixed card link generation to use lowercase URLs: card.to_path?.replace('[client]', client.toLowerCase())
  • Updated file system access to handle capitalized directory names while maintaining lowercase URLs
  • Added 4-column grid layout for client portal cards (previously 3-column)
  • Implemented responsive grid: 4 columns (desktop) → 2 columns (tablet) → 1 column (mobile)

Client Data Standardization

File: site/src/content/people/clients.json
  • Updated all client IDs to lowercase format for URL consistency:
    • "Laerdal""laerdal"
    • "Tonguc""tonguc"
    • "Param""param"
    • "Hypernova""hypernova"
    • "Avalanche""avalanche"
    • "Flourish""flourish"
    • "Colearn""colearn"
    • "Obsidian-Plugin-Community""obsidian-plugin-community"

Portal Card Configuration

File: site/src/content/messages/clientPortalCards.json
  • Updated all card paths to use dynamic [client] placeholder
  • Consolidated portfolio cards: removed separate "Portfolio Thread" card, updated main Portfolio card to direct to magazine format
  • Final card structure:
    • Reader: /client/[client]/read
    • Recommendations: /client/[client]/thread/recommendations
    • Projects: /client/[client]/thread/projects
    • Portfolio: /client/[client]/thread/portfolio

Stealth Client Card Updates

File: site/src/components/basics/messages/ClientCard--sm--stealth.astro
  • Added clientId prop to component interface
  • Implemented conditional portal linking with lowercase URL generation
  • Added proper link styling with portal-link class
File: site/src/components/basics/messages/ClientListHorizontalScroller--stealth.astro
  • Updated to pass client.id to each stealth card component
  • Enables proper navigation from stealth cards to client portals

Technical Details

URL Structure Transformation

Before:
text
/client/Laerdal (404 - case mismatch)
/client/Hypernova/thread/portfolio (404 - case mismatch)
After:
text
/client/laerdal (✓ works)
/client/hypernova/thread/portfolio (✓ works)

File System Access Pattern

The system now maintains a dual approach:
  • URLs: Always lowercase for consistency (/client/laerdal)
  • File System: Uses actual directory names for content access (content/client-content/Laerdal/)
Implementation Pattern:
javascript
// Generate lowercase URL
params: { client: originalClient.toLowerCase() }

// Preserve actual directory name for file access
props: { actualClientName: originalClient }

// File system access uses actual case
const clientForFiles = client.charAt(0).toUpperCase() + client.slice(1);
const ogPath = path.resolve(contentBasePath, `client-content/${clientForFiles}/opengraph.json`);

Portfolio Magazine Integration

Added portfolio support to the existing magazine system:
javascript
const collectionMap = {
  'recommendations': { collection: 'client-recommendations', urlPrefix: '/client/' },
  'projects': { collection: 'client-projects', urlPrefix: '/client/' },
  'portfolio': { collection: 'client-portfolios', urlPrefix: '/client/' }, // NEW
};
This enables portfolio content to be displayed in the same threaded magazine format as recommendations and projects.

Grid Layout Enhancement

Updated client portal cards to display in a 4-column responsive grid:
css
.icon-header-message-card-grid {
  grid-template-columns: repeat(4, 1fr); /* Was 3, now 4 */
}

@media (max-width: 1024px) {
  .icon-header-message-card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 640px) {
  .icon-header-message-card-grid {
    grid-template-columns: 1fr;
  }
}

Integration Points

Content Collections Integration

The system integrates with three main content collections:
  • client-recommendations: Strategic recommendations and insights
  • client-projects: Active projects and case studies
  • client-portfolios: Portfolio items and completed work

Dynamic Route Generation

All client routes now follow consistent patterns:
  • Main portal: /client/{lowercase-client-name}
  • Reader: /client/{lowercase-client-name}/read
  • Magazines: /client/{lowercase-client-name}/thread/{magazine-type}
  • Individual content: /client/{lowercase-client-name}/{content-type}/{slug}

Stealth Card Navigation

Stealth client cards on the main page now properly navigate to lowercase client portals, maintaining consistency across the entire user journey.

Documentation

Client Directory Structure

text
content/client-content/
├── Laerdal/           (directory: capitalized)
│   ├── opengraph.json
│   ├── tool-gallery.yaml
│   ├── reference-terms.json
│   ├── essays/
│   ├── Projects/
│   └── Recommendations/
├── Hypernova/         (directory: capitalized)
│   └── Portfolio/     (contains .md files for magazine display)
└── [other-clients]/

URL Patterns

All client URLs now follow lowercase conventions:
  • Portal: https://site.com/client/laerdal
  • Reader: https://site.com/client/laerdal/read
  • Recommendations: https://site.com/client/laerdal/thread/recommendations
  • Projects: https://site.com/client/laerdal/thread/projects
  • Portfolio: https://site.com/client/hypernova/thread/portfolio

Configuration Files

Client Data: site/src/content/people/clients.json
  • Contains lowercase IDs for URL generation
  • Maintains proper case names for display
  • Includes stealth information for homepage cards
Portal Cards: site/src/content/messages/clientPortalCards.json
  • Uses [client] placeholder for dynamic URL generation
  • Automatically replaced with lowercase client names at runtime
This implementation provides a robust, scalable client portal system with consistent URL structure and comprehensive content access across all client types.