PRODUCT NOTE / PLATFORM PRD

nzw.jp

個人開発者 nzw のポートフォリオ兼 AI プラットフォーム。
この文書は、このサイトそのものをなぜ・誰のために・どんな思想で作っているかから記録した開発ノートです。

ステータスActive(継続運用・開発中)
ドメインnzw.jp(姉妹サイト zerohalf.jp と別ドメインで共存)
運営nzw(Hidekazu Nozawa) — PM × 作家 × バイブコーダー
載せているもの技術書 / モバイルアプリ / Web ゲーム / AI ツール / 開発ノート / グッズ
最終更新2026-08-30
技術構成FastAPI ・ Tailwind ・ Canvas ・ Flutter Web ・ Nginx ・ EC2 / Docker
関連リンク トップAbout(運営者)グッズ開発ノート一覧
TL;DR

ひとことで

nzw.jp は、1 人の開発者がつくるアプリ・ゲーム・AI ツール・技術書・開発ノートを一元公開する場です。単なる作品展示場ではなく、「AI に任せる」ではなく「AI を使うことで、あなた自身が強くなる」という設計思想(zerohalf ミッション)を体現するプラットフォームを目指しています。

Problem / Mission

背景・なぜ作るか

土台にあるのは zerohalf のミッション「AI が全てできる時代に、人間としての価値を育てる」。

そこで、理論(本)・実証(プロダクト)・記録(開発ノート)をひとつの場で束ねて見せるプラットフォームとして nzw.jp を運営している。

Who

ターゲット

見せる相手

  • アプリ・ゲームのエンドユーザー
  • AI エージェント設計に関心のあるエンジニア・PM
  • 設計支援を検討する相手(B2B 導線)

nzw の立ち位置

「PM × 作家 × バイブコーダー」を 1 人で横断する交差点そのものが参入障壁。汎用 AI が持てない「偏愛」と「積み重ねた文脈」で勝負する。

Scope

載せるもの・載せないもの

スコープ(In scope)

  • 技術書『チームに溶け込む AI エージェント開発』
  • モバイルアプリ(Engly / DayGrid / MyDictly)
  • Web ゲーム(Synapse Link / BOM ほか 30+ 作品)
  • AI ツール(AI Workspace / グループチャット)
  • 開発ノート(本ドキュメント群)
  • グッズ(/goods/:アクリルキーホルダーほか)
  • zerohalf ブランドへの導線

やらないこと(Non-goals)

  • Big Tech の土俵(汎用パーソナル OS)での正面勝負
  • 「AI に任せて終わり」を促す体験
  • 思想を語らない、ただの作品リスト化
Success Metrics

成功指標(KPI)

「思想とプロダクトが結びついて届く」状態かを見る。指標は仮置き

本 → 相談
書籍からの設計支援問い合わせ
(B2B 導線が回るか)
回遊
アプリ ⇄ 開発ノートの回遊
(裏側まで読まれるか)
継続
各プロダクトの継続利用
("育てる AI" が刺さるか)
Front-end Craft

トップページのブラックホール

トップページには、ときどきブラックホールが現れて画面上をゆっくり横切る。Synapse Link の敵役をそのまま連れてきたもので、タップするとそのゲームが開く。絵の中身(6 層の重ね方・配色・脈動)は Synapse Link の開発ノートに書いたので、ここではサイトに載せるためにやったことを残す。

Flutter の描画を Canvas 2D に置き換える

原典は Flutter の BlackHoleRenderer.draw()。層の順番・係数・色は一切変えず、API だけ差し替えた。数値を触らないと決めたので、見比べても違いが分からない状態を保てている。

FlutterCanvas 2D注意した点
ui.Gradient.radialctx.createRadialGradient()停止位置の配列をそのまま addColorStop に写す
MaskFilter.blurctx.filter = 'blur(7px)'未対応環境があるので起動時に一度だけ判定し、駄目なら素の輪郭で描く
BlendMode.plusglobalCompositeOperation = 'lighter'降着円盤だけに掛け、save/restore で確実に戻す
HSLColor.fromAHSLhsla(...) 文字列色相は 0〜360 に丸めてから渡す
Color.lerp自前の lerpColor()危険度による紫 → 赤 → 金の補間で使う
1 フレーム = 60fps 前提step = dt ÷ (1/60)原典の += 0.02 にこの係数を掛け、高リフレッシュレートでも速くならないようにした

