Skip to content

✅ server: use single postgres instance for test#610

Merged
cruzdanilo merged 1 commit intomainfrom
postgres
Dec 31, 2025
Merged

✅ server: use single postgres instance for test#610
cruzdanilo merged 1 commit intomainfrom
postgres

Conversation

@cruzdanilo
Copy link
Member

@cruzdanilo cruzdanilo commented Dec 30, 2025

Summary by CodeRabbit

  • Tests

    • Standardized tests to use fixed credential IDs and removed test-time DB mock.
    • Added a shared embedded PostgreSQL setup for test environments.
  • Chores

    • Switched test infrastructure from the previous lightweight DB to embedded PostgreSQL.
    • Enabled coverage reporting, extended test timeouts, and updated test startup behavior.
  • Misc

    • Added changelog metadata entry (non-functional).

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Dec 30, 2025

🦋 Changeset detected

Latest commit: db322a6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR replaces the test-time PGlite mock with an embedded PostgreSQL setup for tests, adds a test database globalSetup utility, updates vitest configuration and devDependencies, removes the mock database module, and adjusts many tests to use fixed credential IDs and the real DB setup.

Changes

Cohort / File(s) Summary
Embedded PostgreSQL infrastructure
patches/embedded-postgres.patch, server/test/database.ts
Adds a patch removing a graceful shutdown hook and a new server/test/database.ts globalSetup that starts EmbeddedPostgres, deploys Drizzle schema, derives/inserts test credentials, and returns an async teardown.
Vitest config & globalSetup
server/vitest.config.mts
Adds test/database.ts to globalSetup, enables coverage (lcov), sets test/hook timeouts, updates POSTGRES_URL to a full connection string, and reorganizes e2e conditional settings.
DevDependencies / package changes
server/package.json, package.json
Removes @electric-sql/pglite; adds embedded-postgres, wait-on, @types/wait-on; reorders/introduces embedded-postgres.patch in root patchedDependencies; updates nx outputs pattern.
Mock removal
server/test/mocks/database.ts
Removes the mock database module that previously provided a PGlite-based Drizzle instance and schema application for tests.
Test updates — credential/id refactor
server/test/api/activity.test.ts, server/test/api/auth.test.ts, server/test/api/kyc.test.ts, server/test/hooks/activity.test.ts, server/test/hooks/panda.test.ts, server/test/hooks/persona.test.ts
Remove mock imports and dynamic account derivation; switch tests to use fixed string credential IDs (e.g., bob, activity, default, eth, sig, 404) and adjust headers, DB queries, and expectations accordingly.
Test updates — card tests & fixtures
server/test/api/card.test.ts
Replace address/UUID-based IDs with string public IDs (eth, default, sig, 404), update seeding, keeper interactions, requests, expectations, and simplify cleanup.
Release metadata
.changeset/ready-experts-fly.md
Adds a new changeset file (contains divider lines).

Sequence Diagram(s)

sequenceDiagram
    participant Vitest as Vitest (test runner)
    participant GlobalSetup as test/database.ts (globalSetup)
    participant EmbeddedPG as EmbeddedPostgres
    participant Drizzle as Drizzle ORM
    participant FS as Filesystem / Artifact
    participant Shutdown as Detached shutdown helper

    Vitest->>GlobalSetup: invoke global setup
    GlobalSetup->>FS: remove existing pg-data dir
    GlobalSetup->>EmbeddedPG: start instance (persisted dir)
    EmbeddedPG-->>GlobalSetup: connection info / ready
    GlobalSetup->>Shutdown: spawn detached shutdown helper
    GlobalSetup->>Drizzle: connect with DB URL and schema
    Note over GlobalSetup,Drizzle: suppress stdout during schema push
    GlobalSetup->>Drizzle: deploy schema (schema.push)
    Drizzle-->>GlobalSetup: schema deployed
    GlobalSetup->>FS: read factory artifact JSON
    FS-->>GlobalSetup: factory artifact (address, owner)
    GlobalSetup->>GlobalSetup: derive test account from factory/owner
    GlobalSetup->>Drizzle: insert test credentials row(s)
    Drizzle-->>GlobalSetup: credentials persisted
    GlobalSetup-->>Vitest: return teardown fn
    Note over Vitest,EmbeddedPG: tests run against real Postgres
    Vitest->>GlobalSetup: invoke teardown
    GlobalSetup->>EmbeddedPG: stop instance
    EmbeddedPG-->>Vitest: stopped / cleanup complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • nfmelendez

Pre-merge checks and finishing touches

✅ 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 clearly and specifically summarizes the main change: migrating server tests to use a single shared PostgreSQL instance instead of multiple instances.
✨ 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 postgres

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

@gemini-code-assist
Copy link

Summary of Changes

