docs: rebrand implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,927 @@
|
||||
# Roundtable Rebrand 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.
|
||||
>
|
||||
> **Testing:** Per project feedback, skip all test authoring and test runs during this work. Verify manually by running the app.
|
||||
|
||||
**Goal:** Rebrand FabledScryer to Roundtable: full visual reskin plus full rename of package, config, containers, and docs.
|
||||
|
||||
**Architecture:** Staged as six sequential PRs. PR 1 is a pure visual/copy reskin that still ships under the FabledScryer name. PRs 2–4 perform the mechanical rename in order (package → config → container + user-visible strings) with a fallback shim in PR 3 so self-hosters don't break mid-upgrade. PR 5 updates docs. PR 6 removes the shim after one release cycle.
|
||||
|
||||
**Tech Stack:** Python 3.13, Quart, SQLAlchemy + Alembic (asyncpg), Jinja2 templates, Docker Compose, Postgres 16.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-04-13-rebrand-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
**Modified (PR 1 — visual reskin):**
|
||||
- `fabledscryer/templates/base.html` — palette tokens, logo SVG, font, background, wordmark, `<title>`
|
||||
- `fabledscryer/templates/auth/login.html` — themed tagline
|
||||
- `fabledscryer/templates/errors/404.html` (create if missing) — themed 404
|
||||
- `fabledscryer/templates/errors/500.html` (create if missing) — themed 500
|
||||
- `fabledscryer/templates/dashboard/*.html` — hero title "Under Watch, Under Care"
|
||||
- Any template with an empty-state message — themed line
|
||||
|
||||
**Renamed (PR 2 — package):**
|
||||
- `fabledscryer/` → `roundtable/` (directory + every `from fabledscryer` / `import fabledscryer` reference)
|
||||
- `pyproject.toml` — name, entry point, hatch packages
|
||||
- `alembic.ini` — `script_location`
|
||||
- `tests/**` — imports (tests not executed, but must not break collection; update imports mechanically)
|
||||
|
||||
**Modified (PR 3 — config & env):**
|
||||
- `fabledscryer/config.py` → `roundtable/config.py` (already moved in PR 2) — read both `ROUNDTABLE_*` and `FABLEDSCRYER_*` with deprecation warning
|
||||
- `.env.example`, `config.example.yaml` — new names
|
||||
- First-boot migration of `~/.config/fabledscryer` → `~/.config/roundtable` (if the app uses it — verify during task)
|
||||
|
||||
**Modified (PR 4 — container + user strings):**
|
||||
- `Dockerfile` — COPY paths, CMD, image labels
|
||||
- `docker-compose.yml` — service name, image, container_name, volumes, env
|
||||
- `entrypoint.sh` — package path for `nut_setup.py` invocation
|
||||
- `roundtable/templates/base.html` — wordmark text "Fabled Scryer" → "Roundtable", `<title>`
|
||||
- `roundtable/templates/auth/login.html` — any residual "Fabled Scryer" text
|
||||
- `README.md` — first-page references (full doc sweep is PR 5)
|
||||
|
||||
**Modified (PR 5 — docs):**
|
||||
- `README.md`, `docs/**/*.md`
|
||||
|
||||
**Modified (PR 6 — cleanup):**
|
||||
- `roundtable/config.py` — remove fallback shim
|
||||
|
||||
---
|
||||
|
||||
## PR 1 — Visual Reskin
|
||||
|
||||
### Task 1: Replace palette tokens in `base.html`
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/base.html:13-35`
|
||||
|
||||
- [ ] **Step 1: Open `fabledscryer/templates/base.html` and replace the `:root` block (lines 13–35) with the Pewter & Gold palette**
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bg: #131315;
|
||||
--bg-card: #1d1d20;
|
||||
--bg-elevated: #24242a;
|
||||
--border: #30303a;
|
||||
--border-mid: #3a3a44;
|
||||
--text: #d4d0c0;
|
||||
--text-muted: #b8b8b0;
|
||||
--text-dim: #8a8a92;
|
||||
--gold: #c8a840;
|
||||
--gold-hover: #d8b850;
|
||||
--gold-dim: #2a2410;
|
||||
--pewter: #8a8a92;
|
||||
--accent: var(--gold);
|
||||
--accent-hover: var(--gold-hover);
|
||||
--green: #4aa86a;
|
||||
--green-dim: #162a1c;
|
||||
--yellow: #d4a840;
|
||||
--yellow-dim: #2a2410;
|
||||
--orange: #c87840;
|
||||
--orange-dim: #2a1a10;
|
||||
--red: #c84048;
|
||||
--red-dim: #2a1014;
|
||||
--font-serif: 'EB Garamond', Georgia, serif;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/base.html
|
||||
git commit -m "style: pewter & gold palette tokens"
|
||||
```
|
||||
|
||||
### Task 2: Swap Google Font to EB Garamond
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/base.html:9-11`
|
||||
|
||||
- [ ] **Step 1: Replace the font preconnect + stylesheet link (lines 9–11) with EB Garamond**
|
||||
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,600;0,700;1,400&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/base.html
|
||||
git commit -m "style: swap Libertinus Serif → EB Garamond"
|
||||
```
|
||||
|
||||
### Task 3: Replace crystal ball logo with Heraldic Seal
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/base.html:187-214`
|
||||
|
||||
- [ ] **Step 1: Replace the `<svg>` block inside `nav .brand` (lines 188–213) with the locked seal SVG**
|
||||
|
||||
```html
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="10.5" fill="none" stroke="#c8a840" stroke-width="1.5"/>
|
||||
<circle cx="12" cy="12" r="9.3" fill="#8a8a92" opacity="0.1"/>
|
||||
<path d="M7 10 L7 5.8 L9 7.8 L10.5 5 L12 7.2 L13.5 5 L15 7.8 L17 5.8 L17 10 Z" fill="#c8a840"/>
|
||||
<ellipse cx="12" cy="15.5" rx="5.2" ry="1" fill="#c8a840"/>
|
||||
<rect x="9.6" y="15.5" width="1" height="3.8" fill="#c8a840"/>
|
||||
<rect x="13.4" y="15.5" width="1" height="3.8" fill="#c8a840"/>
|
||||
</svg>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Change the brand wordmark gradient (lines 68–71) to solid gold**
|
||||
|
||||
Replace:
|
||||
```css
|
||||
background: linear-gradient(110deg, #c8b4f8 0%, var(--gold) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
```
|
||||
|
||||
With:
|
||||
```css
|
||||
color: var(--gold);
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/base.html
|
||||
git commit -m "feat: heraldic seal logo (crown & ellipse table)"
|
||||
```
|
||||
|
||||
### Task 4: Replace star field with candlelit glow
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/base.html:42-46` (CSS), `182` (markup), `266-369` (script)
|
||||
|
||||
- [ ] **Step 1: Replace the `#star-field` CSS rules (lines 42–46) with a candlelit glow rule**
|
||||
|
||||
```css
|
||||
#candle-glow {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% 40%, rgba(200, 168, 64, 0.045) 0%, transparent 70%),
|
||||
radial-gradient(ellipse 50% 40% at 20% 80%, rgba(200, 168, 64, 0.025) 0%, transparent 65%);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Rename the markup `<div id="star-field">` (line 182) to `<div id="candle-glow">`**
|
||||
|
||||
```html
|
||||
<div id="candle-glow"></div>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Delete the entire star-field IIFE script block (lines 266–369)** — from `<script>` through `</script>` that contains `var field = document.getElementById('star-field');`. The glow is CSS-only; no JS needed.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/base.html
|
||||
git commit -m "style: candlelit glow background replaces star field"
|
||||
```
|
||||
|
||||
### Task 5: Update `<title>` tag
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/base.html:6`
|
||||
|
||||
- [ ] **Step 1: Change the title block**
|
||||
|
||||
```html
|
||||
<title>{% block title %}Roundtable{% endblock %}</title>
|
||||
```
|
||||
|
||||
Note: the visible wordmark text still reads "Fabled Scryer" — that flips in PR 4. This only changes the browser tab title, which is acceptable to flip early since it's not visible inside the UI.
|
||||
|
||||
Actually, leave the visible `<title>` as "Fabled Scryer" in PR 1 to keep this PR purely about palette/logo/font/background. Revert this change if already applied.
|
||||
|
||||
- [ ] **Step 2: Revert line 6 back to `Fabled Scryer` if modified, then commit nothing for this task.** (PR 1 does not change any user-visible strings.)
|
||||
|
||||
### Task 6: Add themed empty-state and login tagline
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/auth/login.html`
|
||||
- Modify: existing empty-state markup in list templates (identify via grep)
|
||||
|
||||
- [ ] **Step 1: Identify empty-state lines**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
grep -rn 'class="empty"' fabledscryer/templates/
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Replace each empty-state copy with a one-line themed variant**
|
||||
|
||||
For each hit, replace the inner text with a single themed sentence. Examples:
|
||||
- Hosts list empty → `No hosts yet. Summon one to the table.`
|
||||
- Alerts list empty → `Silence in the realm. No alerts to show.`
|
||||
- Plugins list empty → `No plugins installed. The table awaits new seats.`
|
||||
|
||||
Use judgment — one sentence per list. Keep them short.
|
||||
|
||||
- [ ] **Step 3: Add login tagline**
|
||||
|
||||
Open `fabledscryer/templates/auth/login.html`. Below the wordmark/heading, add:
|
||||
|
||||
```html
|
||||
<p style="color: var(--text-dim); font-family: var(--font-serif); font-style: italic; font-size: 0.95rem; margin-top: 0.25rem;">Where the realm's watch convenes.</p>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/
|
||||
git commit -m "copy: themed empty states + login tagline"
|
||||
```
|
||||
|
||||
### Task 7: Add 404 and 500 templates
|
||||
|
||||
**Files:**
|
||||
- Check: `fabledscryer/templates/errors/` (create if missing)
|
||||
- Create or modify: `fabledscryer/templates/errors/404.html`, `fabledscryer/templates/errors/500.html`
|
||||
|
||||
- [ ] **Step 1: Check if error templates and handlers already exist**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
ls fabledscryer/templates/errors/ 2>/dev/null
|
||||
grep -rn "errorhandler\|@app.error" fabledscryer/app.py fabledscryer/*/routes.py
|
||||
```
|
||||
|
||||
- [ ] **Step 2: If templates exist, update their copy to themed messages. If they don't exist, create them and wire handlers in `fabledscryer/app.py`.**
|
||||
|
||||
Content for `fabledscryer/templates/errors/404.html`:
|
||||
|
||||
```html
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Not Found — Roundtable{% endblock %}
|
||||
{% block content %}
|
||||
<div style="text-align:center; padding: 4rem 2rem; font-family: var(--font-serif);">
|
||||
<h1 style="color: var(--gold); font-size: 2.5rem; margin-bottom: 0.5rem;">404</h1>
|
||||
<p style="color: var(--text); font-size: 1.2rem; margin-bottom: 0.25rem;">No such seat at this table.</p>
|
||||
<p style="color: var(--text-dim); margin-bottom: 1.5rem;">The page you sought is not among us.</p>
|
||||
<a href="/" class="btn">Return to the hall</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
Content for `fabledscryer/templates/errors/500.html`:
|
||||
|
||||
```html
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Error — Roundtable{% endblock %}
|
||||
{% block content %}
|
||||
<div style="text-align:center; padding: 4rem 2rem; font-family: var(--font-serif);">
|
||||
<h1 style="color: var(--red); font-size: 2.5rem; margin-bottom: 0.5rem;">500</h1>
|
||||
<p style="color: var(--text); font-size: 1.2rem; margin-bottom: 0.25rem;">The watch has faltered.</p>
|
||||
<p style="color: var(--text-dim); margin-bottom: 1.5rem;">An unexpected error occurred. The cause has been logged.</p>
|
||||
<a href="/" class="btn">Return to the hall</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: If handlers are missing, add them to `fabledscryer/app.py` near other Quart error wiring**
|
||||
|
||||
```python
|
||||
@app.errorhandler(404)
|
||||
async def not_found(_):
|
||||
return await render_template("errors/404.html"), 404
|
||||
|
||||
@app.errorhandler(500)
|
||||
async def server_error(_):
|
||||
return await render_template("errors/500.html"), 500
|
||||
```
|
||||
|
||||
Match `render_template` import style already used in the file.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/errors/ fabledscryer/app.py
|
||||
git commit -m "feat: themed 404 and 500 pages"
|
||||
```
|
||||
|
||||
### Task 8: Dashboard hero title "Under Watch, Under Care"
|
||||
|
||||
**Files:**
|
||||
- Modify: `fabledscryer/templates/dashboard/index.html` (or equivalent)
|
||||
|
||||
- [ ] **Step 1: Locate the dashboard top-of-page template**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
ls fabledscryer/templates/dashboard/
|
||||
grep -rn "page-title\|dashboard" fabledscryer/templates/dashboard/ | head
|
||||
```
|
||||
|
||||
- [ ] **Step 2: At the top of the dashboard page content block, add a hero title**
|
||||
|
||||
```html
|
||||
<h1 class="page-title" style="text-align:center; color: var(--gold); font-size: 1.8rem; letter-spacing: 0.02em;">Under Watch, Under Care</h1>
|
||||
```
|
||||
|
||||
If the dashboard already has a `.page-title`, replace its text content with "Under Watch, Under Care" rather than adding a second title.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add fabledscryer/templates/dashboard/
|
||||
git commit -m "copy: dashboard hero title"
|
||||
```
|
||||
|
||||
### Task 9: Manual visual verification
|
||||
|
||||
- [ ] **Step 1: Start the app**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Open `http://localhost:5000` in a browser and walk through**
|
||||
- Login page — tagline visible, gold wordmark, candle glow background
|
||||
- Dashboard — hero title, logo in nav, no purple anywhere
|
||||
- Hosts / Alerts / Plugins / Settings — palette applied consistently
|
||||
- Trigger a 404 (e.g. `/nope`) — themed page renders
|
||||
- Check any empty state you can produce
|
||||
|
||||
- [ ] **Step 3: Note visually off items in a scratch file, fix them, and commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "style: visual polish after manual review"
|
||||
```
|
||||
|
||||
**PR 1 done.** Open PR with title `feat: roundtable visual reskin (pewter & gold)`.
|
||||
|
||||
---
|
||||
|
||||
## PR 2 — Python Package Rename
|
||||
|
||||
### Task 10: Rename the package directory
|
||||
|
||||
**Files:**
|
||||
- Rename: `fabledscryer/` → `roundtable/`
|
||||
|
||||
- [ ] **Step 1: Rename the directory**
|
||||
|
||||
```bash
|
||||
git mv fabledscryer roundtable
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Confirm the move**
|
||||
|
||||
```bash
|
||||
ls roundtable/ | head
|
||||
git status | head
|
||||
```
|
||||
|
||||
Expected: see `__init__.py`, `app.py`, `cli.py`, etc. inside `roundtable/`.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git commit -m "refactor: rename package directory fabledscryer → roundtable"
|
||||
```
|
||||
|
||||
### Task 11: Rewrite all `fabledscryer` imports to `roundtable`
|
||||
|
||||
**Files:**
|
||||
- Modify: every file under `roundtable/`, `tests/`, `alembic.ini`, `entrypoint.sh`, `Dockerfile` that imports from the old package
|
||||
|
||||
- [ ] **Step 1: Find every remaining `fabledscryer` reference in Python code**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
grep -rn "fabledscryer" roundtable/ tests/ alembic.ini entrypoint.sh Dockerfile pyproject.toml
|
||||
```
|
||||
|
||||
Keep the output visible as a checklist.
|
||||
|
||||
- [ ] **Step 2: Run a safe codemod across Python files**
|
||||
|
||||
```bash
|
||||
grep -rl "fabledscryer" roundtable/ tests/ | xargs sed -i 's/fabledscryer/roundtable/g'
|
||||
```
|
||||
|
||||
This touches only files under `roundtable/` and `tests/`. Do NOT run it across the whole repo yet — `docs/`, `.env.example`, `docker-compose.yml`, `config.example.yaml` and `README.md` are handled in later PRs.
|
||||
|
||||
- [ ] **Step 3: Spot-check a few critical files**
|
||||
|
||||
```bash
|
||||
grep -n "roundtable\|fabledscryer" roundtable/app.py roundtable/cli.py roundtable/config.py roundtable/migrations/env.py
|
||||
```
|
||||
|
||||
Expected: only `roundtable` references remain; no stray `fabledscryer`.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "refactor: update imports fabledscryer → roundtable"
|
||||
```
|
||||
|
||||
### Task 12: Update `pyproject.toml`
|
||||
|
||||
**Files:**
|
||||
- Modify: `pyproject.toml`
|
||||
|
||||
- [ ] **Step 1: Replace the project name, script entry, and hatch packages**
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "roundtable"
|
||||
version = "0.1.0"
|
||||
# ... dependencies unchanged ...
|
||||
|
||||
[project.scripts]
|
||||
roundtable = "roundtable.cli:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["roundtable"]
|
||||
```
|
||||
|
||||
Leave `[project.optional-dependencies]`, `[tool.pytest.ini_options]`, and all dependency pins untouched.
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add pyproject.toml
|
||||
git commit -m "build: rename package to roundtable in pyproject"
|
||||
```
|
||||
|
||||
### Task 13: Update `alembic.ini`
|
||||
|
||||
**Files:**
|
||||
- Modify: `alembic.ini`
|
||||
|
||||
- [ ] **Step 1: Change `script_location`**
|
||||
|
||||
```ini
|
||||
[alembic]
|
||||
script_location = roundtable/migrations
|
||||
prepend_sys_path = .
|
||||
version_path_separator = os
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add alembic.ini
|
||||
git commit -m "build: point alembic at roundtable/migrations"
|
||||
```
|
||||
|
||||
### Task 14: Verify the package installs and imports cleanly
|
||||
|
||||
- [ ] **Step 1: Install in editable mode into a throwaway venv**
|
||||
|
||||
```bash
|
||||
python -m venv /tmp/rt-verify
|
||||
/tmp/rt-verify/bin/pip install -e .
|
||||
/tmp/rt-verify/bin/python -c "import roundtable; import roundtable.app; import roundtable.cli; print('ok')"
|
||||
/tmp/rt-verify/bin/roundtable --help
|
||||
```
|
||||
|
||||
Expected: `ok` and CLI help output. No ImportError.
|
||||
|
||||
- [ ] **Step 2: Remove venv**
|
||||
|
||||
```bash
|
||||
rm -rf /tmp/rt-verify
|
||||
```
|
||||
|
||||
- [ ] **Step 3: No commit needed (verification only).**
|
||||
|
||||
**PR 2 done.** Open PR with title `refactor: rename python package fabledscryer → roundtable`.
|
||||
|
||||
---
|
||||
|
||||
## PR 3 — Config & Environment Variables
|
||||
|
||||
### Task 15: Add env-var fallback shim in `roundtable/config.py`
|
||||
|
||||
**Files:**
|
||||
- Modify: `roundtable/config.py`
|
||||
|
||||
- [ ] **Step 1: Replace the env var lookups with a fallback helper**
|
||||
|
||||
Open `roundtable/config.py` and replace the existing `load_bootstrap` body so it reads `ROUNDTABLE_*` first and falls back to `FABLEDSCRYER_*` with a deprecation warning.
|
||||
|
||||
```python
|
||||
def _env_with_fallback(new_name: str, old_name: str) -> str | None:
|
||||
val = os.environ.get(new_name)
|
||||
if val is not None:
|
||||
return val
|
||||
val = os.environ.get(old_name)
|
||||
if val is not None:
|
||||
logger.warning(
|
||||
"%s is deprecated, use %s instead. Fallback will be removed "
|
||||
"in a future release.",
|
||||
old_name, new_name,
|
||||
)
|
||||
return val
|
||||
return None
|
||||
```
|
||||
|
||||
Then inside `load_bootstrap`, replace the existing env lookups with:
|
||||
|
||||
```python
|
||||
database_url = (
|
||||
_env_with_fallback("ROUNDTABLE_DATABASE_URL", "FABLEDSCRYER_DATABASE_URL")
|
||||
or _env_with_fallback("ROUNDTABLE_DATABASE__URL", "FABLEDSCRYER_DATABASE__URL")
|
||||
or raw.get("database", {}).get("url")
|
||||
)
|
||||
if not database_url:
|
||||
raise ValueError(
|
||||
"Database URL is required. Set ROUNDTABLE_DATABASE_URL env var "
|
||||
"or add 'database.url' to config.yaml."
|
||||
)
|
||||
|
||||
# ...
|
||||
plugin_dir = (
|
||||
_env_with_fallback("ROUNDTABLE_PLUGIN_DIR", "FABLEDSCRYER_PLUGIN_DIR")
|
||||
or raw.get("plugin_dir", "plugins")
|
||||
)
|
||||
```
|
||||
|
||||
And in `_resolve_secret_key`:
|
||||
|
||||
```python
|
||||
from_env = (
|
||||
_env_with_fallback("ROUNDTABLE_SECRET_KEY", "FABLEDSCRYER_SECRET_KEY")
|
||||
or raw.get("secret_key")
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Grep for any other `FABLEDSCRYER_` or `FABLEDNETMON_` env var reads across `roundtable/`**
|
||||
|
||||
```bash
|
||||
grep -rn "FABLEDSCRYER_\|FABLEDNETMON_" roundtable/
|
||||
```
|
||||
|
||||
For each hit, apply the same pattern (new name first, old as fallback with warning). If `FABLEDNETMON_` is pure residue with no current consumer, delete the reference.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add roundtable/config.py
|
||||
git commit -m "feat: ROUNDTABLE_* env vars with FABLEDSCRYER_* fallback"
|
||||
```
|
||||
|
||||
### Task 16: Update `.env.example` and `config.example.yaml`
|
||||
|
||||
**Files:**
|
||||
- Modify: `.env.example`, `config.example.yaml`
|
||||
|
||||
- [ ] **Step 1: Rewrite `.env.example`**
|
||||
|
||||
```bash
|
||||
grep -n "FABLEDSCRYER\|FABLEDNETMON" .env.example
|
||||
```
|
||||
|
||||
Replace every occurrence with `ROUNDTABLE_*`. Add a short comment at top:
|
||||
|
||||
```
|
||||
# Roundtable environment configuration.
|
||||
# Only ROUNDTABLE_DATABASE_URL is required. Other settings live in the DB.
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Rewrite `config.example.yaml`**
|
||||
|
||||
Replace the header and example strings:
|
||||
|
||||
```yaml
|
||||
# Roundtable — Bootstrap Configuration Example
|
||||
#
|
||||
# The only REQUIRED setting is the database URL.
|
||||
# Set it via env var (recommended for Docker):
|
||||
#
|
||||
# ROUNDTABLE_DATABASE_URL=postgresql+asyncpg://user:pass@host/db
|
||||
#
|
||||
# All other settings are stored in the database and managed via
|
||||
# the Settings UI at /settings/.
|
||||
|
||||
database:
|
||||
url: "postgresql+asyncpg://roundtable:password@localhost/roundtable"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add .env.example config.example.yaml
|
||||
git commit -m "docs: ROUNDTABLE_* env var examples"
|
||||
```
|
||||
|
||||
### Task 17: Manual config verification
|
||||
|
||||
- [ ] **Step 1: Run the app with only the new env var**
|
||||
|
||||
```bash
|
||||
ROUNDTABLE_DATABASE_URL=postgresql+asyncpg://fabledscryer:fabledscryer@localhost/fabledscryer \
|
||||
python -m roundtable.cli --host 127.0.0.1 --port 5001
|
||||
```
|
||||
|
||||
(Use whatever local DB you have; the old db name is fine — data isn't being renamed.)
|
||||
|
||||
Expected: app starts, no deprecation warning.
|
||||
|
||||
- [ ] **Step 2: Run the app with only the old env var**
|
||||
|
||||
```bash
|
||||
FABLEDSCRYER_DATABASE_URL=postgresql+asyncpg://fabledscryer:fabledscryer@localhost/fabledscryer \
|
||||
python -m roundtable.cli --host 127.0.0.1 --port 5001
|
||||
```
|
||||
|
||||
Expected: app starts, deprecation warning logged once.
|
||||
|
||||
- [ ] **Step 3: Kill processes.** No commit.
|
||||
|
||||
**PR 3 done.** Open PR with title `feat: ROUNDTABLE_* env vars (FABLEDSCRYER_* fallback)`.
|
||||
|
||||
---
|
||||
|
||||
## PR 4 — Container, Deploy, User-Visible Strings
|
||||
|
||||
### Task 18: Update `Dockerfile`
|
||||
|
||||
**Files:**
|
||||
- Modify: `Dockerfile`
|
||||
|
||||
- [ ] **Step 1: Replace `fabledscryer` references**
|
||||
|
||||
Change:
|
||||
```dockerfile
|
||||
COPY fabledscryer/ fabledscryer/
|
||||
```
|
||||
to
|
||||
```dockerfile
|
||||
COPY roundtable/ roundtable/
|
||||
```
|
||||
|
||||
Change the CMD:
|
||||
```dockerfile
|
||||
CMD ["roundtable", "--host", "0.0.0.0", "--port", "5000"]
|
||||
```
|
||||
|
||||
Leave everything else (apt packages, gosu, app user, EXPOSE 5000) untouched.
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add Dockerfile
|
||||
git commit -m "build: update Dockerfile for roundtable package"
|
||||
```
|
||||
|
||||
### Task 19: Update `entrypoint.sh`
|
||||
|
||||
**Files:**
|
||||
- Modify: `entrypoint.sh`
|
||||
|
||||
- [ ] **Step 1: Replace the `nut_setup.py` invocation path**
|
||||
|
||||
Change every `/app/fabledscryer/nut_setup.py` to `/app/roundtable/nut_setup.py`.
|
||||
|
||||
Update any comment that says "FabledScryer container entrypoint." to "Roundtable container entrypoint."
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add entrypoint.sh
|
||||
git commit -m "build: entrypoint.sh uses roundtable package path"
|
||||
```
|
||||
|
||||
### Task 20: Update `docker-compose.yml`
|
||||
|
||||
**Files:**
|
||||
- Modify: `docker-compose.yml`
|
||||
|
||||
- [ ] **Step 1: Replace the service definition**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
roundtable:
|
||||
build: .
|
||||
container_name: roundtable
|
||||
image: roundtable:latest
|
||||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- app_data:/data
|
||||
- ./plugins:/app/plugins:ro
|
||||
- /mnt/Data/traefik/log:/var/log/traefik:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- ROUNDTABLE_DATABASE_URL=postgresql+asyncpg://roundtable:roundtable@db/roundtable
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: roundtable
|
||||
POSTGRES_PASSWORD: roundtable
|
||||
POSTGRES_DB: roundtable
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U roundtable"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
app_data:
|
||||
```
|
||||
|
||||
**Data note:** the existing dev database is named `fabledscryer` with user `fabledscryer`. For local dev, either (a) drop and recreate the DB with the new name, or (b) leave the existing compose `environment` values pointing at the old DB name if you want to preserve data. Pick based on whether the local DB has data worth keeping — document the choice in the commit message.
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add docker-compose.yml
|
||||
git commit -m "build: docker-compose service → roundtable"
|
||||
```
|
||||
|
||||
### Task 21: Flip user-visible wordmark and title
|
||||
|
||||
**Files:**
|
||||
- Modify: `roundtable/templates/base.html`
|
||||
|
||||
- [ ] **Step 1: Update the `<title>` block (around line 6)**
|
||||
|
||||
```html
|
||||
<title>{% block title %}Roundtable{% endblock %}</title>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update the nav wordmark (around line 214)**
|
||||
|
||||
Change `Fabled Scryer` inside `nav .brand` to `Roundtable`.
|
||||
|
||||
- [ ] **Step 3: Grep for any other user-visible "Fabled Scryer" strings in templates**
|
||||
|
||||
```bash
|
||||
grep -rn "Fabled Scryer\|FabledScryer" roundtable/templates/
|
||||
```
|
||||
|
||||
Replace each with "Roundtable".
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add roundtable/templates/
|
||||
git commit -m "copy: flip visible wordmark → Roundtable"
|
||||
```
|
||||
|
||||
### Task 22: Manual container verification
|
||||
|
||||
- [ ] **Step 1: Rebuild and run**
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify**
|
||||
- Container named `roundtable` runs
|
||||
- Browser shows "Roundtable" in tab title and nav
|
||||
- Login, dashboard, and error pages all render with the new palette and wordmark
|
||||
- Logs show no import errors and no unhandled deprecation warnings
|
||||
|
||||
- [ ] **Step 3: Stop**
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
**PR 4 done.** Open PR with title `feat: roundtable container & wordmark flip`.
|
||||
|
||||
---
|
||||
|
||||
## PR 5 — Docs & Repo
|
||||
|
||||
### Task 23: Sweep `README.md` and `docs/`
|
||||
|
||||
**Files:**
|
||||
- Modify: `README.md`, `docs/**/*.md`
|
||||
|
||||
- [ ] **Step 1: Find every remaining reference**
|
||||
|
||||
```bash
|
||||
grep -rn "fabledscryer\|FabledScryer\|Fabled Scryer" README.md docs/
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Replace mechanically, then proofread**
|
||||
|
||||
```bash
|
||||
grep -rl "fabledscryer\|FabledScryer\|Fabled Scryer" README.md docs/ \
|
||||
| xargs sed -i \
|
||||
-e 's/FabledScryer/Roundtable/g' \
|
||||
-e 's/fabledscryer/roundtable/g' \
|
||||
-e 's/Fabled Scryer/Roundtable/g'
|
||||
```
|
||||
|
||||
Then read each changed file top-to-bottom and fix any mangled sentences (e.g. capitalization at the start of sentences, code blocks that now reference a directory that still needs a `./` prefix, etc.). Pay extra attention to:
|
||||
- `docs/architecture.md`
|
||||
- `docs/reference/code-map.md`
|
||||
- `docs/core/configuration.md`
|
||||
- `docs/plugins/writing-a-plugin.md`
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add README.md docs/
|
||||
git commit -m "docs: roundtable rename sweep"
|
||||
```
|
||||
|
||||
### Task 24: Rename the Forgejo repo
|
||||
|
||||
- [ ] **Step 1: Via Forgejo UI or API, rename the repo from `FabledScryer` to `Roundtable`.** The old URL will redirect for one grace period.
|
||||
|
||||
- [ ] **Step 2: Update your local remote URL**
|
||||
|
||||
```bash
|
||||
git remote set-url origin <new-url>
|
||||
git remote -v
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Optionally rename the local working directory**
|
||||
|
||||
```bash
|
||||
# from the parent dir
|
||||
cd ..
|
||||
mv FabledScryer Roundtable
|
||||
cd Roundtable
|
||||
```
|
||||
|
||||
- [ ] **Step 4: No commit.**
|
||||
|
||||
**PR 5 done.** Open PR with title `docs: roundtable rename sweep`.
|
||||
|
||||
---
|
||||
|
||||
## PR 6 — Cleanup (deferred one release cycle)
|
||||
|
||||
### Task 25: Remove env var fallback shim
|
||||
|
||||
**Files:**
|
||||
- Modify: `roundtable/config.py`
|
||||
|
||||
- [ ] **Step 1: Delete `_env_with_fallback` and inline direct `os.environ.get("ROUNDTABLE_*")` lookups**
|
||||
|
||||
Replace each `_env_with_fallback("ROUNDTABLE_X", "FABLEDSCRYER_X")` call with `os.environ.get("ROUNDTABLE_X")`. Delete the helper.
|
||||
|
||||
- [ ] **Step 2: Grep to confirm no `FABLEDSCRYER_` references remain**
|
||||
|
||||
```bash
|
||||
grep -rn "FABLEDSCRYER_\|FABLEDNETMON_" .
|
||||
```
|
||||
|
||||
Expected: zero hits (or only historical commit messages, which don't show up in `grep`).
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add roundtable/config.py
|
||||
git commit -m "refactor: remove FABLEDSCRYER_* env var fallback shim"
|
||||
```
|
||||
|
||||
### Task 26: Final sweep
|
||||
|
||||
- [ ] **Step 1: Search the entire repo one last time**
|
||||
|
||||
```bash
|
||||
grep -rn "fabledscryer\|FabledScryer\|Fabled Scryer\|FABLEDSCRYER\|FABLEDNETMON" .
|
||||
```
|
||||
|
||||
Expected: zero results outside of `.git/` and historical `docs/superpowers/plans/` or `docs/superpowers/specs/` files (those record the rename intentionally — leave them).
|
||||
|
||||
- [ ] **Step 2: If any unexpected hits appear, fix and commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "refactor: final rename sweep"
|
||||
```
|
||||
|
||||
**PR 6 done.** Rebrand complete.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review Notes
|
||||
|
||||
- Spec coverage: all 5 spec sections mapped to PRs 1–5; PR 6 handles the cleanup implied by the shim in PR 3.
|
||||
- No placeholders — every template replacement includes concrete code; every grep includes the actual pattern.
|
||||
- Type consistency: config helper is `_env_with_fallback` in both Task 15 and Task 25; env var names are `ROUNDTABLE_DATABASE_URL`, `ROUNDTABLE_PLUGIN_DIR`, `ROUNDTABLE_SECRET_KEY` consistently.
|
||||
- Tests intentionally skipped per project feedback; verification is manual (browser + container).
|
||||
Reference in New Issue
Block a user