DeepSeek Harness Remote
DeepSeek Harness Remote: DeepSeek Harness 실행 PC와 모바일·PC를 안전하게 연결해 어디서나 작업 이어받기
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기a helpful website for students
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A small app for keeping track of a semester's coursework: which lectures you've watched, what homework is due and when, how far along each course is, and how your degree is progressing overall. Built with Next.js, Postgres (via Prisma), and Cloudflare R2 for file storage. Optionally syncs lectures, final exams and homework to your own Google Calendar and Google Tasks.
Data is organized as semesters → courses → lectures and homework. Each course tracks a lecture count so you can see watched/total progress at a glance, and homework items can have a due date, an assignment file, and your own answer (either typed text or an uploaded file). Everything is scoped to a signed-in user — there's no sharing between accounts.
Accounts are invite-gated: signup requires a shared invite code, so this isn't meant to be a public sign-up app. It's built for a small group of people you hand the code to yourself.
GOOGLE_EVENT_TIMEZONE to change it, 1 hour
long if no end time is given)./privacy, linked from
signup and every footer.fetch (no Google
client library)You'll need Node.js, a Postgres database (a free Neon database works fine, which is also what production uses), and a Cloudflare R2 bucket for file uploads.
Install dependencies:
npm install
Copy .env.example to .env and fill in the values:
cp .env.example .env
See Environment variables below for what each one is and where to get it.
Push the schema to your database:
npx prisma migrate deploy
Start the dev server:
npm run dev
Open http://localhost:3000, go to /signup, and
create an account using your invite code.
All of these go in .env locally, and in your host's environment variable
settings for production (they are never read from .env in production).
| Variable | Required | Where to get it |
|---|---|---|
DATABASE_URL | Yes | Your Postgres connection string (pooled, if your provider distinguishes). On Neon: project → Connect → copy the connection string. |
DIRECT_URL | Yes | Same as above, but the unpooled connection — used for running migrations. If your provider only gives you one string, use it for both. |
R2_ACCOUNT_ID | Recommended | Cloudflare dashboard → R2 → shown on the R2 overview page. |
R2_ACCESS_KEY_ID | Recommended | Cloudflare dashboard → R2 → Manage API Tokens → Create API Token, scoped to Object Read & Write on your bucket. Shown once when created. |
R2_SECRET_ACCESS_KEY | Recommended | Same token creation step as above — shown once, save it immediately. |
R2_BUCKET_NAME | Recommended | The name you gave the bucket when you created it (Cloudflare dashboard → R2 → Create bucket). |
BLOB_READ_WRITE_TOKEN | Optional | Vercel project → Storage → Blob. Only needed if you want the legacy Vercel Blob fallback available; leave unset for a fresh setup — see File storage below. |
SESSION_SECRET | Yes | A random secret used to sign session cookies. Generate one with:node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" |
SIGNUP_INVITE_CODE | Yes | Whatever code you want to require for signup. Pick something and share it with whoever you want to be able to create an account. |
GOOGLE_CLIENT_ID | For Google sync | Google Cloud Console → APIs & Services → Credentials → your OAuth client ID (Web application). |
GOOGLE_CLIENT_SECRET | For Google sync | Same OAuth client — shown when you create it. |
GOOGLE_REDIRECT_URI | For Google sync | Must exactly match an authorized redirect URI on that OAuth client: http://localhost:3000/api/google/callback locally, in production. |
File uploads (src/lib/blob.ts) auto-select their backend at runtime, with
no code change needed to switch:
R2_* variables are set, uploads go to Cloudflare R2.BLOB_READ_WRITE_TOKEN).For a brand-new setup, just configure R2 and ignore Vercel Blob entirely — the fallback exists for continuity with deployments that started on Blob before R2 support was added, not because you need both.
Regardless of backend, uploaded PDFs are stored as private objects and
served through /api/files/[...path], which checks server-side that the
requesting user actually owns the lecture/homework row referencing that file
before streaming it back — an unguessable URL is not treated as
authorization on its own.
Each user can connect their own Google account from Settings. Three independent toggles control what syncs:
Sync is one-way: the app writes to Google and never reads your calendar or tasks. Pressing Save in Settings makes Google match the app: missing items are added, items whose title, date, time or done-state changed are updated, and items whose date you cleared are removed. Only items that changed since the last sync are sent (the app stores a fingerprint of what each Google item holds), so repeating Save is quick and sends nothing when nothing changed. It then tells you how many items changed, or why Google refused (for example, the Calendar API isn't enabled). If you deleted events or tasks in Google by hand, press Re-send everything, which ignores the fingerprints; disconnecting or connecting a Google account does the same. After that, creating, editing or deleting an item updates Google, and deleting a course, semester or account removes the matching events/tasks. If Google no longer has an item (deleted by hand, say), the next edit recreates it. Disconnecting revokes the app's access at Google.
Setting it up (one time, in Google Cloud Console):
calendar.events and tasks.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and
GOOGLE_REDIRECT_URI.GOOGLE_TOKEN_ENCRYPTION_KEY. Connecting is refused without it.Things worth knowing:
[google] prefix, so search your host's logs for
that when something doesn't show up in Google.GOOGLE_* variables
(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI,
GOOGLE_TOKEN_ENCRYPTION_KEY) is missing on the server. The server log
line [google] cannot connect: <NAME> is not set. says which. After adding
it in your host's settings, redeploy.GOOGLE_TOKEN_ENCRYPTION_KEY, users have to disconnect and reconnect.GOOGLE_CALENDAR_SYNC.md is the original design plan. The code has moved on
(timed events, exam dates, self-healing updates), so treat this section as
the source of truth.
The public privacy note lives at /privacy (content in
src/lib/privacyContent.ts, English and Hebrew) and is linked from the
sign-up form and every page footer. If a feature starts storing or sending
new kinds of data, update that file and its date in the same change.
Deleting a course, semester or account also deletes the uploaded PDFs and
the Google Calendar events/Tasks the app created (src/lib/cleanup.ts).
npm test # Vitest suite
npm run typecheck # tsc --noEmit
npm run lint # ESLint
Runs the Vitest suite: input validation, path-safety checks, and pure
scheduling/calendar logic always run. A live round-trip test against your
actual R2 bucket (upload → read back → delete) additionally runs whenever
the four R2_* variables are present in your environment — otherwise it's
skipped, not failed.
The app is set up to deploy on Vercel with a Neon Postgres database and a Cloudflare R2 bucket attached, but any host that can run a Next.js app and reach a Postgres database will work. A few things that aren't obvious if you're setting this up fresh:
.env automatically
in production. If you use Google sync, add your production redirect URI
to the OAuth client too.scripts/migrate-if-production.js) runs pending
migrations automatically during a production build, but skips preview
builds so a preview deploy can't run migrations against your real database.node scripts/migrate-blob-to-r2.js --dry-run, then without the flag once
it looks right. It only copies — it never deletes the source Blob store,
so do that manually afterward once you've confirmed the app reads
correctly with the R2_* variables set.I built Student Keep by directing Claude Code, Anthropic's AI coding agent. Claude Code wrote the code; I did not type it by hand. My part was deciding what to build and in what order, choosing the stack and services (Next.js, Neon Postgres, Cloudflare R2 and Vercel), testing every feature in the real app, reporting bugs, asking for a security review, and deciding what got merged. I use the app every day for my own semester, which is how most of the bugs were found. Building it taught me how to get reliable work out of an AI agent, and where it goes wrong, which is why I test each change in the real app before it ships.
next.config.ts).src/lib/cleanup.ts).package.json has an overrides block pinning patched versions of a few
transitive dependencies. Re-check with npm audit --omit=dev when
upgrading, and drop an override once the package that pulled it in has
caught up.getLang() + t(lang, key)
(src/lib/i18n/); new strings need a key in both en and he in
src/lib/i18n/dictionary.ts — TypeScript won't catch a missing
translation, only a missing key.useActionState-based pattern ({error} return
values, not throws) via the shared ActionForm/AuthForm components.https://<your-domain>/api/google/callbackGOOGLE_EVENT_TIMEZONE | Optional | IANA time zone for timed lecture events. Defaults to Asia/Jerusalem. |
GOOGLE_TOKEN_ENCRYPTION_KEY | Required for Google sync | A random 32-byte key that encrypts users' Google tokens in the database. Generate with the same command as SESSION_SECRET. Connecting Google is refused without it, and changing it later means each user must reconnect. |