ThreadBridgeProduct Requirements & Technical Specification

ThreadBridge

Product Requirements and Technical Specification

Tagline: Turn every video into a structured conversation.

Document version: 1.0 Document status: Build-ready specification Primary platform: Responsive web application Working title: ThreadBridge Primary development language: TypeScript Primary external integration: YouTube Data API v3


1. Executive Summary

ThreadBridge is a video-centered discussion platform where each supported YouTube video becomes a structured discussion room.

A room contains:

  1. An official embedded YouTube player.
  2. A local ThreadBridge discussion board.
  3. Public YouTube comments imported through the official API.
  4. An optional feature allowing a connected user to publish selected ThreadBridge posts to YouTube.
  5. Clear labels showing whether content originated from ThreadBridge, YouTube, or both.

The central product is not the YouTube comment section. The central product is a richer discussion environment built around video content.

ThreadBridge will add independent functionality such as:

Users can participate in one of two ways:

Local participation

The user signs into ThreadBridge and posts exclusively on ThreadBridge. No YouTube authorization is required.

Connected participation

The user connects a YouTube account and may choose, for each individual post, whether to also publish that post publicly on YouTube.

YouTube publishing must never happen silently, automatically, or merely because a user previously enabled it.


2. Product Vision

ThreadBridge should become a place where people can have thoughtful, organized conversations around videos without being restricted by the structure of the original comment section.

The platform should feel like a combination of:

The product should be useful even when YouTube integration is unavailable.

That means a temporary YouTube API outage, expired OAuth token, disabled comment section, or exhausted API quota must not prevent local ThreadBridge discussions from continuing.


3. Problem Statement

Video comment sections are useful for quick reactions, but they are not always well suited to long, structured discussions.

Potential discussion problems include:

ThreadBridge addresses this by turning the video into context rather than treating the original comment section as the entire product.


4. Product Principles

4.1 Local-first operation

ThreadBridge must remain fully functional without YouTube account authorization.

Users must be able to:

4.2 Explicit publishing consent

Every action that publishes, updates, or deletes content on YouTube must be separately and clearly approved by the user.

The composer should contain an unchecked option similar to:

Also publish this publicly on YouTube as Channel Name

The final button should change accordingly:

The checkbox must not be preselected.

4.3 Transparent content origin

Users must always know where content came from.

Every post must display one of these source states:

Local reactions must be labeled as ThreadBridge reactions and must never be presented as YouTube likes.

4.4 No silent automation

ThreadBridge must not:

4.5 Graceful degradation

When YouTube functionality is unavailable:

4.6 Separation of sources

ThreadBridge content and YouTube content must remain conceptually and technically separate.

A synchronized post represents two related pieces of content:

  1. The ThreadBridge copy.
  2. The YouTube copy.

They may later diverge because one copy could be edited, moderated, or deleted independently.


5. Project Goals

5.1 MVP goals

The first production-ready version must allow users to:

5.2 Quality goals

The system must be:


6. Non-Goals for the MVP

The MVP will not include:


7. Core Terminology

Term Meaning
Room The ThreadBridge page associated with a particular video.
Thread A top-level discussion post inside a room.
Post A top-level thread or reply.
Local post Content stored and displayed only by ThreadBridge.
Imported post A public YouTube comment retrieved through the API.
Synchronized post A ThreadBridge post that also has a related YouTube comment.
Connection A user-authorized Google/YouTube OAuth relationship.
Active channel The YouTube channel identity under which the next YouTube action will occur.
External author A YouTube commenter who does not necessarily have a ThreadBridge account.
Outbound synchronization Publishing ThreadBridge content to YouTube.
Inbound synchronization Importing or refreshing YouTube comments.
Reconciliation Checking whether local YouTube mappings still match remote state.
Independent value Functionality provided by ThreadBridge that is not merely a copy of YouTube.

8. User Roles

8.1 Guest

A guest may:

A guest may not:

8.2 Registered member

A registered member may:

8.3 YouTube-connected member

A YouTube-connected member has all registered-member permissions and may also:

8.4 Room moderator

A room moderator may:

Hiding imported content on ThreadBridge must not imply that it was deleted from YouTube.

8.5 Platform administrator

An administrator may:


9. Supported Video Rules

9.1 Supported input formats

The room-creation service should recognize common official YouTube URL patterns, including:

The service must extract the video identifier locally and must never fetch an arbitrary URL supplied by the user.

9.2 URL security

Only approved YouTube hostnames may be accepted.

The application must reject:

This prevents the room-creation feature from becoming an SSRF or injection vector.

9.3 Canonical room behavior

The MVP should have one canonical public room for each supported video.

When a user submits a video that already has a room:

  1. The backend identifies the existing canonical room.
  2. The user is redirected to it.
  3. No duplicate room is created.

The database must enforce a unique constraint on the YouTube video identifier.

A future community feature may allow multiple community-specific rooms for the same video using a compound uniqueness rule such as:

youtube_video_id + community_id

9.4 Unsupported video states

The application must handle:

For the MVP, the preferred rule is to allow room creation only for publicly retrievable and embeddable videos.

If comments are disabled, the local room may still operate, but YouTube comment publishing must be disabled with a clear message.


10. Room Experience

10.1 Desktop layout

The desktop room page should use a two-column layout:

┌────────────────────────────────────────────────────────────┐
│ Header: title, channel, room controls                      │
├─────────────────────────────┬──────────────────────────────┤
│                             │ Discussion controls          │
│ Official YouTube player     │ Source filters               │
│                             │ Sort controls                 │
│ Video information           │ Composer                     │
│                             │ Discussion threads            │
├─────────────────────────────┴──────────────────────────────┤
│ Additional room information                                │
└────────────────────────────────────────────────────────────┘

Recommended proportions:

The video may remain sticky while the user scrolls only while it remains visibly present on the page. It must not behave as hidden background playback.

10.2 Mobile layout

On mobile:

  1. The video appears at the top.
  2. The room title follows.
  3. Source and sorting controls follow.
  4. The composer appears next.
  5. Discussion threads appear below.

The video player must preserve its aspect ratio.

10.3 Room header

The room header should show:

YouTube-supplied information must be clearly attributed to YouTube.

10.4 Source filters

The room should provide:

Global search should index local ThreadBridge content only.

Imported YouTube comments may be searched inside their individual room, but they should not be aggregated into a global cross-channel comment-search product.

10.5 Sorting

Initial sorting options:

“Top on ThreadBridge” must use only local ThreadBridge reactions or local activity. It must not be represented as a YouTube ranking.


11. Thread and Reply Behavior

11.1 Local threads

A registered user may create a local top-level thread.

Local threads support:

11.2 Local reply depth

ThreadBridge may support deep local nesting.

Recommended rendering behavior:

A configurable maximum depth may be used to prevent abuse, but it should be substantially deeper than YouTube’s structure.

11.3 YouTube reply restrictions

YouTube currently supports replies only to top-level comments, not replies to replies. (Google for Developers)

Therefore:

Future versions may offer a flattening flow:

Publish this as a reply to the top-level YouTube comment and include an @name reference.

That future flow must show the exact transformed text before the user approves it.


12. Composer Specification

12.1 Default state

The composer should contain:

Default destination:

ThreadBridge only

12.2 Connected state

When YouTube is connected, the composer should display:

Post destination

● ThreadBridge
○ ThreadBridge and YouTube

YouTube identity: Channel Name

Alternatively:

[ ] Also publish this publicly on YouTube as Channel Name

The YouTube option must be unchecked by default for every new post.

12.3 Plain-text transformation

ThreadBridge may support safe local Markdown, but YouTube receives plain text.

Before publishing to YouTube:

  1. Convert local formatting to readable plain text.
  2. Remove unsupported markup.
  3. Preserve line breaks.
  4. Show a preview of the exact YouTube text.
  5. Require final user submission.

12.4 Draft preservation

A draft must survive:

Drafts should be stored locally in the browser and may additionally be stored server-side for signed-in users.

12.5 Submission result

When posting locally only:

Posted to ThreadBridge

When requesting YouTube publication:

Posted to ThreadBridge
Sending to YouTube…

After a successful API response:

Sent to YouTube

The system should not immediately claim “Public on YouTube” unless public visibility has actually been confirmed.


13. Detailed User Flows

13.1 Guest opens a room

  1. Guest follows a ThreadBridge room link.
  2. Room metadata loads.
  3. Official YouTube player loads.
  4. Visible ThreadBridge and YouTube-origin discussions appear.
  5. Guest may filter and sort.
  6. Posting controls direct the guest to sign in.

13.2 Member creates a room

  1. Member selects Create room.
  2. Member pastes a YouTube URL.
  3. Frontend validates the general format.
  4. Backend extracts the video identifier.
  5. Backend checks whether the room already exists.
  6. If it exists, redirect to the room.
  7. Otherwise retrieve supported metadata through the official API.
  8. Validate video availability and embed eligibility.
  9. Create the video and room records in one transaction.
  10. Queue an initial comment synchronization.
  11. Redirect to the new room.

13.3 Member posts locally

  1. Member writes content.
  2. Destination remains ThreadBridge only.
  3. Frontend validates the content.
  4. Backend validates authorization and rate limits.
  5. Backend stores the post.
  6. Post immediately appears in the room.
  7. Notifications are created for mentioned or replied-to members.

No YouTube token is required.

13.4 Member connects YouTube

  1. Member opens Settings → Connections.
  2. Member selects Connect YouTube.
  3. ThreadBridge displays a pre-consent explanation.
  4. The explanation states that ThreadBridge will be able to publish, update, or delete YouTube comments only when the user directly requests those actions.
  5. User continues to Google OAuth.
  6. The server validates OAuth state on callback.
  7. Authorization code is exchanged server-side.
  8. Refresh token is encrypted before storage.
  9. Available channel identity information is retrieved.
  10. User explicitly selects the active channel when necessary.
  11. Settings page confirms the active identity.

13.5 Member publishes a top-level comment to both systems

  1. Member writes the post.
  2. Member selects ThreadBridge and YouTube.
  3. Interface displays the active YouTube channel.
  4. Interface displays the exact YouTube plain-text version.
  5. User selects the final submit button.
  6. Backend stores the local post.
  7. Backend creates an outbound synchronization job.
  8. Local post displays immediately with Sending to YouTube.
  9. Worker publishes through commentThreads.insert.
  10. Returned YouTube identifier is stored.
  11. Status changes to Sent to YouTube.
  12. Failure leaves the local post intact.

13.6 Member replies to an imported YouTube top-level comment

  1. Member selects Reply.
  2. Composer determines that the parent has a top-level YouTube identifier.
  3. Member may choose local-only or local-plus-YouTube.
  4. Member approves the exact outgoing text.
  5. Local reply is saved.
  6. Worker publishes the reply through comments.insert.
  7. Mapping is recorded.
  8. UI updates synchronization status.

13.7 Member replies to a deep local reply

  1. Member selects Reply.
  2. Composer detects that the parent is not an eligible YouTube top-level comment.
  3. YouTube publishing control is disabled.
  4. Explanatory text appears:

This reply will stay on ThreadBridge because YouTube currently supports replies only to top-level comments.

  1. Member posts locally.

13.8 Editing a synchronized post

Editing must never silently modify both copies.

The user should receive separate options:

For Update both:

  1. Show both resulting versions.
  2. Require explicit approval.
  3. Update ThreadBridge transactionally.
  4. Queue the YouTube update.
  5. Preserve an edit history.
  6. Display divergence if the remote update fails.

The MVP may initially support local editing only and add YouTube updating in the next release.

13.9 Deleting a synchronized post

The delete dialog must clearly distinguish:

Deleting from ThreadBridge does not automatically mean deleting from YouTube.

Deleting from YouTube must require:

13.10 Disconnecting YouTube

  1. User selects Disconnect YouTube.
  2. Interface explains what will happen.
  3. User confirms.
  4. Application revokes the token programmatically.
  5. Stored refresh and access tokens are deleted immediately.
  6. YouTube-authorized cached data associated with the connection is deleted according to the data-deletion process.
  7. Local ThreadBridge posts remain unless the user separately deletes them.
  8. Posts previously synchronized display an appropriate disconnected state.
  9. No future YouTube writes may occur for that connection.

14. Functional Requirements

