Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
37 changes: 23 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ spindle の実装作業を始める前に、このファイルを最初に読む
## このプロジェクトは何か

TrueNAS 上で動く単一コンテナの音楽ライブラリ管理アプリ。CD リッピング、
メタデータ一括編集、ReplayGain、プレイリスト、簡易再生。
**設計は完了している。** 仕様は `docs/SPEC.md`、判断の理由は `docs/DECISIONS.md`、
着手順は `docs/TASKS.md` にある。
メタデータ一括編集、ReplayGain、プレイリスト、簡易再生、端末(Android / iPhone)への配信。
P0〜P5 は実装済みで、v0.6.0 を本番で運用している。ドキュメントの地図は `docs/README.md`。

読む順序: `docs/TASKS.md` で担当タスクを確認 → 該当する `docs/SPEC.md` の節 →
`docs/DECISIONS.md` で背景を確認。
- 仕様: `docs/spec/`(章ごと。`SPEC §7.5` は `docs/spec/README.md` の目次で引く)
- 判断の理由: `docs/decisions/`(`D-62` は `docs/decisions/D-062.md`)
- 過去のタスクと受け入れ条件: `docs/development/tasks-history.md`(履歴。新しいタスクは書かない)

読む順序: 依頼に関係する `docs/spec/` の章・節 → そこから参照される `docs/decisions/` で背景を確認。

## 絶対に守る不変条件

Expand Down Expand Up @@ -47,8 +49,10 @@ TrueNAS 上で動く単一コンテナの音楽ライブラリ管理アプリ。
- **圧縮レベルを揃えるための FLAC 一括再エンコード。** 削減は 1% 未満で、
200GB の書き直しとスナップショット肥大に見合わない。
- **非可逆 → 非可逆の再エンコード。** 世代劣化する。配布ビューは原本を返す。
- 明示の例外: Apple 向けの `aac` 系統だけは非可逆の原本も AAC に変換する(`lossy_sources`。
ミュージック.app は Opus を読めない)。D-75。
- **仕様にない判断を黙って入れること。** 迷ったら実装を止めて質問する。
決めた場合は `docs/DECISIONS.md` に追記案を出す。
決めた場合は `docs/decisions/` に追記案を出す。
- **`db/migrations/*.sql` の既存ファイルの書き換え。** スキーマ変更は
必ず新しい連番ファイルを追加する。

Expand Down Expand Up @@ -140,17 +144,22 @@ cd web && npm install && npm run dev # フロント単体(API は SPINDLE
cd web && npm run build # 同梱用ビルド(tsc -b + vite)
cd web && npx vitest run && npm run lint # 純粋ロジックのテストと oxlint

