frontend.md

Frontend

mino.ink (Cloudflare Pages), built-in server UI, hybrid auth, and mobile apps.

← Back to docs


The Web Interface (mino.ink)

Hosting: Cloudflare Pages (Free)

The mino.ink website is a static Next.js export deployed to Cloudflare Pages. It's a thin shell β€” all data processing, storage, and AI happen on the user's linked server.

mino.ink / test.mino.ink (Cloudflare Pages)
  β”œβ”€ Static HTML/JS/CSS (Next.js static export)
  β”œβ”€ Landing page + workspace shell
  β”œβ”€ Dedicated /link handler (prefilled URL support)
  β”œβ”€ Local profile auth (API key in localStorage)
  β”œβ”€ Unified docs explorer (reads /docs + /docstart)
  └─ All API calls β†’ user's server (direct HTTPS or Cloudflare Tunnel)

The Same UI, Everywhere

The exact same Next.js app is served from two places:

SourceURLWhen to use
Cloudflare Pageshttps://test.mino.ink / https://mino.inkRemote access to any linked server
Built-in server UIhttp://localhost:3000/Local access, air-gapped, no internet needed

The built-in UI works identically to mino.ink β€” it's the same code, just served from the Docker container's static files instead of Cloudflare.

Hybrid Auth Model

No account is ever required. Users have three options:

ModeHow it worksCredentials storedMulti-device?
AnonymousOpen /link (prefilled URL or manual) and link with API keylocalStorage only❌ Manual per device
Google sign-inSign in with Google β†’ link server(s) to accountServer-side (mino.ink DB)βœ… Auto-syncs linked servers
Local instanceOpen http://localhost:3000 β†’ auto-connectedServer's own credentials❌ One device

The Google account doesn't store notes. It only stores which servers the user has linked. Notes always live on the user's server.

Free Tier (No Self-Hosting Required)

When a user signs into mino.ink with Google but doesn't link a server, they get a free managed instance:

  • Limited storage (e.g. 100MB / 1000 notes)
  • Core features: notes, search, folders, tags
  • AI Agent: bring your own API key (OpenAI/Anthropic)
  • No local tools (Whisper, OCR) β€” API keys required for those
  • No sandbox, no custom plugins
  • Upgrade path: deploy your own server for unlimited everything

Page Structure

PagePathDescription
Landing/Marketing + onboarding entrypoint
Link Server/linkDedicated handler that parses serverUrl + apiKey, verifies, links, stores profile, and redirects
Workspace/workspace?profile=<id>Main shell with linked-server status and authenticated note list
Docs Explorer/docsServes both blueprint docs (/docs) and implementation docs (/docstart)

/link Handler Contract

Flow for GET /link?serverUrl=...&apiKey=...:

  1. Parse query params.
  2. Normalize and validate serverUrl.
  3. Call POST /api/v1/auth/verify using X-Mino-Key.
  4. Call POST /api/v1/auth/link.
  5. Persist linked server profile in localStorage.
  6. Remove apiKey from browser URL (history.replaceState).
  7. Redirect to /workspace?profile=<id>.

If params are missing or invalid, /link shows a manual fallback form.

Cloudflare Pages Build Settings

Use two Pages projects (test + production) with the same build pipeline.

Relay note:

  • The /link?relayCode=... flow depends on a running relay backend.
  • See docs/relay.md for relay deployment and required server variables.

Test project (test.mino.ink)

  • Framework preset: None
  • Build command: pnpm install --no-frozen-lockfile && pnpm --filter @mino-ink/web build
  • Build output directory: apps/web/out
  • Root directory: /
  • Environment variables:
    • NODE_VERSION=20
    • NEXT_PUBLIC_APP_ENV=test
    • NEXT_PUBLIC_APP_ORIGIN=https://test.mino.ink
    • NEXT_PUBLIC_DEFAULT_LINK_TARGET=https://test.mino.ink
    • NEXT_PUBLIC_RELAY_URL=https://relay.mino.ink

Production project (mino.ink)

  • Same build settings as test
  • Environment variables:
    • NODE_VERSION=20
    • NEXT_PUBLIC_APP_ENV=production
    • NEXT_PUBLIC_APP_ORIGIN=https://mino.ink
    • NEXT_PUBLIC_DEFAULT_LINK_TARGET=https://mino.ink
    • NEXT_PUBLIC_RELAY_URL=https://relay.mino.ink