ID Requirement MVP acceptance condition
FR-001 Account registration and login A user can create and access a secure account.
FR-002 Room creation A signed-in user can create a room using a supported video URL.
FR-003 Canonical room detection Submitting the same video redirects to the existing room.
FR-004 Embedded playback Supported videos render in an official embedded player.
FR-005 Local top-level posts Members can create local discussion threads.
FR-006 Local replies Members can reply to visible posts.
FR-007 Nested local replies Local reply relationships support multiple levels.
FR-008 Source labels Every displayed post clearly identifies its source.
FR-009 YouTube OAuth A user can authorize YouTube access server-side.
FR-010 Channel identity The active channel is shown before every YouTube write.
FR-011 Top-level YouTube publishing An authorized user can publish a new top-level comment.
FR-012 YouTube reply publishing An authorized user can reply to an eligible top-level comment.
FR-013 Per-action consent Every YouTube write requires explicit user initiation.
FR-014 Comment import Public YouTube comments can be retrieved and displayed.
FR-015 Full reply retrieval Missing replies are retrieved separately when necessary.
FR-016 Synchronization status Users see pending, sent, failed, unknown, or removed states.
FR-017 Safe retry Retryable failures can be manually retried without duplicating local posts.
FR-018 Local editing Authors can edit their local content.
FR-019 Local deletion Authors can remove their local content.
FR-020 Local reactions Members can react to local posts.
FR-021 Reporting Members can report content.
FR-022 Moderation Moderators can hide and restore local content.
FR-023 Filters Users can filter discussions by content origin.
FR-024 Sorting Users can sort by local recency or local engagement.
FR-025 Notifications Replies and mentions create ThreadBridge notifications.
FR-026 Quota fallback Local posting continues when YouTube quota is unavailable.
FR-027 Token revocation Users can revoke the integration from ThreadBridge.
FR-028 Data deletion Users can request deletion of stored integration data.
FR-029 Audit logging Sensitive moderation and integration actions are recorded.
FR-030 Responsive design Core workflows function on phone, tablet, and desktop.

15. YouTube API Integration

15.1 Required methods

Retrieve video metadata

Use the supported YouTube Data API video resource to retrieve:

Avoid search.list when the user already supplied a direct URL. Parse the identifier locally and retrieve the specific video.

Retrieve top-level comments

Use:

commentThreads.list

Recommended request characteristics:

Retrieve all replies

A commentThread may contain only a subset of its replies. The application must compare the returned reply collection with totalReplyCount and call comments.list using the parent identifier when the complete reply collection is needed. (Google for Developers)

Publish top-level comments

Use:

commentThreads.insert

The request requires authorization with:

https://www.googleapis.com/auth/youtube.force-ssl

The request body requires the associated channel identifier, video identifier, and original comment text. The operation costs 50 quota units. (Google for Developers)

Publish replies

Use:

comments.insert

The request requires the same YouTube OAuth scope and requires the top-level parent comment identifier plus original reply text. The operation costs 50 quota units. (Google for Developers)

Update comments

Use:

comments.update

Only support this where the active user has the required permission. The action must be initiated separately by the user.

Delete comments

Use:

comments.delete

Only support deletion of comments the authorized user is permitted to delete. The delete action must be unmistakably identified as a YouTube action.

15.2 OAuth architecture

YouTube publishing cannot use an API key alone.

Use a server-side OAuth 2.0 authorization-code flow:

  1. Generate authorization URL on the server.
  2. Include a cryptographically strong state value.
  3. Prefer PKCE in addition to state.
  4. Redirect the user to Google.
  5. Validate state in the callback.
  6. Exchange the authorization code server-side.
  7. Encrypt the refresh token.
  8. Never send the refresh token to the browser.
  9. Refresh access tokens server-side.
  10. Reauthorize when refresh fails.

Google’s server-side OAuth guidance requires secure redirect handling, state validation, HTTPS in production, and secure token storage. Standard service accounts are not a replacement for normal user authorization for this use case; YouTube service-account support is limited to qualifying content-owner workflows. (Google for Developers)

15.3 Incremental authorization

Application login and YouTube authorization should be separate.

Initial Google login may request only:

openid
email
profile

The YouTube scope should be requested only after the user selects Connect YouTube.

This avoids requesting broad permissions before the corresponding feature exists or is used.

15.4 Comment hierarchy

YouTube currently supports:

Top-level comment
├── Reply
├── Reply
└── Reply

ThreadBridge supports:

Top-level post
└── Reply
    └── Reply
        └── Reply

The application must preserve the richer local hierarchy without pretending that the same hierarchy exists on YouTube.

15.5 Comment synchronization is polling-based

YouTube push notifications cover video uploads and changes to a video’s title or description; they do not provide comment notifications. Comment synchronization must therefore use scheduled or on-demand API reads. (Google for Developers)

15.6 Policy requirements

ThreadBridge must add significant independent value rather than act as a replacement copy of YouTube. YouTube actions must be clearly identified, distinct from local actions, directly initiated by the user, and expressly approved before execution. Automated comments without the user’s prior specific consent are prohibited. (Google for Developers)

15.7 Data freshness and retention

Cached YouTube API data must be refreshed or deleted within the applicable policy period. General API data that does not qualify for longer storage must be deleted or refreshed after no more than 30 calendar days. The application must make reasonable efforts to keep displayed data current. (Google for Developers)

Every imported YouTube entity should therefore include:

last_refreshed_at
refresh_due_at
remote_status

A scheduled compliance worker must:

  1. Find YouTube-derived records approaching expiration.
  2. Refresh records still needed.
  3. Delete records that cannot or should not be refreshed.
  4. Remove stale external profile data.
  5. Record the operation in an audit log.

15.8 User deletion and revocation

ThreadBridge must provide an easy way to revoke YouTube authorization.

When the user revokes through ThreadBridge:

YouTube’s current developer policy specifies deletion as soon as possible and within seven calendar days for user-requested stored-data deletion and in-product revocation. (Google for Developers)

15.9 Made-for-Kids handling

The application should not be designed as a child-directed API client.

For each embedded video:

YouTube requires API clients to check the Made-for-Kids status of embedded videos, and child-directed API clients cannot perform YouTube write actions such as commenting. (Google for Developers)

15.10 Production OAuth verification

Development should begin with a testing OAuth consent configuration and explicitly registered test users.

Before broad public launch, prepare:

Google requires production applications using sensitive or restricted scopes to complete the applicable OAuth verification process unless an exception applies. (Google Support)


16. Recommended Technical Stack

16.1 Monorepo

Use:

16.2 Web application

Use:

16.3 Backend

Use Next.js route handlers for browser-facing API requests, but keep business logic in separate service modules.

Do not place YouTube API logic directly inside:

Instead, use service and adapter layers.

16.4 Database

Use:

PostgreSQL will store:

16.5 Background worker

Use a separate Node.js worker process.

Recommended responsibilities:

Use a PostgreSQL-backed queue such as pg-boss, or implement a queue abstraction that can later be replaced.

16.6 Testing

Use:

16.7 Observability

Use:


17. High-Level Architecture

┌──────────────────────────┐
│ Browser                  │
│ Next.js user interface   │
└────────────┬─────────────┘
             │ HTTPS
             ▼
┌──────────────────────────┐
│ Web/API application      │
│ Authentication           │
│ Validation               │
│ Room and post services   │
└───────┬──────────┬───────┘
        │          │
        │          └─────────────────────┐
        ▼                                ▼
┌─────────────────┐             ┌──────────────────┐
│ PostgreSQL      │             │ Google OAuth    │
│ Core data       │             │ Authorization   │
│ Queue metadata  │             └──────────────────┘
└────────┬────────┘
         │
         ▼
┌──────────────────────────┐
│ Background worker        │
│ Sync and reconciliation  │
│ Quota management         │
└────────────┬─────────────┘
             │
             ▼
┌──────────────────────────┐
│ YouTube Data API v3      │
└──────────────────────────┘

17.1 Architectural rules

  1. All YouTube write requests occur on the server.
  2. OAuth refresh tokens never reach the browser.
  3. Local content is saved before a YouTube job is attempted.
  4. External API requests are wrapped by a provider interface.
  5. External failures cannot roll back a successful local post.
  6. Every background job must be traceable.
  7. Every write job must be idempotent at the application level.
  8. No raw YouTube API response should be passed directly to the UI.
  9. Public API models and database models must be separate.
  10. Sensitive fields must never appear in logs.

18. Repository Structure

threadbridge/
├── apps/
│   ├── web/
│   │   ├── app/
│   │   ├── components/
│   │   ├── features/
│   │   ├── lib/
│   │   ├── server/
│   │   └── tests/
│   └── worker/
│       ├── src/
│       │   ├── jobs/
│       │   ├── processors/
│       │   ├── schedules/
│       │   └── index.ts
│       └── tests/
├── packages/
│   ├── database/
│   │   ├── prisma/
│   │   └── src/
│   ├── youtube/
│   │   ├── src/
│   │   │   ├── adapter.ts
│   │   │   ├── google-youtube-provider.ts
│   │   │   ├── mock-youtube-provider.ts
│   │   │   ├── mappers.ts
│   │   │   ├── errors.ts
│   │   │   └── schemas.ts
│   │   └── tests/
│   ├── auth/
│   ├── queue/
│   ├── ui/
│   ├── validation/
│   ├── config/
│   └── observability/
├── docs/
│   ├── architecture.md
│   ├── youtube-compliance.md
│   ├── threat-model.md
│   ├── synchronization.md
│   └── deployment.md
├── AGENTS.md
├── PROJECT_SPEC.md
├── docker-compose.yml
├── pnpm-workspace.yaml
├── turbo.json
├── package.json
└── .env.example

19. Data Model

19.1 User

users
-----
id
email
email_verified_at
display_name
avatar_url
role
status
created_at
updated_at
deleted_at

Possible roles:

MEMBER
MODERATOR
ADMIN

Possible statuses:

ACTIVE
SUSPENDED
DELETION_PENDING
DELETED

19.2 YouTube connection

youtube_connections
-------------------
id
user_id
google_subject
channel_id
channel_title
channel_avatar_url
encrypted_refresh_token
token_key_version
granted_scopes
status
last_validated_at
last_successful_refresh_at
reauthorization_required_at
revoked_at
created_at
updated_at

Connection statuses:

CONNECTED
NEEDS_REAUTHORIZATION
REVOKED
DISABLED
DELETION_PENDING

Constraints:

19.3 Video

videos
------
id
youtube_video_id
owner_channel_id
owner_channel_title
title
description_excerpt
thumbnail_url
published_at
embeddable
made_for_kids
availability_status
comments_status
last_refreshed_at
refresh_due_at
created_at
updated_at

Availability statuses:

AVAILABLE
PRIVATE
DELETED
RESTRICTED
UNAVAILABLE
UNKNOWN

Comment statuses:

AVAILABLE
DISABLED
UNKNOWN

19.4 Room

rooms
-----
id
video_id
slug
created_by_user_id
title_override
description
visibility
status
locked_at
created_at
updated_at

Visibility:

PUBLIC
UNLISTED
PRIVATE

Only PUBLIC is required for the MVP.

Status:

ACTIVE
LOCKED
ARCHIVED
REMOVED

19.5 Post

posts
-----
id
room_id
author_user_id
external_author_id
parent_post_id
root_post_id
depth
body
body_format
origin
visibility
moderation_status
created_at
updated_at
deleted_at

Origins:

THREADBRIDGE
YOUTUBE_IMPORTED
THREADBRIDGE_AND_YOUTUBE

Visibility:

VISIBLE
HIDDEN
DELETED
PENDING_REVIEW

Rules:

19.6 Post version

post_versions
-------------
id
post_id
body
created_by_user_id
reason
created_at

This provides an audit history for local edits.

19.7 External YouTube author

external_authors
----------------
id
youtube_channel_id
display_name
avatar_url
channel_url
last_refreshed_at
refresh_due_at
created_at
updated_at

An external author is not automatically converted into a ThreadBridge user.

19.8 YouTube comment mapping

youtube_comment_mappings
------------------------
id
post_id
youtube_comment_id
youtube_top_level_comment_id
youtube_parent_comment_id
direction
youtube_author_channel_id
youtube_text_snapshot
youtube_published_at
youtube_updated_at
etag
remote_visibility
sync_status
last_error_code
last_error_message_safe
last_attempt_at
last_refreshed_at
refresh_due_at
created_at
updated_at

Direction:

IMPORTED
OUTBOUND

Synchronization status:

NOT_REQUESTED
PENDING
SENDING
SENT
CONFIRMED
FAILED_RETRYABLE
FAILED_FINAL
UNKNOWN
REMOTE_REMOVED
CONNECTION_REVOKED

Constraints:

19.9 Local reaction

post_reactions
--------------
id
post_id
user_id
reaction_type
created_at

Possible reactions:

LIKE
INSIGHTFUL
AGREE
DISAGREE
QUESTION

Add a unique constraint:

post_id + user_id + reaction_type

These are explicitly ThreadBridge reactions.

19.10 Report

reports
-------
id
post_id
reported_by_user_id
reason
details
status
reviewed_by_user_id
reviewed_at
created_at

Reasons:

SPAM
HARASSMENT
HATE
MISINFORMATION
OFF_TOPIC
PERSONAL_INFORMATION
OTHER

19.11 Moderation action

moderation_actions
------------------
id
room_id
post_id
target_user_id
moderator_user_id
action
reason
metadata
created_at

Actions:

HIDE_POST
RESTORE_POST
LOCK_THREAD
UNLOCK_THREAD
FEATURE_THREAD
UNFEATURE_THREAD
WARN_USER
SUSPEND_FROM_ROOM

19.12 Notification

notifications
-------------
id
user_id
type
actor_user_id
post_id
room_id
read_at
created_at

19.13 Room synchronization state

room_sync_states
----------------
room_id
last_started_at
last_completed_at
last_success_at
last_error_code
next_scheduled_at
recent_thread_cursor
sync_priority
status
updated_at

19.14 Quota ledger

youtube_quota_ledger
--------------------
id
date_bucket
operation
estimated_units
request_count
user_id
room_id
job_id
created_at

This is an application-side estimate and must not be presented as the official Google quota balance.

19.15 Audit log

audit_logs
----------
id
actor_user_id
action
entity_type
entity_id
request_id
safe_metadata
ip_hash
created_at

Never include:


20. Database Indexes and Constraints

Required indexes include:

videos.youtube_video_id UNIQUE
rooms.video_id UNIQUE
posts(room_id, created_at)
posts(parent_post_id, created_at)
posts(root_post_id, created_at)
posts(author_user_id, created_at)
youtube_comment_mappings.youtube_comment_id UNIQUE
youtube_comment_mappings(post_id) UNIQUE
youtube_connections(user_id, channel_id) UNIQUE
reports(status, created_at)
notifications(user_id, read_at, created_at)
room_sync_states(next_scheduled_at)

Application-level validation must ensure:


21. Application API Design

21.1 Rooms

Method Path Purpose
POST /api/rooms Create or resolve a room from a video URL.
GET /api/rooms/:roomId Retrieve room information.
GET /api/rooms/:roomId/posts Retrieve paginated room posts.
POST /api/rooms/:roomId/sync Request an authorized or rate-limited refresh.

Example room request:

{
  "youtubeUrl": "USER_SUPPLIED_YOUTUBE_URL"
}

Example response:

{
  "room": {
    "id": "room_uuid",
    "slug": "video-title-video-id",
    "video": {
      "youtubeVideoId": "video_id",
      "title": "Video title"
    }
  },
  "created": true
}

21.2 Posts

Method Path Purpose
POST /api/rooms/:roomId/posts Create a local thread or reply.
PATCH /api/posts/:postId Edit local content.
DELETE /api/posts/:postId Remove local content.
POST /api/posts/:postId/reactions Add a local reaction.
DELETE /api/posts/:postId/reactions/:type Remove a local reaction.
POST /api/posts/:postId/report Report content.

Create-post request:

{
  "body": "The discussion text",
  "parentPostId": null,
  "destinations": ["THREADBRIDGE"],
  "youtubeConnectionId": null,
  "youtubeTextPreviewHash": null
}

Dual-publication request:

{
  "body": "The local discussion text",
  "parentPostId": null,
  "destinations": ["THREADBRIDGE", "YOUTUBE"],
  "youtubeConnectionId": "connection_uuid",
  "youtubeText": "The exact plain-text YouTube version",
  "youtubeTextPreviewHash": "server_verified_hash"
}

The preview hash prevents the frontend from approving one version while a different version is sent.

21.3 YouTube connections

Method Path Purpose
GET /api/connections/youtube List the user’s current connections.
POST /api/connections/youtube/start Begin OAuth authorization.
GET /api/connections/youtube/callback Handle OAuth callback.
PATCH /api/connections/youtube/:id/active Select active channel.
DELETE /api/connections/youtube/:id Revoke and delete connection data.

21.4 YouTube publication

Method Path Purpose
POST /api/posts/:postId/youtube/publish Request publication after explicit consent.
POST /api/posts/:postId/youtube/retry Manually retry a safe failure.
PATCH /api/posts/:postId/youtube Explicitly update the YouTube copy.
DELETE /api/posts/:postId/youtube Explicitly delete the YouTube copy.

21.5 Moderation

Method Path Purpose
GET /api/moderation/reports Retrieve authorized reports.
POST /api/moderation/posts/:postId/hide Hide local content.
POST /api/moderation/posts/:postId/restore Restore local content.
POST /api/moderation/threads/:postId/lock Lock a local thread.
POST /api/moderation/threads/:postId/feature Feature a local thread.

21.6 Internal worker endpoints

Any internal HTTP worker endpoint must be:


22. YouTube Provider Interface

All YouTube-specific behavior should be hidden behind an interface.

export interface YouTubeProvider {
  getVideo(input: {
    videoId: string;
  }): Promise<YouTubeVideoResult>;

  getAuthorizedChannels(input: {
    connectionId: string;
  }): Promise<YouTubeChannelIdentity[]>;

  listCommentThreads(input: {
    videoId: string;
    pageToken?: string;
    maxResults?: number;
  }): Promise<YouTubeCommentThreadPage>;

  listReplies(input: {
    topLevelCommentId: string;
    pageToken?: string;
    maxResults?: number;
  }): Promise<YouTubeReplyPage>;

  publishTopLevelComment(input: {
    connectionId: string;
    channelId: string;
    videoId: string;
    text: string;
  }): Promise<YouTubePublishedComment>;

  publishReply(input: {
    connectionId: string;
    topLevelCommentId: string;
    text: string;
  }): Promise<YouTubePublishedComment>;

  updateComment(input: {
    connectionId: string;
    commentId: string;
    text: string;
  }): Promise<YouTubePublishedComment>;

  deleteComment(input: {
    connectionId: string;
    commentId: string;
  }): Promise<void>;

  revokeConnection(input: {
    connectionId: string;
  }): Promise<void>;
}

Implementations:

GoogleYouTubeProvider
MockYouTubeProvider

The mock provider should support:

This allows development and automated testing without consuming real quota.


23. Outbound Synchronization

23.1 Local-first transaction

