Skip to content

feat: patent status#109

Merged
hmbanan666 merged 2 commits intomainfrom
patent
Aug 29, 2025
Merged

feat: patent status#109
hmbanan666 merged 2 commits intomainfrom
patent

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Aug 29, 2025

Summary by CodeRabbit

  • New Features

    • Added a patent status field to the Partner Agreement form with selectable statuses and labels.
    • Agreements list now shows a dedicated "Concluded" date column and a "Patent status" column, updated headers and default sorting by Concluded.
  • Bug Fixes

    • User type badge on user cards now displays the correct label.
  • Style

    • Added a slide-left motion effect to agreement file items for smoother UI transitions.

@hmbanan666 hmbanan666 self-assigned this Aug 29, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 29, 2025

Walkthrough

Adds patentStatus across DB types, schema, service, helpers, form, and agreements table UI; wires missing getUserTypeLabel import in UserCard and adds a slide-left motion class to AgreementFilesBlock. Formats concludedAt into its own column and surfaces patent status in lists and forms.

Changes

Cohort / File(s) Summary
Database types & schema
packages/database/src/types.ts, packages/database/src/tables.ts
Added AgreementPatentStatus type and new partnerAgreements.patentStatus column (varchar, not null, default 'in_work', typed as AgreementPatentStatus).
Service schema: update payload
apps/web-app/shared/services/partner.ts
Extended updatePartnerAgreementSchema (and inferred UpdatePartnerAgreement) to include optional patentStatus ('in_work' | 'on_registration' | 'registered').
Helpers for patent status
apps/web-app/shared/utils/helpers.ts
Added getPatentStatus(status: AgreementPatentStatus) (label mapping) and getPatentStatusForSelect() (select options); imported AgreementPatentStatus.
Form: UpdatePartnerAgreement
apps/web-app/app/components/form/UpdatePartnerAgreement.vue
Added UFormField/USelectMenu for patent status with selectedPatentStatus, patentStatuses from helper, watcher syncing to state.patentStatus, and inclusion in PATCH submission.
Agreements page table updates
apps/web-app/app/pages/agreement/index.vue
Introduced concludedAt column (sortable) and patentStatus column; moved concludedAt rendering to its own slot; updated headers, default sorting (to concludedAt), visibility, and cell renderers to use row.getValue(...).
UserCard helper import
apps/web-app/app/components/UserCard.vue
Imported getUserTypeLabel to match existing template usage.
UI motion tweak
apps/web-app/app/components/AgreementFilesBlock.vue
Added motion-preset-slide-left class to the root container; no logic changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Form as UpdatePartnerAgreement Form
  participant Helpers as shared/utils/helpers
  participant Service as partner.ts
  participant API as Backend API
  participant DB as Database
  rect rgba(100,150,255,0.06)
    User->>Form: Open form (current patentStatus loaded)
    Form->>Helpers: getPatentStatusForSelect()
    Helpers-->>Form: [{value,label}, ...]
    User->>Form: Select new patent status
    Form->>Form: watcher updates state.patentStatus
    User->>Form: Submit
    Form->>Service: onSubmit({ ..., patentStatus })
    Service->>API: PATCH /partner-agreements/:id { patentStatus, ... }
    API->>DB: UPDATE partner_agreements SET patent_status=...
    DB-->>API: OK
    API-->>Service: 200 OK
    Service-->>Form: success
    Form-->>User: confirmation
  end

  rect rgba(150,220,150,0.06)
    participant Page as AgreementsPage
    Page->>API: GET /partner-agreements
    API-->>Page: [{ concludedAt, patentStatus, ... }]
    Page->>Helpers: getPatentStatus(patentStatus)
    Helpers-->>Page: "Russian label"
    Page-->>User: Table with concludedAt and patentStatus columns
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

A rabbit scripts with whiskers bright,
Patents hop into columns of light.
Dates find their own tidy place,
Selects and labels fall into place.
I nibble a bug, then bound with glee—merge done, carrot tea! 🥕


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d35d06c and c466bb2.

📒 Files selected for processing (1)
  • apps/web-app/app/components/form/UpdatePartnerAgreement.vue (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web-app/app/components/form/UpdatePartnerAgreement.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch patent

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@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: 8

🧹 Nitpick comments (5)
apps/web-app/app/components/AgreementFilesBlock.vue (2)

2-2: Respect reduced-motion preferences for the new animation

Gate the motion preset so it won’t animate for users who prefer reduced motion.

-  <div class="flex flex-row gap-1.5 items-center motion-preset-slide-left">
+  <div class="flex flex-row gap-1.5 items-center motion-safe:motion-preset-slide-left">

If motion-safe: isn’t available in your CSS stack, add an equivalent @media (prefers-reduced-motion: reduce) guard.


13-21: Open in new tab: add rel for security

Links opened with target="_blank" should also set rel="noopener noreferrer" to prevent tabnabbing. Verify ULink sets this automatically when external is true; if not, pass rel explicitly.

apps/web-app/shared/utils/helpers.ts (1)

45-51: Build select options from a single source of truth

Generate options from AGREEMENT_PATENT_STATUSES to avoid literal duplication.

-export function getPatentStatusForSelect(): { value: AgreementPatentStatus, label: string }[] {
-  return [
-    { value: 'in_work', label: 'В работе' },
-    { value: 'on_registration', label: 'На регистрации' },
-    { value: 'registered', label: 'Зарегистрирован' },
-  ]
-}
+export function getPatentStatusForSelect(): { value: AgreementPatentStatus, label: string }[] {
+  const map: Record<AgreementPatentStatus, string> = {
+    in_work: 'В работе',
+    on_registration: 'На регистрации',
+    registered: 'Зарегистрирован',
+  }
+  return AGREEMENT_PATENT_STATUSES.map((s) => ({ value: s, label: map[s] }))
+}

If AGREEMENT_PATENT_STATUSES isn’t exported from @roll-stack/database yet, see my types.ts comment.

apps/web-app/shared/services/partner.ts (1)

51-51: UI says “required”, schema says “optional” — pick one

The Update schema makes patentStatus optional, but the form marks it required. Align them to avoid UX confusion and false validation expectations. I recommend keeping it optional in both places (DB has a default).

apps/web-app/app/components/form/UpdatePartnerAgreement.vue (1)

72-88: “Роспатент” field marked required but schema is optional

Drop the required flag to match updatePartnerAgreementSchema and DB default.

-    <UFormField
-      label="Роспатент"
-      name="patentStatus"
-      required
-    >
+    <UFormField
+      label="Роспатент"
+      name="patentStatus"
+    >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3cce1df and d35d06c.

📒 Files selected for processing (8)
  • apps/web-app/app/components/AgreementFilesBlock.vue (1 hunks)
  • apps/web-app/app/components/UserCard.vue (1 hunks)
  • apps/web-app/app/components/form/UpdatePartnerAgreement.vue (4 hunks)
  • apps/web-app/app/pages/agreement/index.vue (6 hunks)
  • apps/web-app/shared/services/partner.ts (2 hunks)
  • apps/web-app/shared/utils/helpers.ts (2 hunks)
  • packages/database/src/tables.ts (2 hunks)
  • packages/database/src/types.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/web-app/shared/utils/helpers.ts (1)
packages/database/src/types.ts (1)
  • AgreementPatentStatus (21-21)
packages/database/src/tables.ts (1)
packages/database/src/types.ts (1)
  • AgreementPatentStatus (21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (5)
apps/web-app/app/components/UserCard.vue (1)

41-41: LGTM: helper import and usage

Importing getUserTypeLabel and using it in the badge improves readability and consistency.

apps/web-app/shared/utils/helpers.ts (1)

1-1: LGTM: type import

Import of AgreementPatentStatus keeps UI helpers aligned with DB types.

apps/web-app/app/pages/agreement/index.vue (3)

221-223: Sorting by string date can be wrong if non-ISO — verify

If concludedAt isn’t ISO-8601, alphanumeric sort will misorder dates. Consider TanStack’s datetime/custom sorting fn or store concludedAt as ISO.


246-260: Nice: dedicated, sortable “Заключен” column

Clean separation from internalId-cell improves readability and sorting UX.


295-298: New “Роспатент” column: ensure store/data is populated

Confirm PartnerAgreementWithAllData includes patentStatus and partnerStore.agreements supplies it after the DB migration; otherwise cells will be empty.

Comment on lines +154 to +160
const patentStatuses = computed(() => getPatentStatusForSelect())

const selectedPatentStatus = ref<{ value: AgreementPatentStatus, label: string }>(patentStatuses.value.find((patentStatus) => patentStatus.value === agreement.value?.patentStatus) ?? { value: 'in_work', label: 'Не определено' })

watch(selectedPatentStatus, (newValue) => {
state.value.patentStatus = newValue?.value
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Selected option must be one of items (object identity) — avoid custom fallback

Creating a new object for the fallback can break selection rendering in USelectMenu. Use the first item from patentStatuses instead.

-const selectedPatentStatus = ref<{ value: AgreementPatentStatus, label: string }>(patentStatuses.value.find((patentStatus) => patentStatus.value === agreement.value?.patentStatus) ?? { value: 'in_work', label: 'Не определено' })
+const selectedPatentStatus = ref<{ value: AgreementPatentStatus, label: string }>(
+  patentStatuses.value.find((s) => s.value === agreement.value?.patentStatus) ?? patentStatuses.value[0]
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const patentStatuses = computed(() => getPatentStatusForSelect())
const selectedPatentStatus = ref<{ value: AgreementPatentStatus, label: string }>(patentStatuses.value.find((patentStatus) => patentStatus.value === agreement.value?.patentStatus) ?? { value: 'in_work', label: 'Не определено' })
watch(selectedPatentStatus, (newValue) => {
state.value.patentStatus = newValue?.value
})
const patentStatuses = computed(() => getPatentStatusForSelect())
const selectedPatentStatus = ref<{ value: AgreementPatentStatus, label: string }>(
patentStatuses.value.find((s) => s.value === agreement.value?.patentStatus)
?? patentStatuses.value[0]
)
watch(selectedPatentStatus, (newValue) => {
state.value.patentStatus = newValue?.value
})
🤖 Prompt for AI Agents
In apps/web-app/app/components/form/UpdatePartnerAgreement.vue around lines 154
to 160, the selectedPatentStatus fallback creates a new object literal which
breaks USelectMenu selection identity; change the fallback to use the actual
first item from patentStatuses (e.g. patentStatuses.value.find(...) ??
patentStatuses.value[0]) so the selected option is one of the existing items by
reference, keeping the same typed shape.

Comment on lines +92 to +94
<template #concludedAt-cell="{ row }">
{{ format(new Date(row.getValue('concludedAt')), 'd MMMM yyyy', { locale: ru }) }}
</template>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard date formatting against null/invalid values

If concludedAt is missing/invalid, format() will throw. Render a dash instead.

-      <template #concludedAt-cell="{ row }">
-        {{ format(new Date(row.getValue('concludedAt')), 'd MMMM yyyy', { locale: ru }) }}
-      </template>
+      <template #concludedAt-cell="{ row }">
+        <span v-if="row.getValue('concludedAt')">
+          {{ format(new Date(row.getValue('concludedAt')), 'd MMMM yyyy', { locale: ru }) }}
+        </span>
+        <span v-else>-</span>
+      </template>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<template #concludedAt-cell="{ row }">
{{ format(new Date(row.getValue('concludedAt')), 'd MMMM yyyy', { locale: ru }) }}
</template>
<template #concludedAt-cell="{ row }">
<span v-if="row.getValue('concludedAt')">
{{ format(new Date(row.getValue('concludedAt')), 'd MMMM yyyy', { locale: ru }) }}
</span>
<span v-else>-</span>
</template>
🤖 Prompt for AI Agents
In apps/web-app/app/pages/agreement/index.vue around lines 92 to 94, guard the
date formatting so format() is not called with null/invalid values: check the
concludedAt value (row.getValue('concludedAt')) and if it's missing or not a
valid Date, render a dash (e.g. '—'); otherwise create the Date and call format
with the ru locale. Implement the check using a simple falsy/valid Date test (or
date-fns isValid) and return the dash early to avoid format() throwing.

Comment on lines +133 to +137
<template #patentStatus-cell="{ row }">
<div class="text-sm/4 whitespace-pre-wrap max-w-56">
{{ getPatentStatus(row.getValue('patentStatus')) }}
</div>
</template>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing import for getPatentStatus

The template calls getPatentStatus but it isn’t imported.

 <script setup lang="ts">
 import type { DropdownMenuItem, TableColumn } from '@nuxt/ui'
 import type { PartnerAgreement } from '@roll-stack/database'
 import type { PartnerAgreementWithAllData } from '~/stores/partner'
+import { getPatentStatus } from '~~/shared/utils/helpers'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<template #patentStatus-cell="{ row }">
<div class="text-sm/4 whitespace-pre-wrap max-w-56">
{{ getPatentStatus(row.getValue('patentStatus')) }}
</div>
</template>
<script setup lang="ts">
import type { DropdownMenuItem, TableColumn } from '@nuxt/ui'
import type { PartnerAgreement } from '@roll-stack/database'
import type { PartnerAgreementWithAllData } from '~/stores/partner'
import { getPatentStatus } from '~~/shared/utils/helpers'
// ...rest of your script setup code
</script>
🤖 Prompt for AI Agents
In apps/web-app/app/pages/agreement/index.vue around lines 133 to 137, the
template calls getPatentStatus but it is not imported; add an import for
getPatentStatus at the top of the component script (or <script setup>) from the
module that defines it (e.g., the utility/composable where you implemented it),
ensuring you use the correct named/default import syntax and that the function
is exported from that module; if the helper doesn't exist yet, create and export
getPatentStatus from an appropriate utils/composables file and then import it
into this component so the template can call it without runtime errors.

Comment on lines +38 to +39
const patentStatus = type('"in_work" | "on_registration" | "registered"')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid type drift: reuse the canonical AgreementPatentStatus union

You're re-declaring the union inline. Import the DB type to keep runtime validation and TS in sync.

+import type { AgreementPatentStatus } from '@roll-stack/database'
 ...
-const patentStatus = type('"in_work" | "on_registration" | "registered"')
+const patentStatus = type<AgreementPatentStatus>('"in_work" | "on_registration" | "registered"')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const patentStatus = type('"in_work" | "on_registration" | "registered"')
// at the top of the file, alongside your other imports
import type { AgreementPatentStatus } from '@roll-stack/database'
// …later, replace the inline union with the imported type
const patentStatus = type<AgreementPatentStatus>("in_work" | "on_registration" | "registered")
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts around lines 38-39, the code
re-declares the patent status union inline as type('"in_work" |
"on_registration" | "registered"'), which causes type drift; replace this inline
declaration by importing the canonical AgreementPatentStatus type/union from the
DB/types module and use that exported union for the runtime validator (or derive
the validator from the imported union), so TypeScript and runtime validation
stay in sync—update the import, swap the inline string-union with the imported
AgreementPatentStatus reference, and adjust any typing/validator creation
accordingly.

Comment on lines +34 to +43
export function getPatentStatus(status: AgreementPatentStatus) {
switch (status) {
case 'in_work':
return 'В работе'
case 'on_registration':
return 'На регистрации'
case 'registered':
return 'Зарегистрирован'
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add explicit return type and a safe default

At runtime an unexpected value could still slip in; also make the function signature explicit.

-export function getPatentStatus(status: AgreementPatentStatus) {
+export function getPatentStatus(status: AgreementPatentStatus): string {
   switch (status) {
     case 'in_work':
       return 'В работе'
     case 'on_registration':
       return 'На регистрации'
     case 'registered':
       return 'Зарегистрирован'
   }
+  return '—'
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function getPatentStatus(status: AgreementPatentStatus) {
switch (status) {
case 'in_work':
return 'В работе'
case 'on_registration':
return 'На регистрации'
case 'registered':
return 'Зарегистрирован'
}
}
export function getPatentStatus(status: AgreementPatentStatus): string {
switch (status) {
case 'in_work':
return 'В работе'
case 'on_registration':
return 'На регистрации'
case 'registered':
return 'Зарегистрирован'
}
return '—'
}
🤖 Prompt for AI Agents
In apps/web-app/shared/utils/helpers.ts around lines 34 to 43, the
getPatentStatus function lacks an explicit return type and a safe default
branch; update its signature to declare a return type (e.g., string or a
specific localized string union), and add a default/fallback case (or a final
return) to handle unexpected status values so the function never returns
undefined—for example return a sensible default label like 'Неизвестно' or an
empty string and/or log/throw if you prefer strictness.

@@ -1,4 +1,4 @@
import type { NotificationOption, UserGender, UserType } from './types'
import type { AgreementPatentStatus, NotificationOption, UserGender, UserType } from './types'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prefer pgEnum for strong DB-level constraints

Import pgEnum; enum types prevent invalid patent_status values at the database level.

-import { boolean, date, integer, jsonb, numeric, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core'
+import { boolean, date, integer, jsonb, numeric, pgEnum, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { AgreementPatentStatus, NotificationOption, UserGender, UserType } from './types'
import type { AgreementPatentStatus, NotificationOption, UserGender, UserType } from './types'
import { boolean, date, integer, jsonb, numeric, pgEnum, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core'
🤖 Prompt for AI Agents
In packages/database/src/tables.ts around line 1, the file currently imports
TypeScript union types but doesn't define DB-level enums; import pgEnum from
'drizzle-orm/pg-core' and create pgEnum values for AgreementPatentStatus,
NotificationOption, UserGender, and UserType (e.g. const
agreementPatentStatusEnum = pgEnum('agreement_patent_status', ['...'])), then
use those enums in your table column definitions instead of plain text/enum
strings so the database enforces valid values; export the enum constants for
reuse and update/emit a migration to create the enums in Postgres.

Comment on lines +130 to 131
patentStatus: varchar('patent_status').notNull().default('in_work').$type<AgreementPatentStatus>(),
legalEntityId: cuid2('legal_entity_id').references(() => partnerLegalEntities.id),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Define a PostgreSQL enum for patent_status and use it

Varchar + $type doesn’t enforce allowed values. Use pgEnum to guarantee data integrity and make migrations explicit.

+// Place near other type/const defs
+export const patentStatusEnum = pgEnum('agreement_patent_status', ['in_work', 'on_registration', 'registered'])
+
 export const partnerAgreements = pgTable('partner_agreements', {
@@
-  patentStatus: varchar('patent_status').notNull().default('in_work').$type<AgreementPatentStatus>(),
+  patentStatus: patentStatusEnum('patent_status').notNull().default('in_work'),

Run this to confirm a migration exists that adds the column and (if applied) creates the enum:

If you prefer to avoid enums, at least add a CHECK constraint in the migration.


🏁 Script executed:

#!/bin/bash
# Verify migrations mention the new column / enum
rg -n --hidden -S "(agreement_patent_status|patent_status)" -g "!**/node_modules/**" -g "!**/dist/**"

Length of output: 241


Define a Postgres enum for patent_status and add the corresponding migration
The table still uses varchar with a TS‐only type and there’s no migration creating an enum or altering the column, so data‐integrity isn’t enforced. Update your schema and add a migration:

// packages/database/src/tables.ts (near other type defs)
export const patentStatusEnum = pgEnum('agreement_patent_status', ['in_work', 'on_registration', 'registered'])

export const partnerAgreements = pgTable('partner_agreements', {
  // …
-  patentStatus: varchar('patent_status').notNull().default('in_work').$type<AgreementPatentStatus>(),
+  patentStatus: patentStatusEnum('patent_status').notNull().default('in_work'),
  // …
})

Then create a migration that:

  • CREATE TYPE agreement_patent_status AS ENUM ('in_work','on_registration','registered');
  • ALTER TABLE partner_agreements ALTER COLUMN patent_status TYPE agreement_patent_status USING patent_status::agreement_patent_status;
🤖 Prompt for AI Agents
In packages/database/src/tables.ts around lines 130-131 the column patentStatus
is declared as varchar with only a TS type which doesn’t enforce a Postgres
enum; replace it by declaring a pgEnum export (e.g. export const
patentStatusEnum = pgEnum('agreement_patent_status',
['in_work','on_registration','registered'])) and change the partnerAgreements
patentStatus column to use
patentStatusEnum('patent_status').notNull().default('in_work'); then add a DB
migration that runs: CREATE TYPE agreement_patent_status AS ENUM
('in_work','on_registration','registered'); and ALTER TABLE partner_agreements
ALTER COLUMN patent_status TYPE agreement_patent_status USING
patent_status::agreement_patent_status; (and run the migration).

Comment on lines +21 to +22
export type AgreementPatentStatus = 'in_work' | 'on_registration' | 'registered'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

De-duplicate status literals and make them reusable

Export a canonical list to avoid drift across DB, helpers, and forms. Also derive the type from it.

-export type AgreementPatentStatus = 'in_work' | 'on_registration' | 'registered'
+export const AGREEMENT_PATENT_STATUSES = ['in_work', 'on_registration', 'registered'] as const
+export type AgreementPatentStatus = typeof AGREEMENT_PATENT_STATUSES[number]

I can follow up by wiring helpers/selects to consume AGREEMENT_PATENT_STATUSES.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type AgreementPatentStatus = 'in_work' | 'on_registration' | 'registered'
export const AGREEMENT_PATENT_STATUSES = ['in_work', 'on_registration', 'registered'] as const
export type AgreementPatentStatus = typeof AGREEMENT_PATENT_STATUSES[number]
🤖 Prompt for AI Agents
In packages/database/src/types.ts around lines 21-22, the status literals are
duplicated; export a single canonical readonly array/tuple (e.g.
AGREEMENT_PATENT_STATUSES) containing 'in_work', 'on_registration', 'registered'
and then derive the AgreementPatentStatus type from that array
(AgreementPatentStatus = typeof AGREEMENT_PATENT_STATUSES[number]); export both
so helpers/forms/DB can import the canonical list. Ensure the array is readonly
so the derived type stays literal.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
22.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@hmbanan666 hmbanan666 merged commit 63139ab into main Aug 29, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the patent branch August 29, 2025 10:07
This was referenced Sep 2, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 7, 2025
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