174 lines
9.2 KiB
Markdown
174 lines
9.2 KiB
Markdown
# Aurora Dockside — Build Session Log
|
|||
|
|
|
||
|
|
A record of the conversation that produced this project: an Electron + React +
|
||
|
|
TypeScript desktop GUI for managing [DDEV](https://ddev.com) local development
|
||
|
|
environments, built as an independent clone of
|
||
|
|
[DDEV Manager](https://github.com/DDEV-Manager/ddev-manager) (Tauri + React + Rust).
|
||
|
|
|
||
|
|
## Origin
|
||
|
|
|
||
|
|
The session started with an unrelated request — install and configure DDEV
|
||
|
|
itself (Homebrew, OrbStack as the container runtime, mkcert for trusted local
|
||
|
|
HTTPS). Partway through, the idea came up: rather than using the existing
|
||
|
|
DDEV Manager app, build an equivalent from scratch, in our own code.
|
||
|
|
|
||
|
|
### Tech stack decisions (asked up front)
|
||
|
|
|
||
|
|
- **Framework**: Electron + React + TypeScript, chosen over matching the
|
||
|
|
original's Tauri/Rust stack — no Rust toolchain required.
|
||
|
|
- **Scope**: Full feature parity with DDEV Manager, built incrementally
|
||
|
|
(each step runnable/testable) rather than scaffolding everything blind.
|
||
|
|
- **Package manager**: pnpm, enabled via `corepack enable`.
|
||
|
|
- **Name**: Aurora Dockside (chosen by the user over a couple of suggested
|
||
|
|
alternatives).
|
||
|
|
|
||
|
|
A formal plan was written (Plan Mode) covering architecture (Electron main
|
||
|
|
process owns all `ddev` CLI execution; typed `window.api` surface via
|
||
|
|
contextBridge; TanStack Query + Zustand on the renderer side) and a 9-step
|
||
|
|
build order before any code was written.
|
||
|
|
|
||
|
|
## Build steps (each committed separately, each verified against a real
|
||
|
|
running DDEV project — not just typechecked)
|
||
|
|
|
||
|
|
1. **Scaffold** — `electron-vite` + React 19 + TypeScript template via
|
||
|
|
`@quick-start/create-electron`, git-initialized on `main`.
|
||
|
|
2. **Tailwind CSS 4, Vitest, core libraries** — Tailwind via the Vite
|
||
|
|
plugin, Vitest + React Testing Library, Zustand, TanStack Query,
|
||
|
|
Lucide icons. Stripped the electron-vite demo boilerplate.
|
||
|
|
3. **Core project management** — `ddev.ts` CLI wrapper (execFile +
|
||
|
|
JSON envelope parsing), IPC handlers, typed preload API, TanStack Query
|
||
|
|
hooks, two-pane UI (project list + detail panel). Includes a PATH
|
||
|
|
fallback in the main process, since GUI apps launched outside a
|
||
|
|
terminal don't inherit the shell's PATH and can't find Homebrew's
|
||
|
|
`ddev` binary otherwise.
|
||
|
|
4. **Terminal panel, status bar, toasts** — long-running commands
|
||
|
|
(start/stop/restart) now spawn via a `commandRunner.ts` module and
|
||
|
|
stream stdout/stderr to the renderer over IPC instead of waiting for
|
||
|
|
the whole command to finish. Cancel support kills the tracked child
|
||
|
|
process by operation id.
|
||
|
|
5. **Database tools** — snapshot create/list/restore/delete, DB
|
||
|
|
import/export via native file dialogs. `ddev snapshot restore` has no
|
||
|
|
project-name flag (unlike other ddev commands), so it runs with
|
||
|
|
`cwd` set to the project's approot instead.
|
||
|
|
6. **Add-on management** — registry browser (~270 third-party add-ons)
|
||
|
|
with search, install/remove via `ddev add-on get/remove`. Verified
|
||
|
|
working with the project stopped.
|
||
|
|
7. **Log viewer** — `ddev logs -f` streamed over a dedicated IPC channel
|
||
|
|
(decoupled from the terminal/status-bar model, since log tailing runs
|
||
|
|
indefinitely rather than completing). Service switcher, text filter.
|
||
|
|
8. **Project creation wizard** — native directory picker, project name,
|
||
|
|
project type selector, optional docroot, streamed `ddev config`.
|
||
|
|
9. **Settings** — theme (light/dark/system, persisted), zoom controls via
|
||
|
|
a small main-process IPC (`webContents.setZoomLevel`), keyboard
|
||
|
|
shortcuts (Cmd/Ctrl+N, +comma, +=/-/0).
|
||
|
|
10. **Packaging** — cleaned up `electron-builder.yml` (correct appId/
|
||
|
|
productName, removed irrelevant camera/mic/Documents/Downloads
|
||
|
|
Info.plist entries, removed a placeholder auto-update publish
|
||
|
|
config). Verified with a real `pnpm build:unpack` run, launching the
|
||
|
|
packaged (unsigned, no Developer ID cert available) `.app` directly
|
||
|
|
and confirming it could still find and run `ddev`.
|
||
|
|
|
||
|
|
Scoped down from full parity, on purpose: composer/wp-cli-based CMS
|
||
|
|
scaffolding for Drupal/Laravel/Shopware, and auto-update infrastructure.
|
||
|
|
|
||
|
|
## Bugs found via live testing (not just code review)
|
||
|
|
|
||
|
|
Every feature was verified by actually driving the running app — mostly via
|
||
|
|
a small CDP (Chrome DevTools Protocol) driver script that clicked real
|
||
|
|
buttons in the real Electron window, since a lot of this app's correctness
|
||
|
|
depends on real subprocess/IPC/timing behavior that static review can't
|
||
|
|
catch. This caught several real defects:
|
||
|
|
|
||
|
|
- **`window.prompt()` doesn't work in Electron's renderer** — it returns
|
||
|
|
`null` immediately with no dialog, unlike `window.confirm()` which does
|
||
|
|
show a real native dialog. The snapshot-naming UI was rewritten to use
|
||
|
|
an inline text input instead.
|
||
|
|
- **`ddev addon list --installed` omits the `raw` JSON key entirely** when
|
||
|
|
nothing is installed (unlike `ddev list`/`ddev snapshot --list`, which
|
||
|
|
include `raw: null`). The shared JSON-parsing helper treated a missing
|
||
|
|
`raw` as an error, so after removing the last add-on the query would
|
||
|
|
error on refetch and React Query kept showing the stale cached row.
|
||
|
|
Fixed by splitting the helper into a strict variant (for `describe`,
|
||
|
|
where missing data really is an error) and a lenient list variant.
|
||
|
|
- **Log filtering operated on raw stream chunks, not lines** — a single
|
||
|
|
chunk of stdout/stderr can bundle many lines or split one across chunk
|
||
|
|
boundaries, so filtering by chunk let unrelated lines through. Fixed by
|
||
|
|
buffering partial lines per stream and only filtering once full lines
|
||
|
|
are assembled.
|
||
|
|
- **A `react-hooks/set-state-in-effect` lint violation** in the log-stream
|
||
|
|
hook, from resetting state synchronously inside an effect body. Fixed
|
||
|
|
by keying the streaming component by `service` so switching services
|
||
|
|
remounts it — state resets via fresh `useState` initializers instead,
|
||
|
|
which is the React-recommended pattern for this.
|
||
|
|
|
||
|
|
## Post-launch bug reports and fixes
|
||
|
|
|
||
|
|
After the initial 9-step build was declared done, real usage surfaced three
|
||
|
|
more gaps:
|
||
|
|
|
||
|
|
1. **"I created a new container for wordpress, only wp-content was
|
||
|
|
created."** — `ddev config --project-type=wordpress` only scaffolds the
|
||
|
|
DDEV-managed `wp-config.php` bridge and `wp-content/uploads`; it never
|
||
|
|
downloads WordPress core (`wp-admin/`, `wp-includes/`, `index.php`,
|
||
|
|
etc.). Fixed the user's existing project directly (`ddev wp core
|
||
|
|
download`), then added the missing step to the wizard.
|
||
|
|
2. **"Now I get 403 Forbidden. Shouldn't we have an option to set admin
|
||
|
|
username, password, and email while setting it up?"** — right call:
|
||
|
|
`wp core download` only fetches files, `wp core install` is what
|
||
|
|
actually creates the database tables and admin user. The wizard's
|
||
|
|
WordPress path now chains `configure → start → wp core download →
|
||
|
|
wp core install`, with site title/admin username/password/email
|
||
|
|
fields shown only for that project type. wp-cli needs the containers
|
||
|
|
running, so this path always starts the project regardless of the
|
||
|
|
generic "start after creating" checkbox.
|
||
|
|
3. **"What about the ability to delete the site? I can create all day
|
||
|
|
long but not able to delete them from the software."** — a real gap;
|
||
|
|
the original DDEV Manager has this and it hadn't been built yet. Added
|
||
|
|
a Delete button (`ddev delete <name> --yes`, keeping ddev's default
|
||
|
|
database snapshot as a safety net) with a confirmation dialog that
|
||
|
|
clarifies it only removes DDEV's registration/containers/database, not
|
||
|
|
the project's files on disk.
|
||
|
|
4. Also added, per a follow-up request: a **WP Admin quick-link** button
|
||
|
|
for running WordPress-type projects, opening `{primary_url}/wp-admin/`
|
||
|
|
directly.
|
||
|
|
|
||
|
|
All three were verified end-to-end against a fresh throwaway project:
|
||
|
|
full configure→start→download→install chain producing a genuinely working
|
||
|
|
site (200 on the homepage, correct login redirect on `/wp-admin`), and
|
||
|
|
delete actually removing the project from `ddev list`. Two apparent bugs
|
||
|
|
that came up during that verification turned out to be the *test script*
|
||
|
|
reading DOM state before React had re-rendered, or before ddev's
|
||
|
|
multi-step delete (build + start + snapshot + teardown) had actually
|
||
|
|
finished — not real defects.
|
||
|
|
|
||
|
|
## Final artifact
|
||
|
|
|
||
|
|
A packaged, distributable build was produced on request:
|
||
|
|
|
||
|
|
- `dist/aurora-dockside-1.0.0.dmg` — installer
|
||
|
|
- `dist/Aurora Dockside-1.0.0-arm64-mac.zip` — zipped `.app`
|
||
|
|
|
||
|
|
Both unsigned (no Developer ID certificate on this machine) — macOS
|
||
|
|
Gatekeeper requires right-click → Open on first launch.
|
||
|
|
|
||
|
|
## Repository state
|
||
|
|
|
||
|
|
10 commits on `main`, one per build step plus the post-launch fixes:
|
||
|
|
|
||
|
|
```
|
||
|
|
Scaffold Aurora Dockside with electron-vite + React + TypeScript
|
||
|
|
Wire up Tailwind CSS 4, Vitest, and core app libraries
|
||
|
|
Add core DDEV project management (list/describe/start/stop/restart)
|
||
|
|
Add streaming terminal panel, status bar, and toast notifications
|
||
|
|
Add database tools: snapshots and import/export (step 4)
|
||
|
|
Add add-on management: registry browser, install, remove (step 5)
|
||
|
|
Add streaming log viewer with service switching and filtering (step 6)
|
||
|
|
Add project creation wizard (step 7)
|
||
|
|
Add settings: theme, zoom controls, keyboard shortcuts (step 8)
|
||
|
|
Finalize packaging config and verify a real build (step 9)
|
||
|
|
Fix WordPress scaffolding gap; add delete project + WP admin link
|
||
|
|
```
|
||
|
|
|
||
|
|
*(Note: some project files show further edits beyond this log's cutoff —
|
||
|
|
work continued in the project after this session.)*
|