DeepSeek Harness Remote
DeepSeek Harness Remote: DeepSeek Harness 실행 PC와 모바일·PC를 안전하게 연결해 어디서나 작업 이어받기
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗AI meeting notes and action items — built on a 100% free stack.
Live demo: https://meeting-mind-ai-zeta.vercel.app/ — click Try demo to explore a ready-made workspace with five processed meetings, no sign-up needed. Or create your own account and upload or record a short clip.
Record a meeting or upload an existing recording. MeetingMind sends the audio straight to Gemini, which transcribes it, labels speakers, writes a factual summary, logs the decisions that were actually made, extracts action items with owners and due dates, and drafts a follow-up email. Every action item from every meeting lands on one shared board for the team.
Every piece of this project runs on a generous free tier, with no credit card required anywhere in the core product:
| Layer | Choice | Why it's free |
|---|---|---|
| Database | Neon Postgres | Free serverless Postgres tier — also stores uploaded audio directly (as bytea), so no separate storage bucket is needed |
| ORM | Prisma 7 | Open source, connects to Neon via @prisma/adapter-neon |
| Auth | NextAuth.js (Auth.js) v5 | Open source, email/password via bcrypt; optional free Google OAuth |
| AI (transcription, diarization, summary, decisions, action items, follow-up email) | Google Gemini | Free API key, gemini-flash-latest. Gemini accepts audio natively, so one model call does the whole job — no separate Whisper/transcription provider |
| Payments | Stripe test mode | Test-mode keys are free forever. Skip it entirely and billing runs in demo mode automatically |
| Hosting | Vercel free tier (or anywhere Next.js runs) | — |
If you never add a STRIPE_SECRET_KEY, the billing page still works —
"upgrading" a plan just flips the organization's plan in the database
instantly with a demo-mode notice, so the whole product works without ever
creating a Stripe account.
owner / admin / member roles, each holding one or more workspacesmotion scroll-triggered reveals throughout, and a full marketing landing page (hero, stats, how-it-works, feature grid, use cases, testimonials, pricing, FAQ)motion (Framer Motion successor), next-themes for dark mode@prisma/adapter-neon driver adapter) — audio is stored as Bytes on the Meeting rowai, @ai-sdk/google) + Google Gemini, generateObject with a zod schema and an inline audio file partPrerequisites: Node.js 20.9+, a free Neon database, a free Gemini API key.
git clone <your-fork-url> meetingmind-ai
cd meetingmind-ai
npm install # also runs `prisma generate` (postinstall)
Then create a .env file in the project root with this template and fill it in
over the next steps:
# Required
DATABASE_URL="" # Neon connection string
NEXTAUTH_SECRET="" # openssl rand -base64 32
NEXTAUTH_URL="http://localhost:3000"
GOOGLE_GENERATIVE_AI_API_KEY="" # https://aistudio.google.com/apikey
# Optional: Google sign-in
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
# Optional: Stripe (leave blank for demo billing mode)
STRIPE_SECRET_KEY=""
STRIPE_WEBHOOK_SECRET=""
STRIPE_PRICE_TEAM=""
STRIPE_PRICE_BUSINESS=""
.env as DATABASE_URL..env as GOOGLE_GENERATIVE_AI_API_KEY.Without this key the app still runs — uploading a meeting fails cleanly with an "AI is not configured" message instead of a crash.
openssl rand -base64 32
Paste the result into .env as NEXTAUTH_SECRET.
Skip this step; it is not needed. When both variables are set, lib/auth.ts
registers the Google provider and creates a local user on the first Google
sign-in, but the login and sign-up pages do not have a Google button yet, so
email/password is the only sign-in path in the UI. To prepare the backend:
http://localhost:3000/api/auth/callback/google as an authorized redirect URI.GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET in .env.Skip this entirely if you don't need real checkout — billing falls back to demo mode automatically. To wire up real (test-mode, free) Stripe Checkout:
STRIPE_SECRET_KEY, STRIPE_PRICE_TEAM, STRIPE_PRICE_BUSINESS in .env.
(Checkout is server-side redirect, so no publishable key is needed.)stripe listen --forward-to localhost:3000/api/webhooks/stripe and paste the printed secret into STRIPE_WEBHOOK_SECRET.
The webhook keeps the plan in sync on customer.subscription.created,
customer.subscription.updated and customer.subscription.deleted.npx prisma db push
npm run dev
Open http://localhost:3000. Sign up, create an organization, upload a short audio clip (or record one), and watch the transcript, summary, decisions and action items land on the meeting page.
| Script | What it does |
|---|---|
npm run dev | Dev server on http://localhost:3000 |
npm run build | next build (does not touch the database schema, see Deploying) |
npm start | Serve the production build |
npm run lint | ESLint |
npm run seed:demo | Build or reset the public demo org (see Public demo mode) |
npx prisma db push | Sync prisma/schema.prisma to the database |
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | yes | Neon Postgres connection string (app data and uploaded audio) |
NEXTAUTH_SECRET | yes | Signs session JWTs (AUTH_SECRET also works with Auth.js v5) |
NEXTAUTH_URL | local only | Base URL; also the fallback origin for Stripe redirect URLs |
GOOGLE_GENERATIVE_AI_API_KEY | to process meetings | Gemini key; without it uploads fail with a clear "AI is not configured" message |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | no | Register the Google OAuth provider (backend only; no UI button yet) |
STRIPE_SECRET_KEY | no | Real Stripe Checkout; empty = demo billing mode |
STRIPE_WEBHOOK_SECRET | with Stripe | Verifies webhook signatures |
STRIPE_PRICE_TEAM / STRIPE_PRICE_BUSINESS | with Stripe | Recurring Price IDs |
DEMO_PASSWORD | for the public demo | Password of the shared demo account; "Try demo" uses it server-side, it never reaches the browser |
CRON_SECRET | for the public demo | Protects /api/cron/demo-reset; Vercel Cron sends it as a Bearer token |
SEED_USER_EMAIL | no | Target account for scripts/seed-meetings.ts |
VERCEL is set automatically by Vercel and lowers the upload cap to 4 MB (see Known issues).
A Try demo button on the landing page and the login page signs visitors
into a shared demo account ([email protected]) with no typing. The sign-in
happens on the server (POST /api/demo/login), so the password never reaches
the browser. Visitors land in Lumen Labs, a fictional startup on the
Business plan with three members (owner, admin, member) and five fully
processed meetings: a sales discovery call, sprint planning, a client kickoff,
a roadmap review and a hiring debrief. Each one has a speaker-labelled
transcript, summary, decisions, action items with owners and due dates, and a
follow-up email. All AI output is stored in the seed, so browsing the demo never
calls Gemini. The roadmap review has a permanent public link at
/share/demo-lumen-roadmap-review.
Each sample meeting also has a playable recording (prisma/demo-audio/*.mp3,
about 3 minutes and 0.7 MB each). The recordings are generated with Windows'
built-in text-to-speech, one consistent voice per speaker, and every
transcript timestamp is the real moment that line is spoken. Clicking a
timestamp jumps the player there. After editing a transcript in
lib/demo-data.ts, regenerate the audio and its timings on a Windows machine
with npx tsx scripts/demo-audio/generate.mts, then run npm run seed:demo.
If the audio is out of date, the seed skips it and falls back to estimated
timings.
What demo visitors can and can't do
DemoUsage) and a duration check.Setup
# .env — generate both with: openssl rand -base64 32
DEMO_PASSWORD="..."
CRON_SECRET="..."
npx prisma db push # adds the IN_PROGRESS status and the DemoUsage table
npm run seed:demo # builds the demo org; safe to re-run
npm run seed:demo is idempotent. It deletes and rebuilds only the demo org
(the cascade also removes meetings and audio that visitors uploaded) plus the
demo accounts' memberships and the upload counter. Meeting and due dates are
relative to the day it runs. Real users and their data are never touched, and
sign-ups on the reserved @meetingmind.demo / @lumenlabs.demo domains are
refused.
Daily reset. vercel.json schedules GET /api/cron/demo-reset once a day
(00:00 UTC). With CRON_SECRET set in the Vercel project, Vercel sends it as
Authorization: Bearer <CRON_SECRET>, and the route runs the same reset as the
seed script. To trigger it by hand:
curl -H "Authorization: Bearer $CRON_SECRET" https://<your-domain>/api/cron/demo-reset
scripts/seed-meetings.ts adds three finished demo meetings (transcript, summary,
decisions, action items, follow-up email and a playable recording from
scripts/demo-meeting.wav) to an existing account's workspace. Sign up and
create an organization first, then:
npx tsx scripts/seed-meetings.ts [email protected] --dry # preview, writes nothing
npx tsx scripts/seed-meetings.ts [email protected] # insert
npx tsx scripts/check-seed.ts [email protected] # read-only summary
Re-running is safe (meetings are matched by title). The seeded transcripts and summaries are hand-written; upload a real recording to see the Gemini pipeline run.
MediaRecorder recording) to
POST /api/meetings/upload with the workspace id and duration.bytea on a new Meeting row with status PROCESSING.generateObject call (lib/gemini.ts) sends the audio as an
inline file part to gemini-flash-latest with a zod schema for speaker segments,
summary, key topics, decisions, action items (assignee, dueDate, timestamp)
and the follow-up email.READY, or to FAILED with the error message.maxDuration = 60. On Vercel Hobby that's the ceiling; a very long
recording on a slow free-tier Gemini response can occasionally exceed it,
which leaves the meeting stuck in "Processing" — re-uploading fixes it.
Running locally (npm run dev) or on Vercel Pro removes this ceiling.lib/plans.ts detects the VERCEL env
var (set automatically in every Vercel build) and drops FREE_AUDIO_MAX_BYTES
to 4MB there so uploads fail with a clear "too large" message instead of a
raw platform 413. Running locally (npm run dev) or on any non-Vercel Node
host (Railway, Render, a VPS, your own server) keeps the full 20MB cap,
which comfortably covers a real meeting recording. If 4MB is too tight for
your Vercel deployment, that's the actual tradeoff of serverless — self-host
the Node server instead, or add a real object-storage upload path (not
included here, to keep the stack to just Neon + Gemini).status (PROCESSING / READY / FAILED) is the source of truth./invite/<token>
link to your clipboard for you to send; no email is delivered.lib/auth.ts
when its env vars are set, but the auth form only offers email/password.All routes except auth, public/* and the Stripe webhook require a session, and
check the caller's organization membership and role.
| Method | Route | Purpose |
|---|---|---|
POST | /api/auth/signup | Create an account |
GET POST | /api/orgs | Your orgs + workspaces / create an org with its first workspace |
PATCH | /api/orgs/[orgId] | Rename the organization |
POST | /api/orgs/[orgId]/workspaces | Add a workspace |
GET | /api/orgs/[orgId]/members | Members and roles |
PATCH DELETE | /api/orgs/[orgId]/members/[memberId] | Change role / remove (the last owner is protected) |
GET POST | /api/orgs/[orgId]/invites | List / create invite links |
DELETE | /api/orgs/[orgId]/invites/[inviteId] | Revoke an invite |
GET | /api/invites/[token] | Read an invite |
POST | /api/invites/accept | Accept an invite |
GET | /api/meetings?workspaceId=&q= | List meetings (title search) |
POST | /api/meetings/upload | Upload audio and run the Gemini analysis |
GET DELETE | /api/meetings/[id] | Meeting detail / delete |
GET | /api/meetings/[id]/audio | Stream the stored recording |
POST | /api/meetings/[id]/share | Toggle the public share link |
GET | /api/public/meetings/[token] | Public read-only meeting (no auth) |
GET | /api/action-items?orgId= |
meetingmind-ai/
app/
page.tsx # Landing page
login/, signup/ # Auth pages
onboarding/ # Create-org / join-by-invite
invite/[token]/ # Team invite acceptance
share/[token]/ # Public read-only meeting view
(dashboard)/ # Protected dashboard route group
dashboard/, new/, meetings/[id]/, actions/, team/, billing/, settings/
api/
auth/ # NextAuth handler + signup endpoint
orgs/ # Orgs, plus [orgId]/workspaces, /members, /invites
invites/ # Read + accept an invite by token
meetings/ # List, upload (runs Gemini inline), detail, audio, share
public/meetings/[token]/ # Unauthenticated share-link read
action-items/ # Cross-meeting action item board
billing/, webhooks/stripe/ # Stripe checkout, portal, webhook
components/
landing/ # ProductMock (live meeting-detail replica used in the hero)
dashboard/ # AppShell (sidebar, workspace switcher), PersonAvatar
meetings/ # Waveform (live mic level meter), ProcessingSteps, StatusBadge
auth/ # Shared login/signup form
motion/ # Reveal, Stagger, CountUp — replay on every scroll re-entry
ui/ # Dropdown menu, toaster
theme-toggle.tsx # Light / dark / system switch
lib/
prisma.ts, auth.ts, auth.config.ts, session.ts, org.ts
gemini.ts # The single generateObject call that does transcription + analysis
meetings.ts, plans.ts, stripe.ts, format.ts
hooks/ # TanStack Query hooks (use-org, use-meetings, use-action-items, use-team)
prisma/schema.prisma # Full data model (Org → Workspace → Meeting → Transcript/Summary/Decision/ActionItem)
scripts/
seed-meetings.ts, check-seed.ts # Demo data seeder + read-only check
demo-meeting.wav # Audio used by the seeded meetings
proxy.ts # Redirects signed-out visitors (Next.js 16 "proxy", formerly middleware)
Push this repo to GitHub and import it into Vercel. Vercel auto-detects the Next.js framework and build command.
Set environment variables in Project Settings → Environment Variables:
| Variable | Required | Notes |
|---|---|---|
DATABASE_URL | Yes | Same Neon pooled connection string used locally |
NEXTAUTH_SECRET | Yes | Generate with openssl rand -base64 32 — use a different value than local dev |
NEXTAUTH_URL | No | Leave unset. next-auth v5 auto-trusts the host on Vercel |
GOOGLE_GENERATIVE_AI_API_KEY | Recommended | Same free Gemini key as local dev |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | Optional | If enabling Google sign-in, add https://<your-domain>/api/auth/callback/google as an authorized redirect URI first |
STRIPE_* | Optional | Leave blank for demo-mode billing, same as local dev |
Database schema: this repo has no prisma/migrations folder — the
schema is pushed straight with npx prisma db push, and the build script
is just next build (deliberately not prisma migrate deploy: with no
tracked migrations, migrate deploy fails with P3005 the moment it hits
a database that already has tables, which is exactly the state your Neon
DB is in after step 7 above). Point Vercel at the same Neon database
you've been developing against and it just works. If you ever point
production at a different, empty database, run npx prisma db push
against it once first — Vercel's build never applies schema changes on
its own.
Deploy. Vercel runs npm install (which triggers postinstall →
prisma generate), then npm run build.
No output: "standalone" or edge-runtime configuration is needed — every
API route uses the default Node.js runtime, which the Neon Prisma adapter
(@prisma/adapter-neon) requires anyway (it depends on the ws package for
its WebSocket connection). vercel.json only registers the daily demo-reset
cron job (see Public demo mode).
MIT — do whatever you want with it.
| Cross-meeting action item board |
PATCH | /api/action-items/[id] | Update an action item's status |
POST | /api/billing/checkout | Stripe Checkout, or instant plan switch in demo mode |
POST | /api/billing/portal | Stripe Customer Portal |
POST | /api/webhooks/stripe | Stripe webhook receiver |
POST | /api/demo/login | "Try demo": signs in to the shared demo account server-side |
GET | /api/demo/status | Demo uploads left today |
GET | /api/cron/demo-reset | Daily demo reset (requires Authorization: Bearer $CRON_SECRET) |