Skip to content

Dashboard SSR resolves runtime URLs per project (N+1 network calls) #65

@pablopunk

Description

@pablopunk

Context

At commit 3531916, src/pages/index.astro:21-32 does:

const projects = await getProjectsByUserId(user.id);
const projectsWithPreviewUrls = await Promise.all(
  projects.map(async (project) => {
    const urls = await getProjectRuntimeUrls(project);
    ...
  }),
);

getProjectRuntimeUrls (src/server/projects/projectUrls.ts:39-41) performs Tailscale URL resolution (network/IO) per project. With N projects that's 1 query + 2N resolutions blocking SSR of the dashboard — the page everyone lands on. This also brushes against the AGENTS.md rule: "Prefer client-side fetching/hydration for large or potentially unbounded payloads".

Related minor instance in the same theme: src/pages/monitor.astro:53-56 selects ALL non-deleted projects without an owner filter for container mapping. Harmless single-user, but it violates the same rule and will be wrong post-multi-user — add the owner filter while you're here.

What to do

Pick the cheapest approach that fits the codebase:

  1. Preferred: cache the Tailscale base URL/hostname resolution (it's instance-wide, not per-project) so getProjectRuntimeUrls becomes pure string construction per project. Look inside src/server/projects/projectUrls.ts and src/server/tailscale/ to see what's actually network-bound vs derivable; there is an existing TTL-cache utility pattern in src/server/cache/ to follow.
  2. Alternatively, SSR only the project list and hydrate preview URLs client-side (repo rule: SSE/fetch, no polling).

Also: add eq(projects.ownerUserId, user.id) to the monitor.astro projects query.

Acceptance criteria

  • Dashboard SSR does at most O(1) network calls for URL resolution regardless of project count (verify by logging or timing with several projects).
  • Preview/production URLs shown on the dashboard are unchanged for running projects.
  • pnpm check passes (see verification-baseline issue).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions