---
id: TASK-60
title: Canonical subdomain routing + rSwag landing page simplification
status: Done
assignee:
  - '@claude'
created_date: '2026-02-26 00:44'
labels:
  - routing
  - infrastructure
  - simplification
dependencies: []
references:
  - server/index.ts
  - server/shell.ts
  - shared/url-helpers.ts
  - shared/components/rstack-app-switcher.ts
  - shared/components/rstack-space-switcher.ts
  - shared/components/rstack-identity.ts
  - website/shell.ts
priority: high
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Consolidated URL routing so all rApps flow through `{space}.rspace.online/{moduleId}` as the canonical URL pattern, replacing the previous silent URL rewriting from standalone domains.

**rspace-online changes:**
- Subdomain handler now routes ALL modules (previously only served canvas)
- Standalone domains (rvote.online, rphotos.online, etc.) now 301 redirect to canonical `{space}.rspace.online/{moduleId}`
- Created `shared/url-helpers.ts` with `rspaceNavUrl()`, `getCurrentSpace()`, `getCurrentModule()`, `isSubdomain()`
- Updated app-switcher, space-switcher, identity component, and tab-bar navigation to use subdomain-aware URL generation
- Shell inline scripts use global `__rspaceNavUrl()` for all URL generation
- Path-based `rspace.online/:space/:moduleId` still works as fallback
- WebSocket connections on standalone domains still rewritten (WS can't follow redirects)

**rswag-online changes:**
- Replaced full Next.js + FastAPI + PostgreSQL + Redis docker-compose with simple static nginx landing page
- Updated landing page CTA: "Try the Demo" → `https://rspace.online/demo/swag`
- Aligns with the "simple components, JS and HTML wherever possible" philosophy
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 demo.rspace.online/vote serves vote module in demo space
- [ ] #2 Standalone domains (rvote.online etc) 301 redirect to canonical subdomain URL
- [ ] #3 App-switcher and space-switcher generate subdomain-aware links
- [ ] #4 Auto-provision redirect uses subdomain URL pattern
- [ ] #5 Path-based rspace.online/:space/:moduleId still works
- [ ] #6 rswag.online serves static landing page instead of Next.js app
- [ ] #7 TypeScript compiles cleanly
<!-- AC:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Implemented canonical subdomain routing `{space}.rspace.online/{moduleId}` across rspace-online and simplified rswag-online from Next.js to static landing page.\n\nCommits:\n- rspace-online `eab24e2`: feat: canonical subdomain routing\n- rswag-online `1eca70d`: feat: replace Next.js app with static landing page, add demo CTA\n\nBoth repos pushed to main on Gitea.
<!-- SECTION:FINAL_SUMMARY:END -->