When the user selects ThreadBridge and YouTube:

  1. Validate the user.
  2. Validate the room.
  3. Validate the connection.
  4. Validate active channel identity.
  5. Validate the content.
  6. Confirm the approved YouTube text hash.
  7. Create the local post.
  8. Create a mapping record with PENDING.
  9. Enqueue a publication job.
  10. Commit the database transaction.
  11. Return the local post immediately.

The external API request must not occur inside the database transaction.

23.2 Worker sequence

The worker should:

  1. Lock the job.
  2. Verify it has not already completed.
  3. Load the post and connection.
  4. Verify connection status.
  5. Decrypt the refresh token.
  6. Obtain or refresh an access token.
  7. Check application quota budget.
  8. Set mapping status to SENDING.
  9. Call the YouTube provider.
  10. Store the returned remote identifier.
  11. Set status to SENT.
  12. Record estimated quota usage.
  13. Create a user notification.
  14. Complete the job.

23.3 Idempotency

YouTube comment insertion does not provide an application-defined idempotency key.

The application must therefore prevent duplicate attempts using:

Example job key:

youtube-publish:{postId}:{approvedVersionHash}

23.4 Ambiguous timeout

A dangerous case occurs when:

  1. ThreadBridge sends the request.
  2. YouTube creates the comment.
  3. The network fails before ThreadBridge receives the response.

The system cannot safely assume that publication failed.

In this case:

This is preferable to creating duplicate comments.

23.5 Retry rules

Automatically retry only clearly transient failures such as:

Do not automatically retry:

Quota-exhausted publication should require the user to initiate a new attempt after quota becomes available.


24. Inbound Synchronization

24.1 Initial room synchronization

When a room is first created:

  1. Queue an initial comment retrieval.
  2. Retrieve the newest top-level threads.
  3. Upsert each thread using the YouTube comment identifier.
  4. Import returned replies.
  5. Compare imported reply count with total reply count.
  6. Retrieve missing replies separately.
  7. Store refresh timestamps.
  8. Mark the room synchronization complete.

24.2 Ongoing synchronization

Use an adaptive schedule.

Suggested categories:

HOT
WARM
COLD
ARCHIVED

Possible behavior:

Exact intervals should be configurable rather than hardcoded.

24.3 Reply reconciliation

A new reply may be added to an older top-level thread.

The worker should therefore:

  1. Refresh recent top-level threads.
  2. Compare stored reply counts with current reply counts.
  3. Retrieve all replies when a count changed.
  4. Periodically revisit active older threads.
  5. Deduplicate by remote identifier.

24.4 Remote edits

When an imported YouTube comment changes:

For a synchronized ThreadBridge post, do not silently overwrite the local copy.

Instead, record that the remote copy differs:

YouTube copy was changed outside ThreadBridge

24.5 Remote deletion

When a known YouTube comment is confirmed missing:

24.6 Refresh compliance

A daily compliance job must:

  1. Identify YouTube-derived records with approaching refresh deadlines.
  2. Refresh records still actively used.
  3. Delete records that cannot be refreshed.
  4. Remove orphaned external-author data.
  5. Validate active connection tokens.
  6. Process deletion requests.
  7. Record completion metrics.

25. Synchronization State Machine

NOT_REQUESTED
      │
      ▼
   PENDING
      │
      ▼
   SENDING
   ├──────────────► SENT ──────────────► CONFIRMED
   │                  │
   │                  └───────────────► REMOTE_REMOVED
   │
   ├──────────────► FAILED_RETRYABLE
   │                        │
   │                        └──────────► PENDING
   │
   ├──────────────► FAILED_FINAL
   │
   ├──────────────► UNKNOWN
   │                    │
   │                    └──────────────► reconciliation
   │
   └──────────────► CONNECTION_REVOKED

The UI must map technical states to understandable language.


26. Error Model

Use typed application errors.

AUTHENTICATION_REQUIRED
AUTHORIZATION_FAILED
YOUTUBE_CONNECTION_REQUIRED
YOUTUBE_REAUTHORIZATION_REQUIRED
YOUTUBE_CHANNEL_NOT_SELECTED
VIDEO_NOT_FOUND
VIDEO_UNAVAILABLE
VIDEO_NOT_EMBEDDABLE
COMMENTS_DISABLED
PARENT_COMMENT_NOT_FOUND
REPLY_NOT_SUPPORTED
COMMENT_TOO_LONG
COMMENT_INVALID
PERMISSION_DENIED
QUOTA_EXHAUSTED
RATE_LIMITED
REMOTE_TIMEOUT_UNKNOWN
REMOTE_SERVICE_UNAVAILABLE
VALIDATION_FAILED
POST_LOCKED
USER_SUSPENDED
INTERNAL_ERROR

Recommended messages:

Error User message
COMMENTS_DISABLED “This video does not currently accept YouTube comments. Your ThreadBridge post is still available.”
YOUTUBE_REAUTHORIZATION_REQUIRED “Your YouTube connection has expired or was revoked. Reconnect before publishing.”
PARENT_COMMENT_NOT_FOUND “The YouTube comment you were replying to is no longer available.”
REPLY_NOT_SUPPORTED “This reply can remain on ThreadBridge, but it cannot be published as a nested YouTube reply.”
QUOTA_EXHAUSTED “YouTube publishing is temporarily unavailable because the application’s daily API allowance has been reached. Your ThreadBridge post was saved.”
REMOTE_TIMEOUT_UNKNOWN “YouTube may have received this comment, but confirmation was interrupted. ThreadBridge will not retry automatically to avoid creating a duplicate.”
PERMISSION_DENIED “The selected YouTube channel is not permitted to complete this action.”

Never show users:


27. Authentication and Authorization

27.1 Application authentication

Support:

Application authentication and YouTube authorization remain separate.

27.2 Session security

Use:

27.3 Authorization service

Centralize authorization decisions:

canCreateRoom(user)
canPostInRoom(user, room)
canReplyToPost(user, post)
canEditPost(user, post)
canDeletePost(user, post)
canModerateRoom(user, room)
canPublishToYouTube(user, connection, post)
canUpdateYouTubeComment(user, mapping)
canDeleteYouTubeComment(user, mapping)

Do not rely only on hidden buttons. Every operation must be checked server-side.


28. Security Requirements

28.1 Token encryption

Refresh tokens must be encrypted using authenticated encryption such as AES-256-GCM.

Store:

