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
actualClientNameprop 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-portfolioscollection - Implemented case-insensitive client mapping with
clientsMapto 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
actualClientNameprop 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
actualClientNameprop 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
clientIdprop to component interface - Implemented conditional portal linking with lowercase URL generation
- Added proper link styling with
portal-linkclass
File:
site/src/components/basics/messages/ClientListHorizontalScroller--stealth.astro- Updated to pass
client.idto 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 insightsclient-projects: Active projects and case studiesclient-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.