Skip to content

Changelog

Release history for PII Firewall SDK, MCP Server, and REST API.


Unreleased (targeting v0.2.0 — 2026-05-01)

🟡 Changed (Session 172 — app.piifirewall.com public-facing terminology cleanup)

  • app/index.html: meta description updated (publicly visible in Google search snippets)
  • app/src/Login.jsx: login screen badge text updated (visible to all unauthenticated visitors)
  • ⚠️ Requires manual deploy via npm run build --workspace=@pii-firewall/app

🟡 Changed (Session 172 — Blog article withdrawn)

  • landing/blog.html: Removed the article card from the blog index
  • landing/blog/himitsu-bunsan.html: File deleted
  • landing/_redirects: Added Cloudflare 301 permanent redirects from /blog/himitsu-bunsan and /blog/himitsu-bunsan.html to /blog

🟡 Changed (Session 172 — Crawl blocking for not-yet-public landing pages)

  • landing/portal.html / blog.html / index-v2.html / docs.html: Implemented 3-layer crawl blocking (HTML meta noindex,nofollow,noarchive,nosnippet,noimageindex + _headers X-Robots-Tag + new landing/robots.txt Disallow). To be removed page-by-page per the procedure in internal-docs/infra/pre-production-checklist.md §H-Y when each page is ready for public release.
  • landing/robots.txt: Added explicit User-agent blocks for major AI training crawlers (GPTBot / ClaudeBot / anthropic-ai / Google-Extended / PerplexityBot / Bytespider / CCBot / Meta-ExternalAgent / Applebot-Extended and 15+ others). Ensures bots that respect only their own name string are blocked even when a wildcard is set.

🟡 Changed (Session 172 — Landing page terminology cleanup)

  • landing/index.html: Unified technical wording to "Cryptography" / "暗号技術" (13 occurrences). The Privacy-by-Design / zero-knowledge messaging is preserved.

