DEV Community

SHOTA
SHOTA

Posted on

I Built an AI-Powered Japanese Trade Law Compliance Checker as a Chrome Extension

Japan's Subcontracting Act (Toriteki-ho / 取引適正化促進法, commonly called 下請法) governs transactions between large businesses and their subcontractors. It mandates specific payment terms, required contract clauses, and prohibits certain business practices — and violations carry significant penalties from the Fair Trade Commission.

The problem: compliance checking is tedious. Most small businesses and freelancers either don't know the rules or spend time manually cross-referencing contract documents against the law's requirements. I built ToritekiCheck, an AI-powered Chrome extension that analyzes contract text and flags potential violations in seconds.

What the Law Actually Requires

The Subcontracting Act applies to transactions where a larger company subcontracts to a smaller company (thresholds based on capital: manufacturing >=30M yen, services >=50M yen). When it applies, the ordering company must:

  1. Issue a written order (発注書) with specific required fields
  2. Pay within 60 days of receiving the goods/service
  3. Not require promissory note payment (手形払い) in many cases
  4. Not unilaterally reduce prices after work is complete
  5. Not return deliverables without cause

The extension checks for these conditions — specifically scanning for payment term violations and missing required clauses that are most commonly flagged in FTC investigations.

Architecture: Extension + Vercel API Proxy

The core analysis is done by an LLM. Rather than requiring users to provide their own API key, the extension routes requests through a Vercel serverless function:

Chrome Extension -> POST /api/llm/chat (Vercel) -> Claude API -> Response
Enter fullscreen mode Exit fullscreen mode

The Vercel function holds the API key server-side:

// /api/llm/chat/route.ts
export async function POST(request: Request) {
  const { messages, system } = await request.json();

  const response = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.ANTHROPIC_API_KEY!,
      'anthropic-version': '2023-06-01',
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      model: 'claude-haiku-4-5-20251001',
      max_tokens: 1024,
      system,
      messages,
    }),
  });

  return Response.json(await response.json());
}
Enter fullscreen mode Exit fullscreen mode

Using claude-haiku-4-5-20251001 keeps latency low and cost manageable for free-tier users.

Extracting Contract Text from the DOM

Contract documents come in several formats: PDF viewers, HTML pages, Google Docs embeds, and plain text areas. The extension uses a priority-ordered extraction strategy:

function extractContractText(): string {
  // Priority 1: User-selected text
  const selection = window.getSelection()?.toString().trim();
  if (selection && selection.length > 50) return selection;

  // Priority 2: Active textarea / contenteditable
  const activeEl = document.activeElement;
  if (activeEl instanceof HTMLTextAreaElement) return activeEl.value;
  if (activeEl?.getAttribute('contenteditable') === 'true') {
    return activeEl.textContent || '';
  }

  // Priority 3: Main content heuristic
  const candidates = [
    document.querySelector('article'),
    document.querySelector('main'),
    document.querySelector('[role="main"]'),
    document.querySelector('.contract'),
    document.body,
  ].filter(Boolean) as Element[];

  for (const el of candidates) {
    const text = el.textContent?.trim() || '';
    if (text.length > 200) return text.slice(0, 8000);
  }

  return '';
}
Enter fullscreen mode Exit fullscreen mode

The 8000-character limit prevents hitting the LLM's context window and keeps costs predictable.

The Analysis Prompt

The system prompt is the heart of the product. After several iterations with real contract samples, I settled on structured JSON output with severity levels:

const SYSTEM_PROMPT = `You are a Japanese Subcontracting Act compliance expert.

Analyze the provided contract text and identify potential violations or missing required elements.

Output a JSON object with this structure:
{
  "applicable": boolean,
  "violations": [
    {
      "type": string,
      "severity": "high" | "medium" | "low",
      "description": string,
      "relevant_text": string,
      "legal_basis": string
    }
  ],
  "required_clauses_present": {
    "transaction_type": boolean,
    "delivery_date": boolean,
    "inspection_date": boolean,
    "payment_method": boolean,
    "payment_date": boolean,
    "price": boolean
  },
  "summary": string
}

Focus on:
1. Payment terms exceeding 60 days after receipt
2. Promissory note payment requirements
3. Missing mandatory order form fields (Article 3)
4. Price reduction clauses that may violate Article 4
5. Return conditions that may violate Article 4`;
Enter fullscreen mode Exit fullscreen mode

Rendering Results

The popup receives the JSON and renders a color-coded compliance report:

function renderResults(analysis: AnalysisResult): void {
  const container = document.getElementById('results')!;

  if (!analysis.applicable) {
    container.innerHTML = `<div class="notice">この契約書には下請法が適用されない可能性があります。</div>`;
    return;
  }

  const highCount = analysis.violations.filter(v => v.severity === 'high').length;
  const statusClass = highCount > 0 ? 'danger' :
    analysis.violations.length > 0 ? 'warning' : 'safe';

  container.innerHTML = `
    <div class="status ${statusClass}">
      ${highCount > 0 ? `Warning: ${highCount} critical issues` :
        analysis.violations.length > 0 ? `Note: ${analysis.violations.length} issues` :
        'No issues detected'}
    </div>
    ${analysis.violations.map(v => `
      <div class="violation severity-${v.severity}">
        <p>${v.description}</p>
        <code>${v.relevant_text}</code>
        <small>${v.legal_basis}</small>
      </div>
    `).join('')}
    <div class="summary">${analysis.summary}</div>`;
}
Enter fullscreen mode Exit fullscreen mode

Handling Japanese Legal Text

Japanese legal documents have conventions that don't map cleanly to standard NLP:

  • Formal grammar patterns (〜するものとする, 〜する旨) differ significantly from everyday text
  • Counter-intuitive negations: 「支払わないものとする」 looks structurally similar to 「支払うものとする」
  • Payment terms might be expressed as 「60日以内」, 「2ヶ月」, or embedded in prose

The LLM handles most of these naturally, but I add explicit guidance in the prompt to flag ambiguous payment clauses for human review rather than treating them as definitive violations.

Try ToritekiCheck

ToritekiCheck is free for basic compliance scanning. The Pro plan adds detailed clause-by-clause analysis, scan history, and PDF report export.

View on Chrome Web Store

If you work with Japanese business contracts and want to share feedback on analysis accuracy, leave a comment below.


Other tools I've built:

View on Chrome Web Store
View on Chrome Web Store

Top comments (0)