「Busker Beat」制作記：Flask×PostgreSQL×Renderでオブジェクト指向UIを実装

# はじめに


Busker Beat は路上ライブ演者の「出没情報」を地図上に可視化し、演者が日々の演奏記録をつけ、ファンとつながることができるアプリです。
- 技術スタック
  - Flask (Python3)
  - PostgreSQL (Renderでホスト)
  - HTML/CSS/JavaScript/Leaflet.js
  - Git/GitHub + Render でデプロイ・管理
  - 完成イメージ: 地図クリックで投稿場所の緯度経度を自動入力 → モーダルからDBへ登録 → 即時マップに反映


# アプリ概要
1\. 地図（Leaflet.js）
- 地図上で投稿ポイントを可視化
- ダークなタイルレイヤーで独特な雰囲気

2\. 投稿機能
- モーダルを使って演者名・投げ銭額・セトリなどを入力
- マップクリックで緯度経度取得
- Ajaxで即反映し、リロードなしでマーカーが増える

3\. ユーザー認証
- ログイン・新規登録はモーダルで完結
- Flaskセッションでログイン状態を管理
- ログインユーザーだけが投稿可能

UIのコンセプトは「地図が中心」かつ「オブジェクト指向の直感的操作」です。

# ディレクトリ構成
```
busker_beat/
├── myapp.py               # Flaskのエントリポイント
├── requirements.txt
├── static/
│   └── css/
│       └── styles.css     # ダークテーマ＋モノトーン＋赤
├── templates/
│   ├── index.html
│   ├── _map.html
│   ├── _post_cards.html
│   └── _auth_modal.html              
└── config.py　　　　# DB接続情報
```

- _map.html: 地図 + 投稿フォームモーダル
- _post_cards.html: 投稿一覧（左カラム表示）
- _auth_modal.html: ログイン/新規登録のモーダル
- styles.css: 黒背景＋赤要素のUIテーマを定義

# Flaskのルート処理

以下は主要ルートのみ抜粋。
```
@app.route("/")
def home():
    conn = psycopg2.connect(...)
    cur = conn.cursor()
    cur.execute("SELECT * FROM bb_posts ORDER BY id DESC;")
    posts = cur.fetchall()
    # postsをテンプレートへ
    return render_template("index.html", posts=posts)

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # DBからユーザー取得
        # check_password_hashで照合
        # セッションにuser_idを保存
        return redirect("/")
    return render_template("login.html")

@app.route("/signup", methods=["GET", "POST"])
def signup():
    if request.method == "POST":
        # generate_password_hashでハッシュ化
        # DBにINSERT
        return redirect("/")
    return render_template("signup.html")

@app.route("/logout")
def logout():
    session.clear()
    return redirect("/")

@app.route("/posting", methods=["POST"])
def posting():
    # Ajaxで受け取ったFormDataをDBにINSERT
    # 成功ならJSONで { success: True, ...} 返す
    return jsonify(...)
```
ポイント:
- /posting は画面表示しないバックエンド処理
- /login / /signup はモーダル想定だが、従来の画面遷移にも対応
- session["user_id"] があるかどうかでログイン判定

# PostgreSQLでのデータ管理

DB構成は以下。SQLを管理しやすいようにシンプルに作成。
```
CREATE TABLE bb_users (
  id SERIAL PRIMARY KEY,
  uname TEXT UNIQUE NOT NULL,
  email TEXT UNIQUE NOT NULL,
  pw TEXT NOT NULL
);

CREATE TABLE bb_posts (
  id SERIAL PRIMARY KEY,
  user_id INTEGER REFERENCES bb_users(id),
  artist_name TEXT,
  lat FLOAT NOT NULL,
  lng FLOAT NOT NULL,
  audience INTEGER,
  setlist TEXT,
  amount INTEGER,
  event_date DATE,
  created_at TIMESTAMP DEFAULT now()
);
```
- ハッシュ化されたパスワードを pw に保存（werkzeug.security利用）
- user_id で bb_users と紐づけ → 投稿者追跡可能
- lat, lng は FLOAT。地図クリック→AjaxでINSERT

SQLの具体的なINSERT/SELECTはFlaskのコードに埋め込んだ。

# レイアウト：オブジェクト指向UI
1. 地図を画面右側、左に投稿一覧
2. クリックで投稿: マップオブジェクトそのものに手を触れるイメージ
3. モーダルを多用し、「画面遷移」を最小限に抑えた

これにより、「オブジェクトを配置する感覚」＋「入力フォーム」が直感的にマッチ。

企画図：

https://www.figma.com/board/3xWb22s1mYvSnBC4lBOtAm/busker-beat-%E4%BC%81%E7%94%BB%E5%9B%B3?node-id=0-1&t=s4Ujb02UjsvHRk0J-1

ラフ：

https://www.figma.com/design/1C5GvTW0RWBzhQppQpBjpn/Busker-Beat?node-id=0-1&t=GnsenXWoHjMWYLqa-1


# Git/GitHub + Renderでのデプロイ
1. git add . && git commit -m "feat: add map + modals"
2. git push origin main → Renderが自動デプロイ
3. Render でDBを作り、環境変数に SECRET_KEY を設定
4. 公開URL: https://busker-beat.onrender.com

継続的に変更しても、GitHub連携で自動ビルドされるのが便利。

# まとめ & 所感
- Flaskでのルート処理は非常にシンプルに書ける
- Leafletとの連携で直感的な投稿が実現
- PostgreSQLでのリレーション管理により、ユーザー認証と投稿がしっかり紐づく
- オブジェクト指向UI (地図クリック→モーダル投稿→非同期DB保存) は、使ってみるとかなり直感的

今回の制作で学んだのは、シンプルな設計 + UI/UXを意識することで、少ないコード量でも便利なアプリができるということです。

### 今後の拡張
- ログインユーザー別のマイページ
- コメント機能 or いいね機能
- Tailwind導入でUIをさらに洗練
- Docker化で開発環境を安定化


もし似たような機能を作りたい人がいれば、ぜひ参考にしてみてください！

以上、「Busker Beat」開発の備忘録でした。