The encryption key must live in a secret manager or protected environment configuration, not in source control.

28.2 OAuth CSRF protection

Use:

28.3 XSS protection

28.4 SSRF protection

28.5 Abuse prevention

Implement:

28.6 Secrets and logs

Never log:

Authorization headers
OAuth authorization codes
Access tokens
Refresh tokens
Client secrets
Encryption keys
Complete cookies

Log safe identifiers:

request_id
user_id
room_id
post_id
job_id
provider_operation
safe_error_code
duration

28.7 Privilege escalation protection

Every moderator action must verify:

Every administrator action must be audited.

28.8 Dependency security

CI should run:


29. Moderation System

29.1 Local moderation

ThreadBridge moderators control ThreadBridge presentation and participation.

They may:

29.2 Imported YouTube content

Moderators may hide an imported YouTube comment from the ThreadBridge room.

The UI must say:

Hidden on ThreadBridge

It must not say:

Deleted from YouTube

29.3 YouTube moderation

Direct YouTube moderation by connected video/channel owners is a later feature.

It should not be part of the MVP because:

29.4 Locked threads

When a local thread is locked:


30. Notifications

MVP notifications:

Do not generate repeated notifications for the same imported synchronization event.

Notification delivery:


31. Search

31.1 Global search

Global search should index:

31.2 Room search

Room search may include:

Results must preserve source labels.

31.3 Search privacy

Private or unlisted future rooms must not appear in public search.

Deleted or hidden content must not remain searchable to unauthorized users.


32. Quota Strategy

YouTube currently allocates 10,000 daily quota units by default for the combined general API bucket. Comment insertion costs 50 units, while comment and comment-thread list operations cost 1 unit. Even invalid API requests consume at least one unit. (Google for Developers)

The theoretical maximum with no other API usage is approximately:

10,000 / 50 = 200 comment writes per day

Actual capacity will be lower because the application also performs:

32.1 Internal budget

Reserve part of the daily quota for reads.

Example planning budget:

Total general quota:        10,000
Reserved for retrieval:      2,000
Available write budget:      8,000
Estimated comment writes:      160

This is only an application planning estimate.

32.2 Quota controls

Implement:

32.3 Quota exhaustion

When quota is unavailable:

32.4 Efficient retrieval

To conserve quota:


33. Privacy and Compliance Pages

Production must include:

/privacy
/terms
/data-deletion
/settings/connections
/settings/account

The privacy policy must explain:

The interface must include:


34. Accessibility Requirements

Target WCAG 2.2 AA.

Required behavior:

Source badges should combine text and iconography.


35. Performance Requirements

Initial targets:

YouTube publication speed must not block local posting.


36. Observability

36.1 Required metrics

Track:

36.2 Health endpoints

Provide:

/api/health/live
/api/health/ready

Readiness should check:

It should not spend YouTube quota.

36.3 Alerts

Alert on:


37. Testing Strategy

37.1 Unit tests

Test:

37.2 Database integration tests

Test:

37.3 YouTube adapter contract tests

Run the same behavioral contract against:

Contract cases:

37.4 End-to-end tests

Playwright scenarios:

  1. Guest opens a room.
  2. Member creates a room.
  3. Member creates a local thread.
  4. Member replies locally.
  5. Deep reply disables YouTube destination.
  6. Connected user selects YouTube publication.
  7. Successful mocked publication changes status.
  8. Failed publication leaves local post intact.
  9. User manually retries safe failure.
  10. Ambiguous failure does not automatically retry.
  11. Moderator hides a local post.
  12. User disconnects YouTube.
  13. Deleted integration cannot create new jobs.
  14. Mobile room layout functions.
  15. Keyboard-only user can post and navigate.

37.5 Security tests

Test:

37.6 Production smoke tests

After deployment:


38. Environment Configuration

Create a validated .env.example.

NODE_ENV=
APP_URL=

DATABASE_URL=
DIRECT_DATABASE_URL=

AUTH_SECRET=
SESSION_ENCRYPTION_KEY=

GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
GOOGLE_OAUTH_REDIRECT_URI=

YOUTUBE_API_KEY=
YOUTUBE_OAUTH_SCOPE=https://www.googleapis.com/auth/youtube.force-ssl

TOKEN_ENCRYPTION_KEY=
TOKEN_ENCRYPTION_KEY_VERSION=

QUEUE_DATABASE_URL=
WORKER_CONCURRENCY=
INTERNAL_WORKER_SECRET=

YOUTUBE_WRITES_ENABLED=
YOUTUBE_DAILY_READ_RESERVE=
YOUTUBE_ESTIMATED_DAILY_QUOTA=

ROOM_SYNC_HOT_INTERVAL=
ROOM_SYNC_WARM_INTERVAL=
ROOM_SYNC_COLD_INTERVAL=

SENTRY_DSN=
LOG_LEVEL=

RATE_LIMIT_POSTS_PER_MINUTE=
RATE_LIMIT_YOUTUBE_WRITES_PER_DAY=

All environment variables must be validated at startup.

The application should fail fast when required production configuration is missing.


39. Local Development

39.1 Prerequisites

39.2 Typical commands

pnpm install
docker compose up -d
pnpm db:migrate
pnpm db:seed
pnpm dev

Quality commands:

pnpm lint
pnpm typecheck
pnpm test
pnpm test:e2e
pnpm build

39.3 Development modes

Support:

YOUTUBE_PROVIDER=mock
YOUTUBE_PROVIDER=google

Default local development should use mock.

Real Google integration should be intentionally enabled.

39.4 Seed data

Seed:


40. Deployment Architecture

Recommended production services:

  1. Web application service.
  2. Worker service.
  3. Managed PostgreSQL.
  4. Secret manager.
  5. Error tracking.
  6. Log aggregation.
  7. Scheduled job capability.

The web and worker may use the same source repository but must deploy as separate processes.

40.1 Production deployment requirements

40.2 Staging

Staging should have:


41. Delivery Phases

Phase 0: Foundation and documentation

Deliver:

Acceptance:

pnpm install
pnpm lint
pnpm typecheck
pnpm test
pnpm build

all succeed.

Phase 1: Local discussion board

Deliver:

No real YouTube OAuth or writes in this phase.

Phase 2: YouTube connection and outbound publishing

Deliver:

Phase 3: Inbound synchronization

Deliver:

Phase 4: Moderation and notifications

Deliver:

Phase 5: Production hardening

Deliver:

Phase 6: Public launch preparation

Deliver:


42. Codex Working Instructions

Codex reads repository instructions from AGENTS.md, so the root file must explain the architecture, commands, safety rules, and completion criteria. (OpenAI Developers)

The root AGENTS.md should require Codex to:

  1. Read PROJECT_SPEC.md before changing architecture.
  2. Work on one delivery phase or one vertical slice at a time.
  3. Inspect existing code before creating replacement systems.
  4. Use TypeScript strict mode.
  5. Keep YouTube logic behind the provider interface.
  6. Keep secrets and tokens server-side.
  7. Never log credentials.
  8. Add or update tests for every behavior change.
  9. Run lint, type checking, tests, and build before declaring completion.
  10. Update documentation when contracts or architecture change.
  11. Avoid introducing a second library for a responsibility already covered.
  12. Avoid implementing future features during an earlier milestone.
  13. Preserve local-post functionality when YouTube integration fails.
  14. Never create automatic YouTube-comment behavior.
  15. Treat ambiguous remote writes as UNKNOWN, not safe failures.
  16. Ask for explicit environment credentials only when the code genuinely reaches an integration stage.
  17. Use the mock provider in automated tests.
  18. Include database migrations for schema changes.
  19. Report the files changed and commands executed.
  20. Never claim a test passed unless it was actually run successfully.

43. First Prompt to Give Codex

Read AGENTS.md and PROJECT_SPEC.md completely before making changes.

Implement Phase 0 only.

Create the ThreadBridge monorepo using pnpm, Turborepo, TypeScript strict mode, a Next.js web application, a separate Node.js worker application, shared packages, PostgreSQL, Prisma, environment validation, Docker Compose, CI, and health endpoints.

Do not implement user-facing discussion features or real YouTube integration yet.

Requirements:

1. Create the repository structure defined in PROJECT_SPEC.md.
2. Add a root AGENTS.md containing the project rules from the specification.
3. Add apps/web and apps/worker.
4. Add packages/database, packages/youtube, packages/auth, packages/queue, packages/ui, packages/validation, packages/config, and packages/observability.
5. Create the initial Prisma configuration and a minimal health-related schema only where necessary.
6. Add docker-compose.yml for local PostgreSQL.
7. Add a validated .env.example.
8. Add lint, typecheck, test, build, dev, database migration, and formatting scripts.
9. Add a MockYouTubeProvider and the YouTubeProvider interface, but do not call Google.
10. Add /api/health/live and /api/health/ready.
11. Add unit tests for environment validation and the mock provider.
12. Add a CI workflow that runs install, lint, typecheck, tests, and build.
13. Run every quality command.
14. Fix all failures before stopping.
15. Finish with a concise report of architecture created, files changed, commands run, test results, and any assumptions.

Do not add unrelated packages. Do not hardcode secrets. Do not skip tests.

44. Phase 1 Prompt for Codex

After Phase 0 has been reviewed and committed:

Read AGENTS.md and PROJECT_SPEC.md.

Implement Phase 1: Local Discussion Board.

Build one complete vertical slice at a time in this order:

1. Application authentication and user profile.
2. Secure YouTube URL parser with unit tests.
3. Mock video metadata retrieval.
4. Canonical room creation.
5. Responsive room page with mock embedded-video data.
6. Local top-level posts.
7. Local nested replies.
8. Local reactions.
9. Source labels.
10. Cursor pagination.
11. Reporting.
12. End-to-end tests.

Do not implement Google OAuth, real YouTube API calls, inbound synchronization, or YouTube publishing in this phase.

Run lint, typecheck, unit tests, integration tests, end-to-end tests, and production build. Update the project documentation and report all results.

45. Definition of Done for the MVP

The MVP is complete only when:


46. Future Roadmap

46.1 Communities

Allow groups to create independent rooms around the same video.

Examples:

Each community could have:

46.2 AI discussion tools

Possible later features:

AI-generated text must never be published to YouTube automatically.

The user must:

  1. Review the complete text.
  2. Edit it as desired.
  3. Select the YouTube destination.
  4. Approve the exact outgoing version.
  5. Submit the action directly.

46.3 Creator tools

For verified video owners:

46.4 Live watch rooms

Later support:

This must remain separate from YouTube live chat unless a compliant official integration is designed.

46.5 Mobile application

After web product validation:

46.6 Monetization

Possible monetization should focus on ThreadBridge’s independent functionality:

Do not sell access to YouTube API functionality itself.


47. Risk Register

Risk Impact Mitigation
OAuth verification delay Public launch delay Begin testing with approved test users and prepare verification material early.
Daily quota exhaustion YouTube publication unavailable Preserve local-first operation, quota budgeting, adaptive synchronization, manual retry.
Duplicate YouTube comments User trust damage Unique jobs, row locking, unknown state, reconciliation before retry.
Revoked refresh token Publication failure Detect refresh failure, stop jobs, request reconnection.
Comments disabled Remote publishing impossible Clear message and local-only fallback.
Remote deletion Stale local presentation Reconciliation and REMOTE_REMOVED status.
Deep-reply mismatch Confusing discussion structure Keep deep replies local in MVP.
Policy noncompliance API suspension Independent functionality, explicit consent, privacy controls, audit documentation.
Spam and abuse Community harm Rate limits, reports, moderation, suspension, audit logs.
Token exposure Account compromise Server-only storage, authenticated encryption, secret management, log redaction.
Stale API data Incorrect presentation Refresh deadlines and compliance worker.
Ambiguous network timeout Duplicate remote write Mark unknown and avoid automatic retry.
Imported-content aggregation Policy risk Room-scoped imported search and local-only global analytics.
Overly broad initial build Slow delivery Implement phase by phase and require acceptance after each phase.

48. Product Success Measures

Use metrics generated from ThreadBridge’s own system.

Initial measures:

Any metric calculated by ThreadBridge must be clearly identified as a ThreadBridge metric and not a YouTube metric.


49. Final Product Statement

ThreadBridge is an independent, structured discussion platform built around video context.

Its defining behavior is:

ThreadBridge owns the discussion experience.
YouTube provides the video and an optional publication destination.
The user remains in control of every YouTube action.

The MVP succeeds when users can hold complete local discussions without YouTube authorization while connected users can deliberately publish selected comments to YouTube through a secure, transparent, quota-aware, and policy-compliant integration.