- Overview
- Features
- Architecture
- Tech Stack
- Project Structure
- Installation
- Development
- API Documentation
- Database
- Deployment
- Security
- PWA Features
- Testing
- Code Quality
- Troubleshooting
- Contributing
- License
Bookmarket is a modern, full-stack bookmark management application designed to replace traditional browser bookmark systems. Built with a focus on user experience, performance, and self-hosting capabilities, it provides a comprehensive solution for organizing, sharing, and discovering web content.
The application features a monorepo architecture using Turborepo and pnpm, consisting of a Next.js frontend, NestJS backend, and PostgreSQL database, all orchestrated with Docker for seamless development and deployment.
- π Multi-Provider Authentication: JWT-based auth with Google and GitHub OAuth integration
- π Smart Bookmark Management: URL input with automatic metadata and favicon fetching
- π·οΈ Category Organization: Drag-and-drop interface for organizing bookmarks into categories
- π Public Sharing: Share bookmark collections via clean, public URLs
(
/s/username) - β¨οΈ Command Menu: Global search and command interface using cmdk for power users
- π± Progressive Web App: Full PWA support with offline capabilities and native app-like experience
- π« User Slot Management: First-come-first-serve user registration with configurable limits and real-time slot tracking
- π Self-Hosted Metadata: Server-side metadata extraction without external API dependencies
- π Error Monitoring: Comprehensive Sentry integration for both frontend and backend
- π¨ Dark/Light Mode: System-aware theme switching with Tailwind CSS
- π Real-time Updates: Optimistic UI updates with TanStack Query
- π― Type Safety: End-to-end TypeScript for robust development experience
- π Security Headers: Comprehensive security headers and CSP policies
- π Responsive Design: Mobile-first design that works across all devices
- β‘ Real-time Slot Updates: Live slot availability counter with short polling for immediate feedback
- π‘οΈ Race Condition Protection: Atomic slot reservation prevents concurrent signup issues
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (Next.js) β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β β App Router β β Server Actions β β Client State β β
β β (Pages) β β (API Calls) β β (Zustand) β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β β UI Components β β TanStack Query β β PWA Service β β
β β (Radix UI) β β (Server State) β β Worker β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β HTTP/REST API
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Backend (NestJS) β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β β Controllers β β Services β β Guards & β β
β β (REST API) β β (Business Logic)β β Middleware β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β β JWT Auth β β Metadata β β TypeORM β β
β β (OAuth + Local)β β Scraping β β (Database) β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β SQL Queries
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Database (PostgreSQL) β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
β β Users β β Bookmarks β β Categories β β
β β (Auth Data) β β (URLs + Meta) β β (Organization) β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Authentication Flow: OAuth providers β JWT tokens β Cookie storage β Request headers
- Bookmark Creation: URL input β Metadata fetching β Database storage β Real-time UI updates
- Category Management: Drag-and-drop β Optimistic updates β API calls β State synchronization
- Public Sharing: Username-based URLs β Public API endpoints β Cached responses
- π Next.js 15 - React framework with App Router for server-side rendering and static generation
- βοΈ React 19 - Latest React with concurrent features and improved performance
- π TypeScript 5.7 - Static type checking for robust development
- π¨ Tailwind CSS 3.4 - Utility-first CSS framework with custom design system
- π§© Radix UI - Accessible, unstyled component primitives
- β¨ Framer Motion 11 - Production-ready motion library for React
- π TanStack Query 5 - Powerful data synchronization for server state
- π» Zustand 5 - Small, fast, and scalable state management
- π Sentry - Real-time error tracking and performance monitoring
- π± Next PWA - Progressive Web App features with Workbox
- β¨οΈ cmdk - Fast, composable command menu interface
- π next-themes - Perfect dark mode implementation
- π nuqs - Type-safe search params state management
- ποΈ NestJS 10 - Progressive Node.js framework for scalable server-side applications
- π TypeScript 5 - Full-stack type safety
- π PostgreSQL - Advanced open-source relational database
- π§ TypeORM 0.3 - TypeScript ORM with migrations and relationships
- π JWT Authentication - Secure token-based authentication with cookie storage
- π OAuth Integration - Google and GitHub OAuth providers
- π bcrypt - Secure password hashing
- π·οΈ Cheerio - Server-side HTML parsing for metadata extraction
- π Sentry - Backend error tracking and performance monitoring
- πͺ cookie-parser - HTTP cookie parsing middleware
- π― class-validator - Decorator-based validation for DTOs
- π Turborepo 2.4 - High-performance build system for JavaScript monorepos
- π¦ pnpm 8.9.2 - Fast, disk space efficient package manager
- π ESLint 8 - Static code analysis with custom rules and plugins
- β¨ Prettier 3 - Opinionated code formatter with Tailwind plugin
- π³ Docker Compose - Multi-container development environment
- π§ͺ Jest - Comprehensive testing framework for backend
- π GitHub Actions - CI/CD pipeline for automated testing and deployment
- π Geist Font - Modern, clean typography
- π Lucide React - Beautiful, customizable SVG icons
- π React Hook Form - Performant, flexible forms with easy validation
- π Sonner - Elegant toast notifications
- πͺ Vaul - Accessible drawer component for mobile interfaces
- π class-variance-authority - TypeScript-first variant API for component styling
bookmarket/
βββ π apps/
β βββ π web/ # Next.js Frontend Application
β β βββ π src/
β β β βββ π app/ # Next.js App Router
β β β β βββ π (pages)/ # Route Groups
β β β β β βββ π (auth)/ # Authentication pages
β β β β β β βββ π login/
β β β β β β βββ π signup/
β β β β β β βββ π oauth/ # OAuth callbacks
β β β β β βββ π (home)/ # Main application
β β β β β β βββ π home/ # Dashboard & bookmarks
β β β β β β βββ π _components/ # Home-specific components
β β β β β βββ π (shared)/ # Public bookmark sharing
β β β β β βββ π s/[username]/ # Public user pages
β β β β βββ π _common/ # Shared application code
β β β β β βββ π actions/ # Server actions
β β β β β βββ π components/ # Reusable components
β β β β β βββ π hooks/ # Custom React hooks
β β β β β βββ π providers/ # React context providers
β β β β β βββ π state/ # State management
β β β β βββ π _core/ # Core utilities
β β β β βββ π components/ # Base UI components
β β β β βββ π utils/ # Utility functions
β β β βββ π styles/ # Global styles
β β β βββ π middleware.ts # Next.js middleware
β β βββ π public/ # Static assets
β β β βββ π images/ # Application images
β β β βββ π logos/ # Brand assets
β β β βββ π manifest.json # PWA manifest
β β β βββ π sw.js # Service worker
β β βββ π next.config.mjs # Next.js configuration
β β βββ π tailwind.config.ts # Tailwind CSS configuration
β β βββ π package.json
β β
β βββ π server/ # NestJS Backend Application
β βββ π src/
β β βββ π iam/ # Identity & Access Management
β β β βββ π authentication/ # Auth controllers & services
β β β βββ π guards/ # Security guards
β β β βββ π decorators/ # Custom decorators
β β β βββ π social/ # OAuth providers
β β βββ π bookmarks/ # Bookmark management
β β β βββ π dto/ # Data transfer objects
β β β βββ π entities/ # Database entities
β β β βββ π services/ # Business logic
β β β βββ π bookmarks.controller.ts
β β βββ π categories/ # Category management
β β βββ π users/ # User management
β β βββ π common/ # Shared utilities
β β β βββ π entities/ # Base entities
β β β βββ π constants/ # Application constants
β β βββ π migrations/ # Database migrations
β β βββ π main.ts # Application entry point
β β βββ π data-source.ts # Database configuration
β βββ π Dockerfile # Container configuration
β βββ π package.json
β
βββ π packages/ # Shared Configurations
β βββ π eslint-config/ # Shared ESLint configuration
β βββ π prettier-config/ # Shared Prettier configuration
β βββ π typescript-config/ # Shared TypeScript configuration
β
βββ π docker-compose.yml # Development environment
βββ π turbo.json # Turborepo configuration
βββ π pnpm-workspace.yaml # pnpm workspace configuration
βββ π CLAUDE.md # AI assistant instructions
βββ π README.md # This file
- Node.js 18 or higher (Download)
- pnpm 8.9.2 or higher (
npm install -g pnpm@8.9.2) - Docker & Docker Compose (Download)
- Git for version control
-
Clone the repository
git clone https://github.com/yourusername/bookmarket.git cd bookmarket -
Install dependencies
pnpm install
-
Environment Configuration
# Copy environment examples cp apps/web/.env.example apps/web/.env cp apps/server/.env.example apps/server/.env -
Configure Environment Variables
Frontend (
apps/web/.env):# Base Configuration NEXT_PUBLIC_BASE_URL=http://localhost:3000 NEXT_PUBLIC_API_URL=http://localhost:8000 # OAuth Configuration NEXT_PUBLIC_GOOGLE_CLIENT_ID=your_google_client_id NEXT_PUBLIC_GITHUB_CLIENT_ID=your_github_client_id # Optional: Error Monitoring NEXT_PUBLIC_SENTRY_DSN=your_sentry_dsn
Backend (
apps/server/.env):# Database Configuration DATABASE_URL= POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_DB= # JWT Configuration JWT_SECRET= JWT_TOKEN_AUDIENCE= JWT_TOKEN_ISSUER= JWT_ACCESS_TOKEN_TTL= JWT_REFRESH_TOKEN_TTL= # OAuth Secrets GOOGLE_CLIENT_SECRET= GITHUB_CLIENT_SECRET= # Optional: Error Monitoring SENTRY_DSN=
-
Start Development Environment
# Starts PostgreSQL + Frontend + Backend pnpm dev -
Setup Database (First time only)
cd apps/server pnpm run migration:run -
Access the Application
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- Database: localhost:5432
# Start full development environment (DB + Web + Server)
pnpm dev
# Start individual services
pnpm --filter bookmarket-client dev # Frontend only
pnpm --filter bookmarket-server dev # Backend only
# Database only (useful for external API testing)
docker compose up db -d- Feature Development: Create feature branches from
main - Code Quality: Run linting and type checking before commits
- Database Changes: Generate migrations for schema changes
- Testing: Run backend tests before pushing
- Build Verification: Ensure production build works
- Frontend: Automatic hot reloading with Next.js Fast Refresh
- Backend: Automatic restart with NestJS watch mode
- Database: Persistent data with Docker volumes
- Types: Shared TypeScript types with automatic regeneration
The API uses JWT-based authentication with HTTP-only cookies for security:
- Sign Up/Sign In: Returns access & refresh tokens
- Cookie Storage: Tokens stored in secure HTTP-only cookies
- Automatic Refresh: Seamless token refresh on expiration
- OAuth Integration: Google & GitHub OAuth providers
- Development:
http://localhost:8000 - Production: Your deployed backend URL
Creates a new user account with email/password.
Request Body:
{
"email": "user@example.com",
"password": "strongPassword123",
"picture": "https://example.com/avatar.jpg" // optional
}Response:
{
"user": {
"id": "uuid",
"email": "user@example.com",
"username": null,
"firstName": null,
"lastName": null,
"picture": "https://example.com/avatar.jpg",
"isPublic": false,
"auth_provider": "email"
},
"accessToken": "jwt_token",
"refreshToken": "refresh_token"
}Authenticates existing user with email/password.
Refreshes expired access tokens.
Authenticates user via Google OAuth.
Authenticates user via GitHub OAuth.
Returns current authenticated user's profile.
Response:
{
"id": "uuid",
"email": "user@example.com",
"username": "johndoe",
"firstName": "John",
"lastName": "Doe",
"picture": "https://example.com/avatar.jpg",
"isPublic": true
}Updates current user's profile.
Request Body:
{
"username": "newusername", // max 12 characters
"firstName": "John", // max 50 characters
"lastName": "Doe" // max 50 characters
}Checks username availability for current user.
Creates a new bookmark with automatic metadata fetching.
Request Body:
{
"url": "https://example.com",
"title": "Custom Title", // optional, auto-fetched if not provided
"description": "Description", // optional, auto-fetched if not provided
"faviconUrl": "https://...", // optional, auto-fetched if not provided
"category": "Work" // optional, creates category if not exists
}Response:
{
"id": "uuid",
"url": "https://example.com",
"title": "Example Site",
"description": "An example website",
"faviconUrl": "https://example.com/favicon.ico",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"category": {
"id": "uuid",
"name": "Work"
}
}Retrieves all bookmarks for authenticated user.
Query Parameters:
category(optional): Filter by category name
Fetches metadata for a given URL without creating bookmark.
Response:
{
"title": "Example Site",
"description": "An example website",
"faviconUrl": "https://example.com/favicon.ico"
}Updates existing bookmark.
Assigns bookmark to a specific category.
Deletes bookmark.
Creates a new category.
Request Body:
{
"name": "Work Projects"
}Retrieves all categories for authenticated user.
Updates category name.
Deletes category (bookmarks become uncategorized).
Retrieves public bookmarks for a user (no authentication required).
Query Parameters:
category(optional): Filter by category name
Retrieves public categories for a user (no authentication required).
Returns current slot availability information (no authentication required).
Response:
{
"remaining": 85,
"total": 100,
"canSignUp": true
}Description:
remaining: Number of available signup slotstotal: Maximum number of users allowedcanSignUp: Boolean indicating if new signups are permitted
This endpoint is used by the frontend to display real-time slot availability and enable/disable signup functionality.
All endpoints return consistent error responses:
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}Common HTTP status codes:
200- Success201- Created400- Bad Request (validation errors)401- Unauthorized (invalid/missing token)403- Forbidden (insufficient permissions or slots full)404- Not Found500- Internal Server Error
Slot-specific Error Responses:
When signup slots are full, authentication endpoints return:
{
"statusCode": 403,
"message": "No more signup slots available. Maximum of 100 users reached.",
"error": "Forbidden"
}CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR UNIQUE NOT NULL,
username VARCHAR(12) UNIQUE,
first_name VARCHAR(50),
last_name VARCHAR(50),
picture VARCHAR,
password_hash VARCHAR, -- For email auth
google_id VARCHAR, -- For Google OAuth
github_id VARCHAR, -- For GitHub OAuth
auth_provider VARCHAR NOT NULL, -- 'email' | 'google' | 'github'
is_public BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);CREATE TABLE categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR NOT NULL,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(name, user_id) -- Unique category names per user
);CREATE TABLE bookmarks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
url VARCHAR NOT NULL,
title VARCHAR NOT NULL,
description TEXT,
favicon_url VARCHAR,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
category_id UUID REFERENCES categories(id) ON DELETE SET NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);cd apps/server
# Generate new migration after entity changes
pnpm run migration:generate MigrationName
# Run pending migrations
pnpm run migration:run
# Revert last migration
pnpm run migration:revert
# Check migration status
pnpm run typeorm migration:show# Start database only
docker compose up db -d
# Connect to database
docker exec -it bookmarket-db-1 psql -U bokdol -d bookmarket
# View logs
docker compose logs db -f
# Reset database (β οΈ Destructive)
docker compose down -v
docker compose up db -d
cd apps/server && pnpm run migration:runUsers (1) ββββββ (N) Categories
β
βββ (1) ββββββ (N) Bookmarks ββββββ (N) Categories
βββ (1)
- One user can have many categories
- One user can have many bookmarks
- One category can have many bookmarks
- One bookmark belongs to one category (optional)
The user slot system is configured in apps/server/src/slots/slots.service.ts:
private readonly MAX_NEW_USERS = 100; // Configurable limit- Real-time Tracking: Live slot availability displayed on landing page
- Race Condition Protection: Atomic database transactions prevent concurrent signup issues
- Universal Enforcement: Applies to all signup methods (email, Google OAuth, GitHub OAuth)
- Frontend Integration: Real-time updates via 10-second polling
- Error Handling: Graceful error messages when slots are full
- Slots Counter: Visual indicator showing remaining slots with color coding
- Dynamic UI: Signup buttons and forms automatically disable when slots are full
- Real-time Updates: Short polling keeps slot status current across all users
- Atomic Operations: Uses database transactions with pessimistic locking
- Race Prevention: Slot reservation happens atomically with user creation
- Consistent Enforcement: All authentication paths check slots before user creation
-
Prepare Environment Files
# Production environment variables cp apps/web/.env.example apps/web/.env.production cp apps/server/.env.example apps/server/.env.production # Update with production values vim apps/web/.env.production vim apps/server/.env.production
-
Build and Deploy
# Build production containers docker compose -f docker-compose.prod.yml build # Start production services docker compose -f docker-compose.prod.yml up -d # Run database migrations docker compose -f docker-compose.prod.yml exec server pnpm run migration:run
Frontend (Vercel):
- Connect GitHub repository to Vercel
- Set build command:
cd apps/web && pnpm build - Set environment variables in Vercel dashboard
- Deploy automatically on push to main
Backend (Render.io):
- Connect GitHub repository to Render.io
- Set start command:
cd apps/server && pnpm run start:prod - Set environment variables in Render dashboard
Critical Production Variables:
JWT_SECRET- Strong, unique secret keyDATABASE_URL- Production database connectionNEXT_PUBLIC_BASE_URL- Your frontend domain- OAuth client secrets
- Sentry DSN for error tracking
The application includes:
- Database health checks in Docker Compose
- Sentry error monitoring for both frontend and backend
- PostgreSQL connection monitoring
- JWT token validation
- Content Security Policy (CSP) configured in
next.config.mjs - Security Headers: XSS Protection, Frame Options, Content Type Options
- HTTP-only Cookies for JWT token storage
- HTTPS enforcement in production
- Input sanitization for all user inputs
- Image security with allowlist for external images
- JWT Authentication with refresh token rotation
- Password hashing with bcrypt (12 rounds)
- CORS configuration for cross-origin requests
- Rate limiting on authentication endpoints
- SQL injection prevention with TypeORM parameterized queries
- Input validation with class-validator decorators
- Helmet.js for additional security headers
- Connection encryption with SSL in production
- User access controls with PostgreSQL roles
- Data encryption at rest (depends on hosting provider)
- Regular backup strategies recommended
- Never commit secrets to version control
- Use environment variables for all configuration
- Rotate JWT secrets periodically
- Monitor authentication logs for suspicious activity
- Keep dependencies updated with security patches
- Use HTTPS in production with valid SSL certificates
The application is a full-featured PWA with:
- Add to Home Screen on mobile devices
- Desktop installation via browser
- Custom app icons and splash screens
- Standalone display mode (no browser UI)
- Service Worker caches static assets
- Offline fallback pages when network unavailable
- Background sync for bookmark creation when back online
- Cache-first strategy for optimal performance
- Push notifications (ready for implementation)
- Background app refresh
- Native app-like navigation
- Device integration (camera, sharing, etc.)
Manifest (public/manifest.json):
{
"name": "Bookmarket",
"short_name": "Bookmarket",
"description": "Modern bookmark management",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "/logos/logo-base-256x256.png",
"sizes": "256x256",
"type": "image/png"
}
]
}Service Worker Features:
- Workbox-powered service worker
- Automatic asset caching
- Runtime caching strategies
- Background sync capabilities
cd apps/server
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with coverage report
pnpm test:cov
# Run end-to-end tests
pnpm test:e2e
# Run specific test file
pnpm test -- bookmarks.service.spec.tsapps/server/src/
βββ bookmarks/
β βββ __tests__/
β β βββ bookmarks.controller.spec.ts
β β βββ bookmarks.service.spec.ts
β βββ ...
βββ categories/
β βββ __tests__/
β βββ ...
βββ test/ # E2E tests
βββ app.e2e-spec.ts
βββ auth.e2e-spec.ts
- Unit Tests: Test individual functions and methods
- Integration Tests: Test API endpoints and database interactions
- E2E Tests: Test complete user workflows
- Mocking: Mock external dependencies (database, HTTP requests)
- Coverage: Aim for >80% code coverage on critical paths
Recommended setup for frontend testing:
- Vitest for unit testing
- React Testing Library for component testing
- Playwright for E2E testing
- MSW for API mocking
# Run linting across all packages
pnpm lint
# Fix auto-fixable linting issues
pnpm lint --fix
# Format code with Prettier
pnpm format
# Type checking across all packages
pnpm check-types- TypeScript ESLint rules
- React/Next.js specific rules
- Import/export organization
- Unused imports detection
- Custom rules for project conventions
- Consistent formatting across all files
- Tailwind CSS class sorting
- Import sorting with custom order
- Line length limits and spacing rules
- Strict mode enabled
- Path mapping for clean imports
- Shared configurations across packages
- Build-time type checking
# Install husky for git hooks
pnpm add -D husky lint-staged
# Setup pre-commit hook
npx husky add .husky/pre-commit "pnpm lint-staged"# Check if PostgreSQL is running
docker compose ps
# View database logs
docker compose logs db
# Reset database connection
docker compose restart db
# Check database connectivity
docker compose exec db pg_isready -U bokdol -d bookmarket# Find process using port 3000/8000
lsof -ti:3000
lsof -ti:8000
# Kill process using port
kill -9 $(lsof -ti:3000)
# Or use different ports
NEXT_PUBLIC_PORT=3001 pnpm dev# Check Node.js version (needs 18+)
node --version
# Use Node Version Manager
nvm install 18
nvm use 18
# Or use Volta
volta install node@18# Install pnpm globally
npm install -g pnpm@8.9.2
# Clear pnpm cache
pnpm store prune
# Reinstall dependencies
rm -rf node_modules pnpm-lock.yaml
pnpm install# Check migration status
cd apps/server
pnpm run typeorm migration:show
# Revert problematic migration
pnpm run migration:revert
# Generate new migration
pnpm run migration:generate FixIssue- Google OAuth: Ensure redirect URIs match in Google Console
- GitHub OAuth: Check OAuth app settings in GitHub
- Environment Variables: Verify all OAuth secrets are set correctly
- CORS Issues: Ensure frontend URL is allowed in backend CORS settings
# Clear Next.js cache
rm -rf apps/web/.next
# Clear TypeScript cache
rm -rf apps/web/.tsbuildinfo
# Rebuild everything
pnpm clean
pnpm install
pnpm build- Hot Reload Not Working: Restart development server
- Database Schema Changes: Always generate migrations
- Environment Variables: Restart server after changes
- TypeScript Errors: Check import paths and type definitions
- Docker Issues: Try
docker system pruneto clean up
- GitHub Issues: Report bugs and feature requests
- Documentation: Check CLAUDE.md for AI assistant guidance
- Community: Join discussions in GitHub Discussions
- Logs: Always check browser console and server logs for errors
We welcome contributions to Bookmarket! Here's how to get started:
-
Fork & Clone
git clone https://github.com/yourusername/bookmarket.git cd bookmarket -
Install Dependencies
pnpm install
-
Setup Development Environment
cp apps/web/.env.example apps/web/.env cp apps/server/.env.example apps/server/.env # Update environment variables -
Start Development
pnpm dev
- TypeScript: All code must be properly typed
- Linting: Pass ESLint checks (
pnpm lint) - Formatting: Use Prettier (
pnpm format) - Testing: Add tests for new features
- Documentation: Update README for significant changes
- Create Feature Branch:
git checkout -b feature/amazing-feature - Make Changes: Follow code standards and best practices
- Test Changes: Ensure all tests pass
- Commit Changes: Use conventional commit messages
- Push Branch:
git push origin feature/amazing-feature - Open Pull Request: Describe changes and link related issues
type(scope): description
feat(bookmarks): add bulk bookmark import
fix(auth): resolve OAuth callback redirect issue
docs(readme): update installation instructions
Types: feat, fix, docs, style, refactor, test, chore
- Testing: Add frontend tests with Vitest
- Performance: Optimize bundle size and loading times
- Accessibility: Improve keyboard navigation and screen reader support
- Mobile: Enhance mobile user experience
- Features: Bookmark import/export, search functionality
- Documentation: API documentation, deployment guides
- Monitoring: Enhanced error tracking and analytics
- Internationalization: Multi-language support
- Browser Extension: Chrome/Firefox bookmark sync
- Themes: Additional color schemes and themes
- Integrations: Pocket, Instapaper, other bookmark services
- Analytics: User dashboard with bookmark statistics
- Automated Checks: CI/CD runs tests and linting
- Code Review: Maintainers review for quality and standards
- Testing: Manual testing for UI/UX changes
- Documentation: Ensure documentation is updated
- Merge: Approved PRs are merged to main branch
This project is licensed under the MIT License - see the LICENSE file for details.
- β Commercial use allowed
- β Modification allowed
- β Distribution allowed
- β Private use allowed
- β Liability - No warranty provided
- β Warranty - Use at your own risk
- π Documentation: Start with this README and CLAUDE.md
- π Bug Reports: Open an issue
- π‘ Feature Requests: Submit an enhancement
- π¬ Discussions: Join community discussions
- Eric Park - @eric-jy-park
Special thanks to the amazing open-source projects that make Bookmarket possible:
- Next.js team for the incredible React framework
- NestJS community for the robust backend framework
- Vercel for deployment and hosting solutions
- All contributors and users who help improve Bookmarket
