diff --git a/.github/workflows/idea-market-share-qa.yml b/.github/workflows/idea-market-share-qa.yml
new file mode 100644
index 0000000..47c0367
--- /dev/null
+++ b/.github/workflows/idea-market-share-qa.yml
@@ -0,0 +1,30 @@
+name: Idea Market Share Landing QA
+on:
+ pull_request:
+ paths:
+ - share/idea-market/**
+ - tests/idea-market-share.test.mjs
+ - .github/workflows/idea-market-share-qa.yml
+ push:
+ branches: [main]
+ paths:
+ - share/idea-market/**
+ - tests/idea-market-share.test.mjs
+ - .github/workflows/idea-market-share-qa.yml
+permissions:
+ contents: read
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: |
+ share/idea-market
+ tests/idea-market-share.test.mjs
+ sparse-checkout-cone-mode: true
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+ - run: node --test tests/idea-market-share.test.mjs
diff --git a/share/idea-market/index.html b/share/idea-market/index.html
new file mode 100644
index 0000000..474c8d2
--- /dev/null
+++ b/share/idea-market/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+Open an Idea Market idea | SK APPS
+
+
+
+
+
+A friend shared an idea
+Explore this idea in Idea Market. Paid or private details are never shown on this page.
+We couldn't read this invitation. Please ask your friend to share it again.
+Open this idea in the app
+Install Idea Market on Google Play
+Explore SK APPS
+After installing, return to the shared link to open the idea.
+
+
+
diff --git a/share/idea-market/referral.js b/share/idea-market/referral.js
new file mode 100644
index 0000000..d2aa1fc
--- /dev/null
+++ b/share/idea-market/referral.js
@@ -0,0 +1,21 @@
+'use strict';
+// This static landing does NOT request idea details and does not track tokens.
+// Only harmless alphanumeric IDs are used to build an app-specific URI.
+(() => {
+ const id = new URLSearchParams(location.search).get('id') ?? '';
+ const validId = /^[a-zA-Z0-9_-]{1,96}$/.test(id);
+ const open = document.getElementById('open-app');
+ const error = document.getElementById('error');
+ if (validId) {
+ open.href = 'ideamarket://open/ideas/' + encodeURIComponent(id);
+ open.hidden = false;
+ } else {
+ error.hidden = false;
+ }
+ if (navigator.language?.toLowerCase().startsWith('ja')) {
+ document.getElementById('title').textContent = 'アイデアが共有されました';
+ document.getElementById('intro').textContent = 'Idea Marketアプリで共有されたアイデアを開けます。購入前の非公開情報はこのページに表示しません。';
+ open.textContent = 'アプリでアイデアを開く';
+ error.textContent = '共有リンクを確認できません。もう一度共有してもらってください。';
+ }
+})();
diff --git a/tests/idea-market-share.test.mjs b/tests/idea-market-share.test.mjs
new file mode 100644
index 0000000..beaa032
--- /dev/null
+++ b/tests/idea-market-share.test.mjs
@@ -0,0 +1,17 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import {readFileSync} from 'node:fs';
+const html=readFileSync(new URL('../share/idea-market/index.html',import.meta.url),'utf8');
+const js=readFileSync(new URL('../share/idea-market/referral.js',import.meta.url),'utf8');
+test('share page gives real Play acquisition fallback and an explicit app open',()=>{
+ assert.match(html,/play\.google\.com\/store\/apps\/details\?id=jp\.appdevelopsk\.ideamarket/);
+ assert.match(html,/id="open-app"/);
+ assert.match(html,/script src="referral\.js"/);
+ assert.match(html,/noindex,nofollow/);
+});
+test('identifiers cannot inject scripts or arbitrary external redirects',()=>{
+ assert.match(js,/\[a-zA-Z0-9_-\]\{1,96\}/);
+ assert.match(js,/encodeURIComponent\(id\)/);
+ assert.match(js,/ideamarket:\/\/open\/ideas\//);
+ assert.doesNotMatch(js,/innerHTML|window\.location\s*=|fetch\(/);
+});