python3 scripts/preflight.py /mnt/ssd/musics/Opus --dest /mnt/ssd # 移行前チェック
python3 scripts/migrate_plan.py /mnt/ssd/musics --out /tmp/plan # 振り分け一覧
python3 scripts/preflight.py <旧ライブラリ> --dest <コピー先> # 移行前チェック(docs/admin-guide/migration.md)
python3 scripts/migrate_plan.py <旧ライブラリ> --out /tmp/plan # 振り分け一覧
docker build -f deploy/Dockerfile -t spindle .
```

## 作業の進め方

1. `docs/TASKS.md` から次のタスクを 1 つ取る。依存関係を確認する
1. 設計を書き、ユーザの了承を得る。設計書と実装計画は**作業中だけ** `docs/development/` に置く
(`YYYY-MM-DD-<topic>-design.md` / `YYYY-MM-DD-<topic>.md`)。superpowers などのスキルが既定で
書き出す `docs/superpowers/` には置かない
2. 受け入れ条件を満たすテストを先に書く
3. 実装し、`cargo clippy -- -D warnings` と `cargo test` を通す
4. タスクにチェックを入れ、仕様との差異があれば `docs/SPEC.md` も更新する

タスクをまたいで実装を先回りしない。P0 の完了条件は「既存ライブラリ全曲が
表に出て、一括編集と巻き戻しができる」ことであり、それ以外は後回しで良い。
3. 実装し、`cargo clippy -- -D warnings` と `cargo test`(フロントは `npx vitest run` と `npm run lint`)を通す
4. 設計書の要点を `docs/spec/` の該当する章へ、判断とその理由を `docs/decisions/` へ移し
(新しい判断は次の番号の `D-NNN.md` を作り、`docs/decisions/README.md` の一覧に足す)、
設計書と計画を `docs/development/` から消す。利用者の操作が変わるなら `docs/user-guide/` も直す
5. レビュー(codex)→ PR → CI。リリースは `vX.Y.Z-rc.N` を本番で確かめてから `vX.Y.Z`
(`docs/admin-guide/operations.md`「リリース候補(RC)を本番で確かめてから出す」)。`CHANGELOG.md` に版の要点を書く

依頼の範囲を超えて実装を先回りしない。
158 changes: 158 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# 変更履歴

リリースごとの主な変更。形式は [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) に倣い、版は
[Semantic Versioning](https://semver.org/lang/ja/) に従う(1.0 までは minor で機能を足す)。リリース候補(`-rc.N`)は載せない。
各版のイメージと差分は [GitHub Releases](https://github.com/AkashiSN/spindle/releases) にある。括弧の D-n は
[設計判断](docs/decisions/README.md)、P-n は [タスクの履歴](docs/development/tasks-history.md) の番号。

## [Unreleased]

### Changed

- ドキュメントを読者別(`docs/user-guide/` `docs/admin-guide/` `docs/spec/` `docs/decisions/`)に再編し、
仕様は章ごと、設計判断は 1 判断 1 ファイルに分けた。README・CONTRIBUTING・CHANGELOG・LICENSE を足した

## [0.6.0] - 2026-10-19

### Added

- スマホ用の画面 `/m/`。ライブラリを眺める・探す・試し聴きする・プレイリストを作る・YouTube の購読を同期する(D-115)

## [0.5.0] - 2026-10-18

### Added

- Inbox の YouTube 由来の件を、メタデータプラグインで再判定する。判定したプラグインの版を記録する(D-114)

### Fixed

- adb サイドカーの鍵の待ちで tokio のワーカーを塞がない

## [0.4.4] - 2026-10-17

### Added

- Android の同期の進捗を端末タブに出す(D-109)
- MP3 の写像できないキーを ID3v2 の TXXX に読み書きする(D-110)
- Inbox の承認に種類と除外の列、タグのキーに前方一致の候補(D-113)

### Changed

- Derived のジョブは行った処理を結果列に出す(D-111)
- Derived のバッジを O(opus)と A(aac)に分ける(D-112)
- スマートプレイリストのルールの編集中は position のソートを既定にする

## [0.4.3] - 2026-10-16

### Added

- `spindle-agent sync` の進捗を Mac の端末と端末タブに出す(D-108)
- プレイリストの行に同期の状況を出す

### Fixed

- Mac の同期中に「同期が途中です」と強制破棄を出さない

## [0.4.2] - 2026-10-15

### Fixed

- 選曲の見積もりで、送る元のハッシュが無い曲を推定して容量に足す(D-107)
- SSE の応答に `X-Accel-Buffering: no` を付け、nginx 越しでもイベントが届くようにする

## [0.4.1] - 2026-10-15

### Added

- リリース候補(`vX.Y.Z-rc.N`)のイメージを出せるようにする

### Fixed

- 記録画面をスクロールできるようにする

## [0.4.0] - 2026-10-15

### Added

- 「記録」画面(編集履歴・退避ファイル・ログ)と、ジョブの結果の表示

## [0.3.1] - 2026-10-14

### Fixed

- CTDB の 404 を登録なしとして扱う

## [0.3.0] - 2026-10-14

### Added

- DB を失った後に、Android の保存先を新しい登録へ引き継ぐ(P5-7)
- DB を失った後に、Mac の保存先を引き継ぐ `spindle-agent pair --adopt`(P5-8)
- 印のついたプレイリストの削除の規則と、終端した同期の計画の GC(P5-6)

### Fixed

- GC が `tracks` の最大 id の行を消さない(id の再利用を防ぐ)

## [0.2.0] - 2026-10-02

### Added

- 端末への配信(D-95)。端末タブで端末ごとに選曲し、Android へは USB の ADB で直接(adb サイドカー)、
iPhone へは Mac の `spindle-agent` がミュージック.app を経由して同期する(P5-1〜P5-5)
- ReplayGain を解析後に自動でタグへ書き、Derived はその後に作る
- 遡及照合の結果を操作タブとプロパティに出す

## [0.1.3] - 2026-09-26

### Fixed

- Inbox で配置済みの件が「手置き」「変更 N 件」と出るのを直す

## [0.1.2] - 2026-09-26

### Added

- CD の取り込みで品番(と JAN)を手で入れて版を識別し、照会とタグに使う(D-94)

### Fixed

- compose に `init: true` を足し、取り消しで kill した孫プロセスのゾンビを回収させる

## [0.1.1] - 2026-09-26

### Fixed

- ALAC のプロセス内デコードの範囲を ffmpeg の edit list の扱いに揃える(D-89)
- リバースプロキシ越しでのログインの CSRF 判定(`trusted_proxies`)を運用手順に書く

## [0.1.0] - 2026-09-26

最初のリリース。P0〜P4 の主要機能。

### Added

- ライブラリの走査と同一性解決(`(dev, inode)` → `audio_md5` → `rel_path`)、論理削除と GC(P0、P1-11)
- foobar2000 風の 3 ペイン UI、トラック一覧の絞り込み・並べ替え、一括タグ編集・リネーム・バッチ単位の巻き戻し(P0)
- ReplayGain の解析と書き込み、ロスレスの FLAC 正規化、FLAC 健全性チェック(P1)
- Derived(Opus / AAC)の生成と追随、Range 再生(P1-9、P1-10)
- 手動・スマートプレイリスト(foobar2000 風の DSL)、m3u8 の書き出し・取り込み(P1-6〜P1-8)
- CD 取り込み: TOC と DiscID、MusicBrainz 照会、吸い出し、AccurateRip / CTDB 照合、遡及照合、Inbox 経由の配置(P2)
- YouTube(ytmusic)統合: 再生リストの購読と同期、タイトル解析、Inbox への取り込み(P3、P4)
- 認証(argon2id、CSRF 検査)、DB の自動バックアップ、GHCR へのイメージ配布(P0、P4-12)

[Unreleased]: https://github.com/AkashiSN/spindle/compare/v0.6.0...HEAD
[0.6.0]: https://github.com/AkashiSN/spindle/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/AkashiSN/spindle/compare/v0.4.4...v0.5.0
[0.4.4]: https://github.com/AkashiSN/spindle/compare/v0.4.3...v0.4.4
[0.4.3]: https://github.com/AkashiSN/spindle/compare/v0.4.2...v0.4.3
[0.4.2]: https://github.com/AkashiSN/spindle/compare/v0.4.1...v0.4.2
[0.4.1]: https://github.com/AkashiSN/spindle/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/AkashiSN/spindle/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/AkashiSN/spindle/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/AkashiSN/spindle/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/AkashiSN/spindle/compare/v0.1.3...v0.2.0
[0.1.3]: https://github.com/AkashiSN/spindle/compare/v0.1.2...v0.1.3
[0.1.2]: https://github.com/AkashiSN/spindle/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/AkashiSN/spindle/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/AkashiSN/spindle/releases/tag/v0.1.0
56 changes: 56 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# 開発への参加

spindle は作者が自宅の TrueNAS で使うために作っている個人プロジェクトです。Issue や PR は歓迎しますが、
設計の方針(下記の不変条件)に合わないものは取り込めないことがあります。大きな変更は、先に Issue で相談してください。

## 最初に読むもの

- [AGENTS.md](AGENTS.md): 実装の**不変条件・禁止事項・コーディング規約・よくある実装ミス**。人も AI エージェントもここから読む
- [docs/spec/](docs/spec/README.md): 仕様。変更する機能の章を読む
- [docs/decisions/](docs/decisions/README.md): 設計判断とその理由。記録された判断を覆すときは、理由を添えて先に相談する

## 開発環境

- Rust(stable)、Node.js(`web/` の SPA)
- 外部バイナリ `ffmpeg` `flac` `opusenc` `cd-paranoia` `cdrdao` `yt-dlp` `adb`。Docker イメージには同梱される。
ローカルで動かすときは PATH に置くか `config.toml` の `[bin]` で指す。無いと該当するテストは skip する
- 本番と同じ ffmpeg で試すなら CI と同じ `rust:1-bookworm` のコンテナを使う

```bash
cargo build && cargo test # バックエンド
cargo clippy -- -D warnings && cargo fmt --check

cd web && npm install && npm run dev # フロント単体(API は SPINDLE_BACKEND へ中継。既定 127.0.0.1:8080)
cd web && npm run build # 同梱用ビルド(tsc -b + vite)
cd web && npx vitest run && npm run lint # 純粋ロジックのテストと oxlint

docker build -f deploy/Dockerfile -t spindle .
```

CD ドライブとネットワークを要するテストは `#[ignore]` 付きで、`cargo test -- --ignored` で個別に走らせる。
Mac 用の `spindle-agent` は `agent/`([agent/README.md](agent/README.md))。

## 変更の進め方

1. **設計**: 振る舞いが変わる変更は、先に設計を書く。設計書と実装計画は作業中だけ
[docs/development/](docs/development/README.md) に置く
2. **テストを先に**: 受け入れ条件をテストにしてから実装する。同一性解決・パス生成・DSL パース・
AccurateRip CRC のように、壊れても画面上は正常に見える部分は単体テスト必須
3. **ドキュメント**: 実装が済んだら、設計書の要点を [docs/spec/](docs/spec/README.md) へ、判断と理由を
[docs/decisions/](docs/decisions/README.md)(新しい番号の `D-NNN.md`)へ移し、設計書と計画は消す。
画面の操作が変わるなら [docs/user-guide/](docs/user-guide/README.md) も直す
4. **PR**: `cargo fmt` / `cargo clippy -- -D warnings` / `cargo test` / フロントのテストと lint を通す。
CI([.github/workflows/ci.yml](.github/workflows/ci.yml))が同じものを走らせる
5. **リリース**: `main` のコミットに `vX.Y.Z-rc.N` を打って本番で確かめ、問題なければ同じコミットに `vX.Y.Z` を打つ。
CI がイメージと GitHub Release を作る。[CHANGELOG.md](CHANGELOG.md) に版の要点を書く

スキーマ変更は `db/migrations/` に新しい連番ファイルを足す。既存のマイグレーションは書き換えない。

## ドキュメントの置き場所

[docs/README.md](docs/README.md) が地図。使う人向けは `docs/user-guide/`、動かす人向けは `docs/admin-guide/`、
作る人向けは `docs/spec/` と `docs/decisions/`。文章は日本語で書く。

## ライセンス

コントリビューションは [MIT License](LICENSE) で提供されるものとします。
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 AkashiSN

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading