Working with Astro’s Content Collections feature to implement a “Resolved” technical issue logging section, where markdown files are processed into a structured portfolio with navigation, clean URLs, and date-based sorting. The implementation uses Astro’s glob-based content loading with TypeScript schema validation for frontmatter metadata.
Issue
The newly implemented Resolved section suffered from three critical problems: 1) No navigation menu entry despite the /resolved route existing, forcing users to manually type URLs; 2) Content detail pages exposed internal folder structure through URLs (e.g., /resolved/name_2025-10-26-FastMCP20/2025-10-26-1116-fastmcp20-pure-architecturev3); 3) Dev server warnings about unprocessed .astrobackup files; 4) Inconsistent date parsing between filename conventions (2025_10_27) and frontmatter dates (2025-10-27) causing potential sorting issues.
Culprit
Navigation Missing
The Nav.astro component’s textLinks array was hardcoded with only three entries (Home, Work, About), missing the new Resolved section despite the route existing in src/pages/resolved.astro.
URL Path Exposure
Astro’s Content Collections API preserves the full relative file path as the id property. Both ResolvedPreview.astro and [...slug].astro used this raw id for URL generation without path extraction:
// Before: Used full path
const url = `/resolved/${entry.id}`;
Backup File Warnings
Astro processes all files in src/pages/ unless prefixed with _. Backup files like indexraw.astrobackup lacked this prefix, triggering warnings during dev server processing.
Date Parsing Inconsistency
Some markdown filenames used underscores (2025_10_27) while frontmatter used ISO-compatible hyphens (2025-10-27), risking sorting mismatches if filename-based parsing was attempted.
Solution
Navigation Integration
Added the Resolved section to Nav.astro’s textLinks array (line 11):
const textLinks = [
{ label: 'Home', href: '/' },
{ label: 'Work', href: '/work/' },
{ label: 'About', href: '/about/' },
{ label: 'Resolved', href: '/resolved/' } // New entry
];
URL Path Extraction
Implemented filename extraction in both preview and detail components:
// ResolvedPreview.astro & [...slug].astro
const filename = entry.id.split('/').pop()?.replace('.md', '') || entry.id;
This transforms:
/resolved/name_2025-10-26-FastMCP20/2025-10-26-1116-fastmcp20-pure-architecturev3.md
→ /resolved/2025-10-26-1116-fastmcp20-pure-architecturev3
Backup File Handling
Executed bash command to prefix all .astrobackup files:
cd src/pages && for f in *.astrobackup; do mv "$f" "_$f"; done
Files renamed from indexraw.astrobackup → _indexraw.astrobackup
Date Sorting Standardization
Leveraged Astro’s content collections schema with z.coerce.date() to handle multiple formats:
// src/content/config.ts
schema: z.object({
publishDate: z.coerce.date(), // Handles 2025-11-14, 2025-11-14T21:58:29, ISO 8601
// ... other fields
})
Sorting implemented in resolved.astro:
const issues = (await getCollection('resolved')).sort(
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf()
);
Content Collection Configuration
Defined collection in src/content/config.ts:
collections: {
resolved: {
schema: ({ image }) => z.object({
title: z.string(),
description: z.string(),
publishDate: z.coerce.date(),
tags: z.array(z.string())
}),
// Exclude INDEX files and load recursively
entryFilter: (entry) => !entry.id.includes('INDEX')
}
}