Social bookmarking with editorial sensibility. A modern reimagining of del.icio.us.
π Live: https://onlylinks.id
- β Save and organize links with tags (not folders)
- β Search across your entire collection
- β Follow other curators and see their bookmarks
- β Public/private bookmark visibility
- β Fast, keyboard-driven interface
- β Automatic Open Graph image fetching
- β User profiles with avatars
- β Responsive design (desktop + mobile)
- Node.js + Express
- SQLite database
- JWT authentication with httpOnly cookies
- Bcrypt password hashing
- Helmet security headers + CSP
- Rate limiting on auth endpoints
- Vanilla JavaScript (ES6+)
- Component-based architecture
- OKLCH color system
- CSS animations with reduced-motion support
- No frontend framework dependencies
- Node.js 20+
- npm or yarn
# Clone repository
git clone https://github.com/kardelly/only-links.git
cd only-links
# Install dependencies
npm install
# Create .env file
cp .env.example .env
# Edit .env and add JWT_SECRET (generate with: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")
# Start development server
npm start
# Open browser
open http://localhost:3000See DEPLOY.md for complete VPS deployment guide.
Quick deploy checklist: START-HERE.md
.
βββ server.js # Express server + API routes
βββ database.js # SQLite database + queries
βββ public/
β βββ index.html # Landing page
β βββ app.html # Main application
β βββ profile.html # User profiles
β βββ settings.html # Account settings
β βββ app.js # Main app logic
β βββ profile.js # Profile page logic
β βββ settings.js # Settings page logic
β βββ components/ # Reusable UI components
β βββ header.js
β βββ header.html
β βββ sidebar-tags.js
β βββ bookmark-renderer.js
β βββ *.css
βββ PRODUCT.md # Product vision + principles
βββ DESIGN.md # Design system tokens
βββ SECURITY.md # Security hardening guide
βββ PRIVACY.md # Privacy policy
βββ DEPLOY.md # Deployment guide
βββ package.json
- Speed is a feature β Every interaction feels instant
- Tags > folders β Multidimensional organization
- Public by default β Discovery through shared knowledge
- Keyboard > mouse β Every action has a shortcut
- Content first β UI recedes when not needed
Full philosophy: PRODUCT.md
- β JWT tokens with 7-day expiration
- β Bcrypt password hashing (10 rounds)
- β Rate limiting (5 attempts/15min on auth)
- β Content Security Policy (CSP)
- β HTTPS-only cookies in production
- β Input validation on all endpoints
- β SQL injection prevention (parameterized queries)
- β XSS protection
See SECURITY.md for hardening guide.
POST /api/auth/register- Create accountPOST /api/auth/login- LoginPOST /api/auth/logout- LogoutGET /api/auth/me- Get current user
GET /api/bookmarks- List bookmarks (with filters)POST /api/bookmarks- Create bookmarkPUT /api/bookmarks/:id- Update bookmarkDELETE /api/bookmarks/:id- Delete bookmarkGET /api/metadata?url=- Fetch Open Graph metadata
GET /api/tags- Get popular tags
GET /api/users/:username- Get user profilePOST /api/users/:username/follow- Follow userDELETE /api/users/:username/follow- Unfollow userGET /api/users/:username/followers- Get followersGET /api/users/:username/following- Get following
GET /api/settings/preferences- Get preferencesPUT /api/settings/preferences- Update preferencesPUT /api/settings/username- Change usernamePUT /api/settings/email- Change emailPUT /api/settings/password- Change passwordPOST /api/settings/avatar- Upload avatarDELETE /api/settings/avatar- Remove avatarDELETE /api/settings/account- Delete account
- users - User accounts (username, email, password_hash, avatar)
- bookmarks - Saved links (url, title, description, og_image, is_public)
- tags - Tag definitions (name)
- bookmark_tags - Many-to-many (bookmark_id, tag_id)
- follows - Social graph (follower_id, following_id)
- user_preferences - Settings (default_public)
All foreign keys have ON DELETE CASCADE for data integrity.
N- New bookmark (when not typing)Esc- Close modal- More coming soon...
# Required
NODE_ENV=production
JWT_SECRET=your-64-char-secret-here
# Optional (with defaults)
PORT=3000
ALLOWED_ORIGINS=https://onlylinks.id
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=5Generate strong JWT_SECRET:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"This is a personal project, but feel free to:
- Report bugs via Issues
- Suggest features via Discussions
- Fork and experiment
MIT License - See LICENSE
- Inspired by the original del.icio.us (2003-2017)
- Design philosophy influenced by Pinboard, Linear, and Are.na
- Built with the impeccable design system
- Website: https://onlylinks.id
- Email: privacy@onlylinks.id
- GitHub: @kardelly
Made with π by Anderson Cardelli FaΓ§anha