徘徊のさせ方

ゲーム内では重力計算で動くが、サイトには引き合う相手がいない。そこで移動だけを別に書いた。まっすぐ飛ばすと単なるスクリーンセーバーになるので、気まぐれさを足している。

出るかどうかは抽選にした

当初は夜だけ必ず出していたが、必ず居るものは背景の一部になってしまう。朝・昼・夕は 3 回に 1 回、夜は 2 回に 1 回の抽選に変えた。大きさも blackHoleSizes の tiny / small / medium から等確率で引くので、出会えた日と、出会えた大きさが毎回違う。速度は原典の表どおり大きいほど遅く、tiny は 36px/秒、medium は 12px/秒。

コンテンツの前と後ろを行き来する

ずっと手前にいると邪魔になり、ずっと奥だとほぼ見えない。そこで z-index を往復させている。

重なり順の図。手前は z-index 30、奥は z-index -1 で、コンテンツを挟んで往復する。 ヘッダー z-index: 50 ブラックホール(手前)+ 当たり判定 z-index: 30 / 31 カード・セクションなどのコンテンツ z-index: auto ブラックホール(奥)+ 当たり判定 z-index: -1 背景アニメーション(シナプス) z-index: -1 body の背景(時間帯テーマ)

負の z-index は body の背景より上・コンテンツより下に入る。だから奥に回しても消えず、半透明のカード越しにぼんやり透ける。

効いている小技

踏んだ罠 classList.remove()消す対象が無くても class 属性を書き直す。後片付けを毎回無条件に呼んだ結果、MutationObserver → 後片付け → 属性の書き換え → MutationObserver …… とマイクロタスクが循環し、ページが完全に固まった。動作中かどうかのフラグを見て、必要なときだけ片付けるようにして解決。

Operations

構築・運用でつまずいた場所

サイトが落ちるときは、たいてい作り込みではなく足回りで落ちる。同じ穴に二度落ちないよう、実際に踏んだものだけを残す。

証明書が 1 枚だけ切れて、5 日気づかなかった

2026-08-30、zerohalf.jp がブラウザで NET::ERR_CERT_DATE_INVALID になった。証明書は 2026-08-25 に失効していて、同じサーバーの nzw.jp は正常に更新されていた。同居している 3 枚のうち 1 枚だけが更新に失敗し続けていたという壊れ方をしていた。

