-
Notifications
You must be signed in to change notification settings - Fork 179
fix: Improve DX with automated setup and Docker orchestration (#292) #293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Create SavedRepo type definition - Add SavedReposAction and SavedReposUpdateInput types - Export from shared package index
- Create Zustand store with persist middleware - Implement actions: add, remove, toggle, clear, setAll, isSaved - Configure localStorage persistence with key 'oss_saved_repos_v1' - Add duplicate prevention logic - Enforce maximum 100 repos limit
- Create star icon toggle button for each repo row - Implement filled/outline star states - Prevent event propagation to row click - Add accessibility attributes (ARIA labels)
- Create side panel for managing saved repos - Implement export to JSON functionality - Implement import from JSON functionality - Add clear all with confirmation (3-second timeout) - Add empty state and list view - Include responsive design
- Add 'Save' column as first column in table - Render SaveToggle component in each row - Add 'Saved Projects' button with count badge in header - Add SavedProjectsPanel component - Manage panel open/close state
- Add saved_repos JSONB column with default '[]' - Non-breaking change (additive only) - Supports up to 100 repos per user
- Create getSavedRepos function - Create mergeSavedRepos with conflict resolution (newer savedAt wins) - Create updateSavedRepos with add/remove/replace actions - Enforce maximum 100 repos limit - Add validation and error handling
- Add getSavedRepos query (protected, feature flag) - Add updateSavedRepos mutation (protected, feature flag) - Implement merge logic for sync - Add Zod validation schemas - Feature flag: FEATURE_SAVED_REPOS_DB - Fix z.record() type arguments for Zod compatibility
- Create CHANGELOG entry with feature details - Create comprehensive feature documentation (SAVED_REPOS.md) - Add PR plan with commit strategy (PR_PLAN_SAVED_REPOS.md) - Include quickstart guide (QUICKSTART_SAVED_REPOS.md) - Add usage guide, API reference, architecture details - Include troubleshooting and rollout strategy
- Fix import issues in SavedProjectsPanel (add ChangeEvent type import, remove unused SavedRepo, reorder imports) - Add block scope to switch cases in savedRepos.service to prevent variable leaking - Fix invalid Tailwind class hover:bg-white-500 to hover:bg-ox-purple/80 in ProjectsContainer - Add keyboard accessibility (Enter/Space) and aria-labels to buttons - Add importAndValidate method to store for safe data validation and deduplication - Replace unsafe popularity type assertion with proper validation in SaveToggle - Remove nested interactive elements (move onClick to button from div) - Remove unused Checkbox import from SaveToggle - Update PR plan with correct issue number (apsinghdev#219) - Replace hardcoded Windows path with cross-platform placeholder in docs All changes improve code quality, type safety, accessibility, and documentation.
- Remove unused setAll from store destructuring - Keep only used hooks: savedProjects, clearAllSaved, removeProject, importAndValidate
…hdev#292) - Add docker-compose.yml for full-stack orchestration (PostgreSQL, API, Web) - Add Dockerfile.dev with hot-reload support for development - Add Makefile with automation targets (setup, start, stop, logs, etc.) - Add setup.ps1 for Windows users without Make - Add scripts/setup.sh interactive setup wizard - Add apps/web/.env.example environment template - Add apps/api/prisma/seed.ts for database seeding - Add /health endpoint to API for Docker healthchecks - Update README.md with simplified Quick Start guide - Update tsconfig.json to exclude prisma/dist folders - Update .gitignore to allow .env.example files Resolves apsinghdev#292
|
@Lucifer-0612 is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughAdds a Saved Repos feature spanning frontend, backend, shared types, DB migration, docs, and dev tooling. Frontend provides a Zustand localStorage store, UI components (save toggle, panel, import/export), and optional server sync behind FEATURE_SAVED_REPOS_DB with tRPC endpoints and timestamp-based merge logic. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as Client (Browser)
participant UI as Frontend UI
participant Store as Zustand (localStorage)
participant API as tRPC Backend
participant DB as Postgres (User.saved_repos JSONB)
Browser->>UI: Click save/unsave
UI->>Store: toggleProject(id) → update local state & localStorage
alt FEATURE_SAVED_REPOS_DB = true (sync)
UI->>API: updateSavedRepos(action, repos, localRepos?)
API->>DB: SELECT saved_repos FROM users WHERE id=…
DB-->>API: serverSavedRepos
API->>API: if localRepos and action=replace → mergeSavedRepos(local, server)
API->>DB: UPDATE users SET saved_repos = merged/updated
DB-->>API: ack
API-->>UI: return updated saved_repos
UI->>Store: setAll(updatedSavedRepos)
else
UI->>Store: no server sync (client-only)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
- Resolved seed.ts: Combined comprehensive upstream seed with QueryCount - Resolved tsconfig.json: Added include and node_modules to exclude
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (18)
apps/web/src/data/blogs.ts (1)
15-15: Consider using UPPER_SNAKE_CASE for the constant.As per coding guidelines, constants should use UPPER_SNAKE_CASE. Renaming
blogstoBLOGSwould align with the project's naming conventions.🔎 Apply this diff to follow the naming convention:
-export const blogs: BlogPost[] = [ +export const BLOGS: BlogPost[] = [Note: This change will require updating all imports and usages of
blogstoBLOGSthroughout the codebase.Dockerfile.dev (1)
26-26: Minor: trailing whitespace.Line 26 has trailing whitespace after
packages/ui/package.json.🔎 Suggested fix
-COPY packages/ui/package.json ./packages/ui/ +COPY packages/ui/package.json ./packages/ui/setup.ps1 (2)
107-119: Fixed sleep for DB readiness is brittle.Using
Start-Sleep -Seconds 10(line 109) assumes the database will be ready within 10 seconds, but startup time varies by system load. Consider polling the database health endpoint or using a retry loop for more reliable behavior.🔎 Suggested improvement
Write-Host "" Write-Host "Waiting for database to be ready..." -ForegroundColor Yellow -Start-Sleep -Seconds 10 +$maxRetries = 30 +$retryCount = 0 +while ($retryCount -lt $maxRetries) { + try { + docker compose exec -T db pg_isready -U postgres | Out-Null + Write-Host " [OK] Database is ready" -ForegroundColor Green + break + } catch { + $retryCount++ + Start-Sleep -Seconds 1 + } +} +if ($retryCount -eq $maxRetries) { + Write-Host " [WARN] Database may not be fully ready" -ForegroundColor Yellow +}
60-64: Consider disposing the crypto provider.
RNGCryptoServiceProviderimplementsIDisposable. While PowerShell's garbage collector will eventually clean it up, explicit disposal is cleaner for security-sensitive objects.🔎 Suggested fix
function Generate-Secret { $bytes = New-Object byte[] 32 - [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($bytes) + $rng = [Security.Cryptography.RNGCryptoServiceProvider]::Create() + try { + $rng.GetBytes($bytes) + } finally { + $rng.Dispose() + } return [Convert]::ToBase64String($bytes) }README.md (2)
79-86: Markdown formatting improvements.A few markdown lint issues:
- Line 80: Code block lacks a language specifier
- Line 86: Bare URL should use markdown link syntax
🔎 Suggested fixes
6. Copy credentials to `apps/web/.env.local`: - ``` + ```env GOOGLE_CLIENT_ID="your-client-id" GOOGLE_CLIENT_SECRET="your-client-secret" ``` 7. Restart: `make restart` -**Done! 🎉** Visit http://localhost:3000 +**Done! 🎉** Visit [http://localhost:3000](http://localhost:3000)
197-197: Bare URLs in manual setup section.Consider using markdown link syntax for consistency.
🔎 Suggested fix
-Frontend: http://localhost:3000 | API: http://localhost:8080 +Frontend: [http://localhost:3000](http://localhost:3000) | API: [http://localhost:8080](http://localhost:8080)scripts/setup.sh (1)
112-124: Fixed sleep for DB readiness is brittle.Similar to the PowerShell script, using
sleep 8(line 114) assumes database startup time. Consider a health-check loop for more reliable behavior across different systems.🔎 Suggested improvement
echo "" echo -e "${YELLOW}Waiting for database to be ready...${NC}" -sleep 8 +max_retries=30 +retry_count=0 +while [ $retry_count -lt $max_retries ]; do + if docker compose exec -T db pg_isready -U postgres &>/dev/null; then + echo -e "${GREEN} [OK] Database is ready${NC}" + break + fi + retry_count=$((retry_count + 1)) + sleep 1 +done +if [ $retry_count -eq $max_retries ]; then + echo -e "${YELLOW} [WARN] Database may not be fully ready${NC}" +fidocs/PR_PLAN_SAVED_REPOS.md (1)
4-6: Add language specifier to fenced code block.The code block is missing a language specifier. Since it's a PR title (plain text), you can use
textor omit the fence entirely.🔎 Suggested fix:
## PR Title -``` +```text feat: Saved Projects — local persistence + optional DB sync</details> </blockquote></details> <details> <summary>docker-compose.yml (2)</summary><blockquote> `49-50`: **Seed failures are silently ignored.** The `|| true` suppresses seed script failures, which could mask issues during development. If the seed is required for the app to function (as noted in the seed script comment), consider removing `|| true` or logging the failure more explicitly. <details> <summary>🔎 Suggested fix:</summary> ```diff command: > - sh -c "pnpm exec prisma migrate deploy && pnpm exec prisma db seed || true && pnpm run dev" + sh -c "pnpm exec prisma migrate deploy && pnpm exec prisma db seed && pnpm run dev"Alternatively, if you want to allow seed failures but still log them:
command: > sh -c "pnpm exec prisma migrate deploy && (pnpm exec prisma db seed || echo 'Warning: Seed failed') && pnpm run dev"
69-70: Consider waiting for api health before starting web.The
webservice starts as soon as theapicontainer starts, not when it's healthy. This may cause initial connection errors if web tries to reach the api before it's ready.🔎 Suggested fix:
depends_on: - - api + api: + condition: service_healthypackages/shared/types/savedRepos.ts (1)
9-9: Preferunknownoveranyfor extensible metadata.Per coding guidelines, avoid
anytype. UsingRecord<string, unknown>maintains flexibility while requiring type narrowing when accessing values.🔎 Suggested fix:
- meta?: Record<string, any>; // Extensible metadata + meta?: Record<string, unknown>; // extensible metadataapps/web/src/components/dashboard/SaveToggle.tsx (2)
13-13: Use arrow function declaration per coding guidelines.Per project guidelines, prefer
constwith arrow functions over function declarations.🔎 Suggested fix:
-export default function SaveToggle({ project }: SaveToggleProps) { +const SaveToggle = ({ project }: SaveToggleProps) => { const { toggleProject, isSaved } = useSavedProjectsStore(); // ... rest of component -} +}; + +export default SaveToggle;
3-7: Reorganize imports per coding guidelines.Per guidelines, organize imports as: react → third-party → local components → utils → types.
🔎 Suggested fix:
"use client"; +import { StarIcon } from "@heroicons/react/24/solid"; +import { StarIcon as StarOutlineIcon } from "@heroicons/react/24/outline"; +import { SavedRepo } from "@opensox/shared"; + import { useSavedProjectsStore } from "@/store/useSavedProjectsStore"; import { DashboardProjectsProps } from "@/types"; -import { SavedRepo } from "@opensox/shared"; -import { StarIcon } from "@heroicons/react/24/solid"; -import { StarIcon as StarOutlineIcon } from "@heroicons/react/24/outline";apps/api/src/routers/user.ts (2)
40-47: Add error logging with context for debugging.Per coding guidelines, errors should be logged with context (userId, endpoint, timestamp). Consider wrapping the service call in try-catch to log errors before they propagate to the tRPC error handler.
🔎 Apply this diff to add error logging:
getSavedRepos: protectedProcedure.query(async ({ ctx }: any) => { if (process.env.FEATURE_SAVED_REPOS_DB !== "true") { return []; } const userId = ctx.user.id; - return await savedReposService.getSavedRepos(ctx.db.prisma, userId); + try { + return await savedReposService.getSavedRepos(ctx.db.prisma, userId); + } catch (error) { + console.error('getSavedRepos failed', { userId, error, timestamp: new Date().toISOString() }); + throw error; + } }),
82-114: Add error logging with context for debugging.Per coding guidelines, critical operations should be logged with context. Consider adding try-catch with error logging for the mutation.
🔎 Apply this diff to add error logging:
.mutation(async ({ ctx, input }: any) => { if (process.env.FEATURE_SAVED_REPOS_DB !== "true") { throw new Error("Saved repos sync is not enabled"); } const userId = ctx.user.id; + try { // If localRepos provided, merge with server repos if (input.localRepos && input.action === "replace") { const serverRepos = await savedReposService.getSavedRepos( ctx.db.prisma, userId ); const merged = savedReposService.mergeSavedRepos( input.localRepos, serverRepos ); return await savedReposService.updateSavedRepos( ctx.db.prisma, userId, "replace", merged ); } // Otherwise, perform the requested action return await savedReposService.updateSavedRepos( ctx.db.prisma, userId, input.action, input.repos ); + } catch (error) { + console.error('updateSavedRepos failed', { userId, action: input.action, error, timestamp: new Date().toISOString() }); + throw error; + } }),apps/api/src/services/savedRepos.service.ts (1)
9-24: Include userId in error messages for better debugging.The error messages "User not found" on lines 19 and 67 don't include the userId, making debugging harder. Per coding guidelines, errors should be logged with context.
🔎 Apply this diff to improve error messages:
if (!user) { - throw new Error("User not found"); + throw new Error(`User not found: ${userId}`); }Apply the same change on line 67 in
updateSavedRepos.Also applies to: 55-68
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (1)
42-68: Replacealert()with toast notifications for better UX.Lines 53, 55, and 59 use
alert()for user feedback. This provides a poor user experience compared to modern toast notifications. Consider using a toast library (e.g., react-hot-toast, sonner) for non-blocking feedback.The JSON parsing is properly wrapped in try-catch and the validation logic through
importAndValidateis correct.docs/QUICKSTART_SAVED_REPOS.md (1)
41-87: Clarify package manager consistency in Quick Start instructions.The Quick Start mixes
npm run build(line 56) withpnpm run build(line 57) and usespnpmcommands thereafter (lines 65, 76, 86). This could confuse users unfamiliar with monorepo setups. Commit to one package manager or clearly indicate both are interchangeable.Additionally, the migration command on line 82 assumes
add_saved_reposis a new migration name, but if this migration has already been created in the PR, the command will fail. Clarify the expected state.🔎 Suggested clarification:
-# or -pnpm run buildAdd a note above Step 2:
+**Note:** These examples use `pnpm`. If you prefer `npm`, substitute `npm` for `pnpm` in all commands below.For the migration step, add:
-# Run migration -npx prisma migrate dev --name add_saved_repos +# Run migration (skip if already applied) +npx prisma migrate dev
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
CHANGELOG.md(1 hunks)Dockerfile.dev(1 hunks)Makefile(1 hunks)README.md(1 hunks)apps/api/package.json(2 hunks)apps/api/prisma/schema.prisma(1 hunks)apps/api/prisma/seed.ts(1 hunks)apps/api/src/index.ts(1 hunks)apps/api/src/routers/user.ts(2 hunks)apps/api/src/services/savedRepos.service.ts(1 hunks)apps/api/tsconfig.json(1 hunks)apps/web/.env.example(1 hunks)apps/web/.gitignore(1 hunks)apps/web/src/components/dashboard/ProjectsContainer.tsx(6 hunks)apps/web/src/components/dashboard/SaveToggle.tsx(1 hunks)apps/web/src/components/dashboard/SavedProjectsPanel.tsx(1 hunks)apps/web/src/data/blogs.ts(4 hunks)apps/web/src/store/useSavedProjectsStore.ts(1 hunks)docker-compose.yml(1 hunks)docs/PR_PLAN_SAVED_REPOS.md(1 hunks)docs/QUICKSTART_SAVED_REPOS.md(1 hunks)docs/SAVED_REPOS.md(1 hunks)packages/shared/types/index.ts(1 hunks)packages/shared/types/savedRepos.ts(1 hunks)scripts/setup.sh(1 hunks)setup.ps1(1 hunks)
🧰 Additional context used
📓 Path-based instructions (23)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/api/src/index.tsapps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/data/blogs.tsapps/api/prisma/seed.tsapps/api/src/routers/user.tspackages/shared/types/index.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/api/src/index.tsapps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/data/blogs.tsapps/api/prisma/seed.tsapps/api/src/routers/user.tspackages/shared/types/index.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/api/src/index.tsapps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/data/blogs.tsapps/api/prisma/seed.tsapps/api/src/routers/user.tspackages/shared/types/index.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/api/src/index.tsapps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/data/blogs.tsapps/api/prisma/seed.tsapps/api/src/routers/user.tspackages/shared/types/index.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/api/src/index.tsapps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/data/blogs.tsapps/api/prisma/seed.tsapps/api/src/routers/user.tspackages/shared/types/index.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/index.tsapps/api/src/routers/user.tsapps/api/src/services/savedRepos.service.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/index.tsapps/api/src/routers/user.tsapps/api/src/services/savedRepos.service.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/data/blogs.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/SaveToggle.tsxpackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/src/services/savedRepos.service.tsapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/data/blogs.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/data/blogs.tsapps/web/src/store/useSavedProjectsStore.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/api/src/**/{services,models,database}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Encrypt sensitive data (passwords, tokens, API keys) before storing in database
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{database,services}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Handle database connection failures gracefully with retry logic
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{database,models,services}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Always use parameterized queries or ORM methods to prevent SQL injection
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{services,database}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Wrap database transactions in try-catch blocks with proper rollback on failure
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{services,repositories}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid N+1 queries; use eager loading or batch queries when fetching related data
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{services,models}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate data against schema before database operations
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{database,clients,services}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Use connection pooling for database and external service clients
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{services,clients,handlers}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Implement timeouts for external API calls to prevent hanging requests
Files:
apps/api/src/services/savedRepos.service.ts
apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Log all critical operations (auth attempts, payment processing, data mutations)
Files:
apps/api/src/services/savedRepos.service.ts
🧠 Learnings (22)
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers}/*.{js,ts} : Return appropriate HTTP status codes (400 for validation, 401 for auth, 500 for server errors)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Applied to files:
apps/web/src/components/dashboard/SaveToggle.tsx
📚 Learning: 2025-12-17T12:39:29.991Z
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 262
File: apps/web/src/components/checkout/CheckoutWrapper.tsx:5-5
Timestamp: 2025-12-17T12:39:29.991Z
Learning: In Next.js apps, avoid using redirect() from next/navigation inside Client Components during render. It should not be used in event handlers like onClick or onSubmit; for those cases, use useRouter().push() or router.replace() instead. This guidance applies to TSX files (React components) across the codebase; implement in client components to handle conditional redirects during render, and use router-based navigation in handlers.
Applied to files:
apps/web/src/components/dashboard/SaveToggle.tsxapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/database/**/*.{js,ts} : Index frequently queried fields for performance optimization
Applied to files:
apps/api/prisma/seed.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,clients,services}/*.{js,ts} : Use connection pooling for database and external service clients
Applied to files:
apps/api/prisma/seed.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Document all required environment variables in `.env.example`
Applied to files:
apps/web/.env.exampleapps/web/.gitignore
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{config,environment,setup}/*.{js,ts} : Use type-safe environment variable access with proper defaults
Applied to files:
apps/web/.env.exampleapps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Always validate user authentication before processing protected routes
Applied to files:
apps/api/src/routers/user.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/package.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Export types from shared package for consistency across apps
Applied to files:
packages/shared/types/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Remove unused imports
Applied to files:
packages/shared/types/index.tsapps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Never commit `.env` files or hardcode secrets in code
Applied to files:
apps/web/.gitignore
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Use Zustand for global state, located in `src/store/`
Applied to files:
apps/web/src/store/useSavedProjectsStore.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Use zustand for global state (located in `src/store/`)
Applied to files:
apps/web/src/store/useSavedProjectsStore.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{services,repositories}/*.{js,ts} : Avoid N+1 queries; use eager loading or batch queries when fetching related data
Applied to files:
apps/api/src/services/savedRepos.service.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/*.ts : Avoid `any` type; use `unknown` for truly dynamic data and narrow with type guards
Applied to files:
apps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,types}/*.ts : Define strict TypeScript interfaces for request/response bodies
Applied to files:
apps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Organize imports: react → third-party → local components → utils → types
Applied to files:
apps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/api/tsconfig.json
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/api/tsconfig.json
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unused imports
Applied to files:
apps/api/tsconfig.json
🧬 Code graph analysis (2)
apps/web/src/components/dashboard/SaveToggle.tsx (3)
apps/web/src/types/projects.ts (1)
DashboardProjectsProps(1-13)apps/web/src/store/useSavedProjectsStore.ts (1)
useSavedProjectsStore(16-123)packages/shared/types/savedRepos.ts (1)
SavedRepo(1-10)
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (1)
apps/web/src/store/useSavedProjectsStore.ts (1)
useSavedProjectsStore(16-123)
🪛 checkmake (0.2.2)
Makefile
[warning] 4-4: Target body for "help" exceeds allowed length of 5 (32).
(maxbodylength)
[warning] 45-45: Target body for "start" exceeds allowed length of 5 (8).
(maxbodylength)
[warning] 1-1: Missing required phony target "all"
(minphony)
🪛 Checkov (3.2.334)
docker-compose.yml
[medium] 32-33: Basic Auth Credentials
(CKV_SECRET_4)
🪛 dotenv-linter (4.0.0)
apps/web/.env.example
[warning] 8-8: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 12-12: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 13-13: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 21-21: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 22-22: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 LanguageTool
docs/PR_PLAN_SAVED_REPOS.md
[style] ~330-~330: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ecently Saved" section on dashboard? 3. Should we implement folders/tags in this PR or...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~331-~331: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...nt folders/tags in this PR or later? 4. Should we add a limit warning when approaching...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~332-~332: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... warning when approaching 100 repos? 5. Should we add a "Share saved repos" feature? ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🪛 markdownlint-cli2 (0.18.1)
docs/PR_PLAN_SAVED_REPOS.md
4-4: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
README.md
80-80: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
86-86: Bare URL used
(MD034, no-bare-urls)
197-197: Bare URL used
(MD034, no-bare-urls)
197-197: Bare URL used
(MD034, no-bare-urls)
docs/QUICKSTART_SAVED_REPOS.md
62-62: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
69-69: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (32)
apps/web/src/data/blogs.ts (1)
18-78: LGTM! Text corrections improve content quality.All typo fixes, grammar improvements, and formatting consistency changes are accurate and enhance the user-facing content.
apps/web/.gitignore (1)
33-34: LGTM!The pattern correctly ignores all
.env*files while explicitly tracking.env.exampleas a template. This aligns with best practices for documenting required environment variables without committing actual secrets. Based on learnings, this is the recommended approach.apps/api/tsconfig.json (1)
38-41: LGTM with minor consideration.Excluding
distis correct. Excludingprismaprevents TypeScript from checking generated Prisma client types, which is appropriate. However, note thatprisma/seed.tswill also be excluded from type-checking—ensure the seed script is validated separately (e.g., viapnpm exec prisma db seedwhich handles its own compilation).packages/shared/types/index.ts (1)
1-3: LGTM!Barrel export pattern correctly re-exports types from the new
savedReposmodule, maintaining consistency with existing exports. Based on learnings, exporting types from the shared package ensures consistency across apps.apps/web/.env.example (1)
1-27: Well-documented environment template.The file clearly documents all required environment variables with helpful setup instructions. The structure with REQUIRED and OPTIONAL sections improves developer experience. Based on learnings, this follows the guideline to document all required environment variables in
.env.example.The static analysis warnings about quote characters can be safely ignored—quotes are acceptable in
.envfiles and are helpful here to indicate placeholder values.README.md (1)
41-101: Excellent documentation overhaul.The Docker Quick Start section is well-structured with clear steps, visual indicators (✅), and a helpful commands table. The troubleshooting section with collapsible details is a great UX improvement for new contributors. This directly addresses the PR objective of simplifying setup.
scripts/setup.sh (2)
69-88: Good cross-platform secret generation.The OS-specific
sedhandling for macOS vs Linux is correct, and the fallback to/dev/urandomwhenopensslis unavailable ensures the script works in minimal environments.
1-27: Well-structured preflight checks.The Docker validation (both command existence and daemon status) provides clear, actionable error messages. The colored output improves the developer experience significantly.
Dockerfile.dev (1)
21-32: Web stage must build the shared package before running dev, just like the API stage does.The web stage copies the shared package source code (lines 23-25, 28) but never builds it. Since the shared package's
package.jsonexportsdist/index.jsas the main entry point, the web app will fail at runtime when trying to import@opensox/shared. AddRUN pnpm run buildin the shared package directory before starting the web dev server (after copying packages but beforeCMD), similar to how the API stage handles it.apps/api/src/index.ts (1)
101-104: LGTM!The health check endpoint is appropriately simple and stateless, returning only status and timestamp. Not applying rate limiting here is correct since container orchestrators need unrestricted access for health probes.
apps/api/prisma/schema.prisma (1)
42-42: Schema addition looks good.The
Jsontype with default"[]"is appropriate for storing saved repositories. Since the current implementation reads/writes the entire field rather than querying inside the JSON structure, an index isn't required now. If you later add queries filtering by JSON properties (e.g.,saved_repos @> '[{"language": "TypeScript"}]'), consider adding a GIN index.apps/api/package.json (1)
17-19: LGTM!Standard Prisma seed configuration using
tsxwhich is already available in devDependencies.apps/api/prisma/seed.ts (1)
1-28: LGTM!The seed script is well-structured:
- Idempotent via
upsert(safe for repeated runs during development)- Proper error handling with exit code 1 on failure
- Clean disconnection in
finallyblockpackages/shared/types/savedRepos.ts (1)
1-17: Type definitions are well-structured.The types provide a clear contract between frontend and backend. The union type for
SavedReposActionand structuredSavedReposUpdateInputenable type-safe API interactions.apps/web/src/components/dashboard/SaveToggle.tsx (1)
17-64: Well-implemented component with good accessibility.Good implementation choices:
- Type guard
isValidPopularityensures type safetye.stopPropagation()prevents row click conflictsaria-labelandaria-pressedprovide proper accessibilityparseFloat(...) || 0handles invalid competition values gracefullyCHANGELOG.md (1)
1-85: LGTM! Comprehensive feature documentation.The CHANGELOG entry clearly documents the Saved Repos feature across all layers (frontend, backend, shared types, configuration). The code examples accurately reflect the API implementation and the feature flag behavior is well documented.
apps/web/src/components/dashboard/ProjectsContainer.tsx (2)
19-22: LGTM! Clean integration of new components.The imports are well-organized following the coding guidelines (React → third-party → local components → utils), and the "Save" column addition is straightforward.
Also applies to: 49-49
152-154: LGTM! Clean component integration.The SaveToggle and SavedProjectsPanel components are properly integrated with correct props and state management.
Also applies to: 216-219
docs/SAVED_REPOS.md (1)
1-214: LGTM! Excellent comprehensive documentation.The documentation is thorough, well-structured, and covers all aspects of the feature including usage, architecture, API endpoints, troubleshooting, and rollout strategy. The examples accurately reflect the implementation.
apps/api/src/services/savedRepos.service.ts (3)
30-50: LGTM! Efficient merge algorithm with correct conflict resolution.The merge logic correctly uses a Map for O(n+m) complexity and resolves conflicts based on the
savedAttimestamp. The sorting ensures newest repos appear first.
73-97: LGTM! Efficient action handlers with proper validation.The switch statement correctly handles add, remove, and replace actions with efficient Set-based filtering. The default case properly throws for invalid actions.
99-102: LGTM! Proper enforcement of repository limits.The 100 repository limit is correctly enforced and aligned with the documentation.
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (3)
29-40: LGTM! Clean export implementation.The export functionality correctly serializes saved projects to JSON and triggers a download with a timestamped filename. The cleanup with
URL.revokeObjectURLis properly handled.
70-78: LGTM! Good confirmation pattern for destructive action.The two-step confirmation with a 3-second timeout provides a good safety mechanism for the Clear All action.
82-209: LGTM! Well-structured accessible UI.The component properly implements:
- Backdrop click to close
- Accessible buttons with aria-labels
- Proper keyboard navigation support
- Disabled states for empty conditions
- Secure external links with
rel="noopener noreferrer"- Clean responsive layout
Makefile (1)
1-128: LGTM! Well-structured development automation.The Makefile provides comprehensive development workflow automation with clear help text, proper error handling, and safety confirmations for destructive operations.
The checkmake warnings are stylistic preferences:
- The
helptarget exceeds 5 lines because it provides comprehensive user guidance (intentional)- The missing
alltarget is not needed sincehelpis the appropriate default- The body length warnings don't indicate functional issues
The Docker Compose commands, Prisma operations, and interactive prompts are all correctly implemented.
apps/web/src/store/useSavedProjectsStore.ts (3)
21-30: LGTM! Proper duplicate prevention.The
addProjectmethod correctly checks for existing projects by ID before adding, preventing duplicates.
37-51: LGTM! Correct toggle logic.The
toggleProjectmethod properly checks existence and toggles the saved state accordingly.
117-122: LGTM! Proper persistence configuration.The persist middleware is correctly configured with:
- Versioned storage key for future migrations
- localStorage as the storage backend
- Partial state persistence (only
savedProjects)docs/QUICKSTART_SAVED_REPOS.md (3)
1-40:⚠️ Major discrepancy: PR scope mismatch.The PR objectives state this PR addresses #292 ("Improve DX with automated setup and Docker orchestration"), emphasizing single-command setup (
make setup/setup.ps1), Docker Compose orchestration, automatic .env generation, and secret management. However, this document and the AI summary describe an entirely different feature: a "Saved Repos" capability for saving/syncing repositories.Please clarify: Is this PR about Docker/DX automation, or about the Saved Repos feature? The file provided doesn't align with the stated PR objectives.
104-107: Verify cross-device sync testing instructions are actionable.Line 106 suggests verifying saved repos "in the database (Prisma Studio)", but Prisma Studio requires a running server context. Clarify the exact steps: e.g., "Run
npx prisma studioin a separate terminal" or provide a SQL query to inspect the data directly. This ensures users can actually complete this advanced test.
111-116: Verify referenced documentation files exist.The document references
docs/SAVED_REPOS.md,docs/PR_PLAN_SAVED_REPOS.md, andCHANGELOG.md(lines 113–115), and mentions "artifacts in conversation" (line 116). Confirm these files:
- Actually exist in the PR branch
- Are consistent with the quick start instructions provided here
- Are up-to-date with feature implementation details
Broken or outdated references undermine user confidence and cause frustration during onboarding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/api/package.json(2 hunks)apps/api/prisma/seed.ts(1 hunks)apps/api/tsconfig.json(1 hunks)apps/web/.gitignore(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/api/prisma/seed.ts
- apps/api/tsconfig.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Never commit `.env` files or hardcode secrets in code
Applied to files:
apps/web/.gitignore
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Document all required environment variables in `.env.example`
Applied to files:
apps/web/.gitignore
🪛 Biome (2.1.2)
apps/api/package.json
[error] 17-17: The key prisma was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
🔇 Additional comments (1)
apps/web/.gitignore (1)
33-34: ✓ Correct pattern for environment template management.The negation pattern
!.env.examplecorrectly preserves the example configuration in version control while keeping actual secrets ignored. The.env.examplefile is properly documented with all required environment variables and setup instructions, supporting the PR's goal to simplify onboarding for new contributors.
- Replace z.any() with z.unknown() in user router meta fields - Update SavedRepo type to use unknown instead of any - Add proper type narrowing in isValidSavedRepo type guard - Replace hardcoded Tailwind colors with semantic design tokens - Use bg-info/text-info for language badges - Use bg-success/text-success for popularity badges - Replace ox-purple with brand-purple across components - Flatten status colors in Tailwind config for proper utilities - Fix markdown semantics in QUICKSTART_SAVED_REPOS.md - Remove duplicate prisma key from package.json Type safety improvements prevent runtime errors and improve maintainability. Design token migration ensures consistent theming and accessibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/web/src/store/useSavedProjectsStore.ts (1)
57-114: LGTM! Robust validation with proper type narrowing.The
importAndValidatemethod correctly usesunknownfor the input parameter (addressing the previous review concern), implements thorough validation with a type guard, deduplicates by ID, enforces a sensible 100-item limit, and provides helpful feedback.Note: The previous review comment about using
unknowninstead ofanyhas been resolved - line 67 correctly uses(item: unknown): item is SavedRepo.
🧹 Nitpick comments (5)
apps/web/tailwind.config.ts (1)
70-93: The status color DEFAULT mapping is intentional but unnecessarily verbose for developer experience.The .cursorrules file documents that status colors must use full modifier syntax (
bg-success-bg,text-success-text,border-success-border), which is working as designed. However, since the DEFAULT key in Tailwind means "no modifier", setting DEFAULT to the text color requires developers to always use redundant compound selectors likebg-success-bg.This pattern works but creates unnecessary cognitive overhead. Consider adopting separate top-level tokens for cleaner semantics:
- success: { - DEFAULT: colors.status.success.text, - bg: colors.status.success.bg, - text: colors.status.success.text, - border: colors.status.success.border, - }, + "success-bg": colors.status.success.bg, + "success-text": colors.status.success.text, + "success-border": colors.status.success.border,This would allow intuitive usage (
bg-success-bg→bg-success-bgremains the same, buttext-success-textis now unambiguous) while eliminating the confusing DEFAULT fallback. Apply this pattern consistently across success, error, warning, and info.apps/api/src/routers/user.ts (2)
41-47: Consider consistent feature flag behavior.When the feature flag is disabled,
getSavedRepossilently returns an empty array whileupdateSavedReposthrows an error. This inconsistency could confuse clients - they might see an empty list and attempt to save, only to get an error.Consider either:
- Having
getSavedReposalso throw when the flag is disabled- Having
updateSavedRepossilently no-op (less recommended)
54-79: Consider extracting the duplicated repo schema.The Zod schema for a single repo object is duplicated between
reposandlocalReposarrays. Extracting it improves maintainability.🔎 Apply this diff to reduce duplication:
+const savedRepoSchema = z.object({ + id: z.string(), + name: z.string(), + url: z.string(), + language: z.string().optional(), + popularity: z.enum(["low", "medium", "high"]).optional(), + competitionScore: z.number().optional(), + savedAt: z.string(), + meta: z.record(z.string(), z.unknown()).optional(), +}); + updateSavedRepos: protectedProcedure .input( z.object({ action: z.enum(["add", "remove", "replace"]), - repos: z.array( - z.object({ - id: z.string(), - name: z.string(), - url: z.string(), - language: z.string().optional(), - popularity: z.enum(["low", "medium", "high"]).optional(), - competitionScore: z.number().optional(), - savedAt: z.string(), - meta: z.record(z.string(), z.unknown()).optional(), - }) - ), - localRepos: z - .array( - z.object({ - id: z.string(), - name: z.string(), - url: z.string(), - language: z.string().optional(), - popularity: z.enum(["low", "medium", "high"]).optional(), - competitionScore: z.number().optional(), - savedAt: z.string(), - meta: z.record(z.string(), z.unknown()).optional(), - }) - ) - .optional(), + repos: z.array(savedRepoSchema), + localRepos: z.array(savedRepoSchema).optional(), }) )apps/web/src/components/dashboard/ProjectsContainer.tsx (1)
19-22: Reorganize imports to follow guidelines.Per coding guidelines, imports should be organized: React → third-party → local components → utils → types. The
useStateimport from React should be at the top.🔎 Apply this diff to fix import order:
"use client"; +import { useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { useProjectTitleStore } from "@/store/useProjectTitleStore"; import { DashboardProjectsProps } from "@/types"; import Image from "next/image"; import { useFilterStore } from "@/store/useFilterStore"; import { usePathname } from "next/navigation"; import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import SaveToggle from "./SaveToggle"; import SavedProjectsPanel from "./SavedProjectsPanel"; import { useSavedProjectsStore } from "@/store/useSavedProjectsStore"; -import { useState } from "react";As per coding guidelines for import organization.
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (1)
29-78: Solid handler implementations with good UX patterns.The export handler properly cleans up blob URLs, the import handler includes error handling and input reset, and the clear-all implements a nice two-step confirmation pattern.
Optional: Consider using toast notifications instead of alert()
Lines 53, 55, and 59 use
alert()which blocks the UI. Consider using a toast notification library (like sonner or react-hot-toast) for better UX:- alert(result.error || "Projects imported successfully!"); + toast.success(result.error || "Projects imported successfully!");This is purely a UX enhancement and not a blocker.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/api/package.json(2 hunks)apps/api/src/routers/user.ts(2 hunks)apps/api/src/services/savedRepos.service.ts(1 hunks)apps/web/src/components/dashboard/ProjectsContainer.tsx(6 hunks)apps/web/src/components/dashboard/SavedProjectsPanel.tsx(1 hunks)apps/web/src/store/useSavedProjectsStore.ts(1 hunks)apps/web/tailwind.config.ts(1 hunks)docs/QUICKSTART_SAVED_REPOS.md(1 hunks)packages/shared/types/savedRepos.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/api/src/services/savedRepos.service.ts
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/api/src/routers/user.tsapps/web/tailwind.config.tspackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/src/store/useSavedProjectsStore.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/api/src/routers/user.tsapps/web/tailwind.config.tspackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/api/src/routers/user.tsapps/web/tailwind.config.tspackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxpackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/api/src/routers/user.tsapps/web/tailwind.config.tspackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/src/store/useSavedProjectsStore.ts
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/api/src/routers/user.tsapps/web/tailwind.config.tspackages/shared/types/savedRepos.tsapps/web/src/store/useSavedProjectsStore.ts
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/src/store/useSavedProjectsStore.ts
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/routers/user.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/routers/user.ts
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Use Zustand for global state, located in `src/store/`
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : NEVER use hardcoded hex values (e.g., `#5519f7`) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use semantic color names that describe purpose, not appearance
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use 'class:' instead of the ternary operator in class tags whenever possible
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use appropriate border radius: small elements `rounded-lg`, medium `rounded-xl`, large `rounded-2xl`, buttons `rounded-[16px]`
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsx
📚 Learning: 2025-12-17T12:39:29.991Z
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 262
File: apps/web/src/components/checkout/CheckoutWrapper.tsx:5-5
Timestamp: 2025-12-17T12:39:29.991Z
Learning: In Next.js apps, avoid using redirect() from next/navigation inside Client Components during render. It should not be used in event handlers like onClick or onSubmit; for those cases, use useRouter().push() or router.replace() instead. This guidance applies to TSX files (React components) across the codebase; implement in client components to handle conditional redirects during render, and use router-based navigation in handlers.
Applied to files:
apps/web/src/components/dashboard/SavedProjectsPanel.tsxapps/web/src/components/dashboard/ProjectsContainer.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Applied to files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/*.ts : Avoid `any` type; use `unknown` for truly dynamic data and narrow with type guards
Applied to files:
apps/api/src/routers/user.tsapps/web/src/store/useSavedProjectsStore.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/src/routers/user.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use proper TypeScript types and avoid using `any` type
Applied to files:
apps/api/src/routers/user.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{services,models}/*.{js,ts} : Validate data against schema before database operations
Applied to files:
apps/api/src/routers/user.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Always validate user authentication before processing protected routes
Applied to files:
apps/api/src/routers/user.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobile `p-4` (1rem) and desktop `p-[60px]`
Applied to files:
apps/web/tailwind.config.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Maintain proper heading hierarchy
Applied to files:
docs/QUICKSTART_SAVED_REPOS.md
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Maintain proper heading hierarchy in page components
Applied to files:
docs/QUICKSTART_SAVED_REPOS.md
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Use Zustand for global state, located in `src/store/`
Applied to files:
apps/web/src/store/useSavedProjectsStore.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Use zustand for global state (located in `src/store/`)
Applied to files:
apps/web/src/store/useSavedProjectsStore.ts
🧬 Code graph analysis (5)
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (2)
apps/web/src/store/useSavedProjectsStore.ts (1)
useSavedProjectsStore(16-126)apps/web/src/components/ui/badge.tsx (1)
Badge(36-36)
apps/web/src/components/dashboard/ProjectsContainer.tsx (3)
apps/web/src/store/useSavedProjectsStore.ts (1)
useSavedProjectsStore(16-126)apps/web/src/components/dashboard/SaveToggle.tsx (1)
SaveToggle(13-65)apps/web/src/components/dashboard/SavedProjectsPanel.tsx (1)
SavedProjectsPanel(20-211)
apps/api/src/routers/user.ts (2)
apps/api/src/trpc.ts (1)
protectedProcedure(40-40)apps/api/src/services/savedRepos.service.ts (1)
savedReposService(5-115)
apps/web/tailwind.config.ts (1)
apps/web/src/lib/design-tokens.ts (1)
colors(8-118)
apps/web/src/store/useSavedProjectsStore.ts (1)
packages/shared/types/savedRepos.ts (1)
SavedRepo(1-10)
🔇 Additional comments (13)
apps/api/package.json (1)
17-19: LGTM! Prisma seed configuration is correctly placed.The
prisma.seedscript usingtsx prisma/seed.tsproperly integrates with the automated setup workflow described in the PR objectives.packages/shared/types/savedRepos.ts (1)
1-17: LGTM! Well-structured type definitions.The types are properly defined with appropriate use of
Record<string, unknown>for extensible metadata (avoidingany). The union type forpopularityand the action types provide good type safety across the stack.apps/api/src/routers/user.ts (1)
89-114: LGTM! Merge logic is well-implemented.The conditional merge when
localReposis provided with areplaceaction correctly delegates to the service'smergeSavedReposfunction, enabling proper client-server sync with conflict resolution.docs/QUICKSTART_SAVED_REPOS.md (1)
1-224: LGTM! Comprehensive quick start documentation.The guide provides clear setup instructions, testing checklists, and troubleshooting guidance. The markdown structure properly uses headings for section organization.
apps/web/src/components/dashboard/ProjectsContainer.tsx (2)
76-108: LGTM! Excellent accessibility implementation.The buttons correctly implement keyboard navigation with Enter/Space handling, include proper
aria-labelattributes, and use the design system'sbg-brand-purpletoken. The saved projects count badge provides good visual feedback.
152-154: LGTM! Clean component integration.The
SaveToggleandSavedProjectsPanelcomponents are well-integrated with appropriate prop passing and state management using the Zustand store, consistent with the coding guidelines.Also applies to: 216-219
apps/web/src/components/dashboard/SavedProjectsPanel.tsx (4)
1-18: LGTM! Clean imports and type definitions.The imports are properly organized following the coding guidelines (React → third-party → local → types), and the props interface is well-typed.
82-110: LGTM! Proper accessibility and semantic colors.The backdrop and header implementation follows accessibility best practices with
aria-hiddenon the backdrop andaria-labelon the close button. The color usage follows the design token system with semantic names likebg-brand-purple.
112-147: LGTM! Well-structured action buttons.The action buttons properly handle disabled states, use semantic color tokens, and follow the design system guidelines for button styling. The hidden file input pattern is a standard accessible approach.
175-190: Previous color concerns resolved - now using semantic tokens.The code now correctly uses semantic color tokens (
bg-info/15 text-infoandbg-success/15 text-success) instead of the hardcoded values mentioned in previous reviews. Well done!apps/web/src/store/useSavedProjectsStore.ts (3)
1-14: LGTM! Clean imports and well-typed interface.The imports are minimal and necessary, and the
SavedProjectsStateinterface provides a clear contract with proper TypeScript types throughout.
21-55: LGTM! Solid state management methods.The store methods follow Zustand best practices with immutable updates, proper deduplication in
addProject, and clean toggle logic. All methods use efficient patterns appropriate for the use case.
116-126: LGTM! Proper persistence configuration.The
isSavedhelper is clean, and the persist middleware is correctly configured with localStorage, appropriate partialization (only persisting data, not methods), and a versioned storage key that will facilitate future migrations.
- Replace text-red-500 with text-error in remove button icon - Replace hover:bg-red-500/20 with hover:bg-error/20 for hover state - Maintains all existing behavior (opacity, transitions, rounded) - Improves consistency with design system and accessibility
|
please review it :) |
Description
This PR resolves #292 by implementing a complete developer experience (DX) overhaul that enables single-command project bootstrap for new contributors.
Problem
The current setup process was complicated and error-prone:
Solution
This PR introduces automated setup with Docker orchestration:
make setup(Mac/Linux) or .\setup.ps1 (Windows).envfiles from templatesChanges Made
New Files
Modified Files
/healthendpoint for Docker healthchecksdist/foldersHow to Test
1. Fresh Setup Test