Skip to content

Conversation

@gentamura
Copy link
Member

@gentamura gentamura commented Nov 12, 2025

Summary

  • adopt the newly released @listee/api 0.3.2 plus @listee/auth/@listee/types 0.5.0 so the handler stays in sync with listee-libs
  • wire the Supabase auth client and shared types from the libs instead of local copies

Testing

  • bun run lint
  • bun run build

Summary by CodeRabbit

  • New Features

    • Added authentication API endpoints for login, signup, and token refresh with validation and standardized error responses.
    • Introduced a typed environment utility and a cached Supabase auth client for server runtime use.
  • Refactor

    • Authentication integration updated to use a lazily-initialized provider and improved request error handling.
    • App config now loads environment safely during startup.
  • Documentation

    • Expanded README with architecture, env, API, and development guidance.
  • Chores

    • Updated and added dependencies to support environment validation and auth tooling.

@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

Walkthrough

Replaces environment access with a validated, cached env module; adds Supabase-based auth client and replaces header-based authentication in the API handler; introduces three POST auth endpoints (login, signup, token) with Zod validation and centralized route utilities; updates config to load env before Next.js config and bumps related dependencies.

Changes

Cohort / File(s) Summary
Documentation
README.md
Replaces one-line description with a full README covering architecture, env variables, API surface, local dev, migrations, testing, deployment, and conventions.
Environment schema & helpers
src/app/env.ts
Adds Zod/@t3-oss env schema builder, typed AppEnv, getEnv() with lazy caching, and resetEnvCache().
Config files
drizzle.config.ts, next.config.ts
drizzle.config.ts now resolves DB URL via getEnv() with guarded Zod error handling; next.config.ts exports an async function that dynamically loads env module (via jiti) before returning config.
Package manifest
package.json
Bumps @listee/* packages, adds @t3-oss/env-nextjs, drizzle-orm, zod, and dev dep jiti; updates Next/runtime deps.
Supabase auth client
src/app/supabase-auth-client.ts
New singleton factory getSupabaseAuthClient() that initializes and caches a SupabaseAuthClient using getEnv().
API handler (auth integration)
src/app/api/handler.ts
Replaces header-based auth with lazy-loaded Supabase authentication provider via getAuthentication(); invokes provider.authenticate(context); wraps dispatch in try/catch to return standardized 500 on unexpected errors.
Auth utilities
src/app/api/auth/utils.ts
New ApiError class, parseJsonBody, respondWithData, respondWithError, and handleRoute for centralized request parsing and error handling.
Auth validation
src/app/api/auth/validation.ts
New Zod schemas: trimmedNonEmpty helper, emailSchema, passwordSchema, refreshTokenSchema, loginSchema, signupSchema (optional redirectUrl URL), and tokenSchema.
Auth routes
src/app/api/auth/login/route.ts, src/app/api/auth/signup/route.ts, src/app/api/auth/token/route.ts
New POST route handlers that parse and validate request bodies, call Supabase auth client methods (login/signup/refresh), map SupabaseAuthError -> ApiError, and return structured JSON via respondWithData.
Drizzle config env handling
drizzle.config.ts
Now uses getEnv() in an IIFE to obtain POSTGRES_URL, with specific Zod error extraction and clearer error message when POSTGRES_URL is absent/invalid.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant Route as Auth Route
    participant Utils as auth/utils.ts
    participant Validation as auth/validation.ts
    participant Supabase as Supabase Auth Client
    participant Response

    Client->>Route: POST /api/auth/login {email,password}
    Route->>Utils: parseJsonBody(request, loginSchema)
    Utils->>Validation: safeParse(loginSchema)
    alt valid
        Validation-->>Utils: parsed data
        Utils-->>Route: parsed input
        Route->>Supabase: login(parsed input)
        alt success
            Supabase-->>Route: token data
            Route->>Utils: respondWithData(token,200)
            Utils-->>Response: 200 JSON
        else auth error
            Supabase-->>Route: SupabaseAuthError
            Route->>Route: convert to ApiError
            Route->>Utils: handleRoute -> respondWithError
            Utils-->>Response: error JSON (status)
        end
    else invalid
        Validation-->>Utils: first issue message
        Utils->>Response: 400 JSON error
    end
    Response-->>Client: HTTP response
Loading
sequenceDiagram
    autonumber
    participant App as Next.js
    participant Env as src/app/env.ts
    participant Cache as cachedEnv
    participant Handler as api/handler.ts
    App->>Handler: initialize/request
    Handler->>Env: getEnv()
    alt cache empty
        Env->>Env: buildEnv() / zod validate
        Env-->>Cache: store validated AppEnv
        Cache-->>Handler: AppEnv
    else cached
        Cache-->>Handler: AppEnv
    end
    Handler->>Handler: getAuthentication() (lazy) -> cached provider
    Handler->>Supabase: provider.authenticate(context)
    Handler->>App: proceed with request dispatch
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files warranting extra attention:
    • src/app/api/handler.ts — authentication provider initialization, error mapping, and request flow changes.
    • src/app/env.ts — correctness of Zod schema, defaults/coercions, and optional vs required env flags.
    • src/app/api/auth/utils.ts & validation.ts — ensure validation/parse edge cases and error messages are appropriate.
    • Integration between getSupabaseAuthClient() and route handlers — verify singleton lifecycle and no request-state leakage.

Possibly related PRs

Poem

🐰 I hopped through envs, neat and spry,
Zod wrapped my carrots, no crumbs to lie,
Tokens now tumble from a supabase tree,
Routes lined in order — tidy as can be,
I nibble the bugs, then splay a victory cry! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: aligning the API response contract with shared packages (@listee/api, @listee/auth, @listee/types), which is the core objective of the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/api-response-contract

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67bb8c0 and ebb4ba8.

📒 Files selected for processing (1)
  • src/app/env.ts (1 hunks)
🔇 Additional comments (2)
src/app/env.ts (2)

4-11: LGTM: Schema definitions are robust.

The URL and non-empty string validators are well-defined. The whitespace refinement on line 8-10 prevents accidental leading/trailing spaces in sensitive configuration values like API keys, which is a good security practice.


38-51: LGTM: Clean caching implementation.

The type inference, lazy initialization, and cache reset mechanism are well-implemented. The singleton pattern is appropriate for environment configuration, and the reset function provides testability.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gentamura gentamura self-assigned this Nov 12, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6f15ac and 67bb8c0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • README.md (1 hunks)
  • drizzle.config.ts (1 hunks)
  • next.config.ts (1 hunks)
  • package.json (1 hunks)
  • src/app/api/auth/login/route.ts (1 hunks)
  • src/app/api/auth/signup/route.ts (1 hunks)
  • src/app/api/auth/token/route.ts (1 hunks)
  • src/app/api/auth/utils.ts (1 hunks)
  • src/app/api/auth/validation.ts (1 hunks)
  • src/app/api/handler.ts (2 hunks)
  • src/app/env.ts (1 hunks)
  • src/app/supabase-auth-client.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/app/supabase-auth-client.ts (1)
src/app/env.ts (1)
  • getEnv (42-47)
src/app/api/auth/signup/route.ts (5)
src/app/api/auth/login/route.ts (1)
  • POST (12-26)
src/app/api/auth/token/route.ts (1)
  • POST (12-26)
src/app/api/auth/utils.ts (4)
  • handleRoute (41-53)
  • parseJsonBody (12-31)
  • ApiError (3-10)
  • respondWithData (33-35)
src/app/api/auth/validation.ts (1)
  • signupSchema (25-31)
src/app/supabase-auth-client.ts (1)
  • getSupabaseAuthClient (9-20)
drizzle.config.ts (1)
src/app/env.ts (1)
  • getEnv (42-47)
src/app/api/auth/token/route.ts (5)
src/app/api/auth/login/route.ts (1)
  • POST (12-26)
src/app/api/auth/signup/route.ts (1)
  • POST (12-26)
src/app/api/auth/utils.ts (4)
  • handleRoute (41-53)
  • parseJsonBody (12-31)
  • respondWithData (33-35)
  • ApiError (3-10)
src/app/api/auth/validation.ts (1)
  • tokenSchema (33-35)
src/app/supabase-auth-client.ts (1)
  • getSupabaseAuthClient (9-20)
src/app/api/auth/login/route.ts (5)
src/app/api/auth/signup/route.ts (1)
  • POST (12-26)
src/app/api/auth/token/route.ts (1)
  • POST (12-26)
src/app/api/auth/utils.ts (4)
  • handleRoute (41-53)
  • parseJsonBody (12-31)
  • respondWithData (33-35)
  • ApiError (3-10)
src/app/api/auth/validation.ts (1)
  • loginSchema (20-23)
src/app/supabase-auth-client.ts (1)
  • getSupabaseAuthClient (9-20)
src/app/api/handler.ts (1)
src/app/env.ts (1)
  • getEnv (42-47)
🪛 markdownlint-cli2 (0.18.1)
README.md

32-32: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🔇 Additional comments (11)
README.md (1)

1-73: Comprehensive documentation updates look good!

The README now provides clear guidance on architecture, environment configuration, API surface, and local development workflows. The API table is well-structured and the authentication flow is accurately described.

package.json (1)

15-24: Dependency updates align with PR objectives.

The addition of @t3-oss/env-nextjs, updated Zod to v4.1.12, and upgraded shared @Listee packages enable the centralized environment validation and Supabase auth integration. The versions appear current and compatible with Next.js 15 and React 19.

src/app/api/auth/utils.ts (1)

3-53: Well-structured API utilities with proper error handling.

The utilities provide a clean abstraction for request validation, response formatting, and error handling:

  • ApiError class correctly extends Error with a status code
  • parseJsonBody safely validates requests using Zod with appropriate error messages
  • Response helpers maintain the documented contract ({ data } for success, { error } for failures)
  • handleRoute prevents error detail leakage to clients while logging unexpected errors server-side
src/app/api/auth/token/route.ts (1)

12-26: Token refresh route correctly implements the authentication pattern.

The POST handler follows the same structure as login/signup routes with proper input validation, error translation, and standardized responses. The use of handleRoute ensures consistent error handling across all auth endpoints.

src/app/api/auth/signup/route.ts (1)

12-26: Signup route follows the established authentication pattern.

The implementation correctly validates input, handles Supabase errors, and returns a null data response on success (appropriate for signup operations that may require email confirmation before token issuance).

next.config.ts (1)

1-20: Async config correctly loads environment before Next.js starts.

The implementation uses jiti to dynamically import and validate the environment module before returning the Next.js configuration. This ensures environment variables are validated early in the startup process, following the fail-fast principle. The async config pattern is fully supported in Next.js 15.

src/app/supabase-auth-client.ts (1)

9-20: Singleton pattern with lazy initialization is appropriate here.

The cached client factory correctly initializes the Supabase auth client on first access using validated environment variables. While there's a theoretical race condition in concurrent initialization, it's benign for this use case since createSupabaseAuthClient appears to be a lightweight config wrapper and multiple instances would be functionally equivalent.

src/app/api/auth/login/route.ts (1)

12-26: Login route completes the consistent authentication trio.

The implementation follows the exact same pattern as signup and token routes, with proper validation, error translation, and standardized responses. The consistency across all three auth endpoints (/login, /signup, /token) makes the codebase maintainable and predictable.

drizzle.config.ts (1)

9-26: Nice defensive env validation upgrade.
Wrapping getEnv() in the try/catch and translating POSTGRES_URL failures into actionable messages will make Drizzle CLI errors far easier to diagnose.

src/app/api/auth/validation.ts (1)

3-35: Reusable trim helper pays off.
trimmedNonEmpty keeps the auth schemas DRY while guarding against sneaky whitespace—nice touch.

src/app/api/handler.ts (1)

78-107: Appreciate the cached auth + guarded dispatch.
Lazily memoizing the Supabase auth and standardizing the 500 fallback should make the route more resilient.

@gentamura gentamura merged commit 424a42a into main Nov 12, 2025
3 checks passed
@gentamura gentamura deleted the feat/api-response-contract branch November 12, 2025 02:50
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