Skip to content

refactor - #4

Merged
rodyherrera merged 147 commits into
mainfrom
refactor
Sep 6, 2026
Merged

rodyherrera merged 147 commits into
mainfrom
refactor

Conversation

@rodyherrera

Copy link
Copy Markdown
Owner

No description provided.

rodyherrera and others added 30 commits June 15, 2026 13:21
…ring into server.ts and delete the pass-through module

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s 8 now-orphaned imports

Superseded by orchestrator/reconcileHandler (boot reconciliation). Zero call sites;
the 8 imports it owned (Repository, Github, RepositoryHandler, sendMail, IUser,
IRepository, DockerContainer, DockerContainerService) are removed with it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t bodies into one private emit() helper

Each emit* export kept its name + typed signature (call sites and type safety
unchanged); only the repeated userId-guard + try/emit/catch body is deduplicated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…od function

Extract hydrateUser, loadCompleteTenancy, ensurePersonalOrg, ensureOwnerMembership,
linkDefaultOrganization. The 82-line orchestrator is now a linear read of 5 named
single-responsibility steps; each was a self-contained block before. Behavior
preserved (tenancy-* suite green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… function

Extract backfillRepositories; table-drive the 12 org-stamping passes via
ORG_STAMP_PASSES (order preserved: Docker before Metric). 87-line function with
two big loops becomes a short orchestrator. Behavior preserved (tenancy suite green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erNetwork memoization

The two private fields were only ever set to null (never assigned the fetched
value), so the getDockerImage/getDockerNetwork cache guards never fired and the
fetch always ran fresh. Removed the fields, their constructor inits, and the two
dead guard lines. Behavior identical (guards were no-ops); IDockerImage/IDockerNetwork
imports stay (method return types).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ntainer

reloadContainer is typed Promise<void> but returned newContainer; all 6 callers
await it without using the value. Removed the misleading return to match the
signature. (Full step-extraction of this 68-line fn deferred: no behavioral test
exists — reload.test.ts mocks the method — so a daemon-mock test must precede it.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ision.ts

Both buildHandler and deployHandler defined byte-identical populateRepository
helpers. Moved one copy to provision.ts (their shared dependency) as a named
export; both now import it. Dropped buildHandler's now-unused Repository import
(tsc 24->23). Behavior identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erviceFields

normalizeService and parseLegacy.toService both normalized command/environment/
ports/volumes identically; factored into one helper. splitImageRef left untouched
(intentionally different across compose/prebuilt). The '?? raw.env' fallback is a
no-op for legacy entries, so behavior is preserved (templates.test.ts green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…>23 (modules 1-8)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…enant filter

The tenant-scope clause (admin->{} else project $in caller's projectIds) was
copy-pasted verbatim in backupDatabase/restoreDatabase/getConnectionString.
Extracted to a local reachableScope(req) helper. NOTE: scanner suggested routing
these through resolveProjectOr403, but that resolves a :projectId param — these
endpoints key off a database :id, so that helper is the wrong tool; a local filter
helper is the correct dedup. Behavior identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nual_review (modules 9-10)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rel re-export

Trimmed the 13-line copyright header + import/export indirection to a single
`export { default } from './ProtectedRoute'`, matching sibling organism barrels
(AppShell, StatusBar). Client build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rom 4 near-identical hooks

useUserDockerContainers/Images/Networks/PortBinding shared the same paged-fetch +
cleanup-on-unmount shape; each is now a thin config wrapper over a shared
useUserResource. Public hook names + return shapes unchanged (barrel intact).
Behavior preserved verbatim, including the intentional dataKey/cleanupPath
mismatch (e.g. 'dockerContainers' vs 'containers') and portBinding's undefined
initial page. useUserRepositories left as-is (60s polling, different shape).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
StatusChip/StatTile/IconButton had zero imports across client/src (grep-confirmed);
they were left over from a mid-migration that completed. Client build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eUserResource, kit aliases)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
errText (err->string|err.message|fallback) was redefined identically in Alerting,
SetupOrganization, OrganizationSettings, Team. Moved to @utilities/common/errText
and imported. Client build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n file

EnvironmentsModal was a module-scope sibling component (props-only interface
{project,onClose}, no shared state with Projects), so moving it to its own file
is a pure mechanical extraction. Projects.jsx 528->381 LOC; dropped now-unused
StatusBadge + Trash2 imports. Client build green. (Other god-component smells in
this file — 28 useState, modal-reset dup — deferred: no FE test net.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cate util

InstallModal was a module-scope sibling (props-only), extracted to its own file
(Templates.jsx 429->279 LOC). truncate was shared by both parent and modal, so
relocated to @utilities/common/truncate and imported in both (avoids duplication
and a backwards parent<-modal import). Dropped now-unused Input import. Build green.
(CatalogBrowser + 14 useState consolidation deferred: no FE test net.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…emplates + 3 god-components -> manual_review); hook truncate fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ual_review + run summary

Final: 13 completed, 9 manual_review, 15 atomic commits, gate green
(server tsc 23/23, vitest 131/131, client build OK). pending=0, in_progress=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…stopOrchestrator, default barrel

All three were unreferenced: enqueueBuild (only producer of standalone type:'build'
jobs — none are enqueued; runBuild is called directly by deployHandler), stopOrchestrator
(SIGINT handler uses process.exit(0), never calls it), and the export default {...} object
(all import sites use named imports; templateHandler's dynamic import uses the named
.enqueueDatabaseJob). Dispatch 'build' case + buildHandler left intact (runBuild still used).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r.error

The updateContainerFile catch block swallowed errors via console.log(error) (a debug
leftover). Converted to logger.error with the codebase's file-prefix convention so a
writeFile failure is actually recorded instead of going to stdout. Not deleted: the
catch has no other handling, so removing it would silently swallow the error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d-code + dockerFS logger)

2 deletions applied, gate green (server tsc 23/23, vitest 131/131, client build OK).
pending=0, in_progress=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
if(import.meta.env) is always truthy (env is an object), so the timing console.log
and error-tracking middleware ran in PRODUCTION on every API call. Changed to
import.meta.env.DEV to restore the obvious dev-only intent and silence prod console noise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
this.authToken = null was set in the constructor but never read or reassigned
anywhere (grep across client/src). Speculative field, removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + dead field)

2 changes, gate green (server tsc 23/23, vitest 131/131, client build OK). pending=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ive-deployment status

Two bugs surfaced when creating a Git app:

1. HTTP 403 'Pool overlaps with other one on this address space' — randomIPv4Subnet
   picked a /24 blindly with no awareness of existing networks, and could land in
   172.16/12 which overlaps Docker's own /16 bridges. Now pickFreeSubnet() reads the
   live Docker network list and chooses a non-overlapping /24 inside 10.0.0.0/8
   (real 32-bit overlap math, random-then-linear-scan, throws if exhausted). Subnet
   allocation moved from the model's pure pre-save hook to materializeNetwork (it
   needs Docker I/O); subnet index made sparse since it's now filled post-save.

2. Dashboard showed wrong/empty Status — getMyRepositories read deployments[0] (the
   OLDEST deployment) instead of the most recent; now reads the last (push-ordered)
   already-populated deployment's status directly, no extra query.

Adds server/tests/network-subnet.test.ts (5 tests: in-range, no-overlap incl. /16
edge case, deterministic fallback, exhaustion). Verified end-to-end on the live
daemon: 5 consecutive new networks created with zero Pool overlaps; broken repo
redeployed to success. Gate: tsc 23, 136 tests pass, client build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…500)

GET /repository/me/ returned HTTP 500 for any user owning a repo without a linked
GitHub account: getMyRepositories builds 'new Github(user, repo)' per repo, and the
constructor did user.github.getDecryptedAccessToken() — throwing on undefined
user.github, BEFORE getRepositoryInfo's graceful-degrade catch, so one GitHub-less
repo crashed the entire dashboard list.

- Github constructor: null-safe user.github; unauthenticated Octokit when no token
  (API calls then fail into the existing remoteUnavailable degrade path). cloneRepository
  private-clone token interpolation made null-safe too.
- getMyGithubRepositories / detectFramework: explicit 400 Github::Account::NotLinked
  instead of a cryptic 500 when the endpoint genuinely requires GitHub.

Adds server/tests/github-constructor.test.ts (3 tests). Verified live: GET /repository/me/
now 200 with the repo listed (status none, remote unavailable — correct for a GitHub-less
repo). Gate: tsc 23, 139 tests, client build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A validation failure (missing/invalid field) returned HTTP 401, which the frontend
treats as an auth failure → logout / redirect to login. So a routine 'field required'
error (e.g. POST /port-binding without externalPort) logged the user out instead of
showing a field error. ValidationError now maps to 400 Bad Request.

Adds server/tests/error-handler.test.ts (5 tests: ValidationError 400, CastError 400,
dup-key 400, RuntimeError passthrough, JWT stays 401). Verified live: port-binding
without externalPort now returns 400. Gate: tsc 23, 144 tests, client build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… improved styling and layout

style: enhance ChartTooltip and Sparkline components with updated styles

refactor: modify TopList and Chart axes for better visual consistency

fix: adjust PageBody and PageHeader layouts for responsive design

feat: add eyebrow prop to PageHeader for additional context

style: refine ThemeToggle and NotFound components for better user experience

fix: improve ServerUnreachable component layout and messaging

test: clean up tests for Avatar and EntitySelect components

feat: extend API contracts with new navigation and channel interfaces

refactor: enhance query-cache and resource hooks for better state management

test: update optimistic writes and resource stream tests for accuracy

chore: clean up use-remembered-selection hook and related tests

fix: update socket frame tests for correct payload structure

chore: tidy up theme store and format-metrics utility functions

build: streamline Vite configuration for better plugin management
Projects carried a per-project Environment layer (production/staging/preview)
that nothing behaved differently on: every entity stored environmentId as
nullable and always wrote null. Delete the model, service, controller,
routes, error table and dialogs, drop environmentId from the database,
deployment, metric, repository and template contracts, and add
ContainerAddress to docker contracts for repository/database addresses.
Rename the seeded default project from 'Default Environment' to
'Default Project'.
cad6dad deleted the environment contracts but kept the api controller,
model and service and the web dialog that imported them, so the api
crashed on boot and the web build failed on types. Finish the removal.
…tainer

Every new Deployment row started with an empty environmentVariables map,
so a push wiped what the user had saved, and the map only reached
exec-strategy apps through the relaunch exec: Dockerfile and prebuilt
image containers were created without it. Copy the previous
deployment's variables forward and resolve the container Env from one
place that merges the container row with the latest deployment.
…ow its address

Each application had its own bridge network, so nothing could reach
anything else. Attach every container to quantum-org-<env>-<orgId> with
its slugified name as DNS alias, record the IP it gets there on start,
restart and reconcile, and show it as an Address column in Applications
next to a separate Ports column.
Lift the repository page's editor and row helpers into shared so
template installs can reuse them; it autosaves like the rest of the app.
…ment

A stack is a TemplateInstall that owns its spec, parsed from the compose
file (image, command, environment, ports, named volumes, depends_on;
build contexts and bind mounts are refused with the service named), so
provisioning, logs, shell and lifecycle are reused as they are. The file
and each service's variables are editable from the install page, saved
automatically and applied on redeploy, which also tears down services
dropped from the file.
One credential per registry and organization, encrypted at rest and
managed from Settings → Organization; every image pull now goes through
pullImage, which sends the matching credential and, for ghcr.io, falls
back to the connected GitHub account (the OAuth login now asks for
read:packages). A refused pull names the registry and where to fix it.
- Deleted CreateDomainDialog and CreateUpstreamDialog components.
- Removed DomainStatusChip component and its associated styles.
- Eliminated Domains page and its related logic for managing domains.
- Removed domain error messages and status utilities.
- Updated API tests to reflect changes in domain routes to repository routes.
- Introduced autosave functionality in forms with a new useAutosave hook.
- Added SaveStatus component to display save state in forms.
A code-server sidecar per application: Open in VS Code on a repository
or a compose stack page starts a codercom/code-server container that
mounts the same files the app sees (the repository checkout, or every
named volume of the stack under its service name), joins the app's
network and the organization network, and serves on a published port
behind a generated password. The dormant codespace module gains its
job types, its handler entries and repository/install targets; stop
keeps the container down across reconciles, and the workspace goes
away with its application.

Deleting a codespace never removed its container because the row was
gone before the job ran; the ids now travel in the job payload, and
tearing down a network first disconnects whatever is still attached.
A repository can now list container paths to keep: each becomes a named
Docker volume that the deploy recreates the container around, so data
written outside /app survives deploys and restarts. Deploys stop
removing volumes (they only ever held nothing before), the container
row follows the repository's list on every provision, and the settings
page gets a Persistent volumes section that saves and redeploys.

Deleting a repository used to leave its container, ports, network and
deployments behind; repository.deleted now queues a teardown job that
removes them together with the volumes.
After the source is fetched, a .env at the repository's root directory
is parsed with dotenv and every variable the user has not set in the
Environment tab is added to the deployment, so a fresh repository
starts with its own defaults and values set in the panel keep winning.
Rendered from the interface's own fonts and tokens over a real
Applications screenshot, with the template catalogue under the title;
light and dark variants served through a picture element.
Applications, templates, logs, shell, compose editor, environment,
account and organization settings, captured in dark mode from the
running stack; the six captures of the old interface are gone.
Deploying Quantum with Docker comes first, then the features, then where the
data lives and how to develop. Sections that documented the old UI (NGINX
walkthrough, Namecheap, storage screenshots, GitHub OAuth screenshots) are
gone with their images; what remains describes the current stack: dashboard
ports bound to localhost, HTTPS through Traefik with PANEL_HOST, the template
seed command, compose stacks, internal addresses, registries and VS Code.
Copilot AI lite review requested due to automatic review settings September 6, 2026 19:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@rodyherrera
rodyherrera merged commit 44f1377 into main Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants