Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
Jessica와 Founders Doc의 AI가 계약을 몇 분 안에 검토하고 초안 작성
Jessica, Founders Doc's AI, reviews and drafts contracts in minutes. When a contract needs a lawyer's name, our practising lawyers take over. Serving founders worldwide.
비즈니스TypeScript · HTMLGitHub @Lamnguyen0810온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
FDAI — drafting (Sprints 1, 2 and 3)
FoundersDoc's internal AI drafting tool. A lawyer picks a document type, answers a short form, and gets an editable first draft.
Where this has got to — the product is complete enough to use on a real matter:
Everything is optional in layers. With no keys at all it runs on a mock provider. With a free Gemini key it drafts for real. With Supabase it also has login and saving. Each layer is additive — a half-finished setup degrades, it does not break.
👉 To turn on accounts and the database, follow SETUP_SUPABASE.md.README 전문 보기 ↗FoundersDoc's internal AI drafting tool. A lawyer picks a document type, answers a short form, and gets an editable first draft.
Where this has got to — the product is complete enough to use on a real matter:
| Sprint | Delivered |
|---|---|
| 1 | Form → prompt → model → streamed editable draft. One provider adapter, three backends plus a mock |
| 2.1 | Invite-only login, public sign-up disabled, anonymous requests blocked from the API |
| 2.2 | Four tables with row-level security; prompts and field lists in the database, editable with no deploy |
| 2.3 | Every draft saved; reopen from Past drafts to edit, save, or mark final; pagination |
| 2.4 | Usage page — tokens, actual spend, and what the month would cost on a paid model |
| 3.1 | Upload a .docx or .pdf, see exactly what the AI will read, feed it into the draft |
| 3.3 | Download Word on firm letterhead, with drafter's notes excluded by default |
Everything is optional in layers. With no keys at all it runs on a mock provider. With a free Gemini key it drafts for real. With Supabase it also has login and saving. Each layer is additive — a half-finished setup degrades, it does not break.
👉 To turn on accounts and the database, follow SETUP_SUPABASE.md.
npm install
cp .env.example .env.local
# edit .env.local: set AI_PROVIDER=mock
npm run dev
Open http://localhost:3000/draft. The mock provider needs no key and no network. It streams back the exact prompt that would have been sent, which makes it the best prompt-debugging tool in the repo: if a field is missing there, the form is wrong; if a rule is missing there, the system prompt is wrong.
.env.local: AI_PROVIDER=gemini and GEMINI_API_KEY=...node --env-file=.env.local scripts/smoke-ai.mjs
And if a draft ever fails with "model was not found", ask your key what it
can actually use — model ids change, and a stale one answers 404:
node --env-file=.env.local scripts/list-models.mjs
npm run dev, then draft an NDA.⚠️ Read this before typing a client's name
Google's Gemini API terms provide that content submitted to the unpaid services is used to provide, improve and develop Google's products and machine-learning technologies, that human reviewers may read and annotate API input and output, and that sensitive, confidential or personal information should not be submitted to the unpaid services. The paid tier is the opposite — prompts and responses are not used to improve Google products.
So: anonymised, non-confidential material only until a paid key is in place. The banner at the top of every page says the same thing. See "The swap" below.
| Path | What it does |
|---|---|
src/lib/ai/provider.ts | ⭐ The swap point. The only module that knows which provider is in use |
src/lib/ai/gemini.ts | Free tier today |
src/lib/ai/anthropic.ts | Paid replacement, wired and ready, needs only env vars |
src/lib/ai/openai.ts | OpenAI GPT-5.6 (Sol / Terra / Luna) — the drafting-test winners; env vars only |
src/lib/ai/ollama.ts | A model on a machine you control — the Phase 3 private tier |
src/lib/ai/mock.ts | No key, no network. Echoes the prompt |
src/lib/ai/pricing.ts | The money meter: what each draft would cost on a paid model |
src/lib/doctypes.data.mjs | ⭐ The source of truth for the NDA — plain JS so both the app and the seed generator read the same object |
src/lib/doctypes.ts | Types over that data, plus the worked examples |
src/lib/doctypes.server.ts | Reads doc types from Supabase, falls back to the built-in catalogue |
src/lib/supabase/ | Server, middleware and config clients. config.ts explains the key naming |
src/middleware.ts | Refreshes the session and blocks anonymous requests — including to /api/generate |
supabase/001_schema.sql | Tables, row-level security, policies, triggers |
supabase/002_seed_doctypes.sql | Generated seed. Run node scripts/build-seed-sql.mjs after editing a prompt |
src/lib/prompt.ts | Prompt assembly, required-field validation, drafter's-notes split |
src/lib/extract.ts | .docx / .pdf text extraction. Sniffs by magic bytes, not extension |
src/lib/letterhead.ts | ⚠️ Firm details for the Word export — placeholders, replace these |
src/app/api/export/route.ts |
src/app/globals.css carries the tokens, type scale, buttons and card treatment
ported straight from the marketing homepage — the same greys, the same gold
(#f3bf4b), Geist for headings and Inter for body, the same .btn variants. The
app is deliberately light only: foundersdoc.com has no dark mode, and a tool
that flips theme halfway through a journey reads as broken.
src/components/SiteChrome.tsx holds the slim working nav and the site footer.
The nav is intentionally not the marketing nav — no FD AI / Services /
Resources dropdowns. This is a screen people work in, and the navigation should
not compete with the form. The footer is the full one, so the app still reads as
part of foundersdoc.com.
Fonts load via <link> in the root layout, the same way the homepage does it,
rather than next/font. next/font self-hosts, which is better — but it fetches
from Google at build time, and a build that depends on reaching Google is a
build that can fail.
No file outside src/lib/ai may import a model SDK or call a model HTTP endpoint. Everything else calls generateDraft() or generateDraftStream() and has no idea which provider answered. That is why switching from a free Gemini key to a paid Anthropic one is two environment variables rather than a rewrite. If you are about to fetch an AI API from a component or a route, stop and add a provider instead.
systemPrompt holds the instructions; examples holds the worked documents. They are separate fields so that swapping in the firm's own sanitised NDAs at sprint 2.2 changes nothing else. Never paste an example inline into the prompt text.
Admin → AI files → Playbook. The firm's drafting rules — numbering, defined terms, clauses never dropped, wording to use or avoid — firm-wide and per document type. Paste or upload (Word, PDF, Markdown, text); every save is a version, any version can be read or restored, "Switch off" retires the live one. Storage is supabase/044_playbook.sql.
The model reads the playbook before the worked examples and is told it wins where they differ (playbookBlock() in lib/prompt.ts). Do not put a playbook in the training library: the library holds documents to imitate, and a page of rules would be imitated as if it were one.
Feedback beside every draft (admins only): a lawyer says what is wrong, with the passage they selected. Or type a message beginning feedback: in the Slack drafts channel — Zapier (Slack "New Message Posted to Channel", bot messages off → Webhooks POST to /api/feedback/slack, header x-feedback-secret from select public.slack_feedback_secret(), body text/user_name/permalink) forwards it. Both land in Admin → AI files → Feedback & lessons — and the drafter learns from them by itself (lib/learn.ts, supabase/046): the comment is read against the draft it was about (name it with the #ref from the Slack download message: fb #3f9a1c: …), the playbook and the rules already learnt, and rewritten as one rule, live from the next draft, announced in Slack, editable and switchable on the dashboard. Feedback that is not a correction waits for a person; "Turn into rule" and "Add a rule" still work by hand. fb undo in Slack switches off the most recent live rule (supabase/047). Live lessons go into every later draft of that scope after the playbook, with the same authority (lessonsBlock()). Storage is supabase/045_feedback_and_lessons.sql and 046_the_drafter_learns.sql.
With a playbook live, the built-in prompt's own conventions for gaps and notes give way to the playbook's: [●] for a missing fact and [FD Note: …] in the text (shown highlighted on screen and in Word, and listed in the FD Notes card beside the document); no DRAFTER'S NOTES block is asked for. The page and the Word file are set from the playbook's own style parameters — a house_style block (font, body_size_pt, title_size_pt, line_spacing, space_after_pt, heading_space_before_pt, heading_space_after_pt, alignment_body) or the same in prose (documentLook() in lib/playbook.ts). Numbering is read three sub-levels deep: (a), (i), (A).
Sample documents are read with their emphasis kept as marks (**bold**, _italic_ — lib/extract.ts), the model is told to write the same marks where the precedents and playbook use emphasis, and the page and the Word file set them. Re-upload a sample to pick up its bold; samples uploaded before this were read as plain text.
The weekly Zapier analytics report also requires a server-only
ANALYTICS_REPORT_SECRET. Generate a long random value, add it to Vercel, and
send the same value from Zapier as Authorization: Bearer <value> when posting
to /api/analytics/weekly. Never prefix this variable with NEXT_PUBLIC_.
The AI app lives in its own Vercel project, separate from the marketing site, so an AI experiment can never break foundersdoc.com.
git init && git add -A && git commit -m "FDAI drafting: sprints 1 and 2.1-2.2"
gh repo create fdai-draft --private --source=. --push
Then in Vercel:
fdai-draft. Put it in the same Vercel team that owns foundersdoc.com — if that team is already Pro, this project costs nothing extra.AI_PROVIDER and GEMINI_API_KEY (and GEMINI_MODEL if you want to pin it). Apply to Production, Preview and Development.NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY once you have followed SETUP_SUPABASE.md. Env vars are only picked up by a new build — redeploy after adding them.app.foundersdoc.com and create the CNAME Vercel shows you.https://app.foundersdoc.com. That link is the entire integration."Continue with Google" is handled by this app, not by Supabase's OAuth redirect — so Google's consent screen says foundersdoc.com, not a *.supabase.co address, and Google's free brand verification can be granted. Supabase still owns every account; it just receives Google's ID token instead of running the handshake (signInWithIdToken). Set-up, once:
https://foundersdoc.com/auth/google/callback (and http://localhost:3000/auth/google/callback for local work). The old …supabase.co/auth/v1/callback entry can go.GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET (server-only — no NEXT_PUBLIC_), plus NEXT_PUBLIC_GOOGLE_AUTH=1 to show the button and NEXT_PUBLIC_SITE_URL=https://foundersdoc.com so the redirect URI matches byte for byte. Redeploy.supabase/042_google_on_our_domain.sql.foundersdoc.com, status In production, submit. Until approval the screen reads "Sign in to foundersdoc.com"; after it, "Founders Doc".Plan note. Vercel's fair-use guidelines restrict the free Hobby plan to non-commercial personal use, and define commercial usage broadly enough to include a project whose code is written by a paid employee. Check which plan the foundersdoc.com team is on before assuming this is free.
src/lib/letterhead.ts ships with placeholders — [Firm address line 1], a dummy phone number. Replace them. To use the real logo, drop it at public/letterhead-logo.png (about 150×45 px) and it is picked up automatically; if the file is missing the export falls back to a text header rather than failing.
The drafter's notes are excluded from the plain download on purpose. [[TO CONFIRM]] markers and internal assumptions must not leave the firm by accident. There is a separate link to download a copy with the notes, clearly headed "INTERNAL".
Nothing is stored. The file is read in memory, the text is extracted, and only that text is kept — in drafts.source_text. No Supabase Storage bucket, no binary sitting in the cloud while you are on a free-tier API key. If you later need the original kept, add a bucket and a documents row; extract.ts does not change.
Scanned PDFs are detected and refused with an explanation rather than silently producing an empty draft. OCR is not in scope.
| From | To | What changes |
|---|---|---|
| Gemini free | Anthropic paid | AI_PROVIDER=anthropic, ANTHROPIC_API_KEY, ANTHROPIC_MODEL. Nothing else |
| Gemini free | OpenAI paid | AI_PROVIDER=openai, OPENAI_API_KEY, OPENAI_MODEL=gpt-5.6-sol (or -luna). Optional OPENAI_REASONING=none|low|medium|high, default low |
| Gemini free | Gemini paid | Enable billing on the Google Cloud project behind the key. No code change at all |
| Cloud | Local (Phase 3) | AI_PROVIDER=ollama, OLLAMA_BASE_URL, OLLAMA_MODEL |
The trigger for the first swap is not a feeling. It is either (a) a confidential document needs drafting, or (b) the gold-standard test set shows the free model failing scenarios the paid model passes.
| Key | Prefix | Goes to the browser? | Why |
|---|---|---|---|
Supabase publishable / anon | NEXT_PUBLIC_ | ✅ Yes | Designed to be public. Every request it makes is constrained by row-level security |
Supabase secret / service_role | never | ❌ Never | Bypasses RLS entirely. Used only by the Stripe webhook and by the Google callback's "is there an account for this email?" check |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | never | ❌ Never | Read only inside /auth/google and /auth/google/callback on the server |
GEMINI_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY | never | ❌ Never | Read only inside /api/generate on the server |
If you are ever unsure, the rule is: NEXT_PUBLIC_ means "printed on the front page of a newspaper". Only the Supabase publishable key survives that test.
npm run build passes/api/generate/api/generate, and write the test that proves user A cannot read user B's drafts.NDA_DATA block in doctypes.data.mjs, regenerate the seed. Letter of Demand, Letter of Engagement and the standard email are already written up in the prompt library.| Limit | Fixed at |
|---|---|
No rate limiting on /api/generate | Sprint 4.2 |
| Scanned PDFs are refused, not OCR'd | Out of scope; paste the text |
| Uploaded files are not kept, only their text | Deliberate — see above |
| One document type (NDA) | Add more in doctypes.data.mjs |
| Letterhead is a placeholder | src/lib/letterhead.ts |
| Free tier: ~15 requests/min | The swap |
Draft text → .docx on letterhead |
src/app/usage/page.tsx | The money meter |
src/app/api/generate/route.ts | Server route. Streams NDJSON. The API key lives here and never reaches the browser |
src/app/draft/DraftForm.tsx | The form, the streaming editor, the copy button |
src/lib/examples/ | The two worked NDAs, plus the generator that bakes them into a module |