原因は認証方式の食い違い。zerohalf.jp の renewal/*.conf だけ authenticator = standalone になっていた。standalone は certbot 自身が 80 番ポートを listen して ACME チャレンジに応える方式なので、nginx が常時 80 番を握っているこのサーバーでは構造的に成功しない。ログを遡ると、更新開始ライン(失効の 30 日前)にあたる 2026-07-26 の初回試行から失効まで、1 日に数回のペースで同じ失敗を繰り返していた。約 1 か月ぶんの再試行が、すべて同じ理由で落ち続けていたことになる。

証明書authenticator結果
nzw.jpnginx自動更新され続けていた
zerohalf.jpstandaloneCould not bind TCP port 80 で毎回失敗 → 失効

復旧は certbot certonly --nginx --cert-name zerohalf.jp -d zerohalf.jp -d www.zerohalf.jp の 1 発。これで renewal 設定が authenticator = nginx / installer = nginx に書き換わり、nzw.jp と同じ形に揃った。認証方式はサーバー内で 1 つに統一するのが結論で、standalone が使えるのは nginx を止められる新規構築時だけ。

教訓 証明書は「取れた」で終わりにせず、2 回目の自動更新が通るところまでが構築certbot renew --dry-run は全証明書をまとめて検証するので、1 枚足したら必ず流す。そして certbot は更新に失敗しても何も通知しない。今回の 5 日間の空白は、失効を知る手段がブラウザで見ることしか無かったせいで生まれた。

証明書まわりに残っている地雷

デプロイスクリプトの癖

公開は ./deploy.shhtml/ を EC2 の /var/www/html/ へ rsync)だけだが、オプションの選び方がそのまま運用上の制約になっている。

オプション意図結果として起きること
--delete なし取り返しのつかない削除を防ぐローカルで消したファイルはサーバーに残る。古いページが URL 直打ちで生き続けるので、消すときは手で消す
--exclude=*.apk数百 MB の転送を毎回やらないAPK は rsync に乗らない。リリースのたびに別途アップロードが要る(現在 10 本・約 1.1 GB)
--exclude=.well-knownACME のチャレンジ置き場を守るrsync で .well-known を消して証明書更新を壊す事故が起きない
--checksum中身で差分を判定するタイムスタンプだけ変わったビルド成果物を取りこぼさない代わりに、転送前の走査が重い

nginx でしか直せない種類の不具合

失効を二度と見逃さないための監視

今回いちばん効いたのは更新の失敗そのものではなく、失敗が誰にも届かなかったことだった。そこで /usr/local/bin/cert-expiry-check.sh を置き、cron で毎日 JST 09:10(certbot のタイマーが動いたあと)に回している。設計で決めたのは次の 6 点。

踏んだ罠 .envSLACK_WEBHOOK_URL.env.sample のプレースホルダ(YOUR/WEBHOOK/URL)が残っていただけで、送信しても no_team の 404 が返るだけだった。設定されていることと、届くことは別。プレースホルダのままなら送信をスキップして理由をログに書く作りにし、URL を差し替えた時点から通知が始まるようにしてある。

2026-08-30、Slack の Incoming Webhook を作成して差し替え、実際に投稿が届くところまで確認した。以後は毎日 JST 09:10 に自動で走り、判定結果は /var/log/cert-expiry-check.log にも残る。Slack は無料プランのままで問題ない(2022 年 9 月に「連携アプリ 10 個まで」の上限が撤廃されているため)。ただし無料プランはメッセージ履歴が 90 日で古いアラートを遡れないので、ログ側を一次資料として残している。

秘密情報の置き場が緩い(未解決)

監視の通知先を入れたことで、/home/nzw/api/.env に秘密情報がもう 1 つ増えた。このファイルは現在 644 で、サーバー上の他ユーザーからも読める

教訓 秘密情報を新しく足すときは、置き場所の権限が足す前から足りているかを先に見る。動かすことを優先して .env に追記していくと、緩い権限のまま中身だけが重くなっていく。

Decision Log

主要な意思決定ログ

サイトを支える判断を、決定・仮説・結果の 3 点で残す。

infra TLS の認証方式をサーバー内で nginx に統一する
DECISION
zerohalf.jp だけ standalone だった証明書の認証方式を nginx に寄せ、3 枚すべてを同じ方式に揃えた。今後ドメインを足すときも --nginx--cert-name の明示を必須とし、standalone は使わない。
WHY / 仮説
2026-08-30 に zerohalf.jp が証明書失効で開かなくなった。失効は 08-25 で、5 日間気づかなかった。原因は standalone が 80 番を bind できず更新に失敗し続けていたことだが、本当の問題は「同じサーバーの証明書なのに 1 枚だけ更新経路が違う」状態を放置していたこと。方式が混在していると、動いている証明書を見て安心してしまい、壊れている 1 枚に気づけない。揃えること自体が監視の代わりになると考えた。
RESULT
再発行後、certbot renew --dry-run が 3 枚すべて success。有効期限は 2026-11-28 まで回復した。一方で、certbot が pip / apt / snap の 3 系統入りタイマーが 2 本並走していること、nzw.jp-0001 という未使用の重複証明書があること、retrieval.nzw.jp が DNS も SAN も欠けたまま設定だけ残っていることが判明し、宿題として残った。更新失敗が誰にも通知されない点は、同日に期限監視(後述)を入れて塞いだ。
motion ブラックホールは「必ず居る装飾」ではなく「たまに出会うもの」にする
DECISION
夜は必ず出していたのをやめ、時間帯ごとの抽選にした。朝・昼・夕は 1/3、夜は 1/2。大きさも原典の blackHoleSizes から tiny / small / medium を等確率で引き、速度は表どおり大きいほど遅くする。さらに z-index を 30 と -1 で往復させ、コンテンツの前後を行き来させた。
WHY / 仮説
毎晩かならず同じ大きさで同じように横切るものは、2 回目には目に入らなくなる。実際、実装直後に見たときの「何か動いている」という驚きが、翌日にはもう無かった。出るかどうか・どの大きさか・手前か奥かが毎回変わるなら、見つけたときにだけ嬉しいものになると考えた。ずっと手前にいると読む邪魔になる問題も、同じ仕組みで解ける。
RESULT
確率・サイズ・速度・奥行きの入れ替わりをヘッドレスブラウザで実測して検証した(抽選 2000 回で 0.32〜0.36 と 0.52、速度は表と 1% 以内で一致)。副産物として、classList.remove() が属性を無条件に書き直すことに起因する MutationObserver の無限ループを検出でき、公開前に潰せた。
goods グッズは「商品」ではなく「作った記録」として独立ページに置く
DECISION
アクリルキーホルダーを作ったタイミングで /goods/ を新設し、トップのヒーローと Labs & Prototypes の両方から導線を張った。EC・カート・価格表示は一切作らず、ステータスは「試作 / 構想」の 2 段階だけを持たせている。配布・販売の可能性は残すが、決まるまでは「未定」と明記する。
WHY / 仮説
キーホルダーは 1 個しか手元になく、売る算段も配る算段も無い状態で出来上がった。この段階で「SHOP」を名乗ると、買えないものを並べた店になって信頼を落とす。一方で置き場所を作らないと、アプリや書籍の副産物として生まれたキャラクターがどこにも残らない。「作ったものの延長線上にある記録」という枠なら、売れる前でも嘘にならないと判断した。
RESULT
グッズ 1 点でもページとして成立し、2 点目以降はカード(.goods-card)を複製するだけで追加できる形に落ち着いた。販売を始める場合も、ステータスを差し替えて導線を足すだけで移行できる。
arch 静的 HTML + FastAPI + DB カードのハイブリッド構成にする
DECISION
ページは静的 HTML(本番は nginx が直接配信)で高速に見せつつ、トップのカードは /v1/content-cards API から公開中のものを動的注入。API 停止時は静かにスキップして静的閲覧を維持する。
WHY / 仮説
個人運営では「速く・壊れにくく・更新しやすい」の両立が要る。表示は静的で堅牢に、告知やカードだけ DB で運用できれば、重い CMS なしに更新性を得られると考えた。
RESULT
公開/非公開・予約投稿を管理画面から制御しつつ、バックエンドが落ちてもサイトは閲覧可能な構成に。
design デザインシステム(design-system.css)を単一の基準にする
DECISION
配色・タイポ・余白・コンポーネントを --nzw-* トークンに集約し、フレームワーク非依存の CSS で全ページ共通化した。
WHY / 仮説
プロダクトごとに世界観を作り込むほど、サイト全体のトーンがばらつく。単一の基準があれば、個性を出しつつ一体感を保てると考えた(この開発ノート群も同トークンで構築)。
RESULT
各プロダクト LP・開発ノートが同じ土台で作られ、増やしても崩れない基盤を確保。
vision 「代替する AI」ではなく「育てる AI」を全プロダクトの軸にする
DECISION
各プロダクト(英語学習・習慣・単語・チャットの AI)を、ユーザーの能力を肩代わりするのではなく、伸ばす方向で設計する。
WHY / 仮説
「あなたが私を必要としなくなる日が、私の成功」。AI が人間の力を奪う流れに対し、逆張りの一貫した思想が差別化になると考えた。
RESULT
Engly のオフライン学習、DayGrid の継続可視化などに思想が反映され、サイト全体の一貫した価値観になっている。
Milestones

これまでの歩み

インフラ2026-08-30

zerohalf.jp の証明書失効から復旧(standalone → nginx 認証に統一)/運用でつまずいた場所を本ノートに集約/期限監視スクリプトと日次 cron を追加し Slack 通知まで開通させて失効の見逃しを塞ぐ/certbot 3 系統・重複証明書・retrieval.nzw.jp の未整理を宿題として記録

ブラックホール2026-08-15

Synapse Link の描画をトップページへ移植し徘徊させる/出現を時間帯ごとの抽選に変更/コンテンツの前後を天気に応じて往復

グッズ2026-08-11

/goods/ を新設/第1弾「いくぞ!アクリルキーホルダー」を掲載/配布・販売は未定のまま「作った記録」として公開

開発ノート2026-07

各プロダクトの Product Note(PRD / 設計ノート)を整備・公開

Design System2026

design-system.css で配色・トーンを標準化

書籍発売2026-06-23

『チームに溶け込む AI エージェント開発』を公開

アプリ群2026

Engly / DayGrid / LangBridge / Synapse Link を順次リリース、Flutter Web を同一オリジンに統合

プラットフォーム-

FastAPI + 静的 HTML + DB コンテンツカードのハイブリッドとして運用開始

Roadmap / Open Questions

これから

未決事項:MISSION(zerohalf 名義)と VISION(nzw.jp 名義)の主語の整理、B2B 導線の設計。