A modern, privacy-first personal navigation workstation with multi-user cloud synchronization.
English • 简体中文
Homeport is an elegant, full-featured personal navigation workstation designed for productivity enthusiasts, developers, and knowledge workers.
Built with Nuxt 3, Vue 3, and antdv-next, Homeport pairs local-first offline speed with serverless multi-user cloud synchronization powered by GitHub OAuth and Upstash Redis. It runs seamlessly across any desktop and mobile browser, requires zero database maintenance, and deploys effortlessly to Vercel with zero server costs.
- 👤 Multi-User Isolated Cloud Workspaces: Sign in seamlessly via GitHub OAuth (
nuxt-auth-utils). User bookmarks are strictly isolated by unique user ID in cloud storage. - ⚡ Local-First & Offline Resilience: Instant page loads with zero network latency. Works completely offline via browser
localStoragewhen unauthenticated. - 🗄️ Dual-Mode Cloud Storage: Automatically connects to Upstash for Redis in production and falls back to Nitro local storage in development mode.
- 📂 Flexible Spaces & Collections: Organize websites into dedicated workspaces (e.g., Work, Research, Entertainment, Tools) with customizable accent colors and Lucide icons.
- 🔍 Real-Time Instant Search: Fast fuzzy matching across site name, description, domain, category, and tags with keyboard navigation support.
- 🎛️ Custom Views & Sorting: Switch between spacious Grid and compact List views. Sort sites manually via drag-and-drop, alphabetically, or by last used time.
- 📦 Zero Lock-In Portability: Export your entire setup into portable JSON packages. Merge or replace configurations across machines with one click.
- 🤖 Serverless Metadata Extraction: Built-in Nitro API endpoint (
/api/fetch-meta) parses webpage title and OpenGraph info to speed up bookmark creation. - 🌓 Adaptive Amber Theming: Warm amber aesthetic with system-adaptive dark and light mode toggle.
- 📱 Responsive Design: Dedicated desktop sidebar navigation and optimized mobile bottom bar.
| Layer | Technology |
|---|---|
| Framework | Nuxt 3 (Vue 3, Vite, Nitro Engine) |
| UI Components | antdv-next |
| Icons | lucide-vue-next |
| Authentication | nuxt-auth-utils (Encrypted Session Cookies + GitHub OAuth) |
| Cloud Database | Upstash Redis (Serverless REST API) |
| Deployment | Vercel (Zero-Config Build Output API v3) |
- Node.js
>= 18.0.0 - pnpm
>= 9.0.0(recommended)
# 1. Clone repository
git clone https://github.com/CarlOpenLab/homeport.git
cd homeport
# 2. Install dependencies
pnpm install
# 3. Start local development server
pnpm run devOpen http://localhost:3000 in your browser. In development mode, mock testing accounts are available out-of-the-box without needing GitHub OAuth credentials.
pnpm run build
pnpm run previewDeploying Homeport to Vercel takes less than 3 minutes:
- Import Repository: In your Vercel Dashboard, click Add New Project and select your GitHub repository.
- Connect Upstash Redis:
- Go to your Vercel Project -> Storage -> Marketplace -> Select Upstash for Redis.
- Connect it to your project. Vercel automatically injects
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN.
- Configure GitHub OAuth:
- Create an OAuth application at GitHub Developer Settings:
- Homepage URL:
https://<your-project>.vercel.app - Authorization callback URL:
https://<your-project>.vercel.app/api/auth/github
- Homepage URL:
- In Vercel -> Project Settings -> Environment Variables, add:
NUXT_OAUTH_GITHUB_CLIENT_ID: Your GitHub Client IDNUXT_OAUTH_GITHUB_CLIENT_SECRET: Your GitHub Client SecretNUXT_SESSION_PASSWORD: Any random secret string (32+ characters)
- Create an OAuth application at GitHub Developer Settings:
- Deploy: Push changes or click Redeploy to apply the environment variables.
Homeport ships with nuxt-auth-utils, which bundles around 50 OAuth provider handlers
(Google, Microsoft, Apple, Discord, GitLab, Gitea, Keycloak/Auth0/Okta/Cognito, and more). Adding a provider requires no schema or data
changes: one server/api/auth/<provider>.get.ts file, its credentials, and a button.
Every sign-in entry point resolves its internal user ID through resolveUserId() in server/utils/identity.ts.
The mappings live in cloud KV (Upstash Redis in production, Nitro local storage in development):
| Storage key | Meaning |
|---|---|
homeport:identity:<provider>:<providerId> |
Provider identity → internal user ID |
homeport:email:<email> |
Verified email → internal user ID |
Resolution order:
- Identity already registered → reuse its bound user ID, so switching devices or sign-in methods lands in the same cloud workspace;
- Identity unknown but carries a provider-verified email that already belongs to a user → merge into that user;
- Brand-new user → generate
<provider>_<providerId>, identical to the historicalgithub_<id>format — no migration of existing cloud data.
⚠️ Only pass an email toresolveUserId()when the provider has confirmed the address is verified. Passing an unverified email lets another account take over an existing workspace.
// server/api/auth/google.get.ts
export default defineOAuthGoogleEventHandler({
async onSuccess(event, { user }) {
const userId = await resolveUserId({
provider: "google",
providerId: user.sub,
verifiedEmail: user.email_verified ? user.email : null
});
await setUserSession(event, {
user: { id: userId, login: user.email, name: user.name, avatar: user.picture }
});
return sendRedirect(event, "/");
}
});- Create an OAuth client in the Google Cloud Console with
https://<your-domain>/api/auth/googleas the redirect URI; - Add
NUXT_OAUTH_GOOGLE_CLIENT_IDandNUXT_OAUTH_GOOGLE_CLIENT_SECRETto your Vercel environment variables — Nitro maps them toruntimeConfig.oauth.googleautomatically, sonuxt.config.tsneeds no change; - Add a button in
components/UserMenu.vuethat navigates to/api/auth/google.
Providers without OIDC support (Gitee, WeChat, QQ, DingTalk, Feishu) need their own "redirect to authorize → exchange code in callback" flow, but they end with the same
resolveUserId()plussetUserSession()pair, reusing the whole identity-mapping and workspace-isolation path.
This project is licensed under the MIT License.