Hello @cruzdanilo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly overhauls the server's testing infrastructure by transitioning from an in-memory pglite database to a dedicated embedded-postgres instance. This change aims to improve the reliability and fidelity of tests by running them against a full-fledged PostgreSQL database, mirroring production environments more closely. The update centralizes database management for tests, streamlining setup and teardown processes and reducing boilerplate in individual test suites.

Highlights

  • Database Testing Environment Refactor: The testing setup for the server has been refactored to use a single embedded-postgres instance instead of pglite, providing a more robust and consistent PostgreSQL environment for tests.
  • Centralized Database Setup: A new global setup file (server/test/database.ts) has been introduced to handle the initialization, schema application, and seeding of the embedded PostgreSQL database, simplifying individual test files.
  • Dependency Updates: The embedded-postgres package has been added as a development dependency, along with a patch to modify its behavior, and pglite has been removed.
  • Test File Simplification: Numerous test files across the server/test/api and server/test/hooks directories have been updated to remove direct database mocking and simplify credential/account handling, leveraging the new global database setup.
  • Vitest Configuration Enhancements: The vitest.config.mts file has been updated to include the new global database setup, configure test and hook timeouts, and add coverage reporting.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a significant improvement to the testing infrastructure. It replaces pglite with a single embedded-postgres instance for all tests, which will make the tests more reliable and closer to the production environment. The centralization of test data setup in server/test/database.ts and the cleanup of individual test files are excellent changes that improve maintainability and readability.

I've left a few comments on potential improvements, mostly related to making the new test setup even more robust and fixing a minor inconsistency in one of the updated tests. Overall, this is a great piece of work.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/test/api/card.test.ts (1)

172-191: Bug: Query targets wrong credential ID.

The test posts with "test-credential-id": "sig" but queries for "default". This should query for the newly created card associated with "sig".

🔎 Proposed fix
     const created = await database.query.cards.findFirst({
       columns: { mode: true },
-      where: eq(cards.credentialId, "default"),
+      where: eq(cards.credentialId, "sig"),
     });
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7802d7f and 2bc090b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • .changeset/ready-experts-fly.md
  • package.json
  • patches/embedded-postgres.patch
  • server/.gitignore
  • server/package.json
  • server/test/api/activity.test.ts
  • server/test/api/auth.test.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/database.ts
  • server/test/hooks/activity.test.ts
  • server/test/hooks/panda.test.ts
  • server/test/hooks/persona.test.ts
  • server/test/mocks/database.ts
  • server/vitest.config.mts
💤 Files with no reviewable changes (4)
  • server/test/hooks/panda.test.ts
  • server/test/hooks/activity.test.ts
  • server/test/mocks/database.ts
  • server/test/api/auth.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
server/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/server.mdc)

server/**/*.ts: Use c.var object to pass strongly-typed data between Hono middleware and route handlers; do not use c.set
All request validation (headers, body, params) must be handled by @hono/valibot-validator middleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwing new HTTPException() for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLint plugin:n/recommended configuration
Enforce Drizzle ORM best practices using ESLint plugin:drizzle/all configuration, including requiring where clauses for update and delete operations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not access process.env directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; use async/await correctly and be mindful of CPU-intensive tasks to prevent blocking the event loop

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
**/*.{js,ts,tsx,jsx,sol}

📄 CodeRabbit inference engine (AGENTS.md)

Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No any type.

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Omit redundant type names in variable declarations - let the type system explain itself

**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas using type User = v.Input<typeof UserSchema> instead of manually defining interfaces

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation

**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Prefer const for all variable declarations by default; only use let if the variable's value will be reassigned
Declare each variable on its own line with its own const or let keyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always use import type { ... } for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), and for...of loops over traditional syntax
Do not use abbreviations or cryptic names; write out full words like error, parameters, request instead of err, params, req
Use Number.parseInt() instead of the global parseInt() function when parsing numbers
All classes called with new must use PascalCase
Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead of the deprecated new Buffer()
Use @ts-expect-error instead of @ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like - or :
Do not include the type in a variable's name; let the static type system do its job (e.g., use const user: User not const userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
server/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use c.var.db

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

For files with a single default export, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word

Files:

  • server/test/api/activity.test.ts
  • server/test/database.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
**/.changeset/*.md

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Use a lowercase sentence in the imperative present tense for changeset summaries

Files:

  • .changeset/ready-experts-fly.md
🧠 Learnings (13)
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Zero config local dev environment: no `.env` files, mock all external services

Applied to files:

  • server/test/api/activity.test.ts
  • server/vitest.config.mts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Applies to server/**/*.{ts,tsx} : Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use `c.var.db`

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/database/schema.ts : Database schema must be defined in `server/database/schema.ts` as the single source of truth for database structure

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/database/schema.ts : Define relations explicitly in the schema file to enable Drizzle to generate typed query results including related entities

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Enforce Drizzle ORM best practices using ESLint `plugin:drizzle/all` configuration, including requiring `where` clauses for `update` and `delete` operations

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Server (exactly/server) uses Hono (framework), Node.js, Drizzle ORM (database), and PostgreSQL

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Do not access `process.env` directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context

