From e76939cc42ae08dd7c50075324981c3a66987f1a Mon Sep 17 00:00:00 2001 From: posimai Date: Sun, 29 Mar 2026 12:21:18 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20initial=20commit=20=E2=80=94=20posimai-?= =?UTF-8?q?atlas=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- atlas.json | 125 +++++ index.html | 1417 +++++++++++++++++++++++++++++++++++++++++++++++++ manifest.json | 17 + package.json | 7 + sw.js | 31 ++ 5 files changed, 1597 insertions(+) create mode 100644 atlas.json create mode 100644 index.html create mode 100644 manifest.json create mode 100644 package.json create mode 100644 sw.js diff --git a/atlas.json b/atlas.json new file mode 100644 index 0000000..9ac9408 --- /dev/null +++ b/atlas.json @@ -0,0 +1,125 @@ +{ + "meta": { + "owner": "mai", + "description": "Posimai 開発インフラ構成", + "updated": "2026-03-29", + "version": "1" + }, + "nodes": [ + { + "id": "windows-pc", + "label": "Windows PC", + "type": "device", + "description": "メイン開発機。Claude Code / VS Code / Git", + "status": "active" + }, + { + "id": "iphone", + "label": "iPhone", + "type": "device", + "description": "PWA テスト・モバイル確認", + "status": "active" + }, + { + "id": "synology", + "label": "Synology NAS", + "type": "device", + "description": "ローカルストレージ・Gitea ホスト", + "status": "active" + }, + { + "id": "vps-hetzner", + "label": "VPS (Hetzner)", + "type": "server", + "description": "Posimai API 本番サーバー。Docker コンテナで運用", + "url": "https://api.soar-enrich.com", + "status": "active" + }, + { + "id": "tailscale", + "label": "Tailscale", + "type": "network", + "description": "デバイス間 VPN メッシュ。PC / iPhone / Synology / VPS を接続", + "url": "https://tailscale.com", + "status": "active" + }, + { + "id": "cloudflare", + "label": "Cloudflare", + "type": "network", + "description": "DNS 管理。api.soar-enrich.com 等のドメインを管理", + "status": "active" + }, + { + "id": "github", + "label": "GitHub", + "type": "cloud", + "description": "ソースコード管理。push で Vercel 自動デプロイをトリガー", + "url": "https://github.com/posimai", + "status": "active" + }, + { + "id": "vercel", + "label": "Vercel", + "type": "cloud", + "description": "全 posimai-* アプリのホスティング・自動デプロイ", + "url": "https://vercel.com", + "status": "active" + }, + { + "id": "stripe", + "label": "Stripe", + "type": "cloud", + "description": "決済処理。共同開発者と共有", + "url": "https://stripe.com", + "status": "active" + }, + { + "id": "gitea", + "label": "Gitea", + "type": "service", + "description": "ローカル Git バックアップ。Synology 上で Docker 動作", + "url": "http://100.76.7.3:3000", + "status": "active" + }, + { + "id": "docker", + "label": "Docker", + "type": "service", + "description": "VPS 上のコンテナランタイム。Posimai API コンテナを管理", + "status": "active" + }, + { + "id": "posimai-api", + "label": "Posimai API", + "type": "service", + "description": "server.js。認証・記事・TTS・ジャーナル API を提供", + "url": "https://api.soar-enrich.com", + "status": "active" + }, + { + "id": "posimai-apps", + "label": "Posimai Apps", + "type": "app", + "description": "25+ の posimai-* PWA 群。Vercel でホスト", + "url": "https://posimai-dashboard.vercel.app", + "status": "active" + } + ], + "edges": [ + { "from": "windows-pc", "to": "tailscale", "type": "connects", "label": "VPN" }, + { "from": "iphone", "to": "tailscale", "type": "connects", "label": "VPN" }, + { "from": "synology", "to": "tailscale", "type": "connects", "label": "VPN" }, + { "from": "vps-hetzner", "to": "tailscale", "type": "connects", "label": "VPN" }, + { "from": "windows-pc", "to": "gitea", "type": "push", "label": "git push" }, + { "from": "windows-pc", "to": "github", "type": "push", "label": "git push" }, + { "from": "github", "to": "vercel", "type": "trigger", "label": "auto deploy" }, + { "from": "vercel", "to": "posimai-apps", "type": "hosts" }, + { "from": "gitea", "to": "synology", "type": "runs-on" }, + { "from": "docker", "to": "vps-hetzner", "type": "runs-on" }, + { "from": "posimai-api", "to": "docker", "type": "runs-on", "label": "container" }, + { "from": "posimai-apps", "to": "posimai-api", "type": "calls", "label": "API" }, + { "from": "cloudflare", "to": "vps-hetzner", "type": "dns", "label": "DNS" }, + { "from": "posimai-apps", "to": "stripe", "type": "calls", "label": "payment" } + ] +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..f30ab6f --- /dev/null +++ b/index.html @@ -0,0 +1,1417 @@ + + + + + + + + + + + + + + + + + + + Atlas + + + + + + + + + + + + + + + + + + + +
+
+ + Atlas +
+
+ + +
+
+ + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..a2a458c --- /dev/null +++ b/manifest.json @@ -0,0 +1,17 @@ +{ + "id": "/posimai-atlas/", + "name": "Atlas", + "short_name": "Atlas", + "description": "インフラ構成図・サービス依存マップ", + "start_url": "/", + "display": "standalone", + "display_override": ["window-controls-overlay", "standalone"], + "background_color": "#0C1221", + "theme_color": "#0C1221", + "orientation": "any", + "categories": ["productivity", "utilities"], + "icons": [ + { "src": "/logo.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, + { "src": "/logo.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..66f27f6 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "posimai-atlas", + "version": "1.0.0", + "scripts": { + "deploy": "git push gitea main && git push github main" + } +} diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..466331b --- /dev/null +++ b/sw.js @@ -0,0 +1,31 @@ +const CACHE = 'posimai-atlas-v1'; +const STATIC = ['/', '/index.html', '/manifest.json', '/logo.png', '/atlas.json']; + +self.addEventListener('install', e => { + e.waitUntil(caches.open(CACHE).then(c => c.addAll(STATIC))); +}); + +self.addEventListener('activate', e => { + e.waitUntil( + caches.keys().then(keys => + Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))) + ).then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', e => { + if (e.request.method !== 'GET') return; + if (!e.request.url.startsWith(self.location.origin)) return; + + e.respondWith( + caches.open(CACHE).then(cache => + cache.match(e.request).then(cached => { + const network = fetch(e.request).then(res => { + if (res.ok && res.type === 'basic') cache.put(e.request, res.clone()); + return res; + }).catch(() => cached); + return cached || network; + }) + ) + ); +});