Skip to content

beniauer/michi

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Michi mascot

Michi

An open-source AI assistant for legal work — chat over your documents, draft and redline contracts, and look up Swiss case law from primary sources.

License: AGPL v3 TypeScript Next.js Express Supabase

Michi is a self-hostable legal document platform. Upload contracts and filings, ask questions grounded in the actual text, have the AI propose tracked-change edits to Word documents, and pull authoritative Swiss decisions and statutes instead of trusting a model's memory. Users bring their own model API keys, which are encrypted at rest.

⚠️ Michi is a personal/portfolio project, not a certified legal product. Its output is not legal advice. Do not store privileged client data without your own security review.


Screenshots

Add screenshots to docs/screenshots/ to show the Assistant, Swiss Law Search, and Tabular Review views.


Features

  • Document-grounded chat — Ask questions about uploaded documents. Answers cite the specific file and quote the passage, so claims are traceable.
  • AI redlining — The assistant proposes edits to .docx files as native Word tracked changes you can accept or reject.
  • Swiss law lookup — Built-in tools query OpenCaseLaw for federal and cantonal decisions (BGE/BGer), statutes (OR, ZGB, BV, StGB), and scholarly commentary. The model cites real decisions with canonical URLs instead of inventing case numbers.
  • Swiss Law Search — A dedicated search page to query case law, statutes, and doctrine directly, with results linking to the official source.
  • Tabular Review — Extract structured fields across many documents into a spreadsheet-style table (e.g. governing law, term, liability cap across 50 contracts).
  • Workflows — Reusable prompt templates for recurring drafting and review tasks.
  • Projects & sharing — Organize documents into projects and share them with colleagues by email.
  • Bring Your Own Key (BYOK) — Each user supplies their own Anthropic or Google key. Keys are encrypted before storage and never sent back to the browser. Supports Claude, Gemini, and OpenRouter models.

Tech stack

Layer Stack
Frontend Next.js (App Router), React, TypeScript, Tailwind CSS
Backend Express, TypeScript
Auth & DB Supabase (Postgres + Auth)
Storage S3-compatible object storage (e.g. Cloudflare R2)
Documents LibreOffice (DOC/DOCX → PDF), mammoth, docx tracked-change generation
Models Anthropic Claude, Google Gemini, OpenRouter (user-supplied keys)

Architecture

frontend/  Next.js app (UI, calls the backend over HTTP with a Supabase JWT)
backend/   Express API
  ├─ routes/      auth-gated endpoints (chat, documents, projects, caselaw, …)
  ├─ lib/         business logic
  │   ├─ access.ts        ownership/sharing checks (the authorization layer)
  │   ├─ cryptoKeys.ts    AES-256-GCM encryption for user API keys
  │   ├─ chatTools.ts     LLM tool definitions (read docs, edit docx, Swiss law)
  │   └─ swissCaselaw.ts  OpenCaseLaw REST client
  └─ migrations/  one-shot Supabase schema + RLS

Trust model: the backend talks to Supabase with the service role, so it bypasses row-level security by design. Every data route therefore re-checks ownership against the authenticated user via lib/access.ts before returning anything. New routes must do the same.

Security

Security was treated as a first-class concern, not an afterthought:

  • Passwords never touch the app — authentication is handled entirely by Supabase; the backend only verifies signed JWTs.
  • Encrypted API keys — user model keys are sealed with AES-256-GCM (random IV + auth tag per key) using a server-side KEY_ENCRYPTION_KEY. Key columns are revoked from the authenticated/anon Postgres roles, so only the backend can read them, and the plaintext is never returned to the client.
  • Server-side authorization — consistent ownership and project-sharing checks on every document, project, and download route.
  • Hardened transport layer — per-IP rate limiting (stricter on chat and account routes) and helmet security headers.
  • Output safety — AI responses are rendered as escaped Markdown (no raw HTML), so model output can't inject scripts.

A security self-audit lives in .gstack/security-reports/ (kept local). For production use handling real client data, get an independent professional review.

Setup

Install dependencies:

npm install --prefix backend
npm install --prefix frontend

Create local env files from the examples:

cp backend/.env.example backend/.env
cp frontend/.env.local.example frontend/.env.local

Fill in backend/.env. At minimum you need Supabase, S3/R2, and a KEY_ENCRYPTION_KEY:

# Required: 32 random bytes, base64-encoded. Encrypts user API keys.
openssl rand -base64 32

Run the schema in the Supabase SQL editor for a fresh database:

backend/migrations/000_one_shot_schema.sql

(001_encrypt_api_keys.sql is only needed when upgrading a database created before key encryption.)

Start the backend and frontend:

npm run dev --prefix backend     # http://localhost:3001
npm run dev --prefix frontend    # http://localhost:3000

Open http://localhost:3000.

Required services

  • Supabase (Auth + Postgres)
  • S3-compatible object storage, e.g. Cloudflare R2
  • At least one model provider key (or let users supply their own via BYOK)
  • LibreOffice, for DOC/DOCX → PDF conversion

Checks

npm run build --prefix backend
npm run build --prefix frontend
npm run lint --prefix frontend

License

AGPL-3.0-only. If you run a modified version as a network service, you must make your source available under the same license.

About

Open-source AI assistant for legal work: document-grounded chat, AI redlining of Word docs, and Swiss case law lookup. Next.js + Express + Supabase, BYOK with encrypted keys.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 98.4%
  • Other 1.6%