Workspace Layout (from screen.png mockup)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  [≑] WORKSPACE               [πŸ‘€+3] [Share] [Publish]       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€
β”‚            β”‚  Projects > Project_Alpha.md               β”‚    β”‚
β”‚  πŸ“ Projectsβ”‚                                           β”‚ [A]β”‚
β”‚   β”œβ”€ Project β”‚  1  # Project Alpha: System Architecture β”‚ [πŸ–Ό]β”‚
β”‚   β”œβ”€ Roadmap β”‚  2                                       β”‚ [πŸ”—]β”‚
β”‚  πŸ“ Daily    β”‚  3  ## Core Objectives                   β”‚ [✏]β”‚
β”‚   β”œβ”€ Personalβ”‚  4  - Establish robust sync using CRDTs. β”‚    β”‚
β”‚   └─ Ideas   β”‚  5  - Implement end-to-end encryption.   β”‚    β”‚
β”‚  πŸ“ Archive  β”‚  ...                                      β”‚    β”‚
β”‚            β”‚                                             β”‚    β”‚
β”‚ [βš™] [πŸ‘₯]  β”‚                                             β”‚    β”‚
β”‚ Storage 42%β”‚  ● SYNCED  UTF-8  <> MARKDOWN  1,242 WORDS β”‚    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜

Key UI Features

  • Fluid navbar β€” Floating, glass-effect navbar from mino.ink with pill-shaped active indicators
  • Split-pane editor β€” Resizable panels (sidebar / note list / editor) using react-resizable-panels
  • Real-time markdown β€” Live preview with syntax highlighting via react-markdown + react-syntax-highlighter
  • Command palette β€” Cmd+K to search notes, run commands, switch servers (using cmdk)
  • File tree β€” Collapsible folder tree with drag-and-drop reordering (using @dnd-kit)
  • AI chat panel β€” Slide-out panel to chat with the AI organizer
  • Plugin marketplace β€” Browse available plugins, one-click install, configure via UI
  • Server settings β€” API keys, agent config, resource detection results β€” all visual, no terminal
  • Theme switching β€” Dark/light mode with smooth transitions (using next-themes)
  • Status bar β€” Sync status, word count, encoding, cursor position (inspired by VS Code)
  • Collaboration cursors β€” Show other users' cursors in real-time (Yjs awareness)
  • Server picker β€” Switch between multiple linked servers (for multi-server setups)

Landing Page Design

Keep the existing mino.ink design language, updated with logo-derived brand colors:

  • Deep dark background (#121212 base, #1E1E1E surfaces)
  • #BB86FC purple gradient orbs with blur effects
  • Grid pattern overlay with faint purple tint
  • Mouse-reactive parallax elements
  • Feature cards with glass effect and purple-tinted borders
  • The Mino logo (three vertical pills + "ino" text) from logo.svg

Mobile Apps (iOS & Android)

Technology Choice: React Native + Expo

Why not Flutter? React Native + Expo enables:

  • Shared TypeScript types with the server
  • Shared API client with the web app
  • Shared markdown parsing logic
  • Shared React components (via react-native-web bridge)
  • OTA updates without app store review
  • Single codebase for iOS + Android

Mobile Architecture

β”Œβ”€ Mobile App ──────────────────────────────────────────┐
β”‚                                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚           UI Layer (React Native)             β”‚     β”‚
β”‚  β”‚  NoteList β”‚ Editor β”‚ Search β”‚ Settings β”‚ Chat β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                      β”‚                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚           State (Zustand + Yjs)               β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                      β”‚                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚           Local Storage (SQLite via expo)     β”‚     β”‚
β”‚  β”‚  Full offline copy of all notes + index       β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                      β”‚                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚           Sync Engine (Yjs + WebSocket)        β”‚     β”‚
β”‚  β”‚  Offline queue β†’ sync when online              β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Offline-First

  • All notes are stored locally in SQLite on the device
  • Edits are queued when offline and synced via CRDTs when reconnected
  • Conflict resolution is automatic (Yjs CRDT)
  • Server selector in settings lets users point to ANY Mino server

Mobile Auth & Server Setup

1. Open Mino app
2. Option A: Sign in with Google β†’ auto-discovers all linked servers
3. Option B: Enter server URL + API key manually (no Google needed)
4. Select a server β†’ app syncs notes to local SQLite
5. Works fully offline after first sync

Multi-Server Support

The mobile app maintains a list of connected servers:

interface ServerConfig {
  id: string;
  name: string;            // "Personal", "Work", etc.
  endpoint: string;        // "https://my-server.com" or tunnel URL
  authToken: string;       // API key or JWT
  syncEnabled: boolean;
  lastSyncedAt: Date;
}

Users can switch between servers or view notes from all servers in a unified view.