綴Photo を mobile / backend / web に分けて作ってきて、「次に何をやるか」で構造づくりを優先した判断の記録です。
ここで言う「web」は、綴ったものを web でも見られるように開発中のアプリ(紡Book)のことです。
なぜ「テンプレ磨き」より「管を通す」を先にしたか
綴Photo には器が3つあります。スマホで綴る mobile、データを受けて貯める backend、それを美しく見せる web。器はそれぞれ用意できていたのに、間が繋がっていなかった。だから web は、自分で用意したダミーデータ(モック)で動いていて、スマホで実際に綴ったものは流れてきません。
この状態で web の見せ方(テンプレ)を増やしても、中身は架空のサンプルのまま=「使っていない機能のカタログ」になります。自分が日常的に綴ったものが web に出てこないと、自分が一番のユーザーになれません。だから、見栄えを足すより先に、スマホで綴ったものが web で見えるところまで管を1本通すことを選んだ。細くていいから一周させる方が、カタログを並べるより効く、という判断。
3つの器と2本の管
通してみて、全体はこういう形だと分かった。
この列の揃えを、スキーマがミラー と呼んでいます。
両端の叩き方
管の両端は、向きが違うだけで作りはほぼ対称だった。どちらも「APIを叩く+Bearerトークンで認証+JSONでやりとり」。
送る側(mobile・POST):
// 認証ヘッダを付けて JSON を POST する(http パッケージ)
Map<String, String> _headers(String token) {
final headers = {'Content-Type': 'application/json; charset=utf-8'};
if (token.isNotEmpty) headers['Authorization'] = 'Bearer $token'; // ← 認証
return headers;
}
// SyncService が綴りを整形して POST /api/sync/memories/ に送る
// buildSyncItems が「mobile の形 → backend の形」に変換する継ぎ目を担う取る側(web・GET):
// 同じく Bearer トークンを付けて取得し、純関数(同じ入力なら必ず同じ結果を返す変換役)で web の形に変換する
const rows = await apiRequestJson(`${API_BASE}/api/favorites/`, { headers: devAuthHeaders() });
return rows.map(mapFavoriteMemory); // ← サーバの行を web 表示用に整形する「継ぎ目」ひとつ断っておくと、今このトークンは 開発用に手で発行した長命のもの を差しているだけで、本番のログイン認証ではない(ログイン機能は後で作る)。あくまで localhost で一周を確かめるための足場で、トークンの実物はもちろん公開しない。
両端には必ず「変換」がいる
器ごとにデータの形が違います。だから管の両端には、形を合わせる変換が1枚ずつ要ります。
この「継ぎ目(変換)」が、実は一番つまずいた場所だった。画像が無い綴りで空文字を <img> に渡してしまった件も、プレビューが古い索引からデータを引き直していて空になった件も、どちらもこの両端の変換のところで起きています(それぞれ別の記事に書いた)。構造として見ると、器の中身ではなく 継ぎ目に注意がいる、というのが管を通して一番効いた学びだった。
この記事は2026年6月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。