Repository navigation
refactor(monorepo)!: restructure packages with t3-env, zod, and quality gates - #2
Conversation
…ty gates Replace shared-types/shared-utils/shared-infra with domain and platform packages. Centralize configuration via @t3-oss/env-core, validate API and WebSocket contracts with zod, and align CI/Docker with the new layout. BREAKING CHANGE: - Remove @vkara/shared-types, @vkara/shared-utils, and @vkara/shared-infra. - Import paths must use @vkara/env, @vkara/redis, @vkara/cache-redis, @vkara/validators, @vkara/youtube, @vkara/room, and @vkara/personalization. - API validation uses zod (@vkara/validators) instead of TypeBox; delete apps/api/src/schemas/client-message.ts. - Env access in apps/api and apps/web is limited to src/env.ts (t3-env). Platform & env: - Add @vkara/env with embed/redis/server/logger/web factories and FLAG_DOCS. - Add apps/api/src/env.ts and apps/web/src/env.ts (nextjs env for web). - Add root .env.example; sync apps/api/.env.example (no sample Redis password). - Support AIO-relative NEXT_PUBLIC URLs in web-public env schema. Domain packages: - Add @vkara/youtube, @vkara/room, @vkara/personalization from former shared-*. - Add @vkara/validators (WS client-message + YouTube HTTP zod schemas). - Add @vkara/cache-redis (fail-open bool/json Redis caches). - Rename shared-infra to @vkara/redis (createRedisOptions). - Add tooling/typescript shared tsconfig presets. API: - Register @elysiajs/openapi with zod-to-json-schema mapper. - Validate room WebSocket body with wsClientMessageSchema. - Return HTTP 502 on YouTube search/related/suggestions upstream failures (no longer mask errors as empty 200 payloads). - Use validated env in logger (LOG_TO_FILES via env.LOG_TO_FILES). Web: - Migrate imports to domain packages; type-only validators imports. - Wrap WebSocketProvider in Suspense for useSearchParams. - Remove apps/web/eslint.config.mjs; use root eslint.config.mjs. Monorepo quality: - Add root eslint.config.mjs (boundary rules: ban shared-*, packages→apps). - Add lint/typecheck scripts; bun run ci = test → typecheck → lint → build. - Extend vitest projects for new packages; restore/move deleted tests (format, validators-invalid, validators http.schema). CI & Docker: - GitHub CI and build-push-docker prelude use bun run ci. - Drop vkara-web from Docker Hub matrix (NEXT_PUBLIC_* are build-time per domain). - Fix aio build-web COPY packages/validators; Docker install via workspace package.json stubs + bun --filter. - api-redis supervisord: pass REDIS_* to API; compose web build.args for local. Docs & OpenSpec: - Update README, monorepo-architecture, containers/README, PR template. - Archive change platform-env-t3-monorepo; promote 7 specs to openspec/specs/.
There was a problem hiding this comment.
Sorry @lehuygiang28, your pull request is larger than the review limit of 150000 diff characters
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request implements a major monorepo refactoring to transition the codebase to a T3-style architecture. It replaces the legacy shared packages with domain-specific packages (@vkara/env, @vkara/redis, @vkara/cache-redis, @vkara/validators, @vkara/youtube, @vkara/room, and @vkara/personalization), migrates environment variable validation to @t3-oss/env with Zod, and replaces TypeBox schemas with Zod schemas in the Elysia API. Additionally, a unified ESLint configuration is introduced across the workspace. The review feedback highlights a few critical issues and optimization opportunities: a potential 500 error in the /suggestions route that should return a 502, a bug in WebSocket URL resolution that could result in duplicate /ws paths, weak type validation in the Redis JSON caches, and a recommendation to use z.discriminatedUnion instead of z.union for the WebSocket client message schema to improve performance and error reporting.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
Refactors the monorepo package layout by replacing the legacy shared-* packages with explicit domain (youtube, room, personalization, validators) and platform (env, redis, cache-redis) packages, while introducing monorepo-wide quality gates (typecheck + lint) and aligning CI/Docker builds with the new workspace structure.
Changes:
- Introduce new workspace packages (
@vkara/env,@vkara/redis,@vkara/cache-redis,@vkara/validators,@vkara/youtube,@vkara/room,@vkara/personalization) and migrate imports offshared-*. - Migrate API/web validation and env access to zod + t3-env patterns, including Elysia OpenAPI mapping and updated request/WS schemas.
- Add root ESLint flat config + Turbo/CI/Docker updates to enforce boundaries and run
test → typecheck → lint → build.
Reviewed changes
Copilot reviewed 215 out of 241 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.mts | Update Vitest projects for new packages |
| turbo.json | Add globalEnv + lint/task inputs |
| tooling/typescript/package.json | Add shared TS config package exports |
| tooling/typescript/base.json | Base tsconfig preset for repo |
| tooling/typescript/library.json | Library tsconfig preset |
| tooling/typescript/bun.json | Bun-specific tsconfig preset |
| tooling/typescript/nextjs.json | Next.js tsconfig preset |
| README.md | Document new package layout + scripts |
| packages/youtube/package.json | New @vkara/youtube workspace package |
| packages/youtube/tsconfig.json | Adopt shared tsconfig preset |
| packages/youtube/src/index.ts | Barrel exports for YouTube domain utilities |
| packages/youtube/src/youtube.ts | Move YouTube domain types into package |
| packages/youtube/src/youtube-thumbnail.ts | Update thumbnail types import path |
| packages/youtube/src/youtube-playlist-url.ts | Add playlist URL/ID normalization helpers |
| packages/youtube/src/youtube-playlist-details.ts | Add playlist details response types |
| packages/youtube/src/youtube-live.ts | Add live detection heuristic helper |
| packages/youtube/src/youtube-id.ts | Add YouTube video ID validator |
| packages/youtube/src/parse-view-count.ts | Add view-count parsing/coercion helpers |
| packages/youtube/src/parse-relative-upload.ts | Add relative upload label parsing |
| packages/youtube/src/format.ts | Add duration + view-count formatting |
| packages/youtube/src/captions.ts | Add caption language helpers + selection |
| packages/youtube/tests/youtube.test.ts | Tests for channel normalization |
| packages/youtube/tests/youtube-thumbnail.test.ts | Update tests to new import paths |
| packages/youtube/tests/youtube-playlist-url.test.ts | Tests for playlist parsing helpers |
| packages/youtube/tests/youtube-live.test.ts | Tests for live detection helper |
| packages/youtube/tests/youtube-id.test.ts | Tests for video ID validator |
| packages/youtube/tests/validators-invalid.test.ts | Update invalid-input tests post-split |
| packages/youtube/tests/parse-view-count.test.ts | Update tests to new import paths |
| packages/youtube/tests/parse-relative-upload.test.ts | Update tests to new import paths |
| packages/youtube/tests/format.test.ts | Update tests to new import paths |
| packages/youtube/tests/captions.test.ts | Add caption helper tests |
| packages/validators/package.json | New @vkara/validators zod schema package |
| packages/validators/tsconfig.json | Validators tsconfig preset |
| packages/validators/src/index.ts | Re-export shared zod schemas |
| packages/validators/src/ws/client-message.ts | Zod WS client message schema + inferred types |
| packages/validators/src/youtube/http.ts | Zod HTTP body schemas for YouTube routes |
| packages/validators/src/youtube/video.ts | Zod YouTube video schema |
| packages/validators/tests/http.schema.test.ts | Schema tests for HTTP bodies |
| packages/shared-utils/package.json | Remove legacy shared-utils package |
| packages/shared-utils/tsconfig.json | Remove legacy shared-utils tsconfig |
| packages/shared-types/package.json | Remove legacy shared-types package |
| packages/shared-types/src/index.ts | Remove shared-types barrel exports |
| packages/shared-types/src/websocket.ts | Remove legacy WS union/types |
| packages/room/package.json | New @vkara/room domain package |
| packages/room/tsconfig.json | Room package tsconfig preset |
| packages/room/src/index.ts | Barrel exports for room domain |
| packages/room/src/errors.ts | Room error codes + RoomError |
| packages/room/src/websocket.ts | Room + WS message type definitions |
| packages/room/src/room.ts | Room ID + share URL helpers |
| packages/room/src/url.ts | URL normalization helper |
| packages/room/src/playback-sync.ts | Playback sync utilities/constants |
| packages/room/src/persisted-room.ts | Persisted room normalization deps update |
| packages/room/tests/room.test.ts | Update tests to new imports |
| packages/room/tests/url.test.ts | Update tests to new imports |
| packages/room/tests/validators-invalid.test.ts | Move invalid roomId tests into room pkg |
| packages/room/tests/persisted-room.test.ts | Update caption default import source |
| packages/room/tests/persisted-room-invalid.test.ts | Add hostile blob normalization tests |
| packages/room/tests/errors.test.ts | Add RoomError tests |
| packages/redis/package.json | Rename shared-infra → @vkara/redis |
| packages/redis/src/index.ts | Redis package barrel export |
| packages/redis/src/redis.ts | Add createRedisOptions factory |
| packages/personalization/package.json | New @vkara/personalization domain package |
| packages/personalization/tsconfig.json | Personalization tsconfig preset |
| packages/personalization/src/index.ts | Barrel exports for personalization |
| packages/personalization/src/types.ts | Personalization types + limits |
| packages/personalization/src/profile.ts | Profile mutations + scoring |
| packages/personalization/src/rank-videos.ts | Video ranking algorithm |
| packages/personalization/src/suggestions.ts | Suggestion blending logic |
| packages/personalization/src/browse-feed.ts | Browse feed sources + ranking glue |
| packages/personalization/tests/profile.test.ts | Update tests to new imports |
| packages/personalization/tests/profile-engagement.test.ts | Update tests to new imports |
| packages/personalization/tests/rank-videos.test.ts | Update tests to new imports |
| packages/personalization/tests/suggestions.test.ts | Update tests to new imports |
| packages/personalization/tests/browse-feed.test.ts | Update tests to new imports |
| packages/env/package.json | New @vkara/env env factories + parsers |
| packages/env/.gitignore | Package-local ignores for env workspace |
| packages/env/tsconfig.json | Env package tsconfig preset |
| packages/env/src/index.ts | Barrel exports for env factories |
| packages/env/src/base.ts | Canonical env parsers + skipValidation |
| packages/env/src/flags.ts | Feature flag docs + key constants |
| packages/env/src/embed.ts | Embed env factory + helpers |
| packages/env/src/redis.ts | Redis env factory |
| packages/env/src/server.ts | API server env factory |
| packages/env/src/logger.ts | Logger env factory |
| packages/env/src/web-public.ts | Web public env factory (NEXT_PUBLIC_*) |
| packages/env/src/web-server.ts | Web server-only env factory |
| packages/env/tests/base.test.ts | Tests for env parsers |
| packages/curated-playlists/src/index.ts | Update playlist parsing import source |
| packages/curated-playlists/package.json | Depend on @vkara/youtube + add lint scripts |
| packages/cache-redis/package.json | New @vkara/cache-redis helpers |
| packages/cache-redis/tsconfig.json | Cache-redis tsconfig preset |
| packages/cache-redis/src/index.ts | Export bool/json cache helpers |
| packages/cache-redis/src/bool-cache.ts | MGET/SETEX boolean cache helper |
| packages/cache-redis/src/json-cache.ts | JSON cache helper with validation |
| packages/cache-redis/tests/bool-cache.test.ts | Tests for bool cache helper |
| packages/cache-redis/tests/json-cache.test.ts | Tests for JSON cache helper |
| package.json | Add lint/typecheck scripts + update CI pipeline |
| eslint.config.mjs | Add root ESLint flat config + boundary rules |
| openspec/specs/platform-redis/spec.md | Add/refresh redis platform spec |
| openspec/specs/platform-redis-cache/spec.md | Add/refresh redis cache spec |
| openspec/specs/platform-feature-flags/spec.md | Add/refresh feature flags spec |
| openspec/specs/platform-env/spec.md | Add/refresh env platform spec |
| openspec/specs/monorepo-quality/spec.md | Add/refresh monorepo quality spec |
| openspec/specs/monorepo-package-boundaries/spec.md | Add/refresh layering/boundaries spec |
| openspec/specs/elysia-zod-schemas/spec.md | Add/refresh zod-only API schema spec |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/.openspec.yaml | Archive metadata for spec change |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/proposal.md | Archived proposal text |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/platform-redis/spec.md | Archived redis spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/platform-redis-cache/spec.md | Archived redis-cache spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/platform-feature-flags/spec.md | Archived flags spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/platform-env/spec.md | Archived env spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/monorepo-quality/spec.md | Archived quality spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/monorepo-package-boundaries/spec.md | Archived boundaries spec snapshot |
| openspec/changes/archive/2026-06-04-platform-env-t3-monorepo/specs/elysia-zod-schemas/spec.md | Archived zod-schemas spec snapshot |
| docs/vi/README.md | Update Vietnamese docs for new packages |
| docs/monorepo-architecture.md | Document new package layers + gates |
| docs/monorepo-duplication-inventory.md | Mark inventory as historical post-refactor |
| docker-compose.yml | Provide web build args for NEXT_PUBLIC_* |
| containers/README.md | Update container docs for new build strategy |
| containers/api-redis/Dockerfile | Update workspace stub installs + filters |
| containers/api-redis/supervisord.conf | Pass REDIS_* env to API |
| containers/aio/Dockerfile | Update package stubs + workspace filters |
| apps/web/package.json | Switch lint script + add new deps |
| apps/web/tsconfig.json | Add paths for new workspace packages |
| apps/web/next.config.ts | Update transpilePackages list |
| apps/web/eslint.config.mjs | Remove per-app ESLint config (root-only) |
| apps/web/Dockerfile | Update workspace stubs + build args |
| apps/web/.env.example | Update web env examples (new defaults) |
| apps/web/src/env.ts | Add t3-env Next.js env module |
| apps/web/src/middleware.ts | Use validated env for VKARA_AIO |
| apps/web/src/providers/websocket-provider.tsx | Move to env + new package imports |
| apps/web/src/types/websocket.type.ts | Split WS types between room + validators |
| apps/web/src/services/client/api-client.ts | Use env + resolveUrl from room |
| apps/web/src/services/youtube-api.ts | Update types to new youtube package |
| apps/web/src/store/websocketStore.ts | Update WS message type imports |
| apps/web/src/store/youtubeStore.ts | Update room/youtube type imports |
| apps/web/src/store/searchStore.ts | Use personalization package exports |
| apps/web/src/store/personalizationStore.ts | Use personalization + youtube types |
| apps/web/src/lib/site-url.ts | Use validated env variables |
| apps/web/src/lib/seo/metadata.ts | Use env for verification token |
| apps/web/src/lib/tv-room-recovery.ts | Use room + validators WS types |
| apps/web/src/lib/youtube-video.ts | Use youtube helper for live heuristic |
| apps/web/src/lib/youtube-captions.ts | Use youtube caption helpers |
| apps/web/src/lib/room-share.ts | Use room share URL helper |
| apps/web/src/lib/room-queue.ts | Update YouTubeVideo type import |
| apps/web/src/lib/room-payload.ts | Use room validators for roomId |
| apps/web/src/lib/persisted-storage.ts | Split youtube vs room normalization |
| apps/web/src/lib/format-uploaded-at.ts | Use youtube relative upload parser |
| apps/web/src/lib/curated-playlist-thumbnail.ts | Use youtube thumbnails helpers/types |
| apps/web/src/hooks/use-browse-feed.ts | Switch to personalization ranking/source logic |
| apps/web/src/hooks/use-strip-room-query.ts | Use room validators for roomId |
| apps/web/src/hooks/use-playlist-details-cache.ts | Update playlist types import |
| apps/web/src/hooks/use-player-action.ts | Update YouTubeVideo type import |
| apps/web/src/hooks/use-playback-position-sync.ts | Update playback-sync imports |
| apps/web/src/hooks/use-playback-display-time.ts | Update playback-sync imports |
| apps/web/src/hooks/use-join-room.ts | Use room ID validator |
| apps/web/src/hooks/use-curated-starter-visibility.ts | Use personalization source helper |
| apps/web/src/hooks/use-connection-status-ui.ts | Update ConnectionStatus type import |
| apps/web/src/app/[locale]/layout.tsx | Wrap WS provider in Suspense + env usage |
| apps/web/src/app/robots.ts | Use env for deployment detection |
| apps/web/src/app/api/speech/status/route.ts | Use env for WHISPER_URL |
| apps/web/src/app/api/speech/transcribe/route.ts | Use env for WHISPER_URL/HF_TOKEN |
| apps/web/src/components/analytics/cloudflare-web-analytics.tsx | Use env for analytics token |
| apps/web/src/components/video-channels.tsx | Use youtube channel normalization/types |
| apps/web/src/components/settings/room-settings-section.tsx | Use room password/id helpers |
| apps/web/src/components/pages/youtube/* | Update imports for youtube/room utilities |
| apps/web/src/components/curated-playlists/* | Use youtube playlist parser |
| apps/web/tests/lib/* | Update tests for new package imports |
| apps/api/package.json | Add env/zod deps + add lint scripts |
| apps/api/tsconfig.json | Add paths for new workspace packages |
| apps/api/src/env.ts | Add API t3-env composition module |
| apps/api/src/server.ts | Switch swagger → openapi + env.PORT |
| apps/api/src/redis.ts | Use @vkara/redis options factory + env |
| apps/api/src/youtubei.ts | Replace TypeBox bodies with zod schemas + 502 errors |
| apps/api/src/utils/logger.ts | Route logging config through validated env |
| apps/api/src/utils/common.ts | Move youtube normalization imports to domain package |
| apps/api/src/utils/room-store.ts | Move room types/errors to room package |
| apps/api/src/plugins/room-ws.plugin.ts | Use zod WS schema + room ServerMessage |
| apps/api/src/queues/cleanup.ts | Use env + redis options factory |
| apps/api/src/queues/hourly-report.ts | Use env + redis options factory |
| apps/api/src/modules/youtube/* | Update imports + adopt cache-redis helpers |
| apps/api/src/modules/room/* | Split types between room + validators |
| apps/api/src/schemas/client-message.ts | Remove TypeBox WS schema file |
| apps/api/src/config/embed-playability-env.ts | Remove legacy embed env module |
| apps/api/tests/config/env.test.ts | Point tests to env package parsers |
| apps/api/tests/config/embed-playability-env.test.ts | Use env package embed helpers |
| apps/api/tests/schemas/client-message.test.ts | Switch to zod schema checks |
| apps/api/tests/modules/* | Update tests for new packages/imports |
| apps/api/tests/utils/* | Update test type imports |
| apps/api/tests/fixtures/sing-king-search.ts | Update fixture type import |
| apps/api/Dockerfile | Update workspace stubs + filtered installs |
| apps/api/.env.example | Sync env examples with new layout |
| .github/workflows/ci.yml | Collapse into single bun run ci job |
| .github/workflows/build-push-docker.yml | Run bun run ci before docker builds |
| .github/pull_request_template.md | Update checklist for new packages/gates |
| .env.example | Add root env example for monorepo |
Comments suppressed due to low confidence (1)
apps/web/src/providers/websocket-provider.tsx:38
getWebSocketUrlalways appends/wseven whenNEXT_PUBLIC_WS_URLalready includes the/wspath (e.g..env.example/docker-compose setws://localhost:8000/ws). This produces URLs likews://.../ws/wsand breaks the WebSocket connection.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…nteractions - Added error handling for the search suggestions endpoint to log failures and return a 502 status on upstream errors. - Improved validation logic in channel and playlist caching to ensure proper structure and types for cached data. - Introduced new parsing functions for YouTube video, channel, and playlist metadata to enhance data integrity. - Added unit tests for channel and playlist caching to validate the new parsing and error handling logic.
- Introduced EmbedEnvValues type to encapsulate environment variables related to embed functionality. - Updated getEmbedCacheTtlSeconds and isEmbedPrefilterAtListEnabled functions to accept EmbedEnvValues for better flexibility. - Enhanced setEmbeddabilityMany and filterVideosForListPrefilter functions to utilize the new embed parameter for improved cache handling. - Removed outdated tests and added new tests to validate the updated embed environment logic and caching behavior.
- Revised comments in .env.example and apps/api/.env.example to clarify documentation sources for VKARA_* flags. - Enhanced flag documentation in packages/env/src/flags.ts to distinguish between boolean flags and tunables, and introduced VKARA_ENV_DOCS for comprehensive environment variable documentation.
- Renamed and to and for consistency across the codebase. - Updated references in to reflect the new naming, ensuring all usages align with the updated schema names.
…r shared rules - Added a new ESLint configuration file for the web application, utilizing the createWebEslintConfigs function for streamlined TypeScript and Next.js rules. - Refactored shared ESLint rules into a dedicated function to enhance maintainability and reduce duplication in the configuration. - Updated the main ESLint configuration to incorporate the new web-specific settings, ensuring consistent linting across the project.
Summary
Replace shared-types/shared-utils/shared-infra with domain and platform packages. Centralize configuration via @t3-oss/env-core, validate API and WebSocket contracts with zod, and align CI/Docker with the new layout.
BREAKING CHANGE:
Platform & env:
Domain packages:
API:
Web:
Monorepo quality:
CI & Docker:
Docs & OpenSpec: