Keiyaku — Contract AI Reviewer
Self-hosted Japanese SME contract review SaaS. Cloned from time7676/keiyaku (private), deployed on this VPS 2026-05-05.
URLs
- Production: https://keiyaku.cocon-lab.com
- Default locale:
/ja(also/en) - Origin:
127.0.0.1:3002
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 17 —
keiyakuDB,keiyakuuser, password in.env.localDATABASE_URL - Storage — local fs at
/var/www/keiyaku/storage/contracts(replaces GCS)lib/storage.tspatched to fs API- HMAC-signed download URLs via
/api/files/[path]?expires=…&sig=… LOCAL_STORAGE_SIGNING_SECRETenv
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.service→node .next/standalone/server.json127.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 usesHOSTNAMEenv forrequest.url, breaking i18n redirect URL)
Pending (user must fill in .env.local)
GEMINI_API_KEYNEXT_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