Skip to content

feat: frontend API client, React scaffold, and Vite dev server#5

Merged
menny merged 5 commits into
mainfrom
feat/phase-1-frontend-client
Apr 28, 2026
Merged

feat: frontend API client, React scaffold, and Vite dev server#5
menny merged 5 commits into
mainfrom
feat/phase-1-frontend-client

Conversation

@menny
Copy link
Copy Markdown
Member

@menny menny commented Apr 28, 2026

Summary

  • Adds createApiClient — a pure factory function with injected getToken, baseUrl, and fetcher so the HTTP layer is fully testable without Firebase or Vite at module level
  • Wires Firebase Web SDK init with connectAuthEmulator in DEV mode; import.meta.env access is confined to firebase.ts and app-level callers
  • Scaffolds a minimal React 19 app (App.tsx, main.tsx, index.html) and vite.config.ts with sourcemaps
  • Adds frontend/src/vite-env.d.ts (/// <reference types="vite/client" />) so Bazel's tsc recognises import.meta.env types
  • Declares vite bins in MODULE.bazel npm_translate_lock to work around peer-dep version qualifier preventing auto-generation; exposes vite_binary(name = "dev_server") in frontend/BUILD.bazel
  • 3 Node native test runner tests: auth header attached, correct URL constructed, non-ok response throws

Test plan

  • bazel test //frontend/... — all 3 tests pass
  • bazel test //... — full suite green
  • bazel run //:format — no formatting changes
  • bazel run //frontend:dev_server — Vite starts on :5173 (requires .env.local from .env.local.example)

- createApiClient factory with injected getToken/baseUrl/fetcher for
  full testability without Firebase or Vite imports at module level
- Firebase Web SDK init with connectAuthEmulator in DEV mode
- React 19 app scaffold (App.tsx, main.tsx, index.html)
- vite-env.d.ts reference for import.meta.env types under Bazel tsc
- 3 Node native test runner tests covering auth header, URL, and error
- frontend_lib ts_project and vite_binary dev_server in BUILD.bazel
- vite bins declaration in MODULE.bazel npm_translate_lock
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

The following review focuses on the robustness and maintainability of the new frontend infrastructure. Great work on the test coverage for the API client and the migration to static environment variable access for production compatibility. Overall, the foundation for the React frontend is solid, and the testing strategy for the API client is a great pattern for the rest of the project.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

The review identifies blocking resilience and maintenance concerns in the API client, specifically around handling empty responses, fragile URL construction, and opaque error reporting.

- Read response.text() on non-ok and append to error message so server
  validation details survive to the caller
- Return undefined (not parse JSON) on 204 or content-length: 0 to
  avoid "Unexpected end of JSON input" from queue-worker trigger endpoints
- Add two tests covering the new paths
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

While error handling and 204 response logic have improved, several issues regarding URL construction safety, environment variable validation, and build configuration redundancy must be addressed.

- new URL(path, baseUrl) avoids double-slash / missing-slash edge cases
- requireEnv() throws a clear actionable error at startup if any
  VITE_FIREBASE_* var is missing, instead of cryptic Firebase SDK errors
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

The review identifies resilience issues in the API client's JSON parsing and maintenance concerns regarding redundant build targets.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

The PR establishes a solid foundation and includes good test coverage, but several items regarding build configuration, production-safe environment variable injection, and URL resolution logic need to be addressed or clarified.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

While the foundation and testing strategy are solid, there are blocking issues regarding URL construction safety in the API client and redundant build targets that need to be addressed before merging.

Comment thread README.md
bazel run //backend:dev_server

# Terminal 3 — Vite-powered React frontend (not yet implemented)
# Terminal 3 — Vite-powered React frontend (http://localhost:5173)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The PR description still mentions "3 Node native test runner tests," but the implementation (and the previous audit) correctly identifies 5 tests in frontend/index.test.ts. Please update the summary to reflect the excellent additional coverage.

Comment thread frontend/src/apiClient.ts
return {
async post<T>(path: string, body?: unknown): Promise<T> {
const token = await getToken();
const response = await fetcher(new URL(path, baseUrl).toString(), {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The new URL(path, baseUrl) constructor has a well-known pitfall regarding leading and trailing slashes. If baseUrl is http://api/v1 (no trailing slash), v1 is dropped. If path is /ping (leading slash), the entire path of baseUrl is replaced by the root. Given our reliance on environment variables for baseUrl, this is highly likely to cause silent misconfigurations. We should either sanitize the inputs (e.g., baseUrl.replace(//$/, '') + '/' + path.replace(/^//, '')) or use a robust joining utility.

Comment thread frontend/BUILD.bazel
Comment on lines 4 to 17

ts_project(
name = "frontend",
srcs = glob(
["*.ts"],
exclude = ["*.test.ts"],
exclude = [
"*.test.ts",
"vite.config.ts",
],
),
declaration = True,
transpiler = "tsc",
tsconfig = "tsconfig.json",
visibility = ["//visibility:public"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As noted in previous feedback, the frontend target (and the accompanying frontend/index.ts) appears to be a redundant shell now that the source logic has moved into src/ and frontend_lib. We should remove this target and the index.ts file to keep the Bazel build graph clean and avoid developer confusion.

Comment thread frontend/src/firebase.ts
export const auth = getAuth(app);

if (import.meta.env.DEV) {
connectAuthEmulator(auth, 'http://localhost:9099', { disableWarnings: true });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Firebase Auth emulator URL remains hardcoded to http://localhost:9099. While this is the default, our README.md already suggests using FIREBASE_AUTH_EMULATOR_HOST. We should make this configurable via a VITE_ environment variable to ensure developers in containerized or custom environments can connect their frontend to the local services.

Comment thread frontend/src/apiClient.ts
Comment on lines +18 to +20
const detail = await response.text().catch(() => '');
throw new Error(
`HTTP ${response.status}${detail ? `: ${detail}` : ''}`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In the error path, response.text() is used to provide detail. If the server (or a proxy) returns a large HTML error page instead of a short string, the thrown Error message could become unwieldy. Consider truncating the detail string to a reasonable length (e.g., 200 characters) before including it in the error message.

Comment thread frontend/BUILD.bazel
],
entry_point = "index.test.js",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The dev_server target includes glob(["src/**"]) in its data. Since frontend_lib also depends on these files, this is slightly redundant, though it ensures Vite has access to the raw .tsx files for transformation. It's acceptable as-is but worth a note for future refactors of the frontend build rules.

@menny menny merged commit 6a1bfed into main Apr 28, 2026
2 checks passed
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.

1 participant