Keiyaku — Contract AI Reviewer

Self-hosted Japanese SME contract review SaaS. Cloned from time7676/keiyaku (private), deployed on this VPS 2026-05-05.

URLs

Stack

  • Next.js 15.2.1 (App Router, standalone build, output: standalone)
  • React 19, TypeScript, Tailwind 3
  • next-intl (ja default, en)
  • Drizzle ORM + PostgreSQL 17 (local)
  • Firebase Auth + Admin SDK (cloud — keys TBD)
  • Gemini API (Google AI Studio — key TBD)
  • Stripe (optional, blank)
  • Resend (optional, blank)
  • @react-pdf/renderer, html2pdf.js, pdf-parse, mammoth — doc processing

Local services (self-hosted)

  • Postgres 17keiyaku DB, keiyaku user, password in .env.local DATABASE_URL
  • Storage — local fs at /var/www/keiyaku/storage/contracts (replaces GCS)
    • lib/storage.ts patched to fs API
    • HMAC-signed download URLs via /api/files/[path]?expires=…&sig=…
    • LOCAL_STORAGE_SIGNING_SECRET env

Cloud services (still external)

  • Firebase Auth (user-provided keys, blank for now)
  • Gemini API (Google AI Studio)

Deployment

  • Workspace: /var/www/keiyaku/
  • systemd: keiyaku-app.servicenode .next/standalone/server.js on 127.0.0.1:3002
  • nginx vhost: /etc/nginx/sites-enabled/keiyaku.cocon-lab.com
  • TLS: Let’s Encrypt ECDSA via Cloudflare DNS-01 (/etc/letsencrypt/live/keiyaku.cocon-lab.com/)
  • DB migrations: ./node_modules/.bin/drizzle-kit migrate

Custom patches

  • lib/storage.ts — GCS → local fs (drop-in)
  • app/api/files/[path]/route.ts — HMAC signed-URL handler (new)
  • middleware.ts — wraps next-intl middleware to fix Location/x-middleware-rewrite host (Next.js standalone uses HOSTNAME env for request.url, breaking i18n redirect URL)

Pending (user must fill in .env.local)

  • GEMINI_API_KEY
  • NEXT_PUBLIC_FIREBASE_* (6 keys)
  • FIREBASE_ADMIN_CREDENTIALS (base64 service-account JSON)
  • Optional: STRIPE_*, RESEND_API_KEY

Repo

  • GitHub: time7676/keiyaku (private)
  • Created 2026-03-22, last push 2026-04-25
  • 2 branches: main, development

Mobile optimization (nginx)

  • gzip on (compression for HTML/CSS/JS/JSON/SVG)
  • Long-cache /_next/static/ (immutable, 365d)
  • HTTP/2 enabled
  • client_max_body_size 25M (contract uploads)
  • WS upgrade headers (HMR not needed in prod)

Operational

  • Restart: systemctl restart keiyaku-app
  • Logs: journalctl -u keiyaku-app -f
  • Rebuild: cd /var/www/keiyaku && rm -rf .next && set -a && source .env.local && set +a && NODE_ENV=production npm run build && cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/ && systemctl restart keiyaku-app