🔴 Breaking (Session 172 — Admin Phase 3-A RBAC + Supabase Auth full migration)

  • ADMIN_SECRET fully retired: The admin panel and all 9 /admin/* proxy endpoints have migrated from the legacy ADMIN_SECRET Bearer auth to Supabase Auth + admin_users RBAC. After deployment the ADMIN_SECRET Railway variable is no longer required (manual deletion recommended)
  • MFA (TOTP) mandatory: Admin panel login now requires Email OTP + TOTP MFA (AAL=aal2)

🟢 Added (Session 172 — Admin Phase 3-A RBAC)

  • proxy/migrations/004_admin_users.sql (new): admin_users table (email PK / role CHECK 3 values / active / created+updated audit columns / note) + idx_admin_users_active partial index + updated_at trigger + initial admin kmishimasl@gmail.com
  • proxy/index.js: New requireAdminRole(allowedRoles) middleware (JWT verification → AAL=aal2 check → admin_users lookup → role check). New /admin/me, /admin/users CRUD endpoints (GET/POST/PATCH/DELETE). All 9 existing admin endpoints rewritten to use the middleware. Alert ACK/Resolve operator identifier now uses the authenticated email (replacing the Phase 2-A 'admin' constant)
  • admin/src/lib/supabase.js (new): Supabase client initialization + getAccessToken / getAuthHeader / getAuthState / hasTotpFactor / signOut helpers
  • admin/src/Login.jsx (new, ~380 lines): 4-state consolidated login screen (email → OTP → mfa_challenge → mfa_enroll). Ported from landing/console.html OTP + MFA logic (90% reuse) and React-ified
  • admin/src/App.jsx: Fully removed ADMIN_SECRET auth. Added authedFetch wrapper, refreshAuthState orchestrator, can(action) RBAC helper. 5-state authState gating (loading / unauthenticated / mfa_required / mfa_enroll / authenticated / forbidden). Topbar role badge (🛡️/🔧/👁️ + email) + sign-out button. RBAC guards (disabled + tooltip) on Alert ACK/Resolve, Credit Grant, Set Plan, and API key Revoke buttons
  • admin/src/App.jsx: Added "🛡️ Admin User Management" section to the Policy tab (admin role only: add / role change / active toggle / delete; protected against demoting/deleting the last active admin)
  • admin/src/i18n/ja.jsonen.json: ~50 new keys (login.email.*, login.otp.*, login.busy.*, login.error.*, mfa.challenge.*, mfa.enroll.*, mfa.error.*, auth.*, role.*, rbac.error.*, rbac.users.*)

🟢 Added (Session 171 — Admin Phase 2-C CSV Export)

  • admin/src/lib/csv-export.js (new, ~90 lines): toCsv(rows, columns) + downloadCsv(baseName, rows, columns) utilities. RFC 4180 compliant, UTF-8 BOM prepended (for direct Excel JA import), arrays/objects JSON-stringified, null/undefined empty-stringified
  • admin/src/App.jsx: Added 📊 CSV button to 6 tables (Logs / Alerts / Users / Customers / PII Analysis / Credits). All exports reflect Phase 2-B filter state
  • admin/src/App.jsx: Chose self-implementation over papaparse (8.7KB bundle increase vs. 45KB for papaparse)
  • admin/src/App.jsx: ⚠️ P15 compliance — exports contain only aggregates, metadata, and masked tokens. No raw PII (not present in DB)
  • admin/src/App.jsx: Auto timestamp in filename (e.g., logs_2026-05-14_1830.csv)
  • admin/src/i18n/ja.jsonen.json: 36 keys added (csv.button, csv.tooltip, csv.empty + 33 column headers)

🟢 Added (Session 171 — Admin Phase 2-B Date Range & Search Filter)

  • admin/src/App.jsx: Integrated useFilter-equivalent state. Presets (Today / 7d / 30d / 90d / All / Custom) + native <input type="date"> (Custom only) + search box. No new packages required (chose native HTML over react-day-picker)
  • admin/src/App.jsx: Filter state synced to URL query params (?preset=7d&from=...&to=...&q=...). Bookmark and shared URL reproduce filter state
  • admin/src/App.jsx: renderFilterBar() helper shared across 4 tabs (Logs / Alerts / Users / Customers). matchedCount always shown on the right
  • admin/src/App.jsx: Filter applied to Logs (timestamp + email/endpoint/ai_service search), Alerts (created_at + alert_type/email/description search, combined with status filter), Users (filtered to users with logs in range), Customers (lastActive + email search)
  • admin/src/i18n/ja.jsonen.json: 14 keys added (filter.range, filter.preset.*, filter.from/to/search/clear/matched/empty, filter.searchPlaceholder)

🟢 Added (Session 171 — Admin Phase 2-A Alert ACK/Resolve Workflow)

  • proxy/migrations/003_alerts_ack_resolve.sql (new): Added 6 columns to alerts table (status / acknowledged_at / acknowledged_by / resolved_at / resolved_by / resolution_note). CHECK constraint limits status to 3 values (open / acknowledged / resolved). Added idx_alerts_status index + idx_alerts_status_open partial index. Backward compatible: existing rows automatically initialized to status='open'
  • proxy/index.js: Added 2 endpoints PATCH /admin/alerts/:id/ack and PATCH /admin/alerts/:id/resolve. Resolve can be invoked directly without prior ACK (auto-fills acknowledged_* for audit integrity). resolution_note truncated at 1000 chars (DoS protection). Bearer ADMIN_SECRET auth
  • admin/src/App.jsx: Alert workflow UI — status badges (🔴 Open / 🟡 Acknowledged / 🟢 Resolved), status filter tabs (All / Open / Acknowledged / Resolved), ACK button, Resolve modal (resolution note, 1000 char limit), post-resolve display of operator / timestamp / note. Default filter is "Open"
  • admin/src/App.jsx: Topbar open-critical badge (clicking jumps to Alerts tab "Open" filter). Dashboard "Critical Alerts" stat card now uses openCriticalCount (consistent with "Unresolved" subtitle)
  • admin/src/i18n/ja.jsonen.json: 24 keys added (alert.status.*, alert.filter.*, alert.action.*, alert.meta.*, alert.modal.*, alert.error.*, alert.empty.filtered, badge.openCritical)

🟡 Changed (Session 170 — Topbar color follow-up)

  • admin/src/App.jsx: .badge-red changed from --accent2 harsh red to --warn amber (unifies "100 critical alerts" topbar badge and CRITICAL badge inside alert cards)
  • admin/src/App.jsx: .btn-pdf (Export PDF button) changed from --accent2 red to calm slate-blue. Supports both dark/light modes

⚪ Docs (Session 170 wrap)

  • Session 170 handoff and session report created (Session/PIIFirewall_session_2026-05-14_Session170.md + Session/handoff_2026-05-14_Session170.md)
  • internal-docs/project/sprint.md updated (Session 170 block added, Session 168 moved to backlog, next TODO updated for Session 171)
  • memory/project_progress.md updated (admin completeness 75%→85%)

🟢 Added (Session 170 — Admin Phase 1-B Chart.js & dark/light theme)

  • admin/: Implemented dark/light theme toggle (☀/🌙 button in Topbar, persists via localStorage.admin_theme, initial detection via prefers-color-scheme)
  • admin/src/lib/chart-theme.js (new): Chart.js theme integration (cssVar() helper, getChartPalette(), applyChartDefaults(), auto re-render on data-theme attribute change)
  • admin/src/components/charts/ (new): LineChart / BarChart / PieChart / DonutChart wrapper components
  • Dashboard tab: Added daily-trend LineChart (last 14 days, 2 series: requests / PII detections), replaced CSS bar graph for AI service usage with horizontal BarChart
  • PII Analysis tab: Type breakdown BarChart (horizontal, danger color, auto-expanding height) + Category DonutChart (5 categories, total count in center) in 2-column layout. Added PII_CATEGORY_MAP (16 types → 5 categories)
  • Alerts tab: Severity-based PieChart (critical / high / info) + large-number summary card (3 columns, color-coded to match)
  • Users tab: User ranking horizontal BarChart (Top 10, 2 series: requests / PII detections)
  • Logs tab: Hourly usage BarChart (24 hours, off-hours highlighted in danger color) + large-number off-hours summary card. Defines 7:00–22:00 as business hours for shadow usage detection
  • BarChart component: Per-bar coloring support (colors array for semantic color per bar, backward compatible)
  • i18n: Added theme.* (3), chart.* (16), severity.* (3), alerts.summary, users.rankingTitle, and logs.* (5 hourly-related keys) to both ja/en dictionaries

🟢 Added / 🔵 Fixed (Session 170 — Alert i18n structured refactor / Plan A)

  • Supabase migration 002_alerts_i18n.sql (new): Adds description_template TEXT + description_params JSONB columns to alerts table (both nullable, backward compatible) + idx_alerts_template index
  • proxy/cloud-logger.js createAlert(): Now accepts description_template / description_params and writes them to Supabase. Legacy description (Japanese completed string) kept for backward compatibility
  • proxy/cloud-logger.js checkAlertRules(): Emits structured params for 3 alert sites (large_payload / bypass_attempt / prompt_injection)
  • proxy/index.js: Emits structured params for payment_failed (Stripe webhook) and injection_in_upload (file upload)
  • admin/src/App.jsx: Added formatAlertDescription() / formatAlertType() helpers. Prefers description_template, falls back to legacy description. Avoids printing raw key when template is not registered
  • admin/src/i18n/{ja,en}.json: Added 5 alert.type.* keys + 5 alert.* template keys (with ) to both ja/en
  • Known limitation: Injection label itself (e.g., 制限の解除試行) is hardcoded Japanese in core/. Stored as-is in params; admin templates translate only the surrounding text. Future: core/ ENUM refactor

🟡 Changed (Session 170 — Color guideline compliance)

  • admin/src/App.jsx: Added --warn CSS variable per design guidelines (#d4956a warm amber). Light mode uses #b6824a for better contrast. Migrated "warning/risk" usages from harsh red --accent2 to softer --warn (Critical Alerts numbers, Injections Detected numbers, off-hours large number, severity critical number, .pii-tag.danger)
  • admin/src/lib/chart-theme.js: Updated warning palette semantic to derive from --warn (was --accent3 gold). Changed series[1] from accent2 to warn
  • admin/ chart usages: PII detections, PII type, user PII, off-hours bars now use color: "warning" instead of "danger" (reserving --accent2 for true errors only)

🟢 Added (Session 169 — Team Management Tab)

  • landing/console.html: Added 👥 Team Management tab. Business+ users get full features (member list, invite, remove). Free/Starter users see a Business upgrade prompt (PLG gate)
  • landing/console.html: Detects ?team_accept=1 URL parameter and auto-calls POST /team/accept (invitation acceptance flow from email links)
  • proxy/index.js: Updated maxMembersMap to { free:1, starter:1, business:10 } (was { starter:5, business:50 })

🔴 Breaking / ⚪ Docs (Session 162 — P-17 RAG v2 clean-start)

  • @pii-firewall/rag v0.0.0-archived: Legacy implementation archived. rag/src/ renamed to rag/src.history-2026-05-11/ (git history preserved). Legacy API now returns 503 stub
  • New design docs (internal-docs only): P-17 RAG Pipeline design v2 (portable library covering P-14 / Node SDK / Python SDK / MCP across 4 execution contexts) + Core TTL env-var design (PIIFW_TOKEN_TTL as an independent design doc)
  • Two legacy design docs archived: p17-secure-rag-pipeline-design.md (former v0.2.1) and rag-core-integration-design.md archived because they do not meet the new standard (Architecture Principles v1.1 + Design Doc Guide v1.1)
  • New @pii-firewall/rag implementation will start after P-17 v2 design approval. Until then, legacy API calls return a RAG_ARCHIVED error (503)

⚪ Docs / 🟢 Added (Session 158 — SSoT bundle-copy sync CI script)

  • scripts/sync-credential-patterns.js (new): Treats core/data/credential-patterns.json as SSoT and verifies or writes the Python SDK / Java SDK bundle copies. Supports --check / --write / --ci modes. Also verifies the <include>credential-patterns.json</include> registration in Java's pom.xml (Session 156 incident protection)
  • package.json: Added npm run sync:patterns / npm run sync:patterns:check
  • .github/workflows/ssot-sync-check.yml (new): On PR / push touching credential-patterns.json, automatically runs --check --ci and fails on drift (Java repo is separate and skipped in CI)
  • internal-docs/design/credential-patterns-design.md: Documented the new sync workflow (npm run sync:patterns) in §1
  • internal-docs/design/p15-web-security-scanner-design.md: Major redesign in Session 158. Repositioned as "PII + Injection + LLMjacking integrated defense engine"; web scan integrated into existing 4 Tiers; switched to local execution model

🟢 Added (Session 157 — P15-2: LLMjacking Threat Intelligence Engine)

  • core/src/pii-detector.js loadCredentialPatterns(): Added costEstimate / provider / tags field mapping when loading credential patterns
  • core/src/pii-detector.js detectPII(): Credential pattern matches now pass through risk / costEstimate / provider / tags / remediation fields in candidate objects. Standard PII patterns (email, phone, etc.) do not carry these fields — backward compatible
  • proxy/index.js /detect endpoint: Candidates with costEstimate or tags: ["llmjacking"] are enriched with a llmjacking_context object containing threat / estimated_daily_cost / provider / tags / remediation (array) / reference
  • ZAP Groovy already complete (Session 155 v0.2.0 already outputs costEstimate / remediation in alert descriptions)

🔵 Fixed (Session 156 — Java SDK: pom.xml resource include missing)

  • pii-firewall-java/pii-firewall-java-core/pom.xml: Added credential-patterns.json to <build><resources><resource><includes>. The file was added to resources in Session 155 but not registered in pom.xml, causing getResourceAsStream("credential-patterns.json") to return null. After fix: mvn test 89 tests, 0 Failures, 0 Errors (commit 31db33f)

🟢 Added (Session 155 — P-JSON++: SSoT integration for ZAP Groovy / Python SDK / Java SDK)

  • scanner/zap-rules/piifw-passive-scan.groovy v0.2.0: Removed 15 hardcoded patterns. Now loads /zap/wrk/core/data/credential-patterns.json via JsonSlurper, expanded to 19 patterns (Replicate / AWS STS / Docker Registry Token added). Alerts now include id / provider; cwe / wascId are read dynamically from JSON
  • scanner/docker-compose.yml + .github/workflows/weekly-web-scan.yml: Added core/data/ mount as /zap/wrk/core/data:ro (both local and GHA)
  • python-sdk/pii_firewall/_local/credential-patterns.json (new): SSoT bundled copy. Included in wheel via [tool.setuptools.package-data] in pyproject.toml
  • python-sdk/pii_firewall/_local/detector.py: Added load_credential_patterns() (cached). The hardcoded api_key regex in PATTERNS_JA / PATTERNS_EN_UNIVERSAL is replaced with a JSON-driven spread. Python SDK detection expanded by 9 additional types
  • pii-firewall-java/pii-firewall-java-core/src/main/resources/credential-patterns.json (new): SSoT bundled copy (packaged in jar)
  • RegexEngine.java: Added loadCredentialPatterns(). Reads via getResourceAsStream("/credential-patterns.json"), appended to BOTH jaPatterns and enPatterns (credentials are language-agnostic). Removed API_KEY entries from pii-patterns.json (ja + en)

🔴 Breaking (Session 155 — Python SDK / Java SDK detection type granularity)

  • Python SDK detect_pii() / mask_pii(): Old type === "api_key" is replaced by 19 individual pattern IDs (anthropic-api-key, etc.)
  • Java SDK Detection.type: Old "API_KEY" is replaced by 19 individual pattern IDs (anthropic-api-key, etc.). Downstream code branching on hasType(hits, "API_KEY") must migrate

🟢 Added (Session 154 — P-JSON / P-JSON+: Credential Patterns Single Source of Truth)

  • core/data/credential-patterns.json (new): Source of truth data file for 19 credential patterns. Schema: id / name / regex / risk / confidence / cwe / wascId / tags / provider / costEstimate / remediation. Includes Anthropic / OpenAI / Google AI / AWS / GitHub PAT / Stripe Live / HuggingFace / Groq / Perplexity / Replicate (10 existing) + JWT / Google OAuth / Slack Bot / Slack User / SSH Private Key / DB connection strings / Basic Auth URL / AWS STS / Docker Registry Token (9 new)
  • core/src/pii-detector.js: Added loadCredentialPatterns() function. The hardcoded api_key regex in PATTERNS_JA / PATTERNS_EN_UNIVERSAL is replaced with JSON-based loading. mask_pii() / detect_pii() detection coverage expanded by 9 additional types (JWT / Google OAuth / Slack Bot/User / SSH / DB / Basic Auth / AWS STS / Docker)

🔴 Breaking (Session 154 — Credential detection type granularity)

  • mask_pii() / detect_pii() type field: Previously all 10 credential variants were returned under a single api_key type. They now return individual pattern IDs (anthropic-api-key / openai-api-key / stripe-secret-key-live / aws-access-key-id / github-pat / huggingface-token / groq-api-key / perplexity-api-key / replicate-api-key / google-ai-key, etc.). Downstream code branching on type === "api_key" must migrate to individual IDs or tags-based matching

🟡 Changed (Session 151 — Task C: Extracted 3 remaining hardcoded inventories to JSON / separate files)

  • proxy/data/ai-providers.json (new): Source of truth for 25 Shadow AI monitored services. Replaces the inline DEFAULT_AI_SERVICES array in proxy/index.js. Future additions and policy changes are now handled by editing this JSON only (no code changes)
  • proxy/index.js: DEFAULT_AI_SERVICES is now loaded via require("./data/ai-providers.json").services. The 30-line inline definition is reduced to 2 lines
  • proxy/data/ui-providers.json (new): Source of truth for Developer Console UI provider settings (PROVIDERS / COMING_SOON). Contains models, API key acquisition steps, icons/colors for OpenAI / Anthropic / Google. COMING_SOON expanded to include DeepSeek / xAI / Together / Perplexity
  • proxy/providers.js: Reduced to a thin wrapper that loads from ui-providers.json. 115 lines → 21 lines
  • extension/content/monitored-sites.js (new): Exposes Extension's file PII scan target sites via global variable PIIFW_MONITORED_FILE_SITES. Loaded before content.js
  • extension/content/content.js: FILE_INPUT_SITES now references PIIFW_MONITORED_FILE_SITES from monitored-sites.js (with fallback to legacy 3-site list if undefined)
  • extension/manifest.json: Extended content_scripts[0].js to ["content/monitored-sites.js", "content/content.js"] to guarantee load order
  • internal-docs/design/ai-providers-coverage.md: Marked all 3 hardcoded inventory items in § 5-1 as ✅ complete. Updated § 6 add/update flow to JSON-based procedure

🔵 Fixed (Session 151 — NER performance test flakiness)

  • python-sdk/tests/test_local_detector_ner.py: Relaxed test_performance_long_text threshold from 500ms to 1500ms. The GiNZa ja_ginza model's warm-state latency for 1200-character text is measured at 501-511ms, so the original 500ms threshold caused near-constant flakiness. This is a test design issue (threshold setting), not a core detection engine bug

🟢 Added (Session 151 — Python SDK generic wrapper refactoring: arbitrary provider support)

  • python-sdk/pii_firewall/wrap.py: New module. Exposes wrap_function(fn) / wrap_async_function(fn) / wrap_client(client, format). Wraps any str -> str function or LLM SDK client with PII masking and restoration
  • python-sdk/pii_firewall/providers/openai_compatible.py: New module. OpenAICompatible(api_key=, base_url=) provides drop-in support for any OpenAI-compatible API (DeepSeek / xAI Grok / Mistral / Groq / Together AI / Perplexity / Fireworks / Azure OpenAI). AsyncOpenAICompatible async variant included
  • python-sdk/pii_firewall/__init__.py: Exported wrap_function / wrap_async_function / wrap_client as public API
  • python-sdk/tests/test_wrap.py: Added 10 tests (wrap_function 4, wrap_async_function 1, wrap_client OpenAI 3, wrap_client Anthropic 1, integration 1)
  • python-sdk/tests/test_providers.py: Added 5 tests (OpenAICompatible 4, AsyncOpenAICompatible 1)
  • Backwards compatibility: Existing from pii_firewall import openai / anthropic / gemini drop-ins remain fully functional. New API is added alongside (no breaking changes)

🟢 Added (Session 151 — Shadow AI registry expansion: 9 services added)

  • proxy/index.js: Added 9 entries to DEFAULT_AI_SERVICES (id 17-25): DeepSeek (monitoring), xAI Grok (monitoring), Azure OpenAI (approved), AWS Bedrock (approved), Vertex AI (approved), GitHub Copilot (monitoring), Cursor (monitoring), Notion AI (monitoring), DeepL Write (monitoring). Coverage now spans enterprise standards (Azure / Bedrock / Vertex), emerging providers (DeepSeek / xAI), coding tools (Copilot / Cursor), and SaaS integrations (Notion / DeepL). Domain matching limitations (hostname endsWith only — no path/regex support) documented in "8. Known Technical Limitations" of the internal master doc

🟢 Added (Session 143 — OA-2: Outlook Add-in API key auth, advanced injection detection)

  • outlook-addin/taskpane/taskpane.js / landing/outlook-addin/taskpane.js: Updated to v1.2. Added PROXY_URL constant (https://pii-firewallproxy-production.up.railway.app). Added currentApiKey / hasConsent state variables. loadSettingsFromRoaming() restores API key and consent state from roamingSettings on startup. New handleAdvancedInjectClick() implements 3-state routing: no consent → consent modal → API key input → scan. saveApiKey() / clearApiKey() / updateApiKeyUI() / maskApiKey() handle key management UI. runAdvancedInjectionScan() calls proxy /detect-all-injections and renders results into #injection-list. callAdvancedInject() handles 401 (invalid key → clear + show input), 429 (quota exceeded), and network errors individually. normalizeAdvancedResults() normalizes proxy response formats A ({injections:[]}) and B ({results:[]})
  • outlook-addin/taskpane/taskpane.html / landing/outlook-addin/taskpane.html: Added collapsible #api-key-section inside #read-section (shown after consent). Contains password input, save button, delete button, and console link. Changed #btn-advanced-inject handler from showConsentModal() to handleAdvancedInjectClick(). Updated consent modal copy to "API key required (all plans)" (previously "Starter plan or higher required")
  • outlook-addin/taskpane/taskpane.css / landing/outlook-addin/taskpane.css: Added API key section styles: .api-key-section / .api-key-header / .api-key-hint / .api-key-row / .api-key-input / .btn-api-save / .api-key-status.success / .api-key-status.error / .api-key-footer-row / .btn-api-clear / .api-key-console-link

🟢 Added (Session 142 — OA-1: Outlook Add-in read mode, incoming email injection detection)

  • outlook-addin/taskpane/taskpane.js / landing/outlook-addin/taskpane.js: Updated to v1.1. Added read mode support. Office.onReady now auto-detects mode via typeof item.subject === 'string' (read vs. compose). Registers Office.EventType.ItemChanged handler (Mailbox 1.5+, failure is non-fatal). New detectInjectionsLocally(text, lang) function inlines Phase 1 patterns from core/src/injection-detector.js — 11 pattern groups for both JA and EN. normalizeForInjection() handles hiragana→katakana, full-width→half-width, and zero-width character removal. Detection results shown at two severity levels: critical (危険) and warning (警告). roamingSettings-based consent management added as prerequisite for OA-2 Proxy integration
  • outlook-addin/taskpane/taskpane.html / landing/outlook-addin/taskpane.html: Updated v1.0 → v1.1. Added #mode-indicator, #read-section (with #injection-banner, #injection-results, #injection-list, #injection-safe, #btn-advanced-inject), #compose-section wrapper, and consent dialog modal
  • outlook-addin/taskpane/taskpane.css / landing/outlook-addin/taskpane.css: Added mode indicator styles (.mode-compose / .mode-read), injection warning banners (.injection-banner-critical / -warning / -safe), detection list items (.injection-item.critical / .warning), consent modal overlay (.consent-overlay / .consent-modal), and .btn-advanced
  • outlook-addin/manifest.xml / landing/outlook-addin/manifest.xml: Added <Form xsi:type="ItemRead"> to FormSettings. Added MessageReadCommandSurface ExtensionPoint ("インジェクション検知" button in read-mode ribbon). Updated Mailbox requirement from 1.3 → 1.5 (for ItemChanged support)

🟡 Changed (Session 142 — OA-Privacy: Outlook Add-in Privacy by Design compliance, local processing)

  • outlook-addin/taskpane/taskpane.js / landing/outlook-addin/taskpane.js: Changed PII detection from Proxy /detect server-side call to browser-local regex engine. Removed PROXY_URL constant. Implemented new detectPIILocally(text, lang) function (inlines PATTERNS_JA with 19 types and PATTERNS_EN with 11 types from core/src/pii-detector.js). Email body text no longer transmitted to any external server — fully Privacy by Design compliant. Includes full-width→half-width normalization, deduplication, and infinite-loop protection for both JA and EN modes

🟢 Added (Session 141 — FE-2: Tika production integration in docker-compose.selfhosted.yml)

  • proxy/docker-compose.selfhosted.yml: Added tika service (apache/tika:latest-full, internal: true network isolation, JAVA_TOOL_OPTIONS=-Xmx1g, health check). Added TIKA_URL: http://tika:9998 env var and depends_on: tika to piifw-proxy. Self-hosted Proxy customers can now start a full Tika-enabled environment with a single docker compose up
  • proxy/file-extractor.js: Extended Tika timeout from 30s to 120s (scanned PDF OCR can take up to 2 minutes)

🟢 Added (Session 140 — Apache Tika integration, expanded file format support)

  • proxy/file-extractor.js: Added extractWithTika() function. Self-hosted Proxy (with TIKA_URL env var set) can now extract text from scanned PDFs, images (PNG/JPG/TIFF/BMP), legacy PowerPoint (.ppt), and email files (.eml/.msg). Automatically skipped on SaaS version (no TIKA_URL) for Privacy by Design compliance
  • proxy/file-extractor.js: Added automatic OCR fallback to Tika when PDF text extraction returns empty content (scanned/image PDFs)
  • internal-docs/design/file-extraction-design.md: New design document for Apache Tika integration (v1.1 PoC complete). Covers architecture, Docker Compose config (internal: true outbound isolation), Privacy by Design compliance, PoC results (digital PDF <1s / scanned PDF OCR 46.7s), and OCR UX policy
  • internal-docs/sales/competitor-analysis.md: Added detailed PII Tools research. Documents their technical stack (Apache Tika + Tesseract), founder profile, and comparison table vs PIIFirewall

🟡 Changed (Session 138 — Add noindex to index-v2.html)

  • landing/index-v2.html: Added <meta name="robots" content="noindex, nofollow"> to prevent search engine indexing of the in-progress v2 page. Must be removed before production launch.
  • landing/index.html: Removed all injection attack detection/defense content from the landing page due to pending patent application. Includes nav links, Problem card, Feature card, demo tab, SDK code examples, and all JA/EN i18n strings
  • landing/blog.html: Removed article cards for prompt-injection.html and indirect-injection-rag.html (3 instances)
  • landing/_redirects: Added 301 redirects for solutions/injection-defense, blog/prompt-injection, and blog/indirect-injection-ragpiifirewall.com

⚪ Docs (Session 137 — P14-5 Self-hosted Proxy Setup Guide)

  • docs/ja/api/self-hosted-proxy.md / docs/en/api/self-hosted-proxy.md: New Self-hosted Proxy setup guide (JA/EN). Covers quick start (5 steps), environment variable reference, storage configuration (memory/Redis/PostgreSQL), Docker Compose instructions, air-gap mode, SHA256 image verification, Privacy by Design data disclosure, token loss risk warning, and troubleshooting
  • docs/.vitepress/config.ts: Added Self-hosted Proxy link to the "Infrastructure & Operations" / "インフラ・運用" sidebar section in both JA and EN

🟢 Added (Session 137 — P14-4 GitHub Actions GHCR Multi-arch Build)

  • .github/workflows/docker-ghcr.yml: New GitHub Actions workflow for Self-hosted Proxy. Triggers on proxy-v* tag push to build linux/amd64 + linux/arm64 simultaneously via docker buildx and push to GHCR private registry (ghcr.io/kmishimaslgithub/pii-firewall/proxy). Automatically appends SHA256 digest to GitHub Release notes for tamper verification. GitHub Actions cache integration for faster subsequent builds. Also supports manual builds via workflow_dispatch

🟢 Added (Session 136 — P14-3 License key authentication)

  • proxy/license-auth.js: New Self-hosted Proxy license authentication module. Ed25519-signed JWT verification (syntax, expiry, issuer claims). Full signature verification when public key (proxy/certs/piifw_license_public.pem) is present. Supports both air-gap mode (PIIFW_LICENSE_FILE) and standard mode (PIIFW_LICENSE_KEY)
  • proxy/migrations/001_license_keys.sql: Supabase migration SQL for new license_keys and license_usage tables with RLS policy and auto-updated updated_at trigger
  • proxy/index.js: Added startup license check (rejects boot with process.exit(1) if license is invalid when PIIFW_LICENSE_KEY / PIIFW_LICENSE_FILE is set), /license/refresh endpoint (manual monthly report trigger), license info in /health response, API call count middleware (Self-hosted mode only), and automatic 30-day monthly report via setInterval

🟢 Added (Session 135 — P14-1 Self-hosted Proxy Dockerfile)

  • proxy/Dockerfile.selfhosted: New Dockerfile for P-14 Self-hosted Proxy distribution. Multi-stage build (deps → production), non-root user (node UID=1000), linux/amd64 + linux/arm64 support, built-in health check
  • proxy/docker-compose.selfhosted.yml: Customer-facing Docker Compose file with Redis / PostgreSQL optional configurations included as commented-out examples
  • proxy/certs/.gitkeep: Directory for Ed25519 public key placement (P14-7 will add piifw_license_public.pem)
  • .dockerignore: Excludes secrets and unnecessary frontend files from Docker build context

⚪ Docs (Session 134 — GiNZa NER extension developer documentation)

  • docs/ja/guide/limitations.md / docs/en/guide/limitations.md: Added "NER Extension Option (Python SDK) — Enhanced Name Detection" section. Includes detection comparison table for katakana/rare-kanji names, recommended industries (healthcare, HR, legal, finance, government), installation example, and platform availability notice
  • docs/ja/api/sdk.md / docs/en/api/sdk.md: Added Python SDK NER extension tip box directly after the name detection warning
  • internal-docs/design/python-sdk-design.md: Added platform NER coverage matrix (Python SDK / LangChain / Proxy / MCP / Node.js SDK / Chrome Extension / Java SDK)

🔵 Fixed (Session 130 — CORS log noise suppressed)

  • proxy/index.js: Requests without an Origin header (e.g. Railway health checks) were logging [CORS] origin: undefined every minute. Fixed by returning early with allow before logging when origin is undefined.

🟡 Changed (Session 128 — Developer Console UI improvement)

  • Developer Console (landing/console.html): Added a prominent yellow warning box on the TOTP 2FA screen to distinguish it from the email OTP step. Text now clearly states "This is not the email code" and label changed to "Authenticator app code (6 digits)"

⚪ Docs (Session 125 — Plan tables major revision & feature additions)

  • All 4 files (docs/ja/api/plans.md · docs/en/api/plans.md · docs/ja/guide/plans.md · docs/en/guide/plans.md) updated
  • Simplified API call limits (removed unified credit system): Free 300 · Starter 10,000 · Business 300,000 (was 333,333) · Enterprise unlimited
  • detect_injection · detect_all_injections · detect_sql_injection now unlimited on all plans
  • Added to feature tables: detectAllInjections (SQL + prompt composite), detectSQLInjection, lang option, maskMessages
  • Team member invites: Starter ✅→❌ (single-seat) · Business ✅ clarified
  • Add-on packs: renamed unit from "credits" to "API calls"
  • Guide docs: removed unified-credit web-app complexity, simplified to API call model

⚪ Docs (Session 125 — Plan feature table corrections)

  • docs/ja/api/plans.md · docs/en/api/plans.md: Fixed Custom PII rules availability for Starter from ❌ to ✅ in both SDK and REST API tables (reflecting the 2026-04-29 change). Unified PII types display to "24 + custom" for Starter/Business/Enterprise. Updated FAQ wording.
  • docs/ja/guide/plans.md · docs/en/guide/plans.md: Fixed Custom PII rules Starter ❌→✅, PII types display, Team member invites Starter ✅→❌ (Starter is single-user), updated FAQ wording.

🔵 Fixed (Session 119 — logo-light.svg was empty due to PS regex write failure)

  • docs/public/logo-light.svg and internal-docs/public/logo-light.svg were previously written as empty files due to a PowerShell regex variable write failure. Fixed by using IndexOf/Substring string manipulation on the confirmed-working logo-dark.svg content.

🎨 Changed (Session 119 — Logo light/dark split with darker navy)

  • Replaced logo-adaptive.svg with separate logo-light.svg / logo-dark.svg in both docs and internal-docs
  • Light mode: rounded navy background (#0a1929, darker/blacker than before) so the shoebill remains visible
  • Dark mode: transparent background so the shoebill bird floats alone against the site's dark background
  • Uses VitePress logo: { light, dark } syntax for reliable theme switching (SVG media queries in <img> tags are unreliable)
  • Fixed: artboard border polyline removed from source SVG — was causing square appearance over rounded corners

🎨 Changed (Session 118 — Adaptive SVG logo for docs nav)

  • Replaced nav logo in docs and internal-docs with logo-adaptive.svg. Uses SVG @media (prefers-color-scheme): light mode → navy background, dark mode → transparent (blends with site background)

🎨 Changed (Session 118 — Logo icon full redesign)

  • Unified logo across all products (landing / app / extension / admin) with new "Shoebill Shield" design
  • Design: Shoebill stork × shield motif, rounded corners (rx=460), dark navy (#10365a) background
  • Updated files: all PNGs in landing/icons/, app/public/icons/, extension/icons/, admin/favicon.svg, favicon.ico, apple-touch-icon.png, PWA icons (192/512px)

🔵 Fixed (Session 115 — TOTP stuck UX bug)

  • landing/console.html — Added "← Back to email input" link on TOTP challenge screen (login-step3). Users can now escape if they can't access their authenticator app. resetToLoginStep1() signs out the Supabase session and resets all login steps

🟢 Added (Session 115 — P-05 Console UI Webhook tab)

  • landing/console.html — Added "🔔 Webhook" tab to Settings panel. Features: endpoint registration form (URL, event selection, description), registered endpoint list (test send, secret rotation, delete), one-time full secret display with clipboard copy, delivery history table (timestamp, event, status, retry count, error). Free plan shows Starter+ upgrade gate

🟢 Added (Session 115 — P-05 WebhookDispatcher implementation)

  • proxy/index.js — Added WebhookDispatcher class. Fire-and-forget async delivery, HMAC-SHA256 signing, exponential backoff retry (up to 3x: 1s→2s→4s), 5-second timeout, delivery log recording. Privacy by Design: payload never contains raw PII, masked_text, or token values
  • proxy/index.js — Added pii.detected Webhook dispatch to /mask endpoint (API-key authenticated, Starter+, PII detected only)
  • proxy/index.js — Added injection.detected Webhook dispatch to /detect-all-injections endpoint (opt-in, OFF by default)
  • proxy/index.js — Added Webhook management REST API: GET/POST /webhooks (list/register), PATCH/DELETE /webhooks/:id (update/delete), GET /webhooks/:id/logs (delivery history), POST /webhooks/:id/test (test send), POST /webhooks/:id/rotate-secret (secret rotation)
  • proxy/index.js — Added generateWebhookSignature() HMAC-SHA256 signature helper
  • proxy/index.js — Added validateWebhookUrl() SSRF protection (HTTPS required, private IP blocked)
  • proxy/supabase-migrations/008_webhook_endpoints.sqlwebhook_endpoints table migration (applied to Supabase production)
  • proxy/supabase-migrations/009_webhook_logs.sqlwebhook_logs table migration (applied to Supabase production)

🟢 Added (Session 113 — P-04 Framework Middleware implementation)

  • python-sdk/pii_firewall/middleware/_base.py — New shared masking utility _mask_body(). Fully delegates to PIIFirewall instance (no direct _local dependency). Default scan fields: messages / text / prompt / query / input
  • python-sdk/pii_firewall/middleware/fastapi.py — New FastAPI / Starlette ASGI middleware (PIIFirewallMiddleware). Single-line integration: app.add_middleware(PIIFirewallMiddleware). on_license_error="block" default (Autonomous Stop principle). Zero-code integration via ASGI receive override
  • python-sdk/pii_firewall/middleware/flask.py — New Flask WSGI middleware (PIIFirewallFlask). Zero-code integration via WSGI environ["wsgi.input"] replacement — request.get_json() returns pre-masked data automatically
  • python-sdk/pii_firewall/middleware/django.py — New Django middleware (PIIFirewallDjango). Zero-code integration via request._body cache override — request.body / request.data (DRF) return pre-masked data automatically. Configured via settings.py PII_FIREWALL key
  • python-sdk/pii_firewall/middleware/__init__.py — Exports all 3 middleware classes
  • python-sdk/pyproject.toml — Added fastapi / flask / django optional-dependencies
  • sdk/src/middleware.js — Added customPatterns / lang args to Express / Hono / Fastify shared maskBody(). Added query / input fields to default scan targets
  • sdk/src/index.js — Fixed expressMiddleware() / honoMiddleware() / fastifyPlugin() to propagate customPatterns / lang to maskBody()

🟢 Added (Session 112 — Custom PII dictionary: full SDK implementation)

  • sdk/src/index.js / sdk/src/index.d.tscreateFirewall({ customDictionary }) support. Added CustomDictionary, CustomKeyword, CustomPattern types. Patterns compiled at instance creation; auto-applied to mask() / maskMessages() / detect()
  • python-sdk/_local/detector.py — Added build_custom_patterns(entries) (Python port of JS buildCustomPatterns). Added custom_patterns arg to detect_pii()
  • python-sdk/_local/masker.py — Added custom_patterns arg to mask_pii()
  • python-sdk/client.pyPIIFirewall(custom_dictionary=...) support. Accepts pii-dictionary.json directly. Auto-applied to mask_pii() / detect_pii()
  • mcp-server/src/index.js — Added custom_dictionary parameter to mask_pii / detect_pii tools
  • langchain-plugin/callbacks.pyPIIFirewallCallbackHandler(custom_dictionary=...) support
  • langchain-plugin/tools.pyget_pii_tools(custom_dictionary=...) support

🟡 Changed (Session 112 — Custom PII dictionary plan restriction update)

  • proxy/index.js — Removed plan-based restrictions on custom PII dictionary: keyword count limit (previously Starter=10 entries) abolished; regex patterns now allowed on all paid plans (previously Business+ only). Plan differentiation axis changed from "dictionary size" to "user count (Starter=1 user / Business=team)".

🔵 Fixed (Session 110 — proxy Webhook flow fix & SDK Billing Phase 2 full test)

  • proxy/index.js — Changed issueSdkKey import to direct reference from ../core/src/billing (workaround for stale npm workspace symlink)
  • Stripe Webhook endpoint path unified to /stripe/webhook
  • scripts/sdk-billing-test-phase2.js — New regression test script for Stripe Webhook → sdk_keys auto-issue flow (10/10 PASS confirmed)

🟢 Added (Session 109 — P-03 OpenAI / Anthropic Drop-in Wrappers)

  • python-sdk/pii_firewall/openai.py — New OpenAI SDK drop-in wrapper. Change just one import (from pii_firewall import openai) to protect any existing code. Provides OpenAI / AsyncOpenAI with automatic pre-send PII masking and post-receive PII restore, including streaming support via PIIFirewallStream
  • python-sdk/pii_firewall/anthropic.py — New Anthropic SDK drop-in wrapper. Change just one import (from pii_firewall import anthropic) to protect any existing code. Provides Anthropic / AsyncAnthropic
  • python-sdk/pii_firewall/_wrapper/messages.py — Shared message-array mask/restore logic for OpenAI / Anthropic
  • python-sdk/pii_firewall/_wrapper/stream.pyPIIFirewallStream streaming wrapper (sync + async)
  • python-sdk/pyproject.toml — Added openai / anthropic / all optional-deps

🔵 Fixed (Session 102 — api_usage FK constraint removal)

  • proxy/supabase-migrations/007_api_usage_drop_fk.sql — Removed FK constraint (api_usage_api_key_id_fkey) from api_usage.api_key_id. SDK keys (UUIDs from sdk_keys table) can now be recorded in api_usage. Design uses type='proxy' / type='sdk' to distinguish records

🔵 Fixed (Session 102 — OTP input digit count fix)

  • landing/index.html, landing/index-v2.html — Fixed auth modal OTP input from 8 digits to 6 digits (Supabase sends 6-digit OTP)

🟢 Added (Session 98 — Real-time PII detection improvement & multi-site send interception)

  • extension/content/content.js — Improved detection reliability and Google AI support
    • Added 1.5-second polling of the focused input element (startInputPolling / stopInputPolling). PII badge now appears in real-time on sites with unreliable input events (ChatGPT new UI, Google AI, etc.)
    • Added keyup, compositionend, focusin events to all listener attachment points
    • Added quickLocalCheck() — instant regex-based PII check at send time (no API, synchronous)
    • Added findActiveInput() — resolves active input from polling state or focus history
    • Updated onKeyDown / onButtonClick: two-phase interception — Phase 1 (async detection ready → mask) + Phase 2 (no prior detection → quick check → badge)
    • Expanded SEND_BUTTON_SELECTOR: added button[type="submit"], button[jsname="c8mGvb"], button[jsaction*="send"] for Google AI

🔵 Fixed (Session 98 — ChatGPT token format normalization)

  • extension/content/content.js — ChatGPT strips [SECURED:type=name,id=xxx] to [SECURED=name,id=xxx] in responses; extension now handles both formats
    • scanResponsesForTokens(): broadened innerHTML check to detect both [SECURED:type= and [SECURED=
    • getResponseText(): broadened text match to include both token formats
    • getFirstTokenId(): updated regex to [SECURED(?::type=|=)...] (matches both formats)
    • Added normalizeSecuredTokens() — converts [SECURED=name,id=xxx][SECURED:type=name,id=xxx] before sending to proxy
    • applyRestoreText(): applies normalizeSecuredTokens() before sending to proxy

🟢 Added (Session 98 — Extension masking via Proxy, AI response restore, MCP billing)

  • extension/background/background.js — 2 new handlers
    • PROXY_MASK: calls /mask (cryptographic tokenization; free plan, no API key required)
    • PROXY_RESTORE_TEXT: calls /restore-text (free plan, no API key required)
  • extension/content/content.js — masking and restore enhancements
    • applyMask() made async; now calls Proxy API /mask to produce [SECURED:type=xxx,id=yyy] tokens (falls back to local masking if proxy unavailable)
    • AI response restore: detects [SECURED: tokens in ChatGPT / Claude.ai / Gemini response areas → shows fixed bottom-right "🔓 Restore" badge → restore result panel with copy support
    • Added scanResponsesForTokens() / scheduleResponseScan(), integrated into MutationObserver
  • extension/content/content.css — styles for restore badge (#piifw-restore-badge) and restore panel (#piifw-restore-panel)
  • mcp-server/src/index.js — SDK shared billing module integrated
    • Startup: loadKey() (PIIFW_LICENSE_KEY env → ~/.piifw-license.json) + startPolling()
    • Per tool call: billableCheck()checkQuota() + incrementCounter() (applies to: mask_pii, detect_pii, detect_injection, detect_all_injections, rag_ingest, rag_resolve)
    • BillingError returned as structured error (QUOTA_REACHED / KEY_EXPIRED)
    • No-key (free) mode: billing check skipped; proxy-side rate limiter applies

🟢 Added (Session 97 — Extension billing)

  • extension/background/background.js — API key support
    • Shadow AI URL detection (/shadow-ai/check): skipped when no API key; adds Authorization: Bearer header when key is set
    • Injection detection (/detect-injection): returns { ok: false } immediately when no API key
    • Added SET_API_KEY message handler (save / remove from chrome.storage.sync)
    • Added piifw_api_key to GET_SETTINGS
  • extension/popup/popup.html + popup.js — Settings tab and API key UI
    • New "⚙️ 設定" tab (API key input, save, clear; proxy URL change)
    • Shadow AI tab: shows lock UI (🔒) with "Set API Key" button when no key is configured
    • All Shadow AI features unlocked immediately once API key is saved
  • proxy/index.js — API key required for paid endpoints
    • POST /detect-injection — returns 401 API_KEY_REQUIRED without key
    • POST /detect-all-injections — same
    • POST /shadow-ai/check — same

🟢 Added (Session 96 — SDK Billing Phase 4)

  • proxy/sdk-key-routes.js — Added POST /sdk/key-check endpoint (SDK daily polling receiver)
    • Key signature verification (KEY_EXPIRED allowed → triggers new key lookup flow)
    • Upserts cumulative call_count to api_usage table (with type: 'sdk')
    • Simultaneously updates Phase 3 chain state when chain_hash / prev_hash provided
    • Response: { status: 'active'|'new_key_available'|'expired', new_key?, quota_remaining? }
  • core/src/sdk-manager.js (new) — Client-side in-memory key management and daily polling
    • loadKey(options) — loads key from env var / file / direct arg into memory
    • saveKey(keyJson, filePath) — instantly updates in-memory key + persists to file (no restart needed)
    • getInMemoryKey() — returns current in-memory key
    • pollKeyCheck(options) — single call to /sdk/key-check; auto-applies new key if returned
    • startPolling(options) — fires immediately on startup, then repeats every 24h (non-blocking)
    • stopPolling() — stops the polling interval
    • Tests: 9 (loadKey / saveKey / getInMemoryKey)
  • core/index.js — Spread-exported all sdk-manager functions
  • proxy/supabase-migrations/006_api_usage_sdk.sql (new) — Adds type column to api_usage ('proxy' / 'sdk')

🟢 Added (Session 96 — SDK Billing Phase 3)

  • core/src/billing.js — Added hash-chain tamper detection
    • computeChainHash(prevHash, count, keyId, timestamp) — deterministic SHA-256 chain hash computation
    • verifyChain(record, keyId) — counter file tamper detection (throws TAMPER_DETECTED; legacy format skipped for backward compatibility)
    • readCounter() — extended to preserve Phase 3 chain fields (key_id / prev_hash / chain_hash / timestamp)
    • incrementCounter(filePath, keyId) — added keyId argument: verifies chain → computes new hash → persists
    • resetCounter(filePath, keyId) — added keyId argument: initializes genesis chain (prev_hash = key_id)
    • Tests: 35 total (+9 Phase 3 tests)
  • core/index.js — Added exports for computeChainHash and verifyChain
  • proxy/sdk-key-routes.js — Added POST /sdk/verify-chain endpoint (server-side chain verification: validates prev_hash, persists new chain_hash)
  • proxy/supabase-migrations/005_sdk_chain.sql (new) — Adds last_chain_hash / last_call_count / chain_verified_at columns to sdk_keys

🟢 Added (Session 95 — SDK Billing Phase 2)

  • proxy/supabase-migrations/004_sdk_keys.sql (new) — sdk_keys table for storing signed SDK keys (with RLS enabled)
  • proxy/index.js — Integrated SDK key auto-issuance into Stripe Webhooks
    • checkout.session.completed: auto-issue SDK key on subscription purchase and save to sdk_keys
    • invoice.payment_succeeded: auto-issue renewal key on monthly cycle; mark previous key as superseded
  • proxy/sdk-key-routes.js — Added GET /sdk/my-key endpoint (Supabase JWT auth; returns current active key for console display)

🟢 Added (Session 95 — SDK Billing Phase 1)

  • core/src/billing.js (new) — SDK billing & usage management module (Phase 1: basic stop enforcement)
    • BillingError / BillingErrorCode (QUOTA_REACHED / KEY_EXPIRED / INVALID_KEY)
    • issueKey() / signKey() — HMAC-SHA256 signed key generation (proxy/server side)
    • verifyKey() — signature verification + valid_until expiry check (SDK side)
    • checkQuota() — autonomous stop when API call count reaches quota_total
    • readCounter() / incrementCounter() / resetCounter() — persistent local API call counter
  • proxy/sdk-key-routes.js (new) — POST /sdk/issue-key (admin-only signed SDK key issuance API)
    • GET /sdk/key-info — HMAC configuration status check endpoint
  • core/index.js — Export billing module both as namespace and individually

🟢 Added (Session 91 — JPY pricing support)

  • proxy — Added currency parameter to /stripe/create-checkout-session and /stripe/create-credits-checkout (routes to JPY or USD price IDs)
  • landing/index.html — Updated JA pricing display to ¥2,980/¥29,800 (Starter) and ¥49,800/¥498,000 (Business)
  • landing/index-v2.html — Same: updated JA pricing attributes, added _pendingCurrency, and passed currency param in OTP redirect URL
  • landing/console.html — Post-OTP checkout and upgradeFromConsole() now pass currency to the checkout API
  • docs/ja/guide/plans.md / docs/en/guide/plans.md — Added JPY price column (tax-exclusive note, annual discount, credit add-on table)
  • docs/ja/api/plans.md / docs/en/api/plans.md — Added JPY column to plan overview table

🟡 Changed (Session 90 — Security)

  • landing/security.html — Replaced third-party service names with functional category descriptions (e.g., Railway → cloud hosting provider)
  • docs/ja/api/seva.md / docs/en/api/seva.md — "Supabase pgvector" → "cloud vector DB" (infrastructure non-disclosure rule applied)
  • docs/ja/guide/shadow-ai.md / docs/en/guide/shadow-ai.md — "via Supabase" → "via a cloud database"

🟢 Added (Session 90)

  • landing/security.htmlNew Information Security Policy page (JA/EN bilingual)
    • Privacy by Design 7-principle table, basic policy, incident response, third-party services, legal compliance
    • Footer link added to landing/index-v2.html under the "Company" column (JA/EN i18n)

🟢 Added (Session 89)

  • proxy/index.jsBrute-force protection: express-rate-limit v7.5.1
    • Global limiter: all endpoints, 300 req / 15 min (blocks bots and scrapers)
    • Auth limiter: POST /api-keys, POST /user-api-keys/save, 20 req / 15 min (credential stuffing protection)
    • Chat limiter: /chat, /chat-with-file, /chat-multi, 20 req / 1 min (cost-attack protection)
    • Added app.set("trust proxy", 1) for correct real-IP detection behind Railway's reverse proxy
    • /stripe/webhook is excluded from rate limiting
    • Limit exceeded: logs warning + returns 429 Too Many Requests

🟡 Changed (Session 87)

  • landing/console.html — Updated default test text to include custom dictionary keywords ("α計画", "機密") for clear before/after Dictionary demo
  • landing/console.html — Added "🔑 Custom Dictionary: N keywords active" indicator in Request Body area when Dictionary is ON
    • Updates in real time on page load, toggle change, and Save
    • Hidden when toggle is OFF

🔵 Fixed (Session 87)

  • landing/console.html — Dictionary tab: fixed bug where toggling ON did not add customDictionary to the request
    • Root cause: if the user hadn't clicked "Save" before toggling ON, localStorage had no dictionary data and getCustomDictionary() returned null
    • Fix: auto-save editor content when toggle is switched ON; shows error if JSON is invalid and reverts toggle
    • Fallback added: if localStorage has no saved data, reads directly from editor content

🟢 Added (Session 88)

  • core/src/pii-detector.jsJapanese name detection without spaces (surname dictionary, ~400 entries)
    • JAPANESE_SURNAMES Set (2+ char surnames only); longest surname matched first (長谷川 before 長谷)
    • maskPII(text, ["name"], "ja") now masks names like "田中太郎" and "山田花子" without requiring a space
    • False-positive prevention: skips matches when immediately preceded/followed by address or company suffix chars (株, 式, 会, 社, 業, 機, etc.)
    • detectPII returns no-space names as { type: "name", level: "confirm" } candidates
    • No double-masking with the existing space-based pattern ("田中 太郎")
    • 9 unit tests added to pii-detector.test.js
  • core/src/pii-detector.jsSingle-char and multi-char surname detection via honorific/title context
    • JAPANESE_SURNAMES_1CHAR Set (~50 single-char surnames: 林, 森, 原, 岡, 島, 谷, 野, etc.)
    • HONORIFIC_TITLES array (30+ items: さん/様/氏/くん/殿/部長/課長/社長/etc., longest-first matching)
    • 4 detection patterns:
      • A) 1-char surname + honorific (林さん, 金様, 林氏, 南くん)
      • B) 1-char surname + title suffix (森部長, 岡社長)
      • C) [role]の[1-char surname]です (社長の菅です, 部長の原より)
      • D) 2–4 char surname + honorific/title (小林さん, 田中氏, 長谷川様)
    • Masks surname only, preserving honorific/title — e.g. 林さん[SECURE_name_xxx]さん
    • False-positive prevention: skips when immediately preceded by kanji (compound words, place names)
    • Added HONORIFIC_KANJI_1CHAR Set: gLen scan loop breaks before kanji honorifics (氏/様/殿/君) → Root-cause fix preventing "長谷川様" from being over-masked as "長谷川様" when "長谷" (a shorter surname) is also in the dictionary
    • 15 unit tests added to pii-detector.test.js

⚪ Docs (Session 88)

  • docs/en/api/console.md — Renamed page to Test Console (was: API Test Console)
  • docs/en/api/console.md — Added Custom Dictionary section: setup, ON/OFF toggle behavior, demo walkthrough, and localStorage storage details
  • docs/.vitepress/config.ts — JA/EN sidebars: moved Test Console and SEva to "Getting Started" section (was: Infrastructure & Operations)
  • docs/en/guide/limitations.md — Updated name detection section from "space required" to "partial space-free support in progress". Added table showing current detection coverage (dictionary matching + honorific context)
  • docs/ja/api/core-functions.md — Updated extraTypes: ["name"] info callout to reflect dictionary matching and honorific context support

⚪ Docs (Session 87)

  • docs/en/guide/pii-protection-levels.mdNew page: PII Protection Levels by LLM
    • Comparison table for major LLMs (Claude / ChatGPT / Gemini / Copilot / Perplexity / Mistral / Llama / Local LLMs)
    • How-it-works breakdown by route (Chrome Extension / API / MCP / SEva pipeline)
    • Added to User Guide sidebar
  • docs/en/api/mcp.md — Added "Mask All Messages in a Session" tip
    • How to activate PII Firewall for an entire session with a single instruction at session start

🟢 Added (Session 86)

  • core/src/pii-detector.jsCustom PII Dictionary (Privacy by Design: dictionary data never stored on our servers)
    • Added buildCustomPatterns(entries): converts keyword/regex entries into pattern objects compatible with the detection engine
    • detectPII() / maskPII() — added opts.customPatterns option for dynamic pattern injection
  • proxy/index.js/mask / /detect endpoints now accept customDictionary request field
    • Tier-based validation: Starter = max 10 entries, keywords only; Business+ = regex patterns allowed; Enterprise = unlimited
    • Format: { keywords: [{keyword, type}], patterns: [{pattern, type}] }
  • landing/console.html — Added 🔑 Dictionary tab
    • JSON editor, file upload, download, localStorage persistence
    • Apply toggle: when ON, automatically injects customDictionary into all test requests

🟡 Changed (Session 85)

  • core/src/pii-detector.jsEnglish PII detection accuracy improvements (pii-masking-300k benchmark Micro F1: 65.02 → 75.48)
    • drivers_license UNIVERSAL labeled pattern extended: is separator support; lookahead updated to cross spaces/dots ((?=[A-Z0-9]{0,15}\d)(?=[A-Z0-9\s\-\.]{0,40}\d))
    • drivers_license value format extended: space-separated (VIKAS 606107 9 539) and dot-separated (EFSEV.761144.EB.196) values now supported
    • drivers_license JSON key pattern added to UNIVERSAL: "driver_license": "VALUE" format
    • postal_code context-required pattern added: partial UK outward-only codes (CM3, RG7, etc.) via JSON key / XML tag / labeled format in UNIVERSAL
    • F1 score improvements: drivers_license 21.56→53.71, postal_code 33.11→73.85, Micro Avg 65.02→75.48
  • scripts/run-pii-masking-300k-benchmark.js — Benchmark accuracy improvements
    • Extended normalizeValue() to strip DL and postcode JSON key prefixes
    • GT collection logic: split comma-separated multi-value entries for individual comparison (e.g. "dn33eh,dn33eq" → 2 separate GT values)

🟢 Added (Session 84)

  • core/src/pii-detector.jsEnglish Regional Detection Layer (Region-First Exclusive Architecture)
    • Added detectRegion(text) function: score-based automatic detection of 6 regions (US/UK/IN/AU/SG/CA) + Generic fallback
    • PATTERNS_EN_UNIVERSAL: patterns shared across all English modes (labeled/context-required only; no region-specific bare patterns)
    • PATTERNS_EN_US/UK/IN/AU/SG/CA/GENERIC: per-region exclusive pattern sets (postal code, phone, passport, national ID)
    • detectPII(text, "en", { region: "us" }) — explicit region override option added
    • detectRegion() exported via module.exports (available to SDK and testing)
    • Expected benchmark improvement: postal_code Recall 25%→50%+, drivers_license 14%→60%+
    • Supported regions:
      • 🇺🇸 US: bare ZIP (12345), bare SSN, US state address, US phone (555) 123-4567, US DL, EIN
      • 🇬🇧 UK: UK postcode, NIN (with/without label), NHS number (with/without label), DVLA DL format, UK phone 07xxx
      • 🇮🇳 IN: Aadhaar (12-digit), PAN card, 6-digit PIN code, IFSC code, IN phone 9xxxxxxxxx
      • 🇦🇺 AU: state+4-digit postal, TFN, ABN, AU phone 02/04xx, Medicare card
      • 🇸🇬 SG: NRIC/FIN (S/T/F/G + 7 digits + check letter), 6-digit postal (S048616 format), SG phone 6/8/9xxxxxxx, UEN
      • 🇨🇦 CA: SIN (3-3-3 format, distinct from US SSN 3-2-4), Canadian postal K1A 0B1, OHIP/health card, BN
    • Cross-region interference eliminated: CA documents no longer incorrectly match "IN" (from "SIN") as a US state abbreviation

🟡 Changed (Session 82)

  • core/src/pii-detector.js PATTERNS_EN — Major pattern improvements (pii-masking-300k benchmark Micro F1: 57.85 → 65.02)
    • password: Changed to \b(?:password|passwd)\b\s*[:=]\s*\S+. Removed pass/pwd, made [:=] mandatory. FP reduced by 77% (133→31)
    • phone: Added context-required pattern (Phone: 0123456789 form). Recall 42.4%→60.3%, F1 47.41→61.28
    • passport XML: Extended from <passport>\d{9}> to <passport>[A-Z0-9]{6,12}. Covers alphanumeric passports (e.g. A12345678)
    • drivers_license XML: Generalized tag to <[A-Za-z]*licen[sc]e[A-Za-z]*>. Covers <driverslicense>, <drivinglicence> etc.

⚪ Docs

  • docs/ja/api/mcp.md / docs/en/api/mcp.md — Added "Auto PII Protection Setup (Recommended)" section. Documents Method A (CLAUDE.md instructions) and Method B (UserPromptSubmit hook) with usage examples, comparison table, and recommended tip callout (Session 82)

🔵 Landing

  • landing/console.html — Standardized OTP input to 6 digits: updated placeholder, maxlength, validation (!== 6), and label to consistently show 6-digit requirement (Session 82)

🔵 Landing

  • landing/console.html — Fixed plan display bug for users without API keys: when renderApiKeysList() early-returns (no keys), now fetches plan from /credits endpoint as fallback and correctly updates Account tab, SEva file attach button, and TOTP check (Session 82)

🔵 Landing

  • landing/console.html — Fixed plan showing as "Free" due to browser caching: added ?t=Date.now() cache-bust query param to the /api-keys fetch. Root cause: browser returned 304 (Not Modified) with stale cached response (Session 82)
  • landing/console.html — Fixed plan display not updating in Account tab: renderApiKeysList() now calls loadAccountTab() after setting currentPlan from API keys (keys.length > 0 branch was missing this call) (Session 82)
  • landing/console.html — Made loadAccountTab() async: when currentPlan === 'free' (still loading), it now fetches /api-keys directly before rendering, eliminating all timing-dependent "Free" display issues (Session 82)

🟢 Landing

  • landing/console.html — Added refreshSidebarAccess() function. Unlocks Secure RAG sidebar items (🔒→📦 icon, docs link) for Starter+ users after plan is determined. Also centralizes SEva 📎 button control (Session 82)
  • landing/seva/seva.js — Added _attachEnabled instance variable. setAttachmentEnabled() now persists state so it's correctly applied even if called before DOM is ready (Session 82)

🔵 Proxy + Landing + SEva

  • proxy/index.js — Unified email resolution in /upload endpoint to use resolveUserEmail(). Now accepts Supabase JWT (Authorization: Bearer) to identify users, enabling file uploads from the Developer Console (Session 82)
  • proxy/index.js/upload plan check now queries both credits and api_keys tables, using whichever shows a higher plan. Fixes case where credits is outdated (free) but api_keys shows starter (Session 82)
  • landing/seva/seva.js — Added getAuthHeaders callback option. _processFileAttach now includes auth headers in the /upload fetch (Session 82)
  • landing/console.html — Added getAuthHeaders: () => getAuthHeader() to SevaWidget init. Sends Supabase JWT with file upload to pass plan check (Session 82)
  • landing/console.html — Changed onAuthSuccess() to loadApiKeys().then(() => refreshSidebarAccess()). Sidebar now auto-unlocks after login without requiring Account tab visit (Session 82)
  • landing/console.html — Added plan badge to topbar (topbar-plan-badge). Shows colored badge (Free/Starter/Business/Enterprise) immediately after plan is confirmed. Hidden on logout (Session 82)
  • landing/console.html — Added initPlanBadge(): independent plan detection function called on login. Fetches /api-keys directly, sets currentPlan, then calls refreshSidebarAccess(). Decoupled from loadApiKeys() list display logic (Session 82)
  • landing/console.html — Added SEva refreshContext() call inside refreshSidebarAccess(). Context chip now updates to show correct plan (Session 82)

🔵 Landing

  • landing/console.html — Fixed all Japanese sample texts in SCENARIOS and PRESETS to use space-separated names (山田太郎 → 山田 太郎, etc.). Affects mask, detect, RAG ingest, and preset scenarios (Session 82)
  • landing/console.html — Added extraTypes: ["name"] to runRequest() body for Japanese language mode. Console demos now correctly detect and mask Japanese names (Session 82)
  • landing/console.html — Replaced plan gate "View Plans" link with a direct "Upgrade to [Plan]" button. Starter+ features route to Starter Stripe Checkout; Business+ features route to Business Stripe Checkout; Enterprise shows a contact link (Session 82)

🔵 Proxy + Docs

  • proxy/index.js — Added requireStarterPlan() helper function. Unifies plan checking for API key auth (req.apiKey.plan) and Supabase JWT auth (both credits and api_keys tables). Returns 403 for Free plan requests. Reusable middleware for premium endpoints (Session 82)
  • proxy/index.js — Applied requireStarterPlan() to /rag/ingest and /rag/resolve. Secure RAG is now restricted to Starter plan and above at the API level (Session 82)
  • docs/ja/api/rag.md / docs/en/api/rag.md — Added "Starter Plan Required" warning callout at page top. Documents the 403 behavior and links to pricing page (Session 82)

🟢 Landing + SEva

  • landing/seva/seva.js — Fixed file attach button label from "Business" to "Starter+" (both ja/en). File upload is available from Starter plan (Session 82)
  • landing/seva/seva.js_appendSystemNote() now returns the DOM element. _processFileAttach() removes the "Processing file..." message once the review card is displayed (Session 82)
  • landing/seva/seva.js — Added AbortSignal.timeout(60000) to /upload fetch. Times out after 60s with error message instead of hanging indefinitely (Session 82)
  • landing/console.html — Added rag_ingest and rag_resolve to SCENARIOS. Clicking Secure RAG sidebar items now opens a test panel inside the console instead of attempting to open external docs (Session 82)
  • landing/console.html — Added RAG routing and body construction in runRequest() for rag_ingest/rag_resolve scenarios (Session 82)
  • landing/console.html — Added RAG response visualization in renderPreview(): ingest shows chunk list + token count; resolve shows restored text + count (Session 82)

🟡 Landing

  • landing/console.html — Extended SEva file attachment to Starter plan (📎 button now shown for Starter/Business/Enterprise) (Session 82)
  • landing/seva/seva.js — Added 1 MB file size limit; shows error message in chat if exceeded (Session 82)

🟢 Landing

  • landing/seva/seva.js + landing/seva/seva.css + landing/console.html — Business/Enterprise Tier file attachment in SEva chat: added 📎 button to chat input (visible for Business/Enterprise plans only). Flow: select file → proxy /upload (text extraction + PII masking) → in-chat review card (PII count, masked preview) → [Send] pushes masked text into SEva. Supported formats: PDF, Word, Excel, PowerPoint, CSV, TXT, MD, HTML, RTF (Session 82)

🔵 Landing

  • landing/console.html — Fixed TOTP re-enrollment error: automatically unenroll unverified factors before calling mfa.enroll(), eliminating "Failed to get QR code" errors on retry (Session 81)
  • landing/console.html — Fixed TOTP QR code rendering: switched from innerHTML template literal to createElement + img.src assignment. Root cause was double quotes inside the data URI breaking the HTML attribute (Session 81)

🟡 Landing

  • landing/console.html — Account tab: plan-aware action buttons. Free → shows "Upgrade to Starter" and "Upgrade to Business" buttons (direct Stripe Checkout); Starter → shows "Upgrade to Business" button; Business/Enterprise → shows "View Plans" link. Stripe portal button hidden for Free plan users (Session 81)

🟢 Proxy

  • proxy/index.js — Added POST /stripe/create-portal-session. Generates a Stripe Customer Portal URL, enabling the "Open Stripe Portal" button in the Account tab (Session 81)

🟢 Landing

  • landing/console.html — Account Settings page implemented with 4 tabs: Profile / Security / Activity / Account. API Key management moved from sidebar to Security tab. Profile tab allows setting display name and company name (saved to Supabase user_metadata). Activity tab shows login history and account creation date. Account tab shows plan usage, Stripe billing portal link, and account deletion request. Topbar and org selector now show display name / company name when set (Session 80)
  • landing/console.html — Two-factor authentication (TOTP) implemented: required for Business/Enterprise plans, optional banner for Starter. Login flow adds TOTP challenge as Step 3. Supabase MFA enroll/challenge/verify API integration. QR code display and manual secret key entry supported (Session 80)
  • landing/api-keys.md — Removed plan-tier API call limit table; replaced with link to Plans & Feature Limits page to avoid future sync issues (Session 80)

⚪ Docs

  • docs/ja/api/quickstart.md — Fixed the quickstart code example: replaced 田中太郎 (no space, name slipped through) with 田中 太郎 (space) + added extraTypes: ["name"]. Example now correctly shows name being masked (Session 80)
  • docs/ja/guide/limitations.md — Added new section honestly documenting the space-required limitation for Japanese name detection, including workarounds and planned improvement (Session 80)
  • docs/en/guide/limitations.md — Added name detection space requirement to English limitations page, including Japanese-specific impact note (Session 80)
  • docs/ja/api/rag.md — Fixed Proxy API example and test result: replaced 山田太郎 (no space) with 山田 太郎 (space) + added extraTypes: ["name"]. Test result updated to show name tokenized correctly (3/3 → 4/4) (Session 80)
  • docs/en/api/rag.md — Updated Proxy API example to use Alice Smith (space) + extraTypes: ["name"]. Test result updated to include name token (Session 80)

🟡 Landing

  • landing/console.html — Sidebar redesigned (Plan C): restructured into PII Protection / Injection Defense / Secure RAG (Starter+) / Shadow AI (Business+) categories (Session 72)
  • landing/console.html — New endpoints added: POST /detect-sql and POST /detect-all-injections under Injection Defense (Session 72)
  • landing/console.html — New Try It scenarios: SQL Injection and Composite Attack (Session 72)
  • landing/console.html — Plan gate panel: clicking Secure RAG / Shadow AI shows upgrade prompt (Session 72)
  • landing/console.html — EN i18n foundation: I18N object, data-i18n attributes, setLang() extended (Session 72)
  • Support Chat (Supportchat/poc/src/server.ts) — SEva Enterprise Privacy Briefing: STEP 0 added before persona selection. SEva asks for company name, division, contact name, and contact info at the start of Enterprise consultations. Declared terms are registered as session-level custom masks and applied via extractDeclaredPII() + maskWithCustomTerms() before writing to seva_logs — company names and contact PII are never stored in plain text (Session 77)
  • landing/seva/seva.js + landing/console.html — Prospect tracking: userId (Supabase UUID) and endpointsTried added to SEva context; forwarded to Railway for purchase-intent scoring (Session 76)
  • landing/seva/seva.js + landing/console.html — SEva default open: panel opens automatically on console load (defaultOpen: true); users can hide via tab button (Session 76)
  • landing/seva/seva.js — SalesEva: added callsUsed and callLimit to server context note, enabling usage-based upgrade nudges in SYSTEM_PROMPT (Session 76)
  • landing/seva/seva.js + landing/seva/seva.css — SEva feedback button layout fix: buttons now appear BELOW the chat bubble (column layout via .seva-bub-wrap wrapper) instead of to the right (Session 75)
  • landing/seva/seva.js + landing/seva/seva.css — SEva Learning Loop Phase 3: 👍/👎 feedback buttons added to bot messages. _rate() method (fire-and-forget to chatUrl/rate). JA/EN i18n support (Session 74)
  • app/src/main.jsx — Terms of Service agreement screen added: version-based consent (TERMS_VER), terms_agreements Supabase table check, re-consent on version update (Session 74)
  • landing/console.html — OTP input: maxlength changed from 6 to 8; label updated to "確認コード(6〜8桁)" (Supabase sends 8-digit codes in some cases) (Session 73)
  • landing/seva/seva.js + landing/seva/seva.css — SEva (SupportEva) Phase 1: AI technical support widget as standalone reusable module (SevaWidget class); right-side 340px slide panel, Railway chat API connection, Privacy by Design context passing, JA/EN i18n (Session 73)
  • docs/en/api/seva.md + docs/ja/api/seva.md — SEva documentation: overview, Privacy by Design principles, FAQ, example questions; added to sidebar under Infrastructure & Operations (Session 73)
  • landing/console.html — SEva contextFn complete: added endpointsTried (visited endpoint history, dedup, max 10), callsUsed (monthly total across all keys), callLimit (plan limit); all three are behavioral metadata only — Privacy by Design boundary maintained (Session 73)
  • landing/seva/seva.js — SEva Phase 2: full PII Firewall pipeline on every message (detectAllInjections → mask → Railway chat → restore-text); attack blocking with counter, PII mask count display, graceful degradation on pipeline errors (Session 73)
  • docs/en/api/seva.md + docs/ja/api/seva.md — Enriched SEva docs: full pipeline diagram (detectAllInjections → mask → Secure RAG → Claude → restoreAll), Secure RAG knowledge base architecture, real-time protection stats explanation, expanded FAQ and question examples (Session 73)
  • landing/tokusho.html — Phone number updated from "pending" to 070-3630-6741 (JA/EN); removed "pending" note (Session 71)
  • landing/index.html — All nav items (Products, Solutions, Developers, Resources, Pricing, Sign In) fully disabled via pointer-events:none; opacity:0.45; cursor:default; Sign In also gets onclick="return false" during patent application period (Session 71)

🔵 Infrastructure & Security (Session 71)

  • 2FA enabled on all services: GitHub (Passkey+TOTP+Recovery), Cloudflare (TOTP+Backup), Supabase (App 278), Railway (App+Recovery) (Session 71)
  • Vercel account deleted; GitHub Apps cleaned up (Cloudflare + Railway only) (Session 71)
  • Supabase Pro upgrade (M-DEEP inc corporate billing; daily auto-backup 7-day retention) (Session 71)
  • Cloudflare Email Routing updated: support@piifirewall.comsupport@m-deep.com (Active) (Session 71)

⚪ Docs (Session 71)

  • internal-docs/infra/account-migration.md — Added 2FA completion status, GitHub Apps cleanup, Cloudflare security plan, Email Routing, and Google Workspace configuration sections (Session 71)
  • internal-docs/project/tips.md — Added Markdown → Word conversion section (Session 71)
  • /md-to-word skill created (C:\Users\kmish\.claude\commands\md-to-word.md) (Session 71)
  • landing/index.html — Simplified to general-user view for patent application preparation (Session 70): all nav dropdowns hidden, audience section hidden, MCP callout hidden, Developer section hidden, Pricing section hidden, contact form hidden, chat widget hidden, CTA buttons disabled (all via display:none / pointer-events:none, instantly reversible)
  • landing/index-v2.html — Secure RAG section removed (patent pending, not for public disclosure) (Session 67)
  • landing/index-v2.html — Purchase flow fix applied: Start Starter/Business → OTP → redirect with ?plan= param → Stripe Checkout auto-launch (Session 67)
  • landing/index-v2.html — Added missing auth modal HTML (was causing null classList error on Start Starter click) (Session 67)
  • landing/portal.html — Added Stripe Checkout auto-launch on ?plan=starter|business URL param after OTP redirect (Session 67)
  • landing/index.html / index-v2.html — Fixed Magic Link emailRedirectTo to include plan params (plan was lost when Supabase redirected via Site URL) (Session 67)
  • landing/index-v2.html — Secure RAG section changed from deleted to display:none (can be re-enabled after patent filing) (Session 67)
  • landing/index.html / index-v2.html — Fixed OTP form: changed 8-char check to 6-char minimum (Supabase sends 6-digit codes but form was blocking on 8-char requirement) (Session 67)
  • landing/portal.html — Fixed Stripe Checkout: changed window.open to window.location.href to bypass popup blocker (Session 67)

🔵 Fixed

  • landing/console.html — Added "Last Used" column to API key list (last_used_at; shows "—" for unused keys) (Session 69)
  • proxy/api-key-auth.js — API call usage is now aggregated per user (sum across all keys). Monthly call count is preserved on key rotation or new key creation (Session 69)
  • proxy/api-key-auth.js — Fixed broken .rpc reference in Enterprise plan call logging code (Session 69)
  • landing/index.html / index-v2.html — OTP redirect target changed from /portal to /console (5/1 release is developer-facing; portal is not linked) (Session 68)
  • landing/console.html — Fixed POST /detect Preview showing "No PII Detected" even when detections exist (/detect returns candidates array, not detections) (Session 68)
  • landing/console.html — Added Stripe Checkout auto-launch on ?plan= param after OTP redirect from landing (Session 68)
  • landing/console.html — Removed app.piifirewall.com reference in login overlay (app not released until 5/1) (Session 68)
  • landing/console.html — Org name and SANDBOX/LIVE badge now dynamically update on login/logout (was hardcoded "Acme Corp" / "SANDBOX") (Session 68)
  • landing/console.html — API key list now shows monthly call usage: Free shows calls / 300 with progress bar and color warning (yellow ≥70%, red ≥90%); Starter/Business shows raw call count (Session 68)
  • proxy/index.js — CORS: added pii-firewall.pages.dev to allowed origins (Cloudflare Pages preview URLs use hyphen, not piifirewall.com, causing Stripe session fetch to be blocked) (Session 67)
  • Purchase flow: Fixed "Start Starter/Business" → OTP → Stripe Checkout not launching; now auto-triggers checkout after OTP verification (Session 66)
  • Updated @xmldom/xmldom from 0.8.11 → 0.9.10 (High: XML injection vulnerability GHSA-wh4c-j3r5-mjhp) (Session 66)
  • Updated dompurify from 3.3.3 → 3.4.0 (Moderate: ADD_TAGS bypass vulnerability GHSA-39q2-94rc-95cp) (Session 66)

🟢 Added

  • examples/ollama-basic.js — PII Firewall + Ollama basic integration sample (mask → send → restore) (Session 62)
  • examples/ollama-secure-rag.js — Secure RAG + Ollama sample (use internal documents with local LLM) (Session 62)
  • examples/ollama-full-defense.js — Full defense pipeline sample (composite attack detection + PII protection + Ollama) (Session 62)
  • examples/README.md — Ollama integration samples setup & run guide (Session 62)
  • fw.detectAllInjections(text, lang?) — Composite attack detection: detects SQL injection and prompt injection simultaneously; returns { hasSQLInjection, hasPromptInjection, compositeRisk } (Session 58)
  • fw.detectSQLInjection(text) — Standalone SQL injection detection (Session 58)
  • rag_ingest MCP tool — Tokenizes PII in documents for Secure RAG pipelines; returns chunked, anonymized text (Session 59)
  • rag_resolve MCP tool — Restores SRAG tokens in LLM responses to original values (Session 59)
  • MCP Server now has 9 tools (was 6): added detect_all_injections, rag_ingest, rag_resolve
  • API key detection expanded to 11 providers: Anthropic, OpenAI, Stripe, Google AI (AIzaSy…), HuggingFace (hf_), Groq (gsk_), Perplexity (pplx-), Replicate (r8_), AWS (AKIA…), GitHub (ghp_, ghs_, github_pat_) (Session 59)
  • POST /mask Proxy API endpoint — Masks all PII in text and returns { masked, detections }. Designed for external SDKs and AI agents (Session 64)
  • POST /restore-text Proxy API endpoint — Restores SECURED tokens in bulk and returns the restored text. Agent-oriented alternative to /restore-all (Session 64)
  • /detect-all-injections Proxy API endpoint — HTTP endpoint for composite attack detection (Session 58)
  • /rag/ingest and /rag/resolve Proxy API endpoints (Session 58)
  • Enterprise deployment pattern docs: CLAUDE.md + Claude for Teams Projects system prompt enforcement (Session 59)

🟡 Landing

  • All nav: "ソリューション" renamed to "選ぶ理由" / "Why PII Firewall" across all 14 pages (Session 61)
  • landing/solutions/injection-defense.html — Added SQL Injection section, competitive comparison table, updated Hero (Session 61)
  • landing/index-v2.html — UX improvements (9 items): tab button resize, step arrows in How section, larger Secure RAG flow, Pricing center-align, section-desc centering fix, punctuation cleanup (Session 61)
  • landing/index-v2.html — Developer-first full redesign: 8-section structure (Code/HowItWorks/Integrations/Capabilities/RAG/Pricing/Trust/CTA), npm install primary CTA, browser-app CTAs removed, heading punctuation rules established (Session 61)
  • landing/index-v2.html — Hero message redesign: "Ship AI to production. Overcome the last mile with one line of code." (Session 60)

⚪ Docs

  • internal-docs/sessions/ — Session 59/60/61 reports and handoff documents added to sessions index (Session 61)
  • en/api/rag.md — New standalone Secure RAG page split from mcp.md (Session 62)
  • en/api/injection-detection.md — New standalone Composite Attack Detection page split from mcp.md (Session 62)
  • en/api/mcp.md — Trimmed to MCP Server core; cross-links added to Secure RAG and Composite Attack Detection pages (Session 62)
  • en/api/index.md — Overview updated: 5 integration options, 7 key capabilities, API key not required note for MCP/SDK (Session 62)
  • docs/.vitepress/config.ts — JA/EN sidebars reorganized into category groups (Getting Started / Integration / Reference / Implementation Guides / Infrastructure) (Session 62)

⚪ Docs

  • en/api/use-cases.md — Use Cases by Industry guide (Finance, Legal, Healthcare, Manufacturing, Enterprise) (Session 59)
  • ja/api/use-cases.md — 業種別導入事例ガイド + Manufacturing Secure RAG + Enterprise deployment patterns (Session 59)
  • en/api/slack-it-integration.md — Slack & IT/OT System Integration Guide (MCP system prompt + Proxy API patterns) (Session 59)
  • ja/api/slack-it-integration.md — Slack・IT/OT連携ガイド (Session 59)
  • en/api/mcp.md / ja/api/mcp.md — Updated for 9 tools, added Secure RAG pipeline section, API key detection table (Session 59)
  • en/api/sdk.md / ja/api/core-functions.md — Added detectAllInjections() with competitor comparison table (Session 59)
  • Shadow AI monitoring docs added (Session 55–56)

🟡 Changed

  • MCP Server tool count: 6 → 9

v0.1.0 — 2026-04-13

Added

  • @pii-firewall/core — 24 PII types, mask/restore, differential privacy, injection detection (10 categories)
  • @pii-firewall/sdk — Node.js SDK (createFirewall(), maskPII(), detectPII(), detectInjection())
  • @pii-firewall/mcp-server — MCP Server for Claude Desktop / Cursor (6 tools)
  • REST API — /detect, /mask, /restore, /detect-injection endpoints
  • Developer Console — piifirewall.com/console (email OTP auth, API key issuance & management)
  • API key authentication — pf_live_xxx format with plan-based call limits

Language support

  • Japanese (lang: "ja") and English (lang: "en")

Infrastructure

  • Railway (proxy) · Cloudflare Pages (landing) · Cloudflare Workers (app, docs)

Changelog conventions

TypeDescription
🔴 BreakingBreaking API changes (response format, endpoint removal)
🟢 AddedNew features or endpoints
🟡 ChangedChanges to existing features
🔵 FixedBug fixes
⚪ DocsDocumentation-only changes

Last updated:

Privacy by Design.