Self-hosted NFC and QR sharing for local businesses in China. A visitor taps a tag, chooses a platform, gets the right copy and media, then continues in the target app with the shortest reliable fallback.
Live demo · 中文文档 · Platform support · Adapter guide
NFC tags are cheap and permanent, while campaigns, platforms and merchant content change. NFC Merchant Share keeps the physical tag stable and moves routing, prepared content and analytics into a self-hosted service.
NFC / QR tag
-> /t/{tag_id}
-> dynamic Tag Router
-> Merchant + Content Pack
-> Platform Adapter
-> Clipboard / Web Share / Deep Link / Web fallback
- Dynamic Tag Router. Rebind a fixed NFC URL without rewriting the tag.
- Merchant CRUD with independent copy, image, video and Wi-Fi settings.
- Four built-in adapters: Douyin, Xiaohongshu, Meituan and Dianping.
- Capability-driven adapter contract for adding more platforms.
- Clipboard, file sharing, download and deep-link fallback chain.
- SVG QR generation for every Tag.
- Seven-day funnel and platform-click analytics.
- Authenticated admin, login throttling, file signature checks and CSP.
- Docker Compose quick start and GitHub Actions verification.
- Mobile-first UI with light and dark mode.
Requirements: Docker with Compose.
git clone https://github.com/kamjcx/nfc-share.git
cd nfc-merchant-share
docker compose up -d --buildOpen:
- Visitor demo: http://localhost:3000/t/demo
- Admin: http://localhost:3000/admin
- Local demo account:
demo/demo
The Compose profile stores merchant data, tags, events and uploads in named volumes.
npm install
npm startNode.js 20 or newer is required. Development mode enables the local demo account. Production rejects admin login unless ADMIN_USERNAME and ADMIN_PASSWORD are configured.
erDiagram
TAG }o--|| MERCHANT : routes_to
MERCHANT ||--o{ CONTENT_PACK : owns
CONTENT_PACK }o--|| PLATFORM_ADAPTER : prepared_by
TAG ||--o{ EVENT : emits
MERCHANT ||--o{ EVENT : aggregates
Tag: fixed public ID, merchant binding, label and enabled state.Merchant: public profile, media, Wi-Fi and platform configuration.Content Pack: platform-specific copy and preferred media.Event: privacy-reduced interaction record for the analytics funnel.
Read Architecture for route and storage details.
Each adapter declares capabilities and implements the same behavior boundary:
{
capabilities: {
openApp: true,
openPublish: false,
shareFiles: true,
prefillText: false,
clipboard: true,
fallback: true
},
copy(),
shareMedia(),
downloadMedia(),
openPlatform()
}The platform page never needs platform-specific branching. See Adapter Development.
Copy .env.example and set at least:
NODE_ENV=production
PUBLIC_BASE_URL=https://tap.example.com
ADMIN_USERNAME=admin
ADMIN_PASSWORD=replace-with-a-long-random-password
EVENT_SALT=replace-with-a-random-secret
ALLOW_DEMO_ADMIN=falseOptional legal footer:
ICP_NUMBER=your-icp-number
ICP_URL=https://beian.miit.gov.cn/Never expose the local demo account on a public deployment. A hosted public demo should set DEMO_READ_ONLY=true and use disposable storage.
npm run check
npm test
npx playwright install chromium
npm run test:e2eThe suite covers public routing, admin authentication, merchant persistence, uploads, dynamic Tags, QR generation, analytics and mobile user flows.
- Docker: Docker quick start
- Linux, Nginx and systemd: use the templates in
deploy/ - NFC writing: NFC Writing Guide
- Security and privacy: Security Policy and Privacy Notes
v0.1.0 focuses on the complete path from physical entry to prepared platform content. AI generation, media templating, CRM, reseller hierarchies and billing are intentionally outside the core release.
See CHANGELOG and Release Checklist.
Platform adapters are the best place to start. Read CONTRIBUTING, choose an adapter issue, add capability evidence and update PLATFORM_SUPPORT.md with tested OS and App versions.
MIT