Applied to files:

  • server/vitest.config.mts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Use `nx` for running tasks (build, lint, test, e2e) instead of underlying tooling directly

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Test files must end with .t.sol and mirror the name of the contract they test (e.g., ExaPlugin.sol -> ExaPlugin.t.sol)

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Design all tests to run without `.env` files or external services

Applied to files:

  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Use vm.prank to simulate calls from different addresses; avoid changing msg.sender through other means

Applied to files:

  • server/test/api/kyc.test.ts
  • server/test/hooks/persona.test.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/api/**/*.ts : The database client (`db`) should be passed via Hono's context (`c.var.db`), not imported directly into route handlers

Applied to files:

  • server/test/api/kyc.test.ts
🧬 Code graph analysis (4)
server/test/api/activity.test.ts (4)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
.maestro/src/server.ts (1)
  • activity (20-46)
server/api/activity.ts (8)
  • DebitActivity (473-476)
  • DebitActivity (585-585)
  • CreditActivity (478-488)
  • CreditActivity (584-584)
  • InstallmentsActivity (490-515)
  • InstallmentsActivity (587-587)
  • PandaActivity (300-369)
  • PandaActivity (589-589)
server/database/schema.ts (1)
  • cards (25-34)
server/test/database.ts (1)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
server/test/api/card.test.ts (4)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
server/database/schema.ts (2)
  • credentials (9-23)
  • cards (25-34)
common/panda.ts (1)
  • SIGNATURE_PRODUCT_ID (2-2)
.maestro/src/server.ts (1)
  • keeper (130-130)
server/test/hooks/persona.test.ts (1)
server/database/schema.ts (1)
  • credentials (9-23)
🔇 Additional comments (21)
server/.gitignore (1)

7-8: LGTM!

The pg-data ignore rule is correctly added to prevent committing the embedded PostgreSQL data directory created during test runs.

package.json (1)

234-235: LGTM!

The embedded-postgres patch entry is correctly added to patchedDependencies.

server/test/api/activity.test.ts (3)

20-23: LGTM!

The fixed account derivation using padHex("0xb0b") simplifies test setup while maintaining correctness. The account is correctly used for querying on-chain events while the "bob" credential ID is used for API authentication.


43-56: LGTM!

The test correctly uses the fixed "bob" credential ID for authentication, simplifying the test setup without compromising test coverage.


65-66: LGTM!

The card insertion correctly associates with the "bob" credential, aligning with the simplified test credential flow.

server/test/hooks/persona.test.ts (2)

23-25: LGTM!

Good improvement using camelCase "pandaId" instead of kebab-case "panda-id", and simplifying the mock sessionKey value.


262-262: LGTM!

Setting the default referenceId to "bob" aligns with the standardized test credential flow. Individual tests correctly override this when testing different scenarios (e.g., line 76 for the "already-created" credential test).

server/test/api/kyc.test.ts (3)

16-16: LGTM!

Simplified test setup that removes complex account derivation while maintaining test isolation through mock restoration.


19-46: LGTM!

The test correctly uses the fixed "bob" credential for all database operations and authentication, simplifying the test while maintaining coverage.


87-87: LGTM!

The mock assertion correctly verifies that getInquiry is called with the "bob" credential ID.

server/package.json (2)

145-145: Clarify the NX outputs path change.

The generate:broadcasts outputs path changed from a specific Protocol.s.sol path to a wildcard pattern */31337/run-latest.json. While this makes the configuration more flexible, it seems unrelated to the PostgreSQL migration. Is this an intentional improvement, or should it be in a separate PR?


68-83: No action needed. Verification confirms that embedded-postgres does not have a stable (non-beta) release available—only beta versions are published. Using embedded-postgres@^18.1.0-beta.15 for test infrastructure is the appropriate choice.

patches/embedded-postgres.patch (1)

9-10: Confirm explicit PostgreSQL shutdown is properly integrated with test framework.

The patch removes automatic graceful shutdown hook registration (AsyncExitHook(gracefulShutdown)), which eliminates automatic cleanup on process exit. The explicit teardown at lines 63-65 in server/test/database.ts correctly calls await postgres.stop() and is properly returned from the setup function. However, verify that this teardown is registered with the test framework's lifecycle hooks (e.g., afterAll) to ensure it executes consistently across all test runs. Without the AsyncExitHook safety net, orphaned PostgreSQL processes can occur if teardown fails to execute.

server/test/api/card.test.ts (3)

23-37: LGTM! Clean test data setup with fixed credential IDs.

The simplified approach using string-based credential IDs makes the test setup more readable and maintainable compared to derived addresses.


60-60: LGTM!

Simplified cleanup that relies on mock restoration. Test isolation is maintained through unique IDs for additional inserts.


271-301: LGTM!

Templates updated to use consistent string identifiers that align with the test credential setup.

server/test/database.ts (2)

36-43: Pragmatic workaround for noisy output.

Suppressing stdout during schema push is unconventional but acceptable for test setup. Be aware that any errors during this phase won't be visible in stdout.


63-65: LGTM!

Clean teardown pattern that properly stops the embedded PostgreSQL instance.

server/vitest.config.mts (3)

7-10: LGTM!

Good configuration additions:

  • test/database.ts in globalSetup integrates the embedded PostgreSQL setup.
  • Timeouts of ~37s appropriately accommodate the waitOn timeouts (33s) in database setup.
  • Coverage with lcov reporter enables CI integration.

31-31: LGTM!

POSTGRES_URL updated to match the embedded PostgreSQL connection string defined in test/database.ts.


38-42: LGTM!

E2E configuration properly disables the summary reporter to reduce noise during end-to-end test runs.

@cruzdanilo
Copy link
Member Author

@cursor review

@sentry
Copy link

sentry bot commented Dec 31, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.38%. Comparing base (7802d7f) to head (db322a6).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #610      +/-   ##
==========================================
+ Coverage   49.19%   53.38%   +4.18%     
==========================================
  Files          41       48       +7     
  Lines        7096     7772     +676     
  Branches      522      624     +102     
==========================================
+ Hits         3491     4149     +658     
- Misses       3589     3607      +18     
  Partials       16       16              
Flag Coverage Δ
github 53.28% <ø> (+4.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc090b and c12b4f8.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • .changeset/ready-experts-fly.md
  • package.json
  • patches/embedded-postgres.patch
  • server/package.json
  • server/test/api/activity.test.ts
  • server/test/api/auth.test.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/database.ts
  • server/test/hooks/activity.test.ts
  • server/test/hooks/panda.test.ts
  • server/test/hooks/persona.test.ts
  • server/test/mocks/database.ts
  • server/vitest.config.mts
💤 Files with no reviewable changes (4)
  • server/test/api/auth.test.ts
  • server/test/mocks/database.ts
  • server/test/hooks/panda.test.ts
  • server/test/hooks/activity.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/.changeset/*.md

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Use a lowercase sentence in the imperative present tense for changeset summaries

Files:

  • .changeset/ready-experts-fly.md
server/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/server.mdc)

server/**/*.ts: Use c.var object to pass strongly-typed data between Hono middleware and route handlers; do not use c.set
All request validation (headers, body, params) must be handled by @hono/valibot-validator middleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwing new HTTPException() for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLint plugin:n/recommended configuration
Enforce Drizzle ORM best practices using ESLint plugin:drizzle/all configuration, including requiring where clauses for update and delete operations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not access process.env directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; use async/await correctly and be mindful of CPU-intensive tasks to prevent blocking the event loop

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
**/*.{js,ts,tsx,jsx,sol}

📄 CodeRabbit inference engine (AGENTS.md)

Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No any type.

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Omit redundant type names in variable declarations - let the type system explain itself

**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas using type User = v.Input<typeof UserSchema> instead of manually defining interfaces

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation

**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Prefer const for all variable declarations by default; only use let if the variable's value will be reassigned
Declare each variable on its own line with its own const or let keyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always use import type { ... } for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), and for...of loops over traditional syntax
Do not use abbreviations or cryptic names; write out full words like error, parameters, request instead of err, params, req
Use Number.parseInt() instead of the global parseInt() function when parsing numbers
All classes called with new must use PascalCase
Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead of the deprecated new Buffer()
Use @ts-expect-error instead of @ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like - or :
Do not include the type in a variable's name; let the static type system do its job (e.g., use const user: User not const userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
server/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use c.var.db

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

For files with a single default export, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
🧠 Learnings (19)
📚 Learning: 2025-12-31T00:23:55.034Z
Learnt from: cruzdanilo
Repo: exactly/exa PR: 610
File: .changeset/ready-experts-fly.md:1-2
Timestamp: 2025-12-31T00:23:55.034Z
Learning: In the exactly/exa repository, allow and require empty changeset files (containing only --- separators) when changes are not user-facing and do not warrant a version bump. This is needed because CI runs changeset status --since origin/main and requires a changeset file to exist. Ensure such empty changesets are used only for non-user-facing changes and document the rationale in the commit or changelog notes.

Applied to files:

  • .changeset/ready-experts-fly.md
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/.changeset/*.md : Use a lowercase sentence in the imperative present tense for changeset summaries

Applied to files:

  • .changeset/ready-experts-fly.md
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: When implementing changes, follow all rules in `.mdc` files for any code, documentation, or rules you create, including meta-rules like the lowercase prose convention

Applied to files:

  • .changeset/ready-experts-fly.md
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Use vm.prank to simulate calls from different addresses; avoid changing msg.sender through other means

Applied to files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Design all tests to run without `.env` files or external services

Applied to files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Zero config local dev environment: no `.env` files, mock all external services

Applied to files:

  • server/test/api/kyc.test.ts
  • server/vitest.config.mts
  • server/test/api/activity.test.ts
  • server/test/api/card.test.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/api/**/*.ts : The database client (`db`) should be passed via Hono's context (`c.var.db`), not imported directly into route handlers

Applied to files:

  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Do not access `process.env` directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context

Applied to files:

  • server/vitest.config.mts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Applies to server/**/*.{ts,tsx} : Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use `c.var.db`

Applied to files:

  • server/package.json
  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Enforce Node.js best practices using ESLint `plugin:n/recommended` configuration

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Use `nx` for running tasks (build, lint, test, e2e) instead of underlying tooling directly

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Test files must end with .t.sol and mirror the name of the contract they test (e.g., ExaPlugin.sol -> ExaPlugin.t.sol)

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/database/schema.ts : Database schema must be defined in `server/database/schema.ts` as the single source of truth for database structure

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/database/schema.ts : Define relations explicitly in the schema file to enable Drizzle to generate typed query results including related entities

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Enforce Drizzle ORM best practices using ESLint `plugin:drizzle/all` configuration, including requiring `where` clauses for `update` and `delete` operations

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Prefer self-documenting code; avoid comments explaining 'what' the code does; comments should explain 'why' code is written a certain way

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-31T00:20:09.555Z
Learnt from: cruzdanilo
Repo: exactly/exa PR: 610
File: server/test/database.ts:56-60
Timestamp: 2025-12-31T00:20:09.555Z
Learning: In server code: SIWE credentials store the Ethereum address as `publicKey` (20 bytes via `hexToBytes(address)`). The `decodePublicKey` utility has special handling for 20-byte inputs that bypasses COSE decoding, padding to 32 bytes for x-coordinate and using zero bytes for y-coordinate. Only passkey/WebAuthn credentials use COSE-encoded public keys.

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Server (exactly/server) uses Hono (framework), Node.js, Drizzle ORM (database), and PostgreSQL

Applied to files:

  • server/test/database.ts
🧬 Code graph analysis (5)
server/test/hooks/persona.test.ts (1)
server/database/schema.ts (1)
  • credentials (9-23)
server/test/api/kyc.test.ts (2)
server/database/schema.ts (1)
  • credentials (9-23)
server/utils/persona.ts (2)
  • getInquiry (44-55)
  • getAccount (36-42)
server/test/api/activity.test.ts (2)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
server/database/schema.ts (1)
  • cards (25-34)
server/test/api/card.test.ts (3)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
server/database/schema.ts (2)
  • credentials (9-23)
  • cards (25-34)
common/panda.ts (1)
  • SIGNATURE_PRODUCT_ID (2-2)
server/test/database.ts (1)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
🔇 Additional comments (30)
server/test/hooks/persona.test.ts (6)

1-17: LGTM: Import simplification aligns with test migration.

The removal of account derivation imports and beforeAll hook is consistent with the PR's goal of using fixed credential IDs instead of derived accounts. This simplifies the test setup significantly.


52-88: LGTM: Test properly isolates its own data.

This test correctly creates its own credential with a unique ID and verifies that the webhook handler skips Panda account creation when pandaId already exists. The test is self-contained and clear.


90-239: LGTM: Error handling tests are comprehensive.

The tests properly verify:

  • Missing credential scenario with mocked database query
  • Invalid payload validation with appropriate error messages
  • Webhook convention of returning 200 for all cases while logging errors

The use of eslint-disable unicorn/no-useless-undefined on line 91 is appropriate for explicitly mocking a return value.


242-262: LGTM: Payload referenceId aligns with fixed credential approach.

The change from "reference-123" to "bob" on line 262 is consistent with the PR's migration to fixed credential IDs. This matches the credential ID used in the test query on line 43.


42-45: Document or verify the "bob" credential setup.

This test queries for a credential with id: "bob" but doesn't create it within the test. This implies the credential is created in a global test setup (consistent with the PR's centralized test database approach). However, this dependency is not immediately clear from reading this test file.

Consider either:

  1. Adding a comment explaining that "bob" is created in the global test setup
  2. Verifying that the test database setup in server/test/database.ts properly creates this credential
#!/bin/bash
# Verify that test database setup creates the "bob" credential
rg -n -C5 'bob.*credential|insert.*credentials.*bob' server/test/

25-25: No action needed. The change from "test-session-123" to "test" for the sessionKey mock value is safe and follows best practices.

The sessionKey validation only requires a string type with max 100 characters. Both values pass validation. More importantly, the mock's sessionKey value is not used in application logic—real session keys come from the request payload. The test has no assertions on sessionKey, so using simpler mock data is actually preferable.

package.json (1)

234-235: LGTM!

The embedded-postgres patch entry correctly supports the new test infrastructure migration.

server/package.json (2)

68-68: LGTM!

The new dependencies correctly support the embedded PostgreSQL test infrastructure. The addition of wait-on and its types will help ensure the database is ready before tests execute.

Also applies to: 73-73, 83-83


145-145: LGTM!

The wildcard pattern provides flexibility for multiple deployment scripts while maintaining the same directory structure requirement.

server/test/api/activity.test.ts (3)

20-23: LGTM!

The fixed account constant using "bob" credentials provides deterministic test behavior and simplifies test setup.


40-56: LGTM!

The validation tests correctly use distinct credential IDs: "activity" for error cases and "bob" for successful authentication flows.


65-66: LGTM!

The card setup correctly references the fixed "bob" credential, maintaining consistency with the new test infrastructure approach.

server/test/api/kyc.test.ts (2)

19-19: LGTM!

The database operations correctly reference the fixed "bob" credential ID, relying on the global test setup for credential seeding.

Also applies to: 49-49, 65-65


87-87: LGTM!

All Persona API function calls consistently use "bob" as the reference ID, maintaining alignment with the fixed credential approach.

Also applies to: 107-107, 131-132, 155-155

server/vitest.config.mts (4)

7-7: LGTM!

The addition of test/database.ts to globalSetup correctly integrates the embedded PostgreSQL instance into the test lifecycle.


8-10: LGTM!

Coverage reporting enabled and timeouts increased appropriately for database and blockchain setup operations in tests.


31-31: LGTM!

The full PostgreSQL connection string correctly configures the embedded instance with appropriate test credentials and disabled SSL for the local environment.


38-42: LGTM!

The e2e-specific configuration appropriately customizes test discovery and reporting for end-to-end test scenarios.

server/test/api/card.test.ts (5)

24-57: LGTM!

The test setup effectively uses a hybrid approach: fixed credential IDs for most tests and a derived account for blockchain operations. This balances test simplicity with realistic blockchain interaction testing.


62-142: LGTM!

The card retrieval tests correctly use distinct credential IDs for different product types (platinum vs signature) and error scenarios.


172-191: LGTM!

The card creation test correctly uses "sig" credential for both the request and database query, addressing the previous review feedback.


236-267: LGTM!

The migration tests correctly handle card upgrades using the "default" credential, ensuring proper card lifecycle management during migrations.


271-301: LGTM!

The test templates have been appropriately updated to use simplified IDs that align with the fixed credential approach.

patches/embedded-postgres.patch (1)

9-10: No action needed—cleanup is properly handled.

The removal of AsyncExitHook(gracefulShutdown) is intentional for the test environment. The server/test/database.ts setup function provides explicit cleanup: the returned teardown() function calls postgres.stop(), the database client is closed with database.$client.end(), and a spawned child process ensures the postgres instance is killed even if teardown is not called.

server/test/database.ts (6)

1-13: LGTM: Imports are well-organized.

All imports follow the project guidelines with proper use of import type for type-only imports and relative paths for project files.


15-23: LGTM: Database initialization follows best practices.

The setup properly cleans up any existing data and configures the embedded PostgreSQL instance with appropriate test settings.


39-48: LGTM: Proper service readiness handling.

The explicit wait for PostgreSQL on port 5432 (Line 39) ensures the database is ready before schema operations, preventing race conditions during test setup. The parallel execution of schema push and Anvil readiness check is efficient.


50-60: LGTM: Robust factory address extraction with validation.

Using Valibot for runtime validation of the factory JSON structure provides type safety and clear error messages if the deployment output format changes.


61-66: LGTM: Test fixture setup with proper cleanup.

The test credential setup correctly uses SIWE-compatible public key format (20-byte address), and properly closes the database connection after inserting the test data.


68-70: LGTM: Clean teardown implementation.

The teardown function properly stops the embedded PostgreSQL instance, ensuring test resources are cleaned up after the test suite completes.

@cruzdanilo
Copy link
Member Author

@cursor review

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: 2

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c12b4f8 and db322a6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • .changeset/ready-experts-fly.md
  • package.json
  • patches/embedded-postgres.patch
  • server/package.json
  • server/test/api/activity.test.ts
  • server/test/api/auth.test.ts
  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/database.ts
  • server/test/hooks/activity.test.ts
  • server/test/hooks/panda.test.ts
  • server/test/hooks/persona.test.ts
  • server/test/mocks/database.ts
  • server/vitest.config.mts
💤 Files with no reviewable changes (4)
  • server/test/hooks/panda.test.ts
  • server/test/hooks/activity.test.ts
  • server/test/mocks/database.ts
  • server/test/api/auth.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
server/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/server.mdc)

server/**/*.ts: Use c.var object to pass strongly-typed data between Hono middleware and route handlers; do not use c.set
All request validation (headers, body, params) must be handled by @hono/valibot-validator middleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwing new HTTPException() for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLint plugin:n/recommended configuration
Enforce Drizzle ORM best practices using ESLint plugin:drizzle/all configuration, including requiring where clauses for update and delete operations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not access process.env directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; use async/await correctly and be mindful of CPU-intensive tasks to prevent blocking the event loop

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
**/*.{js,ts,tsx,jsx,sol}

📄 CodeRabbit inference engine (AGENTS.md)

Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No any type.

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Omit redundant type names in variable declarations - let the type system explain itself

**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas using type User = v.Input<typeof UserSchema> instead of manually defining interfaces

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation

**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Prefer const for all variable declarations by default; only use let if the variable's value will be reassigned
Declare each variable on its own line with its own const or let keyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always use import type { ... } for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), and for...of loops over traditional syntax
Do not use abbreviations or cryptic names; write out full words like error, parameters, request instead of err, params, req
Use Number.parseInt() instead of the global parseInt() function when parsing numbers
All classes called with new must use PascalCase
Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead of the deprecated new Buffer()
Use @ts-expect-error instead of @ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like - or :
Do not include the type in a variable's name; let the static type system do its job (e.g., use const user: User not const userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
server/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use c.var.db

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

For files with a single default export, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word

Files:

  • server/test/hooks/persona.test.ts
  • server/test/api/card.test.ts
  • server/test/database.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
**/.changeset/*.md

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Use a lowercase sentence in the imperative present tense for changeset summaries

Files:

  • .changeset/ready-experts-fly.md
🧠 Learnings (16)
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Applies to server/**/*.{ts,tsx} : Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - use `c.var.db`

Applied to files:

  • server/package.json
  • server/test/database.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Use `nx` for running tasks (build, lint, test, e2e) instead of underlying tooling directly

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Test files must end with .t.sol and mirror the name of the contract they test (e.g., ExaPlugin.sol -> ExaPlugin.t.sol)

Applied to files:

  • server/package.json
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Use vm.prank to simulate calls from different addresses; avoid changing msg.sender through other means

Applied to files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Design all tests to run without `.env` files or external services

Applied to files:

  • server/test/hooks/persona.test.ts
  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Zero config local dev environment: no `.env` files, mock all external services

Applied to files:

  • server/test/api/card.test.ts
  • server/test/api/kyc.test.ts
  • server/test/api/activity.test.ts
  • server/vitest.config.mts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/database/schema.ts : Database schema must be defined in `server/database/schema.ts` as the single source of truth for database structure

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Prefer self-documenting code; avoid comments explaining 'what' the code does; comments should explain 'why' code is written a certain way

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-31T00:20:09.555Z
Learnt from: cruzdanilo
Repo: exactly/exa PR: 610
File: server/test/database.ts:56-60
Timestamp: 2025-12-31T00:20:09.555Z
Learning: In server code: SIWE credentials store the Ethereum address as `publicKey` (20 bytes via `hexToBytes(address)`). The `decodePublicKey` utility has special handling for 20-byte inputs that bypasses COSE decoding, padding to 32 bytes for x-coordinate and using zero bytes for y-coordinate. Only passkey/WebAuthn credentials use COSE-encoded public keys.

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:56:56.405Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/dev.mdc:0-0
Timestamp: 2025-12-23T19:56:56.405Z
Learning: Server (exactly/server) uses Hono (framework), Node.js, Drizzle ORM (database), and PostgreSQL

Applied to files:

  • server/test/database.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/api/**/*.ts : The database client (`db`) should be passed via Hono's context (`c.var.db`), not imported directly into route handlers

Applied to files:

  • server/test/api/kyc.test.ts
📚 Learning: 2025-12-23T19:57:35.503Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/server.mdc:0-0
Timestamp: 2025-12-23T19:57:35.503Z
Learning: Applies to server/**/*.ts : Do not access `process.env` directly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context

Applied to files:

  • server/vitest.config.mts
📚 Learning: 2025-12-31T00:23:55.034Z
Learnt from: cruzdanilo
Repo: exactly/exa PR: 610
File: .changeset/ready-experts-fly.md:1-2
Timestamp: 2025-12-31T00:23:55.034Z
Learning: In the exactly/exa repository, allow and require empty changeset files (containing only --- separators) when changes are not user-facing and do not warrant a version bump. This is needed because CI runs changeset status --since origin/main and requires a changeset file to exist. Ensure such empty changesets are used only for non-user-facing changes and document the rationale in the commit or changelog notes.

Applied to files:

  • .changeset/ready-experts-fly.md
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/.changeset/*.md : Use a lowercase sentence in the imperative present tense for changeset summaries

Applied to files:

  • .changeset/ready-experts-fly.md
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: When implementing changes, follow all rules in `.mdc` files for any code, documentation, or rules you create, including meta-rules like the lowercase prose convention

Applied to files:

  • .changeset/ready-experts-fly.md
🧬 Code graph analysis (4)
server/test/hooks/persona.test.ts (1)
server/database/schema.ts (1)
  • credentials (9-23)
server/test/database.ts (1)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
server/test/api/kyc.test.ts (3)
server/database/schema.ts (1)
  • credentials (9-23)
server/utils/persona.ts (2)
  • getInquiry (44-55)
  • getAccount (36-42)
.maestro/src/server.ts (1)
  • persona (92-128)
server/test/api/activity.test.ts (4)
common/deriveAddress.ts (1)
  • deriveAddress (18-55)
.maestro/src/server.ts (1)
  • activity (20-46)
server/api/activity.ts (8)
  • DebitActivity (473-476)
  • DebitActivity (585-585)
  • CreditActivity (478-488)
  • CreditActivity (584-584)
  • InstallmentsActivity (490-515)
  • InstallmentsActivity (587-587)
  • PandaActivity (300-369)
  • PandaActivity (589-589)
server/database/schema.ts (1)
  • cards (25-34)
🔇 Additional comments (13)
.changeset/ready-experts-fly.md (1)

1-2: Empty changeset is appropriate for this test infrastructure change.

Based on learnings, this empty changeset correctly signals that no version bump is needed while satisfying the CI requirement for changeset status --since origin/main.

package.json (1)

234-235: LGTM!

The patched dependencies are correctly configured to apply the embedded-postgres patch across the monorepo.

server/test/hooks/persona.test.ts (2)

23-24: Test data simplified with consistent IDs.

The mock data now uses simpler, more consistent identifiers ("pandaId" and "test" instead of "panda-id" and "test-session-123"), improving test readability.


42-42: The "bob" credential is properly seeded in the global test setup in test/database.ts (lines 58-62), where it is inserted with id: "bob" and pandaId: "pandaId". The test dependency is satisfied and the code is correct.

server/test/api/activity.test.ts (1)

20-23: Good separation of account address and credential ID.

The test now correctly derives an account address for blockchain operations while using the fixed credential ID "bob" for database queries. This better reflects the production architecture where account addresses and credential IDs are distinct concepts.

server/vitest.config.mts (2)

9-10: Timeouts increased to accommodate embedded PostgreSQL.

The test and hook timeouts have been significantly increased to ~36 seconds, which is appropriate for the embedded PostgreSQL startup time. This aligns with the observed 66,666ms timeout in activity tests.


31-31: PostgreSQL connection parameters are correctly configured and match the embedded setup.

The POSTGRES_URL in vitest.config.mts (postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable) is identical to the connection string used in test/database.ts and aligns with the EmbeddedPostgres configuration (password: "postgres", port: 5432, database: postgres). The sslmode=disable parameter is appropriate for local testing.

server/test/api/kyc.test.ts (2)

7-7: Test setup significantly simplified.

The removal of beforeAll and dynamic credential generation simplifies the test lifecycle. Tests now rely on the global setup in test/database.ts, making them more maintainable.


87-87: Consistent credential ID usage across assertions.

All Persona API calls now use "bob" as the reference ID, maintaining consistency with the credential lookup. This makes the test flow easier to follow and debug.

patches/embedded-postgres.patch (1)

9-9: Shutdown is properly managed through explicit teardown.

Removing the AsyncExitHook(gracefulShutdown) registration means the embedded PostgreSQL instance will not automatically shut down on process exit. This is intentional—the test setup function explicitly manages shutdown by returning a teardown function that calls postgres.stop() (line 66 of server/test/database.ts). The setup also includes a custom process monitor that kills the postgres process with SIGINT when the test harness closes, ensuring graceful shutdown through the test framework's lifecycle rather than global exit hooks.

server/package.json (1)

73-73: Consider the implications of using a beta version in CI/CD, or document why 18.1.0-beta.15 is required.

The embedded-postgres dependency uses version 18.1.0-beta.15, which is a pre-release. While no known stability issues have been reported for this specific version, beta releases may introduce breaking changes or instability. If this version is necessary for required features, document the rationale. Otherwise, evaluate whether a stable version (e.g., 17.x) would be more appropriate for CI/CD reliability.

server/test/database.ts (1)

15-67: LGTM: Test database setup is well-structured.

The embedded PostgreSQL setup correctly:

  • Provisions a clean database instance with proper lifecycle management
  • Uses Drizzle ORM to push schema (schema-first approach)
  • Waits for service readiness before proceeding
  • Seeds test credentials with valid SIWE publicKey format (20-byte address via hexToBytes)
  • Provides proper teardown for cleanup

The implementation follows coding guidelines and properly integrates with the test infrastructure.

server/test/api/card.test.ts (1)

22-269: Test migration to string-based IDs looks good.

The test suite correctly:

  • Uses fixed string credential IDs ("eth", "default", "sig", "404") consistently throughout
  • Updates all header references and database queries to match
  • Simplifies cleanup with shared database instance (line 60)
  • Maintains proper test coverage for card operations, migration scenarios, and edge cases

The string-based approach aligns well with the single PostgreSQL instance test infrastructure.

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

Comments