Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/test-docx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: test:docx

on:
push:
branches: ["**"]
pull_request:
branches: ["**"]

jobs:
test-docx:
name: docxTrackedChanges round-trip suite
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js 20
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: backend/package-lock.json

- name: Install backend dependencies
run: npm ci --prefix backend

- name: Run docx round-trip suite
run: npm run test:docx --prefix backend

- name: Verify fixture regeneration is a no-op (drift guard)
run: |
cd backend && HUGO_FIXTURES_REGEN=1 npx tsx tests/docx-round-trip/fixtures/generate-fixtures.ts
cd "$GITHUB_WORKSPACE" && git diff --exit-code backend/tests/docx-round-trip/fixtures
202 changes: 152 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,99 @@
# Mike

Mike is a legal document assistant with a Next.js frontend, an Express backend, Supabase Auth/Postgres, and Cloudflare R2-compatible object storage.
Mike is a legal document assistant with a Next.js frontend, an Express backend, Supabase Auth/Postgres, S3-compatible document storage, and LLM-powered chat, review, and document editing workflows.

Website: [mikeoss.com](https://mikeoss.com)
This repository is licensed under AGPL-3.0-only. If you run a modified network service, make the corresponding source available to users as required by the license.

## Contents
## What Is Included

- `frontend/` - Next.js application
- `backend/` - Express API, Supabase access, document processing, and database schema
- `backend/schema.sql` - Supabase schema for fresh databases
- `backend/migrations/` - incremental database updates for existing deployments
- `frontend/` - Next.js app with authentication, projects, documents, assistant chat, workflows, tabular reviews, and account settings.
- `backend/` - Express API for auth-aware data access, document upload/conversion, chat/tool execution, model routing, workflows, tabular review generation, downloads, and account lifecycle operations.
- `backend/migrations/` - `node-pg-migrate` migrations for Supabase/Postgres.
- `backend/migrations/000_one_shot_schema.sql` - one-shot SQL schema for fresh Supabase databases.
- `backend/tests/` - Vitest coverage for auth hardening, cross-tenant access, document processing, chat/tool streams, account deletion, storage, and integration flows.
- `supabase/` - local Supabase CLI configuration.

## Prerequisites
## Notable Changes In This Version

- Replaced the single `backend/schema.sql` setup path with migration-based database management.
- Added RLS policy migrations, auth lookup RPCs, workflow sharing checks, encrypted API key storage, soft-delete user profiles, and account deletion jobs.
- Split backend chat tooling into focused modules for citations, document context, tool schemas, tool running, streaming, workflow loading, and individual tools.
- Added account deletion and restore token support, backend request logging, LLM rate limiting, PDF queue helpers, validation helpers, and a models endpoint.
- Hardened auth, storage, upload, project, document, tabular, workflow, user, and LLM integration code.
- Updated frontend account, project, document, assistant, workflow, and tabular review flows.
- Moved shared frontend providers, contexts, logo, Supabase client, and utilities under the app tree.
- Added backend test suites and DOCX CI workflow coverage.

## Requirements

- Node.js 20 or newer
- npm
- git
- A Supabase project
- A Cloudflare R2 bucket, MinIO bucket, or another S3-compatible bucket
- At least one supported model provider API key: Anthropic, Google Gemini, or OpenAI
- LibreOffice installed locally if you need DOC/DOCX to PDF conversion
- Supabase project with Auth and Postgres
- S3-compatible object storage, such as Cloudflare R2 or MinIO
- LibreOffice available on the backend host for DOC/DOCX to PDF conversion
- At least one supported model provider key:
- Anthropic
- Google Gemini
- OpenRouter

## Database Setup
## Install

For a new Supabase database, open the Supabase SQL editor and run:
Install backend and frontend dependencies:

```sql
-- copy and run the contents of:
-- backend/schema.sql
```bash
npm install --prefix backend
npm install --prefix frontend
```

The schema file is based on `supabase-migration.sql` and folds in the later files in `backend/migrations/`.

For an existing database, do not run the full schema file over production data. Apply the incremental files in `backend/migrations/` instead.

## Environment

Create local env files:
Create local environment files:

```bash
touch backend/.env
touch frontend/.env.local
cp backend/.env.example backend/.env
cp frontend/.env.local.example frontend/.env.local
```

Create `backend/.env`:
## Backend Configuration

Edit `backend/.env`:

```bash
PORT=3001
FRONTEND_URL=http://localhost:3000
DOWNLOAD_SIGNING_SECRET=replace-with-a-random-32-byte-hex-string

SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SECRET_KEY=your-supabase-service-role-key
SUPABASE_ANON_KEY=your-supabase-anon-key

DATABASE_URL=postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres

DOWNLOAD_SIGNING_SECRET=replace-with-a-random-secret-min-32-chars

R2_ENDPOINT_URL=https://your-account-id.r2.cloudflarestorage.com
R2_ACCESS_KEY_ID=your-r2-access-key
R2_SECRET_ACCESS_KEY=your-r2-secret-key
R2_BUCKET_NAME=mike

GEMINI_API_KEY=your-gemini-key
ANTHROPIC_API_KEY=your-anthropic-key
OPENAI_API_KEY=your-openai-key
GEMINI_API_KEY=your-gemini-key
OPENROUTER_API_KEY=your-openrouter-key

RESEND_API_KEY=your-resend-key
USER_API_KEYS_ENCRYPTION_SECRET=your-long-random-secret
HUGO_MASTER_KEY=hex-encoded-32-byte-key
HUGO_RESTORE_TOKEN_SECRET=random-restore-token-secret
```

Create `frontend/.env.local`:
Notes:

- `SUPABASE_SECRET_KEY` must be the service role key.
- `SUPABASE_ANON_KEY` is optional at runtime but required by the cross-tenant test suite.
- `DATABASE_URL` should use the direct Supabase Postgres connection, not the pooler.
- `HUGO_MASTER_KEY` encrypts user-supplied model API keys at rest. Generate one with `openssl rand -hex 32`.
- `HUGO_RESTORE_TOKEN_SECRET` signs account restore tokens. Generate one with `openssl rand -base64 48`.
- Provider keys can be configured globally in `.env`; user-managed keys are stored encrypted when enabled.

## Frontend Configuration

Edit `frontend/.env.local`:

```bash
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
Expand All @@ -73,17 +102,32 @@ SUPABASE_SECRET_KEY=your-supabase-service-role-key
NEXT_PUBLIC_API_BASE_URL=http://localhost:3001
```

Supabase values come from the project dashboard. Use the project URL for `SUPABASE_URL` / `NEXT_PUBLIC_SUPABASE_URL`, the service role key for `SUPABASE_SECRET_KEY`, and the anon/public key for `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY`. If your Supabase project shows multiple key formats, use the legacy JWT-style anon and service role keys expected by the Supabase client libraries.
The frontend uses Supabase Auth directly and calls the backend through `NEXT_PUBLIC_API_BASE_URL`.

## Database Setup

Provider keys are only needed for the models and email features you plan to use. Model provider keys can be configured in `backend/.env` for the whole instance, or per user in **Account > Models & API Keys**. If a provider key is present in `backend/.env`, that provider is available by default and the matching browser API key field is read-only.
For a fresh Supabase project, run the one-shot schema in the Supabase SQL editor:

## Install
```sql
-- copy and run backend/migrations/000_one_shot_schema.sql
```

Install each app package:
For an existing deployment, use migrations from the backend package:

```bash
npm install --prefix backend
npm install --prefix frontend
npm run db:migrate --prefix backend
```

Rollback the most recent migration:

```bash
npm run db:migrate-down --prefix backend
```

Create a new migration:

```bash
npm run db:migrate-create --prefix backend -- <migration-name>
```

## Run Locally
Expand All @@ -94,32 +138,90 @@ Start the backend:
npm run dev --prefix backend
```

Start the main app:
Start the frontend:

```bash
npm run dev --prefix frontend
```

Open `http://localhost:3000`.

## First Run
First local run:

1. Sign up in the app.
2. If you did not set provider keys in `backend/.env`, open **Account > Models & API Keys** and add an Anthropic, Gemini, or OpenAI API key.
3. Create or open a project and start chatting with documents.
1. Sign up in the frontend.
2. If Supabase email confirmation is enabled, confirm the account or disable confirmation for local development.
3. Create a project.
4. Upload documents.
5. Open assistant chat, workflows, or tabular reviews.

## Troubleshooting

**Sign-up confirmation email never arrives.** Confirmation emails are sent by Supabase Auth, not by Mike. For local development, the simplest fix is to disable email confirmation in **Supabase > Authentication > Providers > Email**. For production, configure custom SMTP in Supabase; the built-in mailer is heavily rate-limited and may be restricted on newer projects.
## Available Features

**The model picker shows a missing-key warning.** Add a key for that provider in **Account > Models & API Keys**, or configure the provider key in `backend/.env` and restart the backend.
- Project workspaces with document lists and project-specific assistant chat.
- Document upload, conversion, viewing, versioning, quote highlighting, and signed downloads.
- Assistant chat with document-aware tools for reading, finding, editing, replicating, and generating DOCX output.
- Built-in workflow execution and workflow sharing checks.
- Tabular review creation, generation, regeneration, and export support.
- User model settings with encrypted API key storage.
- Soft-delete account flow with restore token support and asynchronous deletion jobs.
- LLM request rate limiting and backend request logging.

**DOC or DOCX conversion fails.** Install LibreOffice locally and restart the backend so document conversion commands are available on the process path.
## Test And Verification Commands

## Useful Checks
Backend build:

```bash
npm run build --prefix backend
```

Frontend build and lint:

```bash
npm run build --prefix frontend
npm run lint --prefix frontend
```

Backend test suites:

```bash
npm run test:no-db --prefix backend
npm run test:docx --prefix backend
npm run test:golden-log --prefix backend
npm run test:auth-hardening --prefix backend
npm run test:saga --prefix backend
npm run test:cross-tenant --prefix backend
```

`test:cross-tenant` needs a Supabase test project and valid `SUPABASE_URL`, `SUPABASE_SECRET_KEY`, and `SUPABASE_ANON_KEY`.

## Deployment Notes

- The backend `start` script runs migrations before starting the compiled server.
- Build the backend before production start:

```bash
npm run build --prefix backend
npm run start --prefix backend
```

- The frontend includes OpenNext Cloudflare scripts:

```bash
npm run preview --prefix frontend
npm run deploy --prefix frontend
```

- Configure CORS with `FRONTEND_URL`.
- Ensure LibreOffice is installed on the backend runtime if document conversion is required.
- Use private buckets for document storage and expose files through the backend download routes.

## Troubleshooting

- `DOCX conversion failed`: install LibreOffice and restart the backend.
- `Missing provider key`: configure a global provider key in `backend/.env` or add a user key in account settings.
- `Database migration failed`: verify `DATABASE_URL` uses the direct Supabase database host on port `5432`.
- `Cross-tenant tests fail during sign-in`: set `SUPABASE_ANON_KEY` and use a disposable Supabase test project.
- `Frontend cannot reach backend`: verify `NEXT_PUBLIC_API_BASE_URL` and backend CORS `FRONTEND_URL`.

## License

AGPL-3.0-only. See `LICENSE`.
33 changes: 26 additions & 7 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
PORT=3001
FRONTEND_URL=http://localhost:3000

# HMAC key used to sign /download/:token URLs. Required at startup.
# Generate with: openssl rand -hex 32
# Use a dedicated secret distinct from SUPABASE_SECRET_KEY.
DOWNLOAD_SIGNING_SECRET=replace-with-a-random-32-byte-hex-string
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SECRET_KEY=your-supabase-service-role-key
# Required for cross-tenant test suite (npm run test:cross-tenant) to sign test
# users into anon-key sessions and obtain real JWTs. Optional for runtime.
SUPABASE_ANON_KEY=

DOWNLOAD_SIGNING_SECRET=your-random-signing-secret-min-32-chars

R2_ENDPOINT_URL=https://your-account-id.r2.cloudflarestorage.com
R2_ACCESS_KEY_ID=your-r2-access-key
Expand All @@ -15,6 +15,25 @@ R2_BUCKET_NAME=mike

GEMINI_API_KEY=your-gemini-key
ANTHROPIC_API_KEY=your-anthropic-key
OPENAI_API_KEY=your-openai-key

# Optional — when set, enables raw LLM stream console logging (debug only; remove in production)
LLM_STREAM_DEBUG=

OPENROUTER_API_KEY=your-openrouter-key
RESEND_API_KEY=your-resend-key
USER_API_KEYS_ENCRYPTION_SECRET=your-long-random-secret

# Migration runner — Supabase direct connection, NOT the pgBouncer pooler.
# Format: postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres
DATABASE_URL=

# LLM rate limiting (per-user, applies to all LLM-spending routes)
RATE_LIMIT_WINDOW_MS=60000 # Sliding window in milliseconds (default: 60000 = 1 minute)
RATE_LIMIT_MAX=20 # Max LLM requests per user per window (default: 20)

# CLEAN-05 — at-rest encryption of user LLM API keys (AES-256-GCM)
# Generate with: openssl rand -hex 32
HUGO_MASTER_KEY=

# CLEAN-44 — HMAC secret for account-restore tokens (30-day soft-delete window)
# Generate with: openssl rand -base64 48
HUGO_RESTORE_TOKEN_SECRET=
1 change: 0 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ dist
.env*
!.env.example
*.log
logs/
.DS_Store
8 changes: 0 additions & 8 deletions backend/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading