docs: add dual-domain implementation plan
This commit is contained in:
113
docs/superpowers/plans/2026-05-16-dual-domain.md
Normal file
113
docs/superpowers/plans/2026-05-16-dual-domain.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Dual-Domain Support Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Serve the portfolio on both `gabrielkaszewski.dev` and `gabrielkaszewski.pl` with identical content, with `.dev` as the canonical domain for SEO.
|
||||||
|
|
||||||
|
**Architecture:** Two independent changes — Traefik routing config to accept both hostnames, and Next.js metadata to inject a canonical `<link>` tag. No app logic changes.
|
||||||
|
|
||||||
|
**Tech Stack:** Next.js 15 (App Router metadata API), Traefik (Docker labels), Let's Encrypt TLS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Add `.pl` domain to Traefik router
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `compose.yml`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update the Traefik router rule**
|
||||||
|
|
||||||
|
In `compose.yml`, change the router rule label from:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- "traefik.http.routers.gabrielkaszewski.rule=Host(`gabrielkaszewski.dev`)"
|
||||||
|
```
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- "traefik.http.routers.gabrielkaszewski.rule=Host(`gabrielkaszewski.dev`) || Host(`gabrielkaszewski.pl`)"
|
||||||
|
```
|
||||||
|
|
||||||
|
The full `labels` block should look like:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.gabrielkaszewski.rule=Host(`gabrielkaszewski.dev`) || Host(`gabrielkaszewski.pl`)"
|
||||||
|
- "traefik.http.routers.gabrielkaszewski.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.gabrielkaszewski.tls.certresolver=letsencrypt"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Traefik's Let's Encrypt cert resolver automatically provisions a cert for every hostname matched by the router rule, so no additional TLS labels are needed.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add compose.yml
|
||||||
|
git commit -m "feat: add gabrielkaszewski.pl to traefik router"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Add canonical URL to Next.js metadata
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `app/layout.tsx`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add `alternates.canonical` to the metadata export**
|
||||||
|
|
||||||
|
In `app/layout.tsx`, add `alternates` to the existing `metadata` object:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: {
|
||||||
|
default: "Gabriel Kaszewski | Software Engineer",
|
||||||
|
template: "%s | Gabriel Kaszewski",
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"The portfolio of Gabriel Kaszewski, a software engineer specializing in Rust, Python, and modern web technologies.",
|
||||||
|
keywords: [
|
||||||
|
"Gabriel Kaszewski",
|
||||||
|
"Software Engineer",
|
||||||
|
"Rust Developer",
|
||||||
|
"Python Developer",
|
||||||
|
"Next.js",
|
||||||
|
"Portfolio",
|
||||||
|
],
|
||||||
|
alternates: {
|
||||||
|
canonical: "https://gabrielkaszewski.dev",
|
||||||
|
},
|
||||||
|
openGraph: {
|
||||||
|
// ... rest unchanged
|
||||||
|
},
|
||||||
|
// ... rest unchanged
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify the canonical tag is present in the built HTML**
|
||||||
|
|
||||||
|
Run the dev server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in another terminal, check the rendered HTML for the canonical tag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s http://localhost:3000 | grep -i canonical
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
|
||||||
|
```
|
||||||
|
<link rel="canonical" href="https://gabrielkaszewski.dev"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add app/layout.tsx
|
||||||
|
git commit -m "feat: add canonical URL to metadata"
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user