Skip to content

Fix device registration#143

Merged
lourou merged 6 commits into
otr-devfrom
lr/v2-registration-fix
Oct 18, 2025
Merged

Fix device registration#143
lourou merged 6 commits into
otr-devfrom
lr/v2-registration-fix

Conversation

@lourou

@lourou lourou commented Oct 18, 2025

Copy link
Copy Markdown
Member

Fix device registration by clearing duplicate push tokens across existing registrations in src/api/v2/device/handlers/register.ts and allowing subscription without a push token in src/api/v2/notifications/handlers/subscribe.ts

This pull request introduces a helper to wrap the device registration transaction and updates the registration and subscription handlers to align with new push token handling behavior. It centralizes the clearing of duplicate push tokens during registration and adjusts the subscription flow to proceed without requiring a push token.

  • Add performDeviceRegistration helper in register.ts that clears matching pushToken values on other device registrations and upserts the current device with defaults for pushTokenType and apnsEnv
  • Update register handler in register.ts to use performDeviceRegistration and remove explicit Prisma P2002 conflict handling
  • Modify subscribe handler in subscribe.ts to skip notification installation and subscription when a device has no pushToken, logging and returning 200 regardless

📍Where to Start

Start with the performDeviceRegistration helper and its usage in the register handler in register.ts, then review the conditional subscription flow in subscribe.ts.


📊 Macroscope summarized 5ba336f. 2 files reviewed, 10 issues evaluated, 9 issues filtered, 0 comments posted

🗂️ Filtered Issues

src/api/v2/device/handlers/register.ts — 0 comments posted, 2 evaluated, 1 filtered
  • line 165: Error handling regression: previously, unique constraint violations (Prisma error code P2002) were mapped to a 409 conflict response with a specific message. The new implementation removed that handling and now falls through to the generic 500 response for all errors. This changes the externally visible contract: clients encountering a push-token registration race or constraint violation will now receive a 500 instead of a 409, losing actionable semantics and potentially breaking client error handling logic. [ Low confidence ]
src/api/v2/notifications/handlers/subscribe.ts — 0 comments posted, 8 evaluated, 8 filtered
  • line 13: topic is only validated as a string and may be empty ("") or contain invalid characters for the downstream topic format. Forwarding an empty/invalid topic can cause remote API errors. The schema should enforce non-empty and, if applicable, a topic pattern (e.g., .min(1) or a regex). [ Low confidence ]
  • line 14: hmacKeys arrays are allowed to be empty (z.array(...) without .min(1)). Subscribing with an empty hmacKeys array likely violates the downstream API’s requirements for HMAC validation and may cause runtime errors on subscription. Enforce a minimum length (e.g., .min(1)) or explicitly handle the empty case with a 400 response. [ Invalidated by documentation search ]
  • line 16: thirtyDayPeriodsSinceEpoch is only validated as a number. Non-integer or negative values are accepted by the schema and forwarded to the notification server. If the downstream expects a non-negative integer period, this can cause remote errors or undefined behavior at runtime. The schema should enforce an integer and range, e.g., z.number().int().nonnegative(). [ Low confidence ]
  • line 37: req.log is used multiple times without a visible guarantee that the Express Request is augmented with a log property at runtime. If middleware adding req.log is not applied to this route, req.log will be undefined and calls like req.log.info(...) will throw a TypeError, resulting in a 500. Either ensure a guard or rely on types/middleware that guarantee its presence at runtime for this handler. [ Low confidence ]
  • line 70: Potential unbounded input size for hmacKeys arrays and key length could cause excessive memory usage during conversion to Uint8Array, leading to performance degradation or process memory exhaustion (DoS risk). There is no size limit on hmacKeys per topic, and no maximum hex length for key. Consider adding reasonable .max(...) constraints for array length and key length. [ Low confidence ]
  • line 72: Odd-length hex keys are accepted by the schema but may cause hexToUint8Array to throw at runtime. The Zod schema (hmacKeys.*.key) only checks that the string contains hex characters, not that it has an even number of characters. hexToUint8Array typically requires an even-length hex string; an odd-length input can cause a runtime error, resulting in a 500 response instead of a 400 validation error. Add an even-length constraint to the schema or wrap the conversion in a guard and respond with 400 on invalid hex. [ Low confidence ]
  • line 77: When device.pushToken is absent, the handler returns 200 after logging, but does not persist the requested subscriptions anywhere. This silently drops the client’s subscription intent with no mechanism shown to "activate once token is registered." If/when the push token is later registered, the server has no record of which topics/hmac keys to subscribe, resulting in a broken external contract and lost subscriptions. [ Low confidence ]
  • line 89: If device.pushToken is set but device.pushTokenType is null/undefined or invalid, the ternary defaults to firebaseDeviceToken. This can register an APNS token as Firebase (or vice versa), leading to delivery failures. The code should validate pushTokenType when pushToken exists and return a clear 500/400 or map only known values with an explicit else-case error. [ Low confidence ]

Summary by CodeRabbit

  • New Features

    • Device subscription now supports devices without push tokens (subscription proceeds without remote registration).
  • Bug Fixes

    • Device registration resolves conflicts by updating existing device records instead of returning an error.
    • Push token handling improved to clear duplicate tokens from other devices.
    • Improved error handling and logging around subscription and registration flows.

@lourou lourou requested a review from a team as a code owner October 18, 2025 11:56
@coderabbitai

coderabbitai Bot commented Oct 18, 2025

Copy link
Copy Markdown
Contributor

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

Modified device registration and notification subscription handlers to implement idempotent conflict resolution. Device registration now updates existing devices on unique constraint violations instead of returning errors. Notification subscription allows subscriptions without push tokens, conditionally executing installation registration only when tokens are present.

Changes

Cohort / File(s) Summary
Device and Notification Handlers
src/api/v2/device/handlers/register.ts, src/api/v2/notifications/handlers/subscribe.ts
Device registration now implements idempotent update logic on P2002 constraint violations, optionally clearing push tokens from other devices before updating. Notification subscription made push token optional—conditional registration/subscription occurs only when token exists; client record creation proceeds regardless.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler
    participant DB
    participant Remote as Remote Service

    rect rgb(200, 230, 255)
    note over Handler: Device Registration Flow (Before)
    Client->>Handler: Register Device
    Handler->>DB: Create Device
    alt Conflict (P2002)
        DB-->>Handler: Unique Constraint Error
        Handler->>Client: 409 Conflict
    end
    end

    rect rgb(200, 230, 255)
    note over Handler: Device Registration Flow (After)
    Client->>Handler: Register Device
    Handler->>DB: Create Device
    alt Conflict (P2002)
        DB-->>Handler: Unique Constraint Error
        Handler->>Handler: Build Update Data
        opt Push Token Provided
            Handler->>DB: Clear Token from Other Devices
        end
        Handler->>DB: Update Current Device
        Handler->>Client: 200 Success
    end
    end
Loading
sequenceDiagram
    participant Client
    participant Handler
    participant Remote as Remote Service
    participant DB

    rect rgb(230, 255, 200)
    note over Handler: Notification Subscribe Flow (Before)
    Client->>Handler: Subscribe (no push token)
    Handler->>Client: 400 Bad Request (error early)
    end

    rect rgb(230, 255, 200)
    note over Handler: Notification Subscribe Flow (After)
    Client->>Handler: Subscribe
    alt Has Push Token
        Handler->>Remote: Register Installation
        Remote-->>Handler: Installation ID
        Handler->>Remote: Subscribe to Topic
        Remote-->>Handler: Subscription OK
    else No Push Token
        Handler->>Handler: Skip Remote Operations (info log)
    end
    Handler->>DB: Create/Update Client Record
    Handler->>Client: 200 Success
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes involve conditional logic modifications and state management updates across two handlers with interconnected concerns (device registration and push tokens). While individual changes are clear, understanding the implications of making push tokens optional and the idempotent update behavior requires careful verification of edge cases and error paths.

Possibly related PRs

Suggested reviewers

  • neekolas

Poem

🐰 A device now settles, no conflict in sight,
Idempotent updates turn errors to light!
Push tokens optional—the rabbit hops free,
Subscriptions flow smoothly, as smooth as can be!

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
Title Check ✅ Passed The pull request title "Fix device registration" is directly related to the changeset. The primary changes involve modifying the device registration handler to implement idempotent conflict resolution (instead of returning errors) and updating the subscription handler to support devices without push tokens. Both modifications address issues in the device registration flow. The title is clear and specific enough to communicate that the PR addresses device registration problems without being vague like "misc updates" or misleading about the actual content.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 lr/v2-registration-fix

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.

@claude

claude Bot commented Oct 18, 2025

Copy link
Copy Markdown

Claude finished @lourou's task —— View job


Code Review Complete ✅

I've thoroughly reviewed this PR. Below is my feedback organized by category:


🎯 Summary

This PR successfully implements idempotent device registration and allows subscription without push tokens. The changes are well-structured and address the core requirements. However, there are several important issues that should be addressed before merging.


🐛 Critical Issues

1. Empty String Push Token Handling Inconsistency (register.ts:9-15, 125-128)

Issue: The Zod schema transforms empty strings to undefined, but the comment on line 126 says "Normalize: undefined or empty string -> null". This creates inconsistent behavior:

  • On create: pushToken: body.pushToken ?? null correctly stores null
  • On update: The check body.pushToken !== undefined skips setting the field when it's undefined, leaving existing tokens unchanged

Impact: Clients cannot clear push tokens by sending an empty string, potentially leaving stale registrations.

Recommendation:

pushToken: z
  .string()
  .nullable()
  .optional()
  .transform((val) => (val == null || val.trim() === "" ? null : val)),

And simplify the update logic:

if (body.pushToken !== undefined) {
  updateData.pushToken = body.pushToken; // can be string or null
}

2. Potential Race Condition in Token Clearing (register.ts:42-71)

Issue: The code uses findFirst followed by updateMany, but there's a gap between the check and the update where another registration could slip through.

Impact: In high-concurrency scenarios, duplicate tokens might not be properly cleared.

Recommendation: The current updateMany approach is actually correct for clearing all conflicts. Consider removing the findFirst check and always run updateMany, then check the count:

const cleared = await tx.deviceRegistration.updateMany({
  where: {
    deviceId: { not: deviceId },
    pushToken,
    pushTokenType: tokenType,
    apnsEnv: environment,
  },
  data: { pushToken: null },
});

if (cleared.count > 0) {
  logger.info(
    { clearedCount: cleared.count, newDeviceId: deviceId },
    "Cleared conflicting push token registrations"
  );
}

3. Subscription Silent Failure Without Push Token (subscribe.ts:77-81)

Issue: When a device has no push token, the handler returns 200 but doesn't persist the subscription intent anywhere. If/when the push token is later registered, there's no mechanism to "activate" these subscriptions.

Impact: Lost subscriptions - the client thinks they're subscribed, but notifications won't be delivered even after registering a push token.

Recommendation: Either:

  • Store subscription requests in the database for later activation, OR
  • Return a different status code (e.g., 202 Accepted) with a clear message that subscriptions will be activated when a push token is registered, OR
  • Document clearly that clients must re-subscribe after registering a push token

⚠️ Important Issues

4. Logging Sensitive Data (register.ts:56)

Good: The code correctly logs hasPushToken: !!pushToken instead of the raw token.

Issue: Earlier reviewers (coderabbitai) noted concerns about logging raw tokens elsewhere. I verified this is handled correctly throughout the file.

5. Invalid Hex Key Handling (subscribe.ts:17)

Issue: The regex /^[0-9a-fA-F]+$/ accepts odd-length hex strings, but hexToUint8Array typically requires even-length strings, causing runtime errors.

Impact: 500 errors instead of proper 400 validation errors.

Recommendation:

key: z.string().regex(/^(?:[0-9a-fA-F]{2})+$/, "Invalid hex string (must be even-length hex)"),

6. Push Token Type Fallback Logic (subscribe.ts:88-91)

Issue: The code defaults to firebaseDeviceToken for unknown types:

device.pushTokenType === "apns" ? "apnsDeviceToken" : "firebaseDeviceToken"

Context: According to the Prisma schema, FCM is "Not supported - kept for database compatibility only", and register.ts:96 explicitly rejects FCM registrations. This fallback is actually reasonable for handling legacy data.

Recommendation: Add a runtime check to warn about unexpected token types:

const deliveryMechanism = device.pushTokenType === "apns" 
  ? "apnsDeviceToken" 
  : device.pushTokenType === "fcm"
    ? "firebaseDeviceToken"
    : (() => {
        req.log.warn({ pushTokenType: device.pushTokenType }, "Unexpected push token type");
        return "firebaseDeviceToken";
      })();

💡 Code Quality & Best Practices

7. Transaction Extraction (register.ts:23-86)

Positive: Excellent refactoring! Extracting performDeviceRegistration improves testability and readability.

8. Error Handling (register.ts:155-168, subscribe.ts:152-168)

Positive: Proper error handling with specific Zod validation errors and generic fallbacks.

Suggestion: Consider using the codebase's AppError pattern (if it exists) for consistency.

9. Compensation Logic (subscribe.ts:103-115, 130-143)

Positive: Excellent error handling with cleanup compensation when operations fail.

Minor: Could extract this pattern into a utility function if used elsewhere.


🔒 Security Concerns

10. Input Validation

Positive: Strong validation using Zod schemas with appropriate constraints.

11. No SQL Injection Risks

Positive: Using Prisma ORM eliminates direct SQL injection risks.

12. Push Token as Sensitive Data

Positive: Correctly avoided logging raw push tokens.


⚡ Performance Considerations

13. Database Operations

Positive:

  • Uses transactions appropriately
  • updateMany is more efficient than multiple individual updates
  • Proper use of upsert reduces round-trips

14. Array Size Limits (subscribe.ts:22-23)

Positive: Good practice limiting topics array to 100 items prevents DoS via large payloads.

Suggestion: Consider adding similar limits for hmacKeys array size per topic.


🧪 Test Coverage

15. Missing Tests for New Behavior

Issue: The PR changes critical behavior (idempotent registration, subscription without tokens), but I don't see corresponding test updates.

Existing tests: Found tests/devices.test.ts but it's for v1 API. The v2 handlers (register.ts, subscribe.ts) appear to lack dedicated test coverage.

Recommendation: Add tests for:

  • Registering same push token on different devices (should clear old device)
  • Registering device without push token
  • Subscribing without push token (verify behavior)
  • Empty string push token handling
  • Concurrent registration scenarios

📋 Other Observations

16. Coderabbit Review Comments

I reviewed the existing bot comments. Key valid concerns:

17. Macroscope Comment

The Macroscope bot raised concerns about using update instead of upsert in conflict handling. However, I don't see this pattern in the current code - it appears to have been already addressed by using upsert at line 75.


📝 Recommendations Summary

