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:
- An official embedded YouTube player.
- A local ThreadBridge discussion board.
- Public YouTube comments imported through the official API.
- An optional feature allowing a connected user to publish selected ThreadBridge posts to YouTube.
- 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:
- Deeply nested local conversations.
- Topic-based discussion threads.
- Local reactions.
- Room moderation.
- Search and filters.
- Bookmarks.
- Mentions.
- Notifications.
- Locked or featured threads.
- Community-specific discussion rooms in later releases.
- Optional AI-generated discussion summaries in later releases.
- Clear separation between local activity and YouTube activity.
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:
- A traditional discussion forum.
- A modern community platform.
- A video watch page.
- An optional bridge to YouTube comments.
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:
- Replies becoming difficult to follow.
- Important comments becoming buried.
- Multiple topics being discussed inside one unstructured feed.
- Limited tools for community-specific moderation.
- No deep local reply hierarchy.
- Difficulty finding an earlier contribution.
- No separation between formal debate, questions, reactions, and general conversation.
- Limited control for communities that want to discuss the same video under their own rules.
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:
- Create local discussion posts.
- Reply locally.
- React locally.
- Report content.
- Receive ThreadBridge notifications.
- Participate in community discussions.
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:
Post to ThreadBridgePost to ThreadBridge and YouTube
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:
- ThreadBridge
- YouTube
- ThreadBridge + YouTube
- Sending to YouTube
- YouTube publishing failed
- YouTube connection removed
- Removed from YouTube
- YouTube status unknown
Local reactions must be labeled as ThreadBridge reactions and must never be presented as YouTube likes.
4.4 No silent automation
ThreadBridge must not:
- Automatically generate YouTube comments.
- Automatically publish AI-generated text.
- Automatically retry a failed YouTube write days later without renewed user action.
- Automatically like videos.
- Automatically subscribe to channels.
- Automatically create views.
- Post from a shared system account while pretending to represent a user.
4.5 Graceful degradation
When YouTube functionality is unavailable:
- Local posting must remain available.
- The user must receive a clear explanation.
- The local post must not be lost.
- Failed YouTube publishing must not create duplicate local posts.
- The system must offer an appropriate manual retry when safe.
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:
- The ThreadBridge copy.
- 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:
- Create an account.
- Sign in securely.
- Submit a supported YouTube video URL.
- Create or open a canonical room for that video.
- Watch the embedded video.
- Read local discussions.
- Read imported public YouTube comments.
- Create local top-level posts.
- Create local replies.
- Connect a YouTube account.
- Select the YouTube channel that will be used.
- Publish a new top-level YouTube comment.
- Publish a reply to a supported top-level YouTube comment.
- See the status of YouTube publishing.
- Retry appropriate failures manually.
- Report local content.
- Moderate local content.
- Disconnect YouTube.
- Delete stored integration data.
- Use the product on desktop and mobile.
5.2 Quality goals
The system must be:
- Secure.
- Responsive.
- Accessible.
- Testable.
- Observable.
- Quota-aware.
- Easy to deploy.
- Easy for Codex to understand and extend.
- Resilient to partial external failures.
6. Non-Goals for the MVP
The MVP will not include:
- Video uploading.
- Video downloading.
- Background audio or video playback.
- Live-chat synchronization.
- YouTube subscriptions.
- YouTube likes or dislikes.
- YouTube playlist management.
- YouTube channel management.
- Automated commenting.
- AI-generated comments posted without human review.
- Full creator analytics.
- Cross-channel YouTube analytics.
- A native Android or iOS application.
- Private communities.
- Paid subscriptions.
- Direct messages.
- Full-text global search across imported YouTube comments.
- Moderating arbitrary YouTube channels.
- Deep YouTube replies.
- Scraping YouTube pages.
- Support for a child-directed application.
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:
- Open public rooms.
- Watch embedded videos.
- Read visible discussions.
- Filter posts by source.
- Open the sign-in page.
A guest may not:
- Post.
- Reply.
- React.
- Report content.
- Connect YouTube.
- Create new rooms.
8.2 Registered member
A registered member may:
- Create rooms.
- Create local threads.
- Create local replies.
- React to local posts.
- Mention other members.
- Bookmark threads.
- Report content.
- Manage their own local posts.
- Connect or disconnect YouTube.
8.3 YouTube-connected member
A YouTube-connected member has all registered-member permissions and may also:
- Publish a top-level comment to YouTube.
- Publish an eligible reply to YouTube.
- Edit their own YouTube comment through a separately confirmed action.
- Delete their own YouTube comment through a separately confirmed action.
- Select an available YouTube channel identity.
- View synchronization status and errors.
8.4 Room moderator
A room moderator may:
- Hide local posts.
- Restore local posts.
- Lock local threads.
- Feature local threads.
- Review reports.
- Temporarily restrict local users from a room.
- Add moderator notes.
- Hide imported YouTube comments from the ThreadBridge presentation.
Hiding imported content on ThreadBridge must not imply that it was deleted from YouTube.
8.5 Platform administrator
An administrator may:
- Manage users.
- Manage rooms.
- Assign moderators.
- Review audit logs.
- Review quota consumption.
- Suspend local accounts.
- Configure rate limits.
- Disable YouTube publishing globally.
- Run synchronization.
- View failed jobs.
- Manage feature flags.
- Review data-deletion requests.
9. Supported Video Rules
9.1 Supported input formats
The room-creation service should recognize common official YouTube URL patterns, including:
- Standard watch URLs.
- Short share URLs.
- Shorts URLs.
- Embed URLs.
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:
- Unknown domains.
- URLs containing credentials.
- Localhost targets.
- Private IP addresses.
- Redirect-based URL tricks.
- Arbitrary iframe code.
- Raw HTML embeds.
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:
- The backend identifies the existing canonical room.
- The user is redirected to it.
- 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:
- Deleted videos.
- Private videos.
- Region-restricted videos.
- Age-restricted videos.
- Videos with embedding disabled.
- Videos whose comments are disabled.
- Temporarily unavailable videos.
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:
- Video panel: approximately 40%.
- Discussion panel: approximately 60%.
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:
- The video appears at the top.
- The room title follows.
- Source and sorting controls follow.
- The composer appears next.
- Discussion threads appear below.
The video player must preserve its aspect ratio.
10.3 Room header
The room header should show:
- Video title.
- Video owner/channel name.
- Thumbnail when the player has not loaded.
- Room status.
- Number of local threads.
- Last synchronization status.
- Share-room button.
- Moderator controls when authorized.
YouTube-supplied information must be clearly attributed to YouTube.
10.4 Source filters
The room should provide:
AllThreadBridgeYouTubeMy postsUnansweredFeatured
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:
- Newest.
- Oldest.
- Top on ThreadBridge.
- Most discussed.
- Featured.
“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:
- Plain text.
- A safe subset of Markdown.
- Mentions.
- Local reactions.
- Editing.
- Deletion.
- Reports.
- Moderator actions.
- Nested replies.
11.2 Local reply depth
ThreadBridge may support deep local nesting.
Recommended rendering behavior:
- Show the first four nesting levels normally.
- Collapse deeper levels into an indented continuation.
- Provide “Continue this thread” for very deep conversations.
- Store the true parent relationship regardless of visual collapsing.
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:
- A reply to a mapped YouTube top-level comment may optionally be published to YouTube.
- A reply to a local post with no YouTube mapping remains local.
- A deep reply to another reply remains local in the MVP.
- The composer must explain why YouTube publishing is unavailable for an ineligible deep reply.
Future versions may offer a flattening flow:
Publish this as a reply to the top-level YouTube comment and include an
@namereference.
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:
- Text area.
- Formatting help.
- Character count.
- Preview.
- Post destination section.
- Active YouTube identity when connected.
- Submit button.
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:
- Convert local formatting to readable plain text.
- Remove unsupported markup.
- Preserve line breaks.
- Show a preview of the exact YouTube text.
- Require final user submission.
12.4 Draft preservation
A draft must survive:
- Opening the YouTube connection flow.
- Token reauthorization.
- Temporary network failure.
- Navigating back from the consent screen.
- A failed YouTube request.
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
- Guest follows a ThreadBridge room link.
- Room metadata loads.
- Official YouTube player loads.
- Visible ThreadBridge and YouTube-origin discussions appear.
- Guest may filter and sort.
- Posting controls direct the guest to sign in.
13.2 Member creates a room
- Member selects
Create room. - Member pastes a YouTube URL.
- Frontend validates the general format.
- Backend extracts the video identifier.
- Backend checks whether the room already exists.
- If it exists, redirect to the room.
- Otherwise retrieve supported metadata through the official API.
- Validate video availability and embed eligibility.
- Create the video and room records in one transaction.
- Queue an initial comment synchronization.
- Redirect to the new room.
13.3 Member posts locally
- Member writes content.
- Destination remains ThreadBridge only.
- Frontend validates the content.
- Backend validates authorization and rate limits.
- Backend stores the post.
- Post immediately appears in the room.
- Notifications are created for mentioned or replied-to members.
No YouTube token is required.
13.4 Member connects YouTube
- Member opens
Settings → Connections. - Member selects
Connect YouTube. - ThreadBridge displays a pre-consent explanation.
- The explanation states that ThreadBridge will be able to publish, update, or delete YouTube comments only when the user directly requests those actions.
- User continues to Google OAuth.
- The server validates OAuth state on callback.
- Authorization code is exchanged server-side.
- Refresh token is encrypted before storage.
- Available channel identity information is retrieved.
- User explicitly selects the active channel when necessary.
- Settings page confirms the active identity.
13.5 Member publishes a top-level comment to both systems
- Member writes the post.
- Member selects
ThreadBridge and YouTube. - Interface displays the active YouTube channel.
- Interface displays the exact YouTube plain-text version.
- User selects the final submit button.
- Backend stores the local post.
- Backend creates an outbound synchronization job.
- Local post displays immediately with
Sending to YouTube. - Worker publishes through
commentThreads.insert. - Returned YouTube identifier is stored.
- Status changes to
Sent to YouTube. - Failure leaves the local post intact.
13.6 Member replies to an imported YouTube top-level comment
- Member selects
Reply. - Composer determines that the parent has a top-level YouTube identifier.
- Member may choose local-only or local-plus-YouTube.
- Member approves the exact outgoing text.
- Local reply is saved.
- Worker publishes the reply through
comments.insert. - Mapping is recorded.
- UI updates synchronization status.
13.7 Member replies to a deep local reply
- Member selects
Reply. - Composer detects that the parent is not an eligible YouTube top-level comment.
- YouTube publishing control is disabled.
- Explanatory text appears:
This reply will stay on ThreadBridge because YouTube currently supports replies only to top-level comments.
- Member posts locally.
13.8 Editing a synchronized post
Editing must never silently modify both copies.
The user should receive separate options:
Edit ThreadBridge copyUpdate YouTube copyUpdate both
For Update both:
- Show both resulting versions.
- Require explicit approval.
- Update ThreadBridge transactionally.
- Queue the YouTube update.
- Preserve an edit history.
- 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:
- Remove from ThreadBridge.
- Delete from YouTube.
- Remove from both.
Deleting from ThreadBridge does not automatically mean deleting from YouTube.
Deleting from YouTube must require:
- A valid YouTube connection.
- Ownership or sufficient permission.
- Explicit confirmation.
- A separate API request.
13.10 Disconnecting YouTube
- User selects
Disconnect YouTube. - Interface explains what will happen.
- User confirms.
- Application revokes the token programmatically.
- Stored refresh and access tokens are deleted immediately.
- YouTube-authorized cached data associated with the connection is deleted according to the data-deletion process.
- Local ThreadBridge posts remain unless the user separately deletes them.
- Posts previously synchronized display an appropriate disconnected state.
- 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:
- Video identifier.
- Title.
- Owning channel identifier.
- Channel title where available.
- Thumbnail.
- Publication date.
- Availability information.
- Embed eligibility.
- Made-for-Kids information where available and applicable.
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:
- Filter by video identifier.
- Request plain-text content.
- Order recent synchronization by time.
- Paginate as required.
- Store returned remote identifiers.
- Deduplicate by remote identifier.
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:
- Generate authorization URL on the server.
- Include a cryptographically strong state value.
- Prefer PKCE in addition to state.
- Redirect the user to Google.
- Validate state in the callback.
- Exchange the authorization code server-side.
- Encrypt the refresh token.
- Never send the refresh token to the browser.
- Refresh access tokens server-side.
- 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:
- Find YouTube-derived records approaching expiration.
- Refresh records still needed.
- Delete records that cannot or should not be refreshed.
- Remove stale external profile data.
- 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:
- Revoke the token immediately.
- Delete stored credentials immediately.
- Delete related authorized data promptly.
- Complete required deletion within the policy period.
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:
- Retrieve applicable Made-for-Kids status.
- Disable unsupported tracking.
- Disable YouTube write actions where required.
- Do not collect unnecessary data.
- Do not attempt to bypass unavailable comments.
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:
- Verified application domain.
- Public privacy policy.
- Terms of service.
- Data-deletion instructions.
- Scope justification.
- OAuth demonstration recording.
- Accurate branding.
- Support email.
- Production redirect URIs.
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:
pnpm- Turborepo
- TypeScript
16.2 Web application
Use:
- Next.js with the App Router.
- React.
- TypeScript strict mode.
- Tailwind CSS.
- Accessible component primitives.
shadcn/uior equivalent.- Zod for request and environment validation.
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:
- React components.
- Route handlers.
- Database models.
Instead, use service and adapter layers.
16.4 Database
Use:
- PostgreSQL.
- Prisma ORM.
- SQL migrations committed to version control.
PostgreSQL will store:
- Accounts.
- Rooms.
- Posts.
- YouTube mappings.
- OAuth connection metadata.
- Sync state.
- Reports.
- Notifications.
- Audit records.
- Quota ledgers.
16.5 Background worker
Use a separate Node.js worker process.
Recommended responsibilities:
- Outbound YouTube publishing.
- Inbound synchronization.
- Token validation.
- API-data refresh.
- Deletion jobs.
- Notification generation.
- Quota reconciliation.
- Retry processing.
Use a PostgreSQL-backed queue such as pg-boss, or implement a queue abstraction that can later be replaced.
16.6 Testing
Use:
- Vitest for unit tests.
- Integration tests against a disposable PostgreSQL database.
- Playwright for browser tests.
- Mock Service Worker or a dedicated mocked YouTube adapter.
- Static type checking.
- ESLint.
- Formatting checks.
16.7 Observability
Use:
- Structured JSON logs.
- Request correlation identifiers.
- Job identifiers.
- Error tracking such as Sentry.
- Health endpoints.
- Quota metrics.
- Sync latency metrics.
- Failed-job alerts.
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
- All YouTube write requests occur on the server.
- OAuth refresh tokens never reach the browser.
- Local content is saved before a YouTube job is attempted.
- External API requests are wrapped by a provider interface.
- External failures cannot roll back a successful local post.
- Every background job must be traceable.
- Every write job must be idempotent at the application level.
- No raw YouTube API response should be passed directly to the UI.
- Public API models and database models must be separate.
- 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:
- Unique user/channel combination.
- Encrypted refresh token must be nullable after revocation.
- A revoked connection must never be used by a job.
- The selected active channel must always be displayed before a write.
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:
- A post has either a local user author or external author.
- Parent and child must belong to the same room.
- A root post points to itself.
- Depth is calculated server-side.
- Imported YouTube posts must not be editable as local user posts.
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:
youtube_comment_idmust be unique.- One post may have at most one current YouTube mapping in the MVP.
- Error messages stored in the database must be sanitized.
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:
- OAuth tokens.
- Authorization codes.
- Client secrets.
- Full request authorization headers.
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:
- A parent post belongs to the same room.
- An imported post cannot claim a local author.
- A YouTube reply maps to a top-level YouTube comment.
- A disconnected connection cannot create jobs.
- Users cannot modify other users’ posts.
- Moderators can act only within authorized rooms unless they are administrators.
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:
- Authenticated with a rotating secret or workload identity.
- Inaccessible from the public user interface.
- Rate-limited.
- Logged.
- Idempotent.
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:
- Successful top-level publication.
- Successful reply.
- Comments-disabled error.
- Invalid-token error.
- Quota-exhausted error.
- Timeout after possible success.
- Deleted-parent error.
- Pagination.
- Partial replies.
- Remote deletion.
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:
- Validate the user.
- Validate the room.
- Validate the connection.
- Validate active channel identity.
- Validate the content.
- Confirm the approved YouTube text hash.
- Create the local post.
- Create a mapping record with
PENDING. - Enqueue a publication job.
- Commit the database transaction.
- Return the local post immediately.
The external API request must not occur inside the database transaction.
23.2 Worker sequence
The worker should:
- Lock the job.
- Verify it has not already completed.
- Load the post and connection.
- Verify connection status.
- Decrypt the refresh token.
- Obtain or refresh an access token.
- Check application quota budget.
- Set mapping status to
SENDING. - Call the YouTube provider.
- Store the returned remote identifier.
- Set status to
SENT. - Record estimated quota usage.
- Create a user notification.
- 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:
- A unique job key.
- A unique mapping per post.
- Database row locks.
- Attempt status.
- A reconciliation state for ambiguous timeouts.
Example job key:
youtube-publish:{postId}:{approvedVersionHash}
23.4 Ambiguous timeout
A dangerous case occurs when:
- ThreadBridge sends the request.
- YouTube creates the comment.
- The network fails before ThreadBridge receives the response.
The system cannot safely assume that publication failed.
In this case:
- Set status to
UNKNOWN. - Do not immediately retry.
- Attempt reconciliation.
- Ask the user to verify before a manual retry if reconciliation cannot determine the result.
This is preferable to creating duplicate comments.
23.5 Retry rules
Automatically retry only clearly transient failures such as:
- Temporary network connection failure before request transmission is established.
- Explicit server-side retryable errors.
- Temporary provider outage.
- Rate-limiting response with a safe retry policy.
Do not automatically retry:
- Invalid content.
- Comments disabled.
- Insufficient permission.
- Parent comment missing.
- Revoked token.
- Unsupported account.
- Quota exhausted for the day.
- Ambiguous timeout.
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:
- Queue an initial comment retrieval.
- Retrieve the newest top-level threads.
- Upsert each thread using the YouTube comment identifier.
- Import returned replies.
- Compare imported reply count with total reply count.
- Retrieve missing replies separately.
- Store refresh timestamps.
- Mark the room synchronization complete.
24.2 Ongoing synchronization
Use an adaptive schedule.
Suggested categories:
HOT
WARM
COLD
ARCHIVED
Possible behavior:
- Hot rooms: refresh every few minutes while actively viewed.
- Warm rooms: refresh at a moderate interval.
- Cold rooms: refresh on user access or a longer schedule.
- Archived rooms: refresh only when reopened or approaching data-expiration limits.
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:
- Refresh recent top-level threads.
- Compare stored reply counts with current reply counts.
- Retrieve all replies when a count changed.
- Periodically revisit active older threads.
- Deduplicate by remote identifier.
24.4 Remote edits
When an imported YouTube comment changes:
- Update the YouTube text snapshot.
- Preserve the local post identity.
- Update
youtube_updated_at. - Record the refresh time.
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:
- Mark the mapping
REMOTE_REMOVED. - Do not automatically delete the local ThreadBridge post.
- Replace imported-only content with an appropriate removed-state presentation.
- Preserve moderation and audit information where legally permitted.
- Avoid displaying stale YouTube content as if it were still available.
24.6 Refresh compliance
A daily compliance job must:
- Identify YouTube-derived records with approaching refresh deadlines.
- Refresh records still actively used.
- Delete records that cannot be refreshed.
- Remove orphaned external-author data.
- Validate active connection tokens.
- Process deletion requests.
- 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:
- Raw OAuth tokens.
- Google client identifiers unnecessarily.
- Stack traces.
- Unfiltered provider responses.
- Database errors.
- Internal encryption details.
27. Authentication and Authorization
27.1 Application authentication
Support:
- Email magic link or email/password.
- Google sign-in.
- Secure server-managed sessions.
Application authentication and YouTube authorization remain separate.
27.2 Session security
Use:
- HTTP-only cookies.
- Secure cookies in production.
- SameSite protection.
- Short-lived sessions with rotation.
- CSRF protection for mutation routes.
- Server-side role checks.
- Session revocation.
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:
- Ciphertext.
- Initialization vector.
- Authentication tag.
- Encryption-key version.
The encryption key must live in a secret manager or protected environment configuration, not in source control.
28.2 OAuth CSRF protection
Use:
- Random state values.
- Short expiration.
- One-time consumption.
- User-session binding.
- PKCE where supported.
- Exact redirect URI validation.
28.3 XSS protection
- Store original local text.
- Render Markdown through a strict sanitizer.
- Treat imported YouTube HTML as untrusted.
- Prefer plain-text YouTube retrieval.
- Use Content Security Policy.
- Escape display names and titles.
- Never use unsafe raw HTML rendering without sanitization.
28.4 SSRF protection
- Parse video URLs without remotely requesting them.
- Allowlist official hostnames.
- Send only extracted video identifiers to the YouTube API.
- Never let the backend fetch user-supplied arbitrary URLs.
- Reject redirects to private networks.
28.5 Abuse prevention
Implement:
- Per-IP rate limits.
- Per-account rate limits.
- Per-room posting limits.
- Per-user YouTube publication limits.
- CAPTCHA after suspicious thresholds.
- Email verification for elevated activity.
- Duplicate-content detection.
- Account suspension.
- Moderator audit trails.
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:
- Moderator role.
- Authorized room.
- Target post room.
- Allowed action.
- Current account status.
Every administrator action must be audited.
28.8 Dependency security
CI should run:
- Dependency audit.
- Secret scan.
- Static analysis.
- Type checking.
- Unit tests.
- Build verification.
29. Moderation System
29.1 Local moderation
ThreadBridge moderators control ThreadBridge presentation and participation.
They may:
- Hide local posts.
- Restore posts.
- Lock threads.
- Feature threads.
- Suspend users locally.
- Review reports.
- Add internal notes.
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:
- It requires additional permission modeling.
- A normal commenter is not necessarily the channel owner.
- Local moderation and YouTube moderation must remain separate.
- Mistaken remote moderation would have consequences outside ThreadBridge.
29.4 Locked threads
When a local thread is locked:
- Existing content remains visible.
- New local replies are disabled.
- YouTube-origin comments may continue to be imported but should not create local reply permissions.
- Moderator identity and reason may be displayed according to policy.
30. Notifications
MVP notifications:
- Someone replied to your ThreadBridge post.
- Someone mentioned you.
- Your YouTube publication succeeded.
- Your YouTube publication failed.
- Your post was moderated.
- A thread you follow received local activity.
Do not generate repeated notifications for the same imported synchronization event.
Notification delivery:
- In-app required.
- Email optional after MVP.
- Push notifications after native or PWA support.
31. Search
31.1 Global search
Global search should index:
- Local ThreadBridge room titles.
- Local ThreadBridge posts.
- Local ThreadBridge users.
- Local tags.
- Local communities in future versions.
31.2 Room search
Room search may include:
- Local posts.
- Currently refreshed imported YouTube comments.
- Author names.
- Thread titles.
- Mentions.
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:
- Video metadata requests.
- Comment list requests.
- Reply list requests.
- Reconciliation.
- Token and channel operations.
- Invalid or failed requests.
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:
- Daily estimated quota ledger.
- Per-user publication limits.
- Per-room synchronization priority.
- Global feature flag for YouTube writes.
- Read-reserve threshold.
- Administrative quota dashboard.
- Alerts when estimated usage exceeds configurable thresholds.
32.3 Quota exhaustion
When quota is unavailable:
- Continue local posting.
- Disable new YouTube publication requests.
- Display a clear status.
- Do not silently defer the YouTube action until another day.
- Require the user to initiate a new publication attempt after availability returns.
32.4 Efficient retrieval
To conserve quota:
- Parse direct video identifiers rather than using search.
- Request only required resource parts.
- Use pagination deliberately.
- Refresh active rooms more frequently than inactive rooms.
- Compare stored reply counts before fetching every reply page.
- Deduplicate by remote identifier.
- Validate requests before sending them.
- Use the mock provider in development and automated tests.
33. Privacy and Compliance Pages
Production must include:
/privacy
/terms
/data-deletion
/settings/connections
/settings/account
The privacy policy must explain:
- What Google/YouTube data is accessed.
- Why it is accessed.
- What is stored.
- How tokens are protected.
- How users revoke access.
- How users delete data.
- That deleting ThreadBridge data does not automatically delete content already stored by YouTube unless the user separately requests and authorizes that YouTube deletion.
- How to contact the operator.
The interface must include:
Disconnect YouTubeDelete YouTube integration dataDelete ThreadBridge accountExport my ThreadBridge data
34. Accessibility Requirements
Target WCAG 2.2 AA.
Required behavior:
- Full keyboard navigation.
- Visible focus indicators.
- Semantic headings.
- Proper form labels.
- Accessible error descriptions.
- Screen-reader status announcements for synchronization changes.
- Adequate contrast.
- No color-only source indicators.
- Reduced-motion support.
- Accessible modal focus trapping.
- Captions remain controlled by the official YouTube player.
- Touch targets suitable for mobile users.
Source badges should combine text and iconography.
35. Performance Requirements
Initial targets:
- Server response for cached room data: under 500 milliseconds at the 95th percentile.
- Largest Contentful Paint: under 2.5 seconds on a reasonable mobile connection.
- Local post creation feedback: under 500 milliseconds after server response.
- Discussion pagination: 20 to 50 top-level threads per page.
- Lazy-load collapsed replies.
- Avoid loading the complete comment history on initial render.
- Use database cursor pagination rather than large offset pagination.
- Cache video metadata while respecting refresh requirements.
- Stream or progressively render room content where practical.
YouTube publication speed must not block local posting.
36. Observability
36.1 Required metrics
Track:
- Local post creation rate.
- Outbound YouTube publication attempts.
- Outbound success rate.
- Retryable failure rate.
- Final failure rate.
- Unknown publication state count.
- Average worker queue delay.
- Inbound synchronization duration.
- Imported-comment upsert count.
- Data-refresh backlog.
- Estimated quota use.
- OAuth refresh failures.
- Data-deletion backlog.
- Moderation-report backlog.
36.2 Health endpoints
Provide:
/api/health/live
/api/health/ready
Readiness should check:
- Database connectivity.
- Queue availability.
- Required configuration.
- Worker heartbeat where applicable.
It should not spend YouTube quota.
36.3 Alerts
Alert on:
- Repeated OAuth failures.
- Queue backlog above threshold.
- Database connection failures.
- Data-refresh deadlines at risk.
- Data-deletion requests nearing deadline.
- Estimated quota exhaustion.
- Unusually high duplicate-publication risk.
- Elevated error rate.
37. Testing Strategy
37.1 Unit tests
Test:
- Video URL parsing.
- Video identifier extraction.
- Source-label mapping.
- Plain-text transformation.
- Preview hash generation.
- Authorization decisions.
- Reply eligibility.
- Synchronization state transitions.
- Error mapping.
- Quota estimation.
- Token encryption and decryption.
- Data-refresh deadline calculations.
- Rate-limit decisions.
37.2 Database integration tests
Test:
- Canonical-room uniqueness.
- Parent and child relationships.
- Remote-comment uniqueness.
- Transaction rollback.
- Job creation with local posts.
- Concurrent publication requests.
- Moderator authorization.
- Connection revocation.
- Data deletion.
- Notification deduplication.
37.3 YouTube adapter contract tests
Run the same behavioral contract against:
MockYouTubeProvider- A controlled integration account in staging where appropriate.
Contract cases:
- Retrieve video.
- Retrieve paginated comments.
- Retrieve complete replies.
- Publish top-level comment.
- Publish reply.
- Invalid token.
- Comments disabled.
- Missing parent.
- Quota error.
- Timeout.
- Remote deletion.
37.4 End-to-end tests
Playwright scenarios:
- Guest opens a room.
- Member creates a room.
- Member creates a local thread.
- Member replies locally.
- Deep reply disables YouTube destination.
- Connected user selects YouTube publication.
- Successful mocked publication changes status.
- Failed publication leaves local post intact.
- User manually retries safe failure.
- Ambiguous failure does not automatically retry.
- Moderator hides a local post.
- User disconnects YouTube.
- Deleted integration cannot create new jobs.
- Mobile room layout functions.
- Keyboard-only user can post and navigate.
37.5 Security tests
Test:
- CSRF protection.
- OAuth state replay.
- Unauthorized post editing.
- Unauthorized moderator endpoint.
- Stored XSS.
- Markdown sanitization.
- Malicious video URL.
- SSRF attempts.
- Rate-limit bypass attempts.
- Token leakage in logs.
- Job endpoint authentication.
- Session fixation.
- Deleted-user access.
37.6 Production smoke tests
After deployment:
- Health endpoints.
- Sign-in.
- Room retrieval.
- Local posting.
- Worker heartbeat.
- OAuth redirect.
- Controlled YouTube publication.
- Synchronization.
- Disconnect and revocation.
- Privacy and deletion pages.
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
- Current stable Node.js release supported by the selected framework.
pnpm.- Docker Desktop.
- Git.
- A Google Cloud development project.
- Test YouTube accounts added to the OAuth consent configuration.
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:
- Administrator.
- Moderator.
- Normal member.
- Connected-member simulation.
- Demo video.
- Demo room.
- Local threads.
- Imported-comment simulations.
- Pending synchronization.
- Failed synchronization.
- Removed remote comment.
40. Deployment Architecture
Recommended production services:
- Web application service.
- Worker service.
- Managed PostgreSQL.
- Secret manager.
- Error tracking.
- Log aggregation.
- Scheduled job capability.
The web and worker may use the same source repository but must deploy as separate processes.
40.1 Production deployment requirements
- HTTPS only.
- Secure cookies.
- Database backups.
- Point-in-time recovery where available.
- Restricted database networking.
- Environment-specific OAuth redirect URIs.
- Health checks.
- Graceful worker shutdown.
- Migration step before application rollout.
- Rollback procedure.
- Feature flag for YouTube writes.
40.2 Staging
Staging should have:
- Separate database.
- Separate OAuth configuration.
- Separate API credentials.
- Test users.
- Lower worker concurrency.
- Mock-provider option.
- No production tokens.
41. Delivery Phases
Phase 0: Foundation and documentation
Deliver:
- Monorepo.
- TypeScript strict configuration.
- Next.js application.
- Worker application.
- Shared packages.
- PostgreSQL Docker configuration.
- Prisma configuration.
- CI workflow.
AGENTS.md.PROJECT_SPEC.md.- Architecture documentation.
- Environment validation.
- Health endpoints.
Acceptance:
pnpm install
pnpm lint
pnpm typecheck
pnpm test
pnpm build
all succeed.
Phase 1: Local discussion board
Deliver:
- Application authentication.
- User profiles.
- Video URL parser.
- Mock video provider.
- Room creation.
- Room page.
- Local top-level posts.
- Local nested replies.
- Local reactions.
- Source labels.
- Pagination.
- Responsive UI.
- Basic reports.
No real YouTube OAuth or writes in this phase.
Phase 2: YouTube connection and outbound publishing
Deliver:
- Google Cloud configuration documentation.
- YouTube OAuth flow.
- Encrypted token storage.
- Channel selection.
- Top-level comment publication.
- Eligible reply publication.
- Outbound queue.
- Synchronization state UI.
- Typed provider errors.
- Manual retry.
- Disconnect and revocation.
Phase 3: Inbound synchronization
Deliver:
- Comment-thread retrieval.
- Complete reply retrieval.
- Imported external authors.
- Deduplication.
- Room synchronization state.
- Adaptive scheduling.
- Remote edit refresh.
- Remote deletion handling.
- Thirty-day refresh compliance process.
Phase 4: Moderation and notifications
Deliver:
- Report queue.
- Moderator dashboard.
- Hide and restore.
- Lock and feature.
- In-app notifications.
- Audit logs.
- User suspension.
- Abuse rate limits.
Phase 5: Production hardening
Deliver:
- Security review.
- Threat-model review.
- Accessibility audit.
- Performance optimization.
- Error monitoring.
- Quota dashboard.
- Data-deletion workflow.
- Privacy policy.
- Terms.
- Production deployment documentation.
- Backup and recovery test.
Phase 6: Public launch preparation
Deliver:
- OAuth brand verification preparation.
- Scope justification.
- Demonstration recording.
- Support documentation.
- Incident-response process.
- Moderation policy.
- Final end-to-end staging test.
- Controlled public rollout.
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:
- Read
PROJECT_SPEC.mdbefore changing architecture. - Work on one delivery phase or one vertical slice at a time.
- Inspect existing code before creating replacement systems.
- Use TypeScript strict mode.
- Keep YouTube logic behind the provider interface.
- Keep secrets and tokens server-side.
- Never log credentials.
- Add or update tests for every behavior change.
- Run lint, type checking, tests, and build before declaring completion.
- Update documentation when contracts or architecture change.
- Avoid introducing a second library for a responsibility already covered.
- Avoid implementing future features during an earlier milestone.
- Preserve local-post functionality when YouTube integration fails.
- Never create automatic YouTube-comment behavior.
- Treat ambiguous remote writes as
UNKNOWN, not safe failures. - Ask for explicit environment credentials only when the code genuinely reaches an integration stage.
- Use the mock provider in automated tests.
- Include database migrations for schema changes.
- Report the files changed and commands executed.
- 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:
- A new developer can follow the setup documentation.
- The application starts from a clean clone.
- Database migrations run successfully.
- A user can create an account.
- A user can create or resolve a canonical video room.
- A user can create a local top-level post.
- A user can create nested local replies.
- Guests can read public rooms.
- Every post has a correct source label.
- A user can connect a YouTube account securely.
- The active YouTube identity is shown before publishing.
- YouTube publishing is never selected by default.
- A local post remains available after YouTube failure.
- Top-level YouTube publication works through the official API.
- Eligible YouTube reply publication works.
- Deep local replies remain local.
- Imported comments are deduplicated.
- Missing replies are retrieved.
- Remote deletions are represented accurately.
- Quota exhaustion does not stop local discussions.
- Tokens are encrypted and never exposed to the browser.
- Revocation works.
- Data-deletion requests work.
- Moderator actions are authorized and audited.
- All major workflows have automated tests.
- Accessibility checks pass.
- Security review has no unresolved critical findings.
- Lint, type checking, tests, and production build pass.
- Privacy, terms, and data-deletion pages exist.
- Production OAuth requirements are addressed before public release.
46. Future Roadmap
46.1 Communities
Allow groups to create independent rooms around the same video.
Examples:
- Churches.
- Schools.
- Sports communities.
- Music fan groups.
- Professional organizations.
- Private study groups.
Each community could have:
- Its own moderators.
- Its own rules.
- Its own featured threads.
- Its own local reactions.
- Its own private or public visibility.
46.2 AI discussion tools
Possible later features:
- Summarize a long local thread.
- Identify unanswered questions.
- Group local posts by topic.
- Generate a neutral debate summary.
- Suggest a reply draft.
- Detect likely duplicate local threads.
- Assist moderators with report prioritization.
AI-generated text must never be published to YouTube automatically.
The user must:
- Review the complete text.
- Edit it as desired.
- Select the YouTube destination.
- Approve the exact outgoing version.
- Submit the action directly.
46.3 Creator tools
For verified video owners:
- Official creator badge.
- Creator Q&A thread.
- Featured answers.
- Thread announcements.
- Local moderation team.
- Optional YouTube moderation integration after separate review.
46.4 Live watch rooms
Later support:
- Synchronized local watch-room discussion.
- Event scheduling.
- Local live chat.
- Post-event conversion into permanent threads.
This must remain separate from YouTube live chat unless a compliant official integration is designed.
46.5 Mobile application
After web product validation:
- React Native or native mobile application.
- Deep links to rooms.
- Push notifications.
- Draft synchronization.
- Offline local draft storage.
46.6 Monetization
Possible monetization should focus on ThreadBridge’s independent functionality:
- Premium community management.
- Private rooms.
- Advanced local moderation.
- Community branding.
- Local discussion exports.
- Creator memberships.
- Organizational plans.
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:
- Number of active rooms.
- Number of local discussion threads.
- Number of local replies.
- Average local reply depth.
- Percentage of threads receiving a reply.
- Number of active registered members.
- Local moderation-report resolution time.
- Outbound synchronization success rate.
- Average synchronization delay.
- Percentage of YouTube failures that preserve the local post.
- Number of connection-revocation failures.
- Data-refresh compliance completion rate.
- Data-deletion completion rate.
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.