docs: Add v1.1.0 architecture and validation documentation
- ADR-033: Database migration redesign - ADR-034: Full-text search with FTS5 - ADR-035: Custom slugs in Micropub - ADR-036: IndieAuth token verification method - ADR-039: Micropub URL construction fix - Implementation plan and decisions - Architecture specifications - Validation reports for implementation and search UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
144
docs/decisions/ADR-039-micropub-url-construction-fix.md
Normal file
144
docs/decisions/ADR-039-micropub-url-construction-fix.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# ADR-039: Micropub URL Construction Fix
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
After the v1.0.0 release, a bug was discovered in the Micropub implementation where the Location header returned after creating a post contains a double slash:
|
||||
|
||||
- **Expected**: `https://starpunk.thesatelliteoflove.com/notes/so-starpunk-v100-is-complete`
|
||||
- **Actual**: `https://starpunk.thesatelliteoflove.com//notes/so-starpunk-v100-is-complete`
|
||||
|
||||
### Root Cause Analysis
|
||||
The issue occurs due to a mismatch between how SITE_URL is stored and used:
|
||||
|
||||
1. **Configuration Storage** (`starpunk/config.py`):
|
||||
- SITE_URL is normalized to always end with a trailing slash (lines 26, 92)
|
||||
- This is required for IndieAuth/OAuth specs where root URLs must have trailing slashes
|
||||
- Example: `https://starpunk.thesatelliteoflove.com/`
|
||||
|
||||
2. **URL Construction** (`starpunk/micropub.py`):
|
||||
- Constructs URLs using: `f"{site_url}/notes/{note.slug}"` (lines 311, 381)
|
||||
- This adds a leading slash to the path segment
|
||||
- Results in: `https://starpunk.thesatelliteoflove.com/` + `/notes/...` = double slash
|
||||
|
||||
3. **Inconsistent Handling**:
|
||||
- RSS feed module (`starpunk/feed.py`) correctly strips trailing slash before use (line 77)
|
||||
- Micropub module doesn't handle this, causing the bug
|
||||
|
||||
## Decision
|
||||
Fix the URL construction in the Micropub module by removing the leading slash from the path segment. This maintains the trailing slash convention in SITE_URL while ensuring correct URL construction.
|
||||
|
||||
### Implementation Approach
|
||||
Change the URL construction pattern from:
|
||||
```python
|
||||
permalink = f"{site_url}/notes/{note.slug}"
|
||||
```
|
||||
|
||||
To:
|
||||
```python
|
||||
permalink = f"{site_url}notes/{note.slug}"
|
||||
```
|
||||
|
||||
This works because SITE_URL is guaranteed to have a trailing slash.
|
||||
|
||||
### Affected Code Locations
|
||||
1. `starpunk/micropub.py` line 311 - Location header in `handle_create`
|
||||
2. `starpunk/micropub.py` line 381 - URL in Microformats2 response in `handle_query`
|
||||
|
||||
## Rationale
|
||||
|
||||
### Why Not Strip the Trailing Slash?
|
||||
We could follow the RSS feed approach and strip the trailing slash:
|
||||
```python
|
||||
site_url = site_url.rstrip("/")
|
||||
permalink = f"{site_url}/notes/{note.slug}"
|
||||
```
|
||||
|
||||
However, this approach has downsides:
|
||||
- Adds unnecessary processing to every request
|
||||
- Creates inconsistency with how SITE_URL is used elsewhere
|
||||
- The trailing slash is intentionally added for IndieAuth compliance
|
||||
|
||||
### Why This Solution?
|
||||
- **Minimal change**: Only modifies the string literal, not the logic
|
||||
- **Consistent**: SITE_URL remains normalized with trailing slash throughout
|
||||
- **Efficient**: No runtime string manipulation needed
|
||||
- **Clear intent**: The code explicitly shows we expect SITE_URL to end with `/`
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- Fixes the immediate bug with minimal code changes
|
||||
- No configuration changes required
|
||||
- No database migrations needed
|
||||
- Backward compatible - doesn't break existing data
|
||||
- Fast to implement and test
|
||||
|
||||
### Negative
|
||||
- Developers must remember that SITE_URL has a trailing slash
|
||||
- Could be confusing without documentation
|
||||
- Potential for similar bugs if pattern isn't followed elsewhere
|
||||
|
||||
### Mitigation
|
||||
- Add a comment at each URL construction site explaining the trailing slash convention
|
||||
- Consider adding a utility function in future versions for URL construction
|
||||
- Document the SITE_URL trailing slash convention clearly
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### 1. Strip Trailing Slash at Usage Site
|
||||
```python
|
||||
site_url = current_app.config.get("SITE_URL", "http://localhost:5000").rstrip("/")
|
||||
permalink = f"{site_url}/notes/{note.slug}"
|
||||
```
|
||||
- **Pros**: More explicit, follows RSS feed pattern
|
||||
- **Cons**: Extra processing, inconsistent with config intention
|
||||
|
||||
### 2. Remove Trailing Slash from Configuration
|
||||
Modify `config.py` to not add trailing slashes to SITE_URL.
|
||||
- **Pros**: Simpler URL construction
|
||||
- **Cons**: Breaks IndieAuth spec compliance, requires migration for existing deployments
|
||||
|
||||
### 3. Create URL Builder Utility
|
||||
```python
|
||||
def build_url(base, *segments):
|
||||
"""Build URL from base and path segments"""
|
||||
return "/".join([base.rstrip("/")] + list(segments))
|
||||
```
|
||||
- **Pros**: Centralized URL construction, prevents future bugs
|
||||
- **Cons**: Over-engineering for a simple fix, adds unnecessary abstraction for v1.0.1
|
||||
|
||||
### 4. Use urllib.parse.urljoin
|
||||
```python
|
||||
from urllib.parse import urljoin
|
||||
permalink = urljoin(site_url, f"notes/{note.slug}")
|
||||
```
|
||||
- **Pros**: Standard library solution, handles edge cases
|
||||
- **Cons**: Adds import, slightly less readable, overkill for this use case
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Version Impact
|
||||
- Current version: v1.0.0
|
||||
- Fix version: v1.0.1 (PATCH increment - backward-compatible bug fix)
|
||||
|
||||
### Testing Requirements
|
||||
1. Verify Location header has single slash
|
||||
2. Test with various SITE_URL configurations (with/without trailing slash)
|
||||
3. Ensure RSS feed still works correctly
|
||||
4. Check all other URL constructions in the codebase
|
||||
|
||||
### Release Type
|
||||
This qualifies as a **hotfix** because:
|
||||
- It fixes a bug in production (v1.0.0)
|
||||
- The fix is isolated and low-risk
|
||||
- No new features or breaking changes
|
||||
- Critical for proper Micropub client operation
|
||||
|
||||
## References
|
||||
- [Issue Report]: Malformed redirect URL in Micropub implementation
|
||||
- [W3C Micropub Spec](https://www.w3.org/TR/micropub/): Location header requirements
|
||||
- [IndieAuth Spec](https://indieauth.spec.indieweb.org/): Client ID URL requirements
|
||||
- ADR-028: Micropub Implementation Strategy
|
||||
- docs/standards/versioning-strategy.md: Version increment guidelines
|
||||
Reference in New Issue
Block a user