Must Fix Before Merge:

  1. ⚠️ Fix empty string push token normalization ([Backend] User, Device, and Conversation tables #1)
  2. ⚠️ Clarify subscription behavior without push token - document or change ([Backend] Push Notifications #3)
  3. ⚠️ Fix hex key validation to prevent runtime errors (Generate prisma client in Dockerfile #5)

Should Fix:
4. 📊 Add test coverage for new behaviors (#15)
5. 🔍 Consider optimizing token clearing logic (#2)
6. 🛡️ Add warning for unexpected push token types (#6)

Nice to Have:
7. 📚 Document the subscription reactivation flow
8. 🧹 Consider extracting compensation logic if reused


✅ Strengths

  • Clean transaction-based approach
  • Good separation of concerns with extracted helper function
  • Proper compensation/cleanup on errors
  • Secure logging practices (no raw tokens)
  • Appropriate input validation limits

Overall Assessment: The core implementation is solid, but there are critical edge cases (empty string tokens, subscription without push token) that need clarification before this is production-ready. With the recommended fixes, this will be a robust solution.


| Branch: lr/v2-registration-fix

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (3)
src/api/v2/device/handlers/register.ts (2)

76-105: Don’t mutate old device’s pushTokenType/apnsEnv; also clear all matches, not just one.

  • Updating the old row with pushTokenType: "apns" and apnsEnv: null changes its metadata unnecessarily.
  • findFirst + single update can leave multiple stale rows if data drift exists.

Null only the token and use updateMany constrained by the same type/env tuple.

-        const existingDevice = await tx.deviceRegistration.findFirst({
-          where: {
-            pushToken: body.pushToken,
-            pushTokenType,
-            apnsEnv,
-            deviceId: { not: body.deviceId },
-          },
-        });
-
-        if (existingDevice) {
-          req.log.info(
-            {
-              oldDeviceId: existingDevice.deviceId,
-              newDeviceId: body.deviceId,
-              pushToken: body.pushToken,
-            },
-            "Push token moving from old device to new device - clearing old registration",
-          );
-
-          // Clear the push token from the old device to avoid unique constraint violation
-          await tx.deviceRegistration.update({
-            where: { deviceId: existingDevice.deviceId },
-            data: {
-              pushToken: null,
-              pushTokenType: "apns",
-              apnsEnv: null,
-            },
-          });
-        }
+        const cleared = await tx.deviceRegistration.updateMany({
+          where: {
+            deviceId: { not: body.deviceId },
+            pushToken: body.pushToken,
+            pushTokenType,
+            apnsEnv,
+          },
+          data: { pushToken: null },
+        });
+        if (cleared.count > 0) {
+          req.log.info(
+            { oldRegistrationsCleared: cleared.count, newDeviceId: body.deviceId },
+            "Cleared stale registrations with same push token",
+          );
+        }

87-94: Avoid logging raw pushToken values.

push tokens can be sensitive identifiers. Prefer not logging them; if needed, log a hash prefix.

-              pushToken: body.pushToken,
+              hasPushToken: true,
src/api/v2/notifications/handlers/subscribe.ts (1)

150-151: Add explicit return after sending the response.

Guideline: always return immediately after res.status().send()/json().

-    res.status(200).send();
+    res.status(200).send();
+    return;
🧹 Nitpick comments (4)
src/api/v2/device/handlers/register.ts (3)

9-15: Empty-string normalization doesn’t clear tokens as the comment suggests.

The transform turns "" into undefined, so updateData.pushToken isn’t set and the token won’t be cleared. If you intend to clear on empty string, accept null and normalize to null.

-  pushToken: z
-    .string()
-    .optional()
-    .transform((val) => (!val || val.trim() === "" ? undefined : val)),
+  pushToken: z
+    .string()
+    .nullable()
+    .optional()
+    .transform((val) => (val == null ? null : val.trim() === "" ? null : val)),
@@
-    if (body.pushToken !== undefined) {
-      // Normalize: undefined or empty string -> null
-      updateData.pushToken = body.pushToken || null;
-    }
+    if (body.pushToken !== undefined) {
+      updateData.pushToken = body.pushToken; // may be string or null
+    }

Also applies to: 56-60


138-206: Reduce dual-path logic: handle idempotency inside the transaction, drop P2002 catch branch.

Current flow duplicates update logic and diverges on validation and cleanup filters. Prefer a single transactional path that:

  • clears conflicting rows with updateMany scoped by (pushToken, pushTokenType, apnsEnv),
  • then upserts.

This removes the need for the P2002 catch or reduces it to a last-resort retry.


121-128: Error handling consistency with AppError/logError utilities.

Consider using the shared AppError pattern and centralized error middleware for consistency across routes.

Also applies to: 210-213

src/api/v2/notifications/handlers/subscribe.ts (1)

16-18: Validate even-length hex for HMAC keys.

hexToUint8Array typically requires an even number of hex chars. Enforce this in Zod to fail fast.

-            key: z.string().regex(/^[0-9a-fA-F]+$/, "Invalid hex string"),
+            key: z
+              .string()
+              .regex(/^(?:[0-9a-fA-F]{2})+$/, "Invalid hex string (must be even-length hex)"),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f99b588 and 32f486a.

📒 Files selected for processing (2)
  • src/api/v2/device/handlers/register.ts (1 hunks)
  • src/api/v2/notifications/handlers/subscribe.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: TypeScript with strict mode and ESNext features
Implement consistent error handling using AppError class
Use object parameter syntax for function arguments: '(args: { paramOne: string }) => {}' instead of '(paramOne: string) => {}' for better readability and extensibility
Keep functions focused and avoid optional parameters. If a function has many optional parameters, consider splitting it into multiple specialized functions for clearer intent and better maintainability
Prefer type inference from Prisma models
Keep types close to their usage (same directory)
Use type exports for shared types
Leverage path aliases (@/) for imports
Don't specify return type on functions. Prefer inferring the value.
Use transactions for multi-table operations
Include necessary relations in queries using include
Use custom AppError class for application errors
Log errors with context using logError utility
Log security-relevant events
Implement caching where needed
Optimize database queries
Use appropriate batch operations
Add JSDoc comments for public APIs

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/{api,routes}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/{api,routes}/**/*.{ts,tsx}: For API route Response types, use simple typing (e.g., 'res: Response') instead of verbose generic types (e.g., 'res: Response<unknown, any>') to keep code clean and readable
Follow RESTful principles for endpoint naming
Always place the 'return;' statement on a new line immediately after sending a response with 'res.status().json()' or similar methods
Use Zod schemas for request validation and type inference
Return appropriate HTTP status codes
Handle file uploads efficiently

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/handlers/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use dedicated handlers directory for route logic

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/{api,routes,handlers, middleware}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/{api,routes,handlers, middleware}/**/*.{ts,tsx}: Implement consistent error responses
Handle validation errors separately from other errors

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/*

📄 CodeRabbit inference engine (.cursorrules)

Follow consistent file naming (kebab-case)

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/{middleware,api,routes}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/{middleware,api,routes}/**/*.{ts,tsx}: Implement rate limiting
Use security headers (Helmet)
Handle authentication consistently

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
**/{api,routes, middleware}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Validate and sanitize inputs

Files:

  • src/api/v2/notifications/handlers/subscribe.ts
  • src/api/v2/device/handlers/register.ts
🧬 Code graph analysis (1)
src/api/v2/device/handlers/register.ts (1)
src/utils/prisma.ts (1)
  • prisma (3-3)
🔇 Additional comments (1)
src/api/v2/notifications/handlers/subscribe.ts (1)

87-93: No action required—behavior is intentional and correct.

The Prisma schema explicitly marks FCM as "Not supported - kept for database compatibility only," with only two enum values: apns and fcm. The code correctly reflects this:

  • register.ts rejects new FCM registrations (line 27)
  • subscribe.ts gracefully handles legacy FCM devices by mapping them to firebaseDeviceToken (lines 89-91)

This is backward-compatible handling of legacy database rows, not an inconsistency. The fallback is appropriate for devices that predate the FCM deprecation.

Comment thread src/api/v2/device/handlers/register.ts Outdated
Comment thread src/api/v2/device/handlers/register.ts Outdated
@lourou lourou merged commit 596ce8e into otr-dev Oct 18, 2025
7 checks passed
@lourou lourou deleted the lr/v2-registration-fix branch October 18, 2025 16:49
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