Skip to content

feat: поле tag хоста из строки в массив tags#159

Open
StylerHub wants to merge 9 commits into
remnawave:devfrom
StylerHub:feat/host-tags-array
Open

feat: поле tag хоста из строки в массив tags#159
StylerHub wants to merge 9 commits into
remnawave:devfrom
StylerHub:feat/host-tags-array

Conversation

@StylerHub
Copy link
Copy Markdown
Contributor

@StylerHub StylerHub commented Apr 8, 2026

Описание

Миграция поля хоста tag из одиночной строки (tag: string | null) в массив (tags: string[]) — по аналогии с тем, как теги уже реализованы для нод.

Мотивация

Сейчас хост поддерживает только один тег, в то время как ноды уже поддерживают несколько. Это ограничивает возможности маркировки — например, нельзя пометить хост сразу для нескольких сценариев использования (тип канала, регион, назначение и т.д.).

Что изменено

База данных:

  • Prisma-схема: tag String?tags String[] @default([])
  • SQL-миграция: добавляет колонку tags, переносит данные из tag, удаляет старую колонку

Контракт (libs/contract):

  • HostsSchema: tag: z.string().nullable()tags: z.array(z.string()).default([])
  • CreateHostCommand / UpdateHostCommand: валидация массива с regex на каждый элемент, максимум 10 тегов
  • ProxyEntryMetadataSchema: tagtags

Бэкенд:

  • HostsEntity, HostResponseModel, HostsConverter: обновление типа поля
  • HostsRepository.getAllHostTags(): переписан на unnest(tags) (как в нодах)
  • HostsRepository.findByCriteria(): исключён tags из Prisma where-фильтра
  • resolve-proxy-config.service.ts: маппинг metadata tagtags
  • xray-json.generator.service.ts:
    • useHostTagAsTag: берёт первый тег как outbound tag
    • sameTagAsRecipient: проверяет пересечение массивов
    • tagRegex: матчит если хотя бы один тег подходит под regex

Ломающие изменения

Изменён API-контракт во всех ручках хостов (POST /api/hosts, PATCH /api/hosts, GET /api/hosts): поле tag: string | null заменено на tags: string[]. Фронтенд обновлён в remnawave/frontend#341.

@snyk-io
Copy link
Copy Markdown

snyk-io Bot commented Apr 8, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@what-the-diff
Copy link
Copy Markdown

what-the-diff Bot commented Apr 8, 2026

PR Summary

  • Establishment of Vulnerability Reporting Process
    Introduced a SECURITY.md document to clarify the procedure for reporting security vulnerabilities.

  • Enhancement of Tagging System
    Made extensive updates in multiple files like create.command.ts, update.command.ts, hosts.schema.ts, resolved-proxy-config.schema.ts, and hosts.entity.ts to transform the space for a single tag into tags enabling users to insert multiple labels as an array rather than a monotone string.

  • Database Schema Upgrade
    Executed an SQL migration to progress the database design from handling a single tag to managing an array of tags.

  • Schema Prisma Field Update
    Edited the Prisma schema (schema.prisma) to rename the tag field to tags, altering its type into an array of strings for more flexibility in categorization.

  • Refactoring of Repository and Service Files
    Refined various repositories and service files to accommodate and effectively work with the new tags structure.

  • Response Model & Interface Adjustments
    Fine-tuned response models and interfaces to better handle tags being conveyed as an array for improved data organization and application performance.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR migrates the host tag field (single nullable string) to a tags array, mirroring how node tags are already implemented. The change spans the DB migration, Prisma schema, Zod contract, entity/converter/response layers, and the xray-JSON generator logic for tag-based routing.

The implementation is thorough and consistent across all layers. The SQL migration correctly preserves existing data by wrapping the old tag value into a 1-element array before dropping the column.

Confidence Score: 5/5

Safe to merge — migration preserves data, all layers updated consistently, no logic errors.

No P0 or P1 findings. The two P2 comments are a redundant NOT NULL guard in the Kysely query and an unrelated placeholder SECURITY.md file — neither affects correctness or runtime behaviour.

No files require special attention beyond the two minor P2 notes.

Vulnerabilities

No security concerns identified. The migration preserves existing data correctly, input validation (regex + length + array-size limits) is applied at the contract layer before data reaches the database, and no new user-controlled data paths are introduced.

Important Files Changed

Filename Overview
prisma/migrations/20260408120000_migrate_host_tag_to_tags/migration.sql Adds tags TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], migrates existing tag values to 1-element arrays, then drops the old column. Data preservation is correct.
prisma/schema.prisma Updates Hosts model: tag String?tags String[] @default([]). Consistent with the migration and mirrors the Nodes model pattern.
libs/contract/commands/hosts/create.command.ts Replaces tag: z.optional(z.string()...) with tags: z.optional(z.array(...).max(10).default([])). Validation is complete with regex, per-tag length, and array-size limits.
libs/contract/commands/hosts/update.command.ts Same array validation as create, intentionally without .default([]) so omitting tags in a PATCH leaves existing tags unchanged — correct PATCH semantics.
src/modules/hosts/repositories/hosts.repository.ts Rewrites getAllHostTags() to use unnest(tags) via Kysely (matching the nodes pattern). Excludes tags from findByCriteria() Omit type to avoid Prisma array-filter limitations. Correct and clean.
src/modules/subscription-template/generators/xray-json.generator.service.ts Updates three tag-based behaviours: useHostTagAsTag takes tags[0], sameTagAsRecipient checks for array intersection, tagRegex tests each tag. All correctly adapted to the array model.
src/modules/subscription-template/resolve-proxy/resolve-proxy-config.service.ts Maps inputHost.tags instead of inputHost.tag into metadata; stub object now initialises with tags: []. No issues.
src/modules/subscription-template/resolve-proxy/interfaces/resolved-proxy-config.interface.ts Interface updated: `tag: string
src/modules/hosts/entities/hosts.entity.ts Entity field updated to tags: string[]. No issues.
src/modules/hosts/hosts.converter.ts Converter updated to map tags instead of tag. Clean 1-line change.
src/modules/hosts/models/host.response.model.ts Response model updated to expose tags: string[]. No issues.
libs/contract/models/resolved-proxy-config.schema.ts Schema updated: tag: z.string().nullable()tags: z.array(z.string()).default([]). Consistent with interface and rest of changes.
SECURITY.md Adds a SECURITY.md file with GitHub's default placeholder text — unrelated to the host tags migration.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Contract as Zod Contract
    participant Service as HostsService
    participant Repo as HostsRepository
    participant DB as PostgreSQL

    Client->>Contract: POST /api/hosts { tags: [TAG1, TAG2] }
    Contract->>Contract: validate array(regex, max 32), max 10 items
    Contract->>Service: CreateHostCommand.Request
    Service->>Repo: create(entity)
    Repo->>DB: INSERT INTO hosts (tags, ...) VALUES (ARRAY['TAG1','TAG2'], ...)

    Client->>Contract: GET /api/hosts
    Contract-->>Client: HostsSchema { tags: string[] }

    Service->>Repo: getAllHostTags()
    Repo->>DB: SELECT DISTINCT unnest(tags) AS tag FROM hosts ORDER BY tag
    DB-->>Repo: flat list of unique tags
    Repo-->>Service: string[]
Loading

Reviews (1): Last reviewed commit: "fix: имя миграции по конвенции 14-значно..." | Re-trigger Greptile

.selectFrom('hosts')
.select(sql<string>`unnest(tags)`.as('tag'))
.distinct()
.where('tags', 'is not', null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Redundant null-check on a NOT NULL column

tags is declared TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[] in the migration, so this WHERE tags IS NOT NULL predicate will always be true and adds no filtering. unnest(ARRAY[]::TEXT[]) already returns zero rows for empty arrays, so there is no functional regression from removing it — but it may mislead future readers into thinking null values are possible.

Or simply omit the .where(...) clause entirely, matching the actual semantics.

Comment thread SECURITY.md
Comment on lines +1 to +9
# Security Policy

## Reporting a Vulnerability

Use this section to tell people how to report a vulnerability.

Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Placeholder SECURITY.md included in feature PR

This file contains GitHub's default template text ("Tell them where to go, how often they can expect to get an update...") and is unrelated to the host-tags migration. It should either be filled in with a real vulnerability-disclosure policy or removed from this PR and tracked separately.

@kastov
Copy link
Copy Markdown
Contributor

kastov commented May 3, 2026

Спасибо.

В планах смержить ближе к релизу 2.9.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants