高校生が「ネップリ共有サイト」をつくった話（兼メモ）

## TL;DR
下のサイトをつくった。
~~https://nepris.herokuapp.com/~~

Githubリポジトリはこちら。
https://github.com/glyzinieh/nepris

備忘録を兼ねて、開発の経緯をご紹介します。

## はじめに
当方初心者のため、至らぬ点があればアドバイスをよろしくお願いいたします。お気軽にコメントください。
それでははじめにネップリ共有サイト **NePriS** のご紹介をさせていただきます。

### そもそも「ネップリ」って？
「ネップリ」とは、セブンイレブン・ファミリーマート・ローソンなどのコンビニエンスストアで提供されている「 **ネットプリント** 」のことを指します。ネットプリントでは、自分で作成・撮影した画像作品を各サービスのアプリやサイトに登録することで予約番号が発行され、それをコンビニにあるマルチコピー機に入力することで、登録した画像をプリントアウトすることができます。

ネットプリントの予約番号を共有することで、様々な作品をプリントアウトすることができるわけです。
この予約番号の共有には、一般的にTwitterなどのSNSが用いられていますが、ネップリの **共有** ・ **検索** ・ **宣伝** のためのポータルを目指して開発されているのがネップリ共有サイト「 **NePriS** （ネプリス）」です。

## 基本方針
-  **0円** で運用
- サーバーは **Heroku**
    - 無料で使えるため
- サーバーサイドは **Flask** を使う
    - 過去に触れたことがあったため
- DBは **Googleスプレッドシート** を利用
    - HerokuのDBは、学生のためクレジットカードが使えないので✕
    - GUIで触れて便利だから
- 画像データは **自宅鯖** （Synology NAS）に保存
    - 自宅鯖で **自作API** を実行し、書き込み・読み込みができるようにする

## 開発
実際に作業を進める上での **ポイント** や **躓いた点** を残します。

### HTML
**レスポンシブ対応** のために`Bootstrap5`を利用します。初めて触ったので分からないことだらけでした。

### navbar
解説サイトを読んでも、なぜか想定通りに動きませんでした。
結局、[公式ドキュメント](https://getbootstrap.jp/docs/5.0/components/navbar/ "Navbar (ナビゲーションバー) · Bootstrap v5.0")をコピペして解決しました。

`nav_link`に、`active`クラスと`aria-current="page"`属性を動的に与える方法を悩んだが、`Javascript`と`Jinja2`を使いゴリ押しで解決しました。

### 登録ページ
方針でも示した通り、データはGoogleスプレッドシート、画像データは自宅鯖に送信します。
```mermaid
graph TD;
    UI--POST-->サーバー;
    サーバー-->Googleスプレッドシート;
    サーバー--POST-->自宅鯖;
```

#### 予約番号
`pattern`属性で文字種・文字数を制限した上で、`Javascript`で強制的に大文字入力になるように設定します。
初期状態では、両方に`required`属性を設定し、一方が入力されたら他方の`required`属性を解除することで、「どちらか必須」のバリデーションを実現しました。

#### validation
`Bootstrap5`の`validation`仕様がよく分からなかったが、調べてみるとどうやら`Javascript`の`form.checkValidity()`関数で適切か判定し、表示しているらしい。
`Javascript`が分かってないとダメですね…
ということで公式ドキュメントのコピペで解決しました。
`Javascript`で対象の要素に対して`setCustomValidity("エラー名")`を実行すると、独自でエラー状態にできる。解除するときは`setCustomValidity("")`の様に空文字を与える。

### データベース
`gspread`の`get_all_records()`を使うと`'00000`が`00000`になってしまう等不都合があるため、`get_all_values()`で取得した **リストのリスト** を **辞書のリスト** に変換する自作メソッドを`gspread.Worksheet`クラスに追加しました。
Githubで`get_all_records()`のコードを確認したところ、同様の実装をしていたので恐らく問題は無いと思います。

### 登録処理
`id`は連番で`1`ずつ加算されるように実装しました。
`Jinja2`で`status`変数によって表示を変えることで、サンクスページにエラー文等を表示できるようにしました。

#### 画像
拡張子ではなく、送信された`MIME-type`で判断しています。
読み込み速度を改善するために、`BytesIO`を使って`pillow`で`webp`形式に変換してから保存します。

### 作品ページ
自宅鯖上の画像を、`BytesIO`を使って、`send_file`で返します。

#### 画像
CSSで以下を設定することで、画像の縦横比を保ったまま、画像のサイズを変えています。
```css
img {
    aspect-ratio: 4 / 3;
    object-fit: contain;
}
```

### 利用規約・プライバシーポリシー
正直全く分からん！
個人情報に当たる情報を収集することになりそうなので掲載します。
これで正しいのか分かりません。
法律家とかに相談してみたいけれど、金欠なのでね……

一応、[良いウェブサービスを支える 「利用規約」の作り方](https://www.amazon.co.jp/%E3%80%90%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88%E3%80%91%E8%89%AF%E3%81%84%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B-%E3%80%8C%E5%88%A9%E7%94%A8%E8%A6%8F%E7%B4%84%E3%80%8D%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E9%9B%A8%E5%AE%AE-%E7%BE%8E%E5%AD%A3/dp/4297103265 "Amazon - 【改訂新版】良いウェブサービスを支える 「利用規約」の作り方 | 雨宮 美季, 片岡 玄一, 橋詰 卓司")がとても参考になりました。

### sitemap.xml
Flaskの拡張機能に[Flask-Sitemap](https://flask-sitemap.readthedocs.io/en/latest/ "Flask-Sitemap — Flask-Sitemap 0.3.0 documentation")なるものがあったのでこれを利用して生成します。
日本語の情報が無いに等しく若干苦労しました。
[こちら](https://stackoverflow.com/questions/59746716/how-do-i-include-dynamic-urls-in-flask-sitemap "How do I include dynamic URLs in flask-sitemap? - Stack Overflow")が参考になりました。

### サービス名決定
[こちら](https://www.find-job.net/startup/notes-on-service-name "ネーミングで後悔したくない！サービス名を決める前に知っておくべき9個の注意点(＋発想メソッド) | FINDJOB! Startup")のサイトを参考にさせていただきました。
商標とかが若干心配ですが、問題ないことを信じます。

### ロゴ
デザインセンスが皆無のため、[友人](https://twitter.com/kamome_nine "鴎（@kamome_nine）さん / Twitter")に依頼しました。ありがたい！

### Google Search Console
サイトをGoogleの検索エンジンに登録するために必要です。
仕様が謎です。何回かリクエストを送信しているが、登録されているのか分かりません。

## おわりに
初めてWebサービスの個人開発をして、技術不足を痛感しました。
とりあえず`Javascript`を学びたいです。

[運営者ギルド](https://qiita.com/organizations/admin-guild "運営者ギルド - Qiita")の皆様に様々なアドバイスを頂きました。この場を借りて御礼申し上げます。ありがとうございました。

## 追記
アクセス数が思うように伸びなかったため、Herokuの有料化をきっかけに休止中です。

## おまけ
開発中に思ったことなどを残しておきます。読み飛ばしていただいて構いません。

### VSCodeは余計なモジュールをimportするな
エディターにVisualStudioCodeを利用していて、自動でモジュールを`import`してくれる機能は便利だが、たまに全く関係ないモジュールが追加されていて、エラーが発生して焦ることがあった。
結局、gitのDiffで余計なモジュールが`import`されていることに気が付き、事なきを得た。

### VSCodeの全角文字
全角文字に対してエラーが出るのは嬉しいが、わざと使ってるのもあるからどうにかしてほしい。

### Ｍermaid
この記事で初めて使った。直感的でいいですね。

### Bootstrap Icons
フォントで使えるから便利。

### 型は大事
型を間違っていてエラーが出た。モジュールを使っていると原因が掴みづらい。
型アノテーションを活用したりして正しい変数を与えると分かりやすくなる。