hikoutei 0.4.3 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.ja.md +155 -103
  2. package/README.ko.md +151 -107
  3. package/README.md +112 -80
  4. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.d.ts +2 -2
  5. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.js +2 -2
  6. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js +1 -0
  7. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js.map +1 -1
  8. package/dist/api/Hikoutei.d.ts +56 -10
  9. package/dist/api/Hikoutei.d.ts.map +1 -1
  10. package/dist/api/Hikoutei.js +84 -13
  11. package/dist/api/Hikoutei.js.map +1 -1
  12. package/dist/api/entity.d.ts +17 -1
  13. package/dist/api/entity.d.ts.map +1 -1
  14. package/dist/api/entity.js +34 -2
  15. package/dist/api/entity.js.map +1 -1
  16. package/dist/api/errors.d.ts +24 -0
  17. package/dist/api/errors.d.ts.map +1 -1
  18. package/dist/api/errors.js +24 -0
  19. package/dist/api/errors.js.map +1 -1
  20. package/dist/application/orm/api/contracts.d.ts +1 -1
  21. package/dist/application/orm/api/contracts.d.ts.map +1 -1
  22. package/dist/application/orm/persistence/flush/flushCoordinator.d.ts.map +1 -1
  23. package/dist/application/orm/persistence/flush/flushCoordinator.js +2 -0
  24. package/dist/application/orm/persistence/flush/flushCoordinator.js.map +1 -1
  25. package/dist/application/sync/inbound/autoSystemConflictResolution.d.ts.map +1 -1
  26. package/dist/application/sync/inbound/autoSystemConflictResolution.js +3 -0
  27. package/dist/application/sync/inbound/autoSystemConflictResolution.js.map +1 -1
  28. package/dist/application/sync/service/SyncServiceBootstrap.d.ts.map +1 -1
  29. package/dist/application/sync/service/SyncServiceBootstrap.js +85 -3
  30. package/dist/application/sync/service/SyncServiceBootstrap.js.map +1 -1
  31. package/dist/application/sync/service/syncAutoStart.d.ts +127 -0
  32. package/dist/application/sync/service/syncAutoStart.d.ts.map +1 -0
  33. package/dist/application/sync/service/syncAutoStart.js +280 -0
  34. package/dist/application/sync/service/syncAutoStart.js.map +1 -0
  35. package/dist/application/sync/sheets/conflictProjectionRegistration.d.ts.map +1 -1
  36. package/dist/application/sync/sheets/conflictProjectionRegistration.js +1 -0
  37. package/dist/application/sync/sheets/conflictProjectionRegistration.js.map +1 -1
  38. package/dist/infrastructure/storage/index.d.ts +2 -2
  39. package/dist/infrastructure/storage/index.d.ts.map +1 -1
  40. package/dist/infrastructure/storage/index.js +1 -1
  41. package/dist/infrastructure/storage/index.js.map +1 -1
  42. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.d.ts.map +1 -1
  43. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.js +1 -0
  44. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.js.map +1 -1
  45. package/package.json +1 -1
package/README.ja.md CHANGED
@@ -4,11 +4,16 @@
4
4
 
5
5
  # Hikoutei
6
6
 
7
- **Google Sheets を利用する MVP 向けの型付きリポジトリと安全な書き込みレイヤー**
7
+ **SQLite でアプリは高速に、Google Sheets でワークフローを見えるままに。**
8
8
 
9
- <a href="https://www.npmjs.com/package/hikoutei">npm パッケージ</a> ·
10
- <a href="https://github.com/ManddarinShop/Hikoutei/issues">Issues</a> ·
11
- <a href="docs/quick-start.md">クイックスタート</a>
9
+ Google Sheets を利用する MVP 向けの型付きリポジトリであり、安全な書き込み
10
+ レイヤー: アプリケーションは型付きエンティティでローカル SQLite を読み書きし、
11
+ コミットされた変更は、人が確認して軽くコラボレーションできるよう Google
12
+ Sheets へ非同期で投影されます。
13
+
14
+ <a href="https://www.npmjs.com/package/hikoutei">npm</a> ·
15
+ <a href="docs/quick-start.md">クイックスタート</a> ·
16
+ <a href="https://github.com/ManddarinShop/Hikoutei/issues">Issues</a>
12
17
 
13
18
  [![npm version](https://img.shields.io/npm/v/hikoutei?style=flat-square)](https://www.npmjs.com/package/hikoutei)
14
19
  [![license](https://img.shields.io/npm/l/hikoutei?style=flat-square)](LICENSE)
@@ -16,39 +21,23 @@
16
21
 
17
22
  </div>
18
23
 
19
- Hikoutei は、TypeScript と Node.js のアプリケーションで Google Sheets を
20
- MVP や社内ワークフローの人間向けの画面として利用できるようにします。
21
- アプリケーションは型付きエンティティとローカル SQLite を使い、サービス
22
- アカウントの Google Sheets provider を通して変更を Google Sheets へ非同期に
23
- 届けられます。
24
-
25
- Hikoutei の対象は意図的に限定されています。汎用データベースの代替、
26
- Prisma/JPA のクローン、汎用 Google Sheets API ラッパーを目的としていません。
27
-
28
- ## Hikoutei が提供するもの
24
+ ## Hikoutei とは
29
25
 
30
- - エンティティ中心のライフサイクル: 作成、検索、変更、永続化、削除、flush。
31
- - Sheet データに対する型付きフィールドマッピングとランタイム検証。
32
- - リモートのスプレッドシート要求を待たないローカル SQLite の読み取り。
33
- - 人による確認や軽い共同作業に使える非同期 Google Sheets ビュー。
34
- - 予期しないスキーマ変更や新しいデータを上書きする問題への保護。
35
-
36
- ## インストール
26
+ Hikoutei は、TypeScript アプリケーションにローカル SQLite を基盤とする型付き
27
+ エンティティ API を提供し、コミットされた変更を Google Sheets へ非同期に
28
+ 同期します。
37
29
 
38
- プロジェクトと npm パッケージ名は `hikoutei` です。
39
-
40
- ```sh
41
- npm install hikoutei @mikro-orm/core @mikro-orm/sql
42
- ```
30
+ 通常の読み書きでは、アプリケーションは Google Sheets を待ちません。Sheets
31
+ 確認・運用・軽いコラボレーションのための画面として残ります。
43
32
 
44
- MikroORM パッケージはルートパッケージの optional peer dependency です。現在の
45
- SQLite provider が内部で利用しますが、ルート public API に MikroORM 型は公開
46
- されません。
33
+ > Hikoutei は生の Sheets API ラッパーではなく、PostgreSQL の代替でもなく、
34
+ > Google Sheets を権威あるアプリケーションデータベースとして扱いません。
35
+ > SQLite が真実の源泉であり、Sheets は人向けの画面です。
47
36
 
48
37
  ## クイックスタート
49
38
 
50
- エンティティ定義と SQLite の lifecycle はルート API だけを使います。Sheet route、
51
- provider credential、provisioning、polling は内部 service bootstrap の責務です。
39
+ スカラーエンティティを定義し、リクエストローカルなマネージャーでローカル
40
+ SQLite の権威を利用します。
52
41
 
53
42
  ```ts
54
43
  import { createTypedSheets, defineTypedSheetsEntity } from "hikoutei";
@@ -76,97 +65,160 @@ user.name = "Ada Lovelace";
76
65
  await em.flush();
77
66
  ```
78
67
 
79
- `createTypedSheets()` はローカルの entity table だけを準備し、Google Sheets へ接続
80
- しません。内部 sync service mapping を登録してタブを provision し、outbound
81
- worker User_Input polling を開始します。service mode では `flush()` が entity、
82
- canonical state、durable outbox を SQLite transaction としてコミットし、リモート
83
- Sheet への配信は非同期に行います。
68
+ **シートには何が起きるのか?** 書き込みは即座にローカル SQLite へコミット
69
+ されます アプリケーションのリクエストは Google を待ちません。同期サービスが
70
+ 有効な場合、Hikoutei は後でエンティティを登録済みの Google Sheet へバック
71
+ グラウンドで投影します。シート上で行われた人の編集は観察・検証され、SQLite
72
+ へ受け入れられるか競合として記録されるかのどちらかで、決して静かに上書き
73
+ されません。
74
+
75
+ ## Hikoutei を使う理由
76
+
77
+ - シートの行を手動で変換する代わりに、型付きエンティティを定義する。
78
+ - Google Sheets を待たずにローカル SQLite で読み書きする。
79
+ - コミットされた変更を Sheets へバックグラウンドで同期する。
80
+ - 予期しない列の変更や重複ヘッダーを検出する。
81
+ - 競合時に新しいシート編集を上書きしない。
84
82
 
85
83
  ## Hikoutei が適しているケース
86
84
 
87
- - スプレッドシートがプロダクトの業務フローの一部である MVP とプロトタイプ。
88
- - 社内ツールと低トラフィックの管理アプリケーション。
89
- - 型付きのアプリケーションデータを保ちながら、Sheets を人が簡単に確認したい
90
- チーム。
91
- - ローカル SQLite を使うことができ、Sheets の非同期更新を受け入れられるサービス。
85
+ Hikoutei は以下のケースに適しています。
86
+
87
+ - 製品ワークフローの一部にスプレッドシートがある MVP・プロトタイプ
88
+ - 社内ツールや低トラフィックの管理アプリケーション
89
+ - 人が Sheets を簡単に確認しつつ、型付きのアプリケーションデータを扱いたい
90
+ チーム
91
+ - SQLite をローカルで使い、非同期のシート更新を受け入れられるサービス
92
92
 
93
- ## 別のツールを選ぶべきケース
93
+ ## 他のツールを選ぶべきケース
94
94
 
95
- 次の要件がある場合は、通常のデータベースと Google API の直接利用を検討してください。
95
+ 次の要件がある場合は、通常のデータベースと Google API を直接使ってください。
96
96
 
97
- - 複数行または複数サービスにまたがる強いトランザクション。
98
- - 高い書き込みスループット、または多数の同時書き込み。
99
- - 複雑なクエリ、JOIN、レポート処理。
100
- - マルチサーバーまたはマルチリージョンの調整。
101
- - Google Sheets で即時の read-after-write 整合性が必要。
102
- - Google Sheets をアプリケーションの主データベースにする必要がある。
97
+ - 多くの行やサービスにまたがる強いトランザクション
98
+ - 高い書き込みスループットや多数の同時ライター
99
+ - 複雑なクエリ・JOIN・レポートワークロード
100
+ - マルチサーバー・マルチリージョンでの調整
101
+ - Google Sheets での読み取り直後の整合性
102
+ - Google Sheets をアプリケーションの主要データベースとして使う場合
103
+
104
+ ## Hikoutei はあなたに合った抽象化か?
105
+
106
+ Hikoutei は `google-spreadsheet` や `@googleapis/sheets` を置き換えるものでは
107
+ ありません — その一段上に位置します。生のスプレッドシート操作だけが必要なら、
108
+ API クライアントを直接使ってください。
109
+
110
+ | 機能 | Hikoutei | google-spreadsheet | @googleapis/sheets |
111
+ | --- | :-: | :-: | :-: |
112
+ | 型付きエンティティモデル | ✅ | ❌ | ❌ |
113
+ | 高速なローカルアプリケーション読み取り | ✅ | ❌ | ❌ |
114
+ | Sheets への非同期投影 | ✅ | ❌ | ❌ |
115
+ | 永続的な書き込み再試行と重複排除 | ✅ | ❌ | ❌ |
116
+ | 競合を考慮したシート更新 | ✅ | ❌ | ❌ |
117
+ | 行・セルの直接操作 | 限定的 | ✅ | ✅ |
118
+ | Google Sheets API へのフルアクセス | Provider 経由 | 部分的 | ✅ |
103
119
 
104
120
  ## Google Sheets の設定
105
121
 
106
- Google Sheets の同期は service-side の責務です。推奨経路はサービスアカウントの
107
- `googleSheetsApi` provider で、ひとつのサービスアカウントがタブの provisioning、
108
- outbound effect の書き込み(高速 append、guarded update/delete、レシート、
109
- 応答喪失の復旧)、テーブル読み取り、行アンカー、ユーザー編集の観察をすべて
110
- 行います。アプリケーションは provider クライアントを import したり、Sheet route
111
- を `createTypedSheets()` に渡したりしません。
112
-
113
- 1. `https://www.googleapis.com/auth/spreadsheets` スコープを持つ Google Cloud
114
- サービスアカウントを作成し、対象スプレッドシートをそのメールアドレスに
115
- **編集者**として共有します。provider がタブ作成、effect 行とレシート記録、
116
- 行アンカー管理を行うため、閲覧者権限では不十分です。Cloud プロジェクトで
117
- Google Sheets API を有効化します。
118
- 2. サービスアカウントキーのファイルパスをサーバーの
119
- `GOOGLE_APPLICATION_CREDENTIALS` に置き、スプレッドシート ID はコミットされない
120
- シークレットストアに保管します。キーをブラウザコードや Git に入れないでください。
121
- 3. `googleSheetsApi` で内部 sync bootstrap を起動します。登録タブのヘッダーを
122
- 作成・検証した後、outbox 配信と User_Input polling を開始します。
123
-
124
- シートの整合性はリクエスト間の Sheet トランザクションから生まれるのではなく、
125
- 隠された effect-receipt タブ、effect-id/payload-hash の重複排除、SQLite の
126
- durable outbox、フェンシング、フィールド単位の compare-and-set 証拠、
127
- postcondition 復旧から生まれます。provider は資格情報・スプレッドシート ID・
128
- URL・payload をログに残さず、要求開始間隔をクラスごと(読み取り/書き込み)
129
- 1,100ms に調整して Google の quota window を守ります。`flush()` はローカル
130
- コミットのみを意味し、配信は非同期で、すべての書き込みはレシートで記録され、
131
- 同じ effect worker が復旧します。
132
-
133
- 追跡される live シナリオはこの provider で実行されます。
134
- [docs/sync-bulk-write-benchmark.md](docs/sync-bulk-write-benchmark.md)
135
- 10,000 行 append と update/delete の live 証拠も同じ REST 経路です。
136
- `scripts/bench/` の生トランスポート実験はレシート/CAS のない unguarded 経路
137
- なので、worker 経由の測定までは性能値を検証済みと見なさないでください。live
138
- 呼び出しは opt-in で、通常の検証は fake provider と SQLite fixture を使います。
139
-
140
- 従来の Apps Script Gateway と `appsScript`/`googleApiWorker` オプションは削除され、
141
- 上記のサービスアカウント provider が唯一の同期経路です。詳しい設定と
142
- トラブルシューティングは [クイックスタート](docs/quick-start.md) を参照してください。
122
+ Google Sheets の同期はサービス側の関心事です。アプリケーションは provider
123
+ クライアントを import したり、`createTypedSheets()` にシートルートを渡したり、
124
+ 書き込みごとに操作を選んだりしません。同期ランタイムはサービスアカウントを
125
+ 使う単一の Google Sheets API provider(内部 `googleSheetsApi` bootstrap オプ
126
+ ション)を使用します Apps Script のデプロイは不要です。
127
+
128
+ ### 環境変数による同期の自動開始
129
+
130
+ スプレッドシートの URL を環境変数に設定すると、`createTypedSheets()` が内部で
131
+ Sheets 同期を開始します — `flush()` はセットアップコードなしで outbox
132
+ ワーカー経由で Google Sheets に流れます:
133
+
134
+ ```sh
135
+ HIKOUTEI_SYNC_SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/<ID>/edit
136
+ GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json
137
+ ```
138
+
139
+ ```ts
140
+ const hikoutei = await createTypedSheets({ dbName: "./hikoutei.sqlite", entities: [User] });
141
+ ```
142
+
143
+ `HIKOUTEI_SYNC_SPREADSHEET_URL` がない場合、`createTypedSheets()` はローカル
144
+ 専用 (SQLite) のままです。起動失敗は明確なメッセージで診断されます: URL
145
+ 不正、資格情報ファイルの欠落・不正、スプレッドシートに共有されていない
146
+ サービスアカウント (共有すべきメールアドレスをエラーが教えてくれます)。
147
+
148
+ ### Service-account provider (googleSheetsApi)
149
+
150
+ 1. **サービスアカウントを作成する。** Cloud プロジェクトで Google Sheets API
151
+ を有効化し、`https://www.googleapis.com/auth/spreadsheets` スコープの
152
+ サービスアカウントを作成して、対象スプレッドシートをそのメールアドレスに
153
+ **編集者(Editor)**として共有します。provider がタブを作成し、効果行と
154
+ receipt レコードを書き、行アンカーを管理するため、閲覧者権限では不十分
155
+ です。
156
+ 2. **キーはサーバー側に置く。** サービスアカウントのキーパスはサーバーの
157
+ `GOOGLE_APPLICATION_CREDENTIALS` に、スプレッドシート ID は追跡されない
158
+ シークレットストアに置きます。キーをブラウザコードや Git に入れないで
159
+ ください。
160
+ 3. **内部 sync bootstrap を起動する。** `googleSheetsApi` を設定すると、
161
+ 登録済みタブのヘッダーを作成・検証した後、outbox 配信と User_Input ポー
162
+ リングを開始します。
163
+
164
+ Hikoutei は、永続的なローカル outbox・冪等な配信・競合を考慮した更新を使う
165
+ ため、一時的な API 障害でコミット済みのアプリケーション書き込みが失われる
166
+ ことはありません。provider は資格情報・スプレッドシート ID・URL・ペイロードを
167
+ ログに残さず、Google の割り当て枠に収まるようリクエスト開始間隔を調整します。
168
+ 詳細な状態機械と復旧ルールは[内部整合性モデル](docs/internal-consistency-model.md)を
169
+ 参照してください。
170
+
171
+ ライブの Google 呼び出しはオプトインであり、通常の検証経路はフェイク
172
+ provider と SQLite フィクスチャです。詳細なセットアップとトラブルシューティン
173
+ グは[クイックスタート](docs/quick-start.md)を参照してください。
174
+
175
+ ## インストール
176
+
177
+ プロジェクト名と npm パッケージ名はどちらも `hikoutei` です。現在の組み込み
178
+ SQLite provider は MikroORM を必要とします。
179
+
180
+ ```sh
181
+ npm install hikoutei @mikro-orm/core @mikro-orm/sql
182
+ ```
183
+
184
+ MikroORM は実装の詳細であり、Hikoutei の公開エンティティ API には現れません。
143
185
 
144
186
  ## ドキュメント
145
187
 
146
- - [クイックスタート](docs/quick-start.md) — インストール、ORM lifecycle、service-side sync 設定。
147
- - [アーキテクチャ](docs/architecture.md) — ローカルストアと Sheet ビューの関係。
148
- - [書き込みと同期の流れ](docs/write-and-synchronization-flow.md) — 非同期配信と復旧動作。
149
- - [開発ガイド](docs/development.md) — ローカル開発とテストコマンド。
150
- - [ベンチマーク記録](docs/sync-bulk-write-benchmark.md) — 日付ごとの測定結果と制約。
188
+ - [クイックスタート](docs/quick-start.md) — インストール、ORM ライフサイクル、
189
+ サービス側の同期設定
190
+ - [アーキテクチャ](docs/architecture.md) — ローカルストアとシートビューの関係
191
+ - [書き込みと同期フロー](docs/write-and-synchronization-flow.md) — 非同期配信と
192
+ 復旧動作
193
+ - [内部整合性モデル](docs/internal-consistency-model.md) — 永続的な outbox、
194
+ 冪等な配信、競合を考慮した更新
195
+ - [開発](docs/development.md) — ローカル開発とテストコマンド
196
+ - [ベンチマークノート](docs/sync-bulk-write-benchmark.md) — 日付付きの測定と
197
+ その限界
151
198
 
152
199
  ## 制限事項
153
200
 
154
- - Google Sheets にはクォータ、レイテンシー、API のレート制限があります。
155
- - Sheet の更新は非同期なので、アプリケーションはローカル状態を読み取るべきです。
156
- - SQLite はサービスにローカルなもので、分散調整レイヤーではありません。
157
- - スキーマ変更、手動編集、競合する変更に対する運用方針は、アプリケーション側で
158
- 別途決める必要があります。
201
+ - Google Sheets には割り当て枠・レイテンシ・API レート制限があります。
202
+ - シートの更新は非同期であり、アプリケーションはローカル状態を読むべきです。
203
+ - SQLite はサービスのローカルのみであり、分散調整レイヤーではありません。
204
+ - スキーマ変更・手動編集・競合更新には、依然としてアプリケーションの運用
205
+ ポリシーが必要です。
206
+
207
+ ## プロジェクトステータス
208
+
209
+ Hikoutei は活発に開発中です。エンティティ API は利用可能ですが、シート編集の
210
+ 取り込みと競合表示はまだ発展途上です。マイナーバージョンのアップグレード前に
211
+ リリースノートを確認してください。
159
212
 
160
213
  ## ロードマップ
161
214
 
162
- - Google Sheets から意図的なユーザー編集を取り込む機能を完成させる。
163
- - update/delete の競合処理と表示を改善する。
164
- - レジストリと直接 provider デプロイ用のセットアップツールを追加する。
165
- - 公開パッケージのリリースを安定化する。
215
+ - Google Sheets からの意図的なユーザー編集の取り込みを完了する
216
+ - 更新・削除の競合処理と表示を改善する
217
+ - レジストリと直接 provider デプロイのセットアップツールを追加する
166
218
 
167
- 現在の作業については [open issues](https://github.com/ManddarinShop/Hikoutei/issues)
168
- を参照してください。
219
+ 現在の作業は[オープンな Issues](https://github.com/ManddarinShop/Hikoutei/issues)
220
+ 参照してください。
169
221
 
170
222
  ## ライセンス
171
223
 
172
- Hikoutei は [MIT License](LICENSE) の下で公開されています。
224
+ Hikoutei は [MIT ライセンス](LICENSE)で公開されています。
package/README.ko.md CHANGED
@@ -4,11 +4,15 @@
4
4
 
5
5
  # Hikoutei
6
6
 
7
- **Google Sheets 기반 MVP를 위한 타입 안전 리포지토리 및 안전한 쓰기 계층**
7
+ **SQLite로 앱은 빠르게, Google Sheets로 업무 흐름은 눈에 보이게.**
8
8
 
9
- <a href="https://www.npmjs.com/package/hikoutei">npm 패키지</a> ·
10
- <a href="https://github.com/ManddarinShop/Hikoutei/issues">이슈</a> ·
11
- <a href="docs/quick-start.md">빠른 시작</a>
9
+ Google Sheets 기반 MVP를 위한 타입 안전 리포지토리이자 안전한 쓰기 계층:
10
+ 애플리케이션은 타입이 지정된 엔티티로 로컬 SQLite를 읽고 쓰고, 커밋된 변경은
11
+ 사람이 검토하고 가볍게 협업할 수 있도록 Google Sheets에 비동기로 투영됩니다.
12
+
13
+ <a href="https://www.npmjs.com/package/hikoutei">npm</a> ·
14
+ <a href="docs/quick-start.md">빠른 시작</a> ·
15
+ <a href="https://github.com/ManddarinShop/Hikoutei/issues">이슈</a>
12
16
 
13
17
  [![npm version](https://img.shields.io/npm/v/hikoutei?style=flat-square)](https://www.npmjs.com/package/hikoutei)
14
18
  [![license](https://img.shields.io/npm/l/hikoutei?style=flat-square)](LICENSE)
@@ -16,39 +20,22 @@
16
20
 
17
21
  </div>
18
22
 
19
- Hikoutei TypeScript와 Node.js 애플리케이션에서 Google Sheets를 MVP 또는
20
- 내부 업무 흐름의 사람이 읽기 쉬운 화면으로 사용할 수 있게 합니다. 애플리케이션은
21
- 타입이 지정된 엔티티와 로컬 SQLite를 사용하고, 서비스 계정 기반 Google
22
- Sheets provider를 통해 변경 내용을 Google Sheets에 비동기적으로 전달할 수
23
- 있습니다.
24
-
25
- Hikoutei의 범위는 의도적으로 작습니다. 범용 데이터베이스 대체재, Prisma/JPA
26
- 클론, 범용 Google Sheets API 래퍼를 목표로 하지 않습니다.
27
-
28
- ## Hikoutei가 제공하는 것
23
+ ## Hikoutei 무엇인가?
29
24
 
30
- - 엔티티 중심 생명주기: 생성, 조회, 변경, `persist`, `remove`, `flush`.
31
- - Sheet 데이터에 대한 타입 필드 매핑과 런타임 검증.
32
- - 원격 스프레드시트 요청을 기다리지 않는 로컬 SQLite 조회.
33
- - 사람이 검토하고 가볍게 협업할 수 있는 비동기 Google Sheets 뷰.
34
- - 예상하지 못한 스키마 변경과 최신 데이터를 덮어쓰는 문제에 대한 보호.
35
-
36
- ## 설치
25
+ Hikoutei는 TypeScript 애플리케이션에 로컬 SQLite를 기반으로 타입 지정
26
+ 엔티티 API를 제공하고, 커밋된 변경을 Google Sheets에 비동기로 동기화합니다.
37
27
 
38
- 프로젝트와 npm 패키지 이름은 모두 `hikoutei`입니다.
39
-
40
- ```sh
41
- npm install hikoutei @mikro-orm/core @mikro-orm/sql
42
- ```
28
+ 일반적인 읽기와 쓰기에서 애플리케이션은 Google Sheets를 기다리지 않습니다.
29
+ Sheets는 검토, 운영, 가벼운 협업을 위한 화면으로 남습니다.
43
30
 
44
- MikroORM 패키지는 루트 패키지의 선택적 peer dependency입니다. 현재 기본
45
- SQLite provider가 내부적으로 사용하지만 루트 public API에는 MikroORM 타입이
46
- 노출되지 않습니다.
31
+ > Hikoutei는 원시 Sheets API 래퍼가 아니며, PostgreSQL의 대체재도 아니고,
32
+ > Google Sheets를 권위 있는 애플리케이션 데이터베이스로 취급하지 않습니다.
33
+ > SQLite가 진실의 원천이고, Sheets는 사람을 위한 화면입니다.
47
34
 
48
35
  ## 빠른 시작
49
36
 
50
- 엔티티 정의와 SQLite lifecycle은 루트 API만 사용합니다. Sheet route,
51
- provider credential, provisioning, polling은 내부 service bootstrap의 책임입니다.
37
+ 스칼라 엔티티를 정의하고 요청-로컬 매니저를 통해 로컬 SQLite authority를
38
+ 사용합니다.
52
39
 
53
40
  ```ts
54
41
  import { createTypedSheets, defineTypedSheetsEntity } from "hikoutei";
@@ -76,100 +63,157 @@ user.name = "Ada Lovelace";
76
63
  await em.flush();
77
64
  ```
78
65
 
79
- `createTypedSheets()`는 로컬 entity table만 준비하며 Google Sheets연결하지
80
- 않습니다. 내부 sync service가 mapping을 등록하고 탭을 provisioning한 뒤
81
- outbound worker와 User_Input polling을 시작합니다. service mode에서
82
- `flush()`는 entity, canonical state, durable outbox를 SQLite transaction으로
83
- 커밋하고 원격 Sheet 전달은 비동기로 수행합니다.
66
+ **시트에는 무슨 일이 일어날까?** 쓰기는 즉시 로컬 SQLite커밋됩니다 —
67
+ 애플리케이션 요청은 Google을 기다리지 않습니다. 동기화 서비스가 활성화되면
68
+ Hikoutei는 나중에 엔티티를 등록된 Google Sheet에 백그라운드로 투영합니다.
69
+ 시트에서 이루어진 사람의 수정은 관찰되고 검증되어 SQLite 수용되거나
70
+ 충돌로 기록되며, 절대 조용히 덮어쓰이지 않습니다.
84
71
 
85
- ## Hikoutei를 사용하기 좋은 경우
72
+ ## Hikoutei를 쓰는 이유
86
73
 
87
- - 스프레드시트가 제품 업무 흐름의 일부인 MVP와 프로토타입.
88
- - 내부 도구와 저트래픽 관리 애플리케이션.
89
- - 타입이 지정된 애플리케이션 데이터를 유지하면서 사람이 Sheets를 쉽게
90
- 확인해야 하는 팀.
91
- - 로컬 SQLite를 사용할 있고 Sheets의 비동기 업데이트를 허용할 수 있는
92
- 서비스.
74
+ - 시트 행을 수동으로 변환하는 대신 타입 지정 엔티티를 정의합니다.
75
+ - Google Sheets를 기다리지 않고 로컬 SQLite로 읽고 씁니다.
76
+ - 커밋된 변경을 Sheets에 백그라운드로 동기화합니다.
77
+ - 예상치 못한 컬럼 변경과 중복 헤더를 감지합니다.
78
+ - 충돌 중에 새로운 시트 수정을 덮어쓰지 않습니다.
93
79
 
94
- ## 다른 도구를 선택해야 하는 경우
80
+ ## Hikoutei를 쓰기 좋은
95
81
 
96
- 다음 요구사항이 있다면 일반적인 데이터베이스와 직접적인 Google API 사용을
97
- 검토하세요.
82
+ Hikoutei는 다음 상황에 맞습니다.
98
83
 
99
- - 여러 또는 여러 서비스에 걸친 강한 트랜잭션.
100
- - 높은 쓰기 처리량 또는 많은 동시 작성자.
101
- - 복잡한 쿼리, 조인, 리포팅 작업.
102
- - 멀티 서버 또는 멀티 리전 조정.
103
- - Google Sheets에서 즉시 쓰기 읽기 일관성이 필요한 경우.
104
- - 애플리케이션의 기본 데이터베이스로 Google Sheets를 사용해야 하는 경우.
84
+ - 제품 워크플로의 일부로 스프레드시트가 있는 MVP와 프로토타입
85
+ - 내부 도구와 저트래픽 관리 애플리케이션
86
+ - 사람들이 Sheets를 쉽게 확인하면서 타입 지정된 애플리케이션 데이터를
87
+ 유지하려는
88
+ - SQLite를 로컬에서 사용하고 비동기 시트 업데이트를 수용할 있는 서비스
89
+
90
+ ## 다른 도구를 선택해야 할 때
91
+
92
+ 다음이 필요하다면 일반 데이터베이스와 Google API를 직접 사용하세요.
93
+
94
+ - 여러 행이나 서비스에 걸친 강력한 트랜잭션
95
+ - 높은 쓰기 처리량 또는 많은 동시 작성자
96
+ - 복잡한 쿼리, 조인, 리포팅 워크로드
97
+ - 멀티 서버·멀티 리전 조정
98
+ - Google Sheets에서의 즉시 읽기-쓰기 일관성
99
+ - Google Sheets를 애플리케이션의 주 데이터베이스로 사용
100
+
101
+ ## Hikoutei가 당신에게 맞는 추상화인가요?
102
+
103
+ Hikoutei는 `google-spreadsheet`나 `@googleapis/sheets`를 대체하지 않습니다 —
104
+ 한 단계 위에 위치합니다. 원시 스프레드시트 접근만 필요하다면 API 클라이언트를
105
+ 직접 사용하세요.
106
+
107
+ | 기능 | Hikoutei | google-spreadsheet | @googleapis/sheets |
108
+ | --- | :-: | :-: | :-: |
109
+ | 타입 지정 엔티티 모델 | ✅ | ❌ | ❌ |
110
+ | 빠른 로컬 애플리케이션 읽기 | ✅ | ❌ | ❌ |
111
+ | Sheets로의 비동기 투영 | ✅ | ❌ | ❌ |
112
+ | 내구성 있는 쓰기 재시도와 중복 제거 | ✅ | ❌ | ❌ |
113
+ | 충돌을 인지하는 시트 업데이트 | ✅ | ❌ | ❌ |
114
+ | 행·셀 직접 조작 | 제한적 | ✅ | ✅ |
115
+ | 전체 Google Sheets API 접근 | Provider 경유 | 부분적 | ✅ |
105
116
 
106
117
  ## Google Sheets 설정
107
118
 
108
- Google Sheets 동기화는 service-side의 책임입니다. 권장 경로는 서비스 계정
109
- 기반 `googleSheetsApi` provider로, 하나의 서비스 계정으로 탭 provisioning,
110
- outbound effect 쓰기(빠른 append, guarded update/delete, receipt, 응답 유실
111
- 복구), 테이블 읽기, anchor, 사용자 편집 관찰을 모두 수행합니다.
112
- 애플리케이션은 provider client를 import하거나 Sheet route를
113
- `createTypedSheets()`에 넘기지 않습니다.
114
-
115
- 1. `https://www.googleapis.com/auth/spreadsheets` scope를 가진 Google Cloud
116
- 서비스 계정을 만들고, 대상 스프레드시트를 이메일로 **Editor** 권한으로
117
- 공유합니다. provider가 생성, effect 행과 receipt 기록, anchor 관리를
118
- 하므로 Viewer 권한으로는 부족합니다. Cloud 프로젝트에서 Google Sheets API를
119
- 활성화합니다.
120
- 2. 서비스 계정 키 파일 경로를 서버의 `GOOGLE_APPLICATION_CREDENTIALS`에 두고,
121
- 스프레드시트 ID는 커밋되지 않는 시크릿 저장소에 보관합니다. 키를 브라우저
122
- 코드나 Git에 넣지 마세요.
123
- 3. `googleSheetsApi`로 내부 sync bootstrap을 시작합니다. 등록된 탭의 헤더를
124
- 생성/검증한 뒤 outbox 전달과 User_Input polling을 시작합니다.
125
-
126
- 시트 일관성은 요청 Sheet 트랜잭션에서 오지 않습니다. 숨겨진
127
- effect-receipt 탭, effect-id/payload-hash 중복 제거, SQLite durable outbox,
128
- fencing, 필드 단위 compare-and-set 증거, postcondition 복구에서 옵니다.
129
- provider는 자격 증명, 스프레드시트 ID, URL, payload를 로그에 남기지 않으며,
130
- 요청 시작 간격을 클래스별(읽기/쓰기) 1,100ms로 조절해 Google quota window를
131
- 지킵니다. `flush()`는 로컬 커밋만 의미하고 전달은 비동기이며, 모든 쓰기는
132
- receipt로 기록되고 같은 effect worker가 복구합니다.
133
-
134
- 추적되는 live 시나리오는 이 provider 실행됩니다.
135
- [docs/sync-bulk-write-benchmark.md](docs/sync-bulk-write-benchmark.md)의
136
- 10,000행 append와 update/delete live 증거도 같은 REST 경로를 사용합니다.
137
- `scripts/bench/`의 원시 전송 실험은 receipt/CAS 없는 unguarded 경로이므로,
138
- worker를 통한 측정 전에는 성능 수치를 검증된 것으로 보지 마세요. live 호출은
139
- opt-in이며, 일반 검증은 fake provider와 SQLite fixture를 사용합니다.
140
-
141
- 기존 Apps Script Gateway와 `appsScript`/`googleApiWorker` 옵션은 제거되어
142
- 서비스 계정 provider가 유일한 동기화 경로입니다. 상세한 설정과 문제 해결
143
- 방법은 [빠른 시작](docs/quick-start.md)설명되어 있습니다.
119
+ Google Sheets 동기화는 서비스 관심사입니다. 애플리케이션은 provider
120
+ 클라이언트를 import하거나, Sheet 라우트를 `createTypedSheets()`에 넘기거나,
121
+ 쓰기마다 연산을 선택하지 않습니다. 동기화 런타임은 서비스 계정을 사용하는
122
+ 하나의 Google Sheets API provider(내부 `googleSheetsApi` bootstrap 옵션)를
123
+ 사용합니다 Apps Script 배포가 없습니다.
124
+
125
+ ### 환경 변수 기반 동기화 자동 시작
126
+
127
+ 스프레드시트 URL을 환경 변수로 설정하면 `createTypedSheets()`가 내부적으로
128
+ Sheets 동기화를 시작합니다 `flush()`는 설정 코드 없이 outbox worker를 통해
129
+ Google Sheets 흘러갑니다:
130
+
131
+ ```sh
132
+ HIKOUTEI_SYNC_SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/<ID>/edit
133
+ GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json
134
+ ```
135
+
136
+ ```ts
137
+ const hikoutei = await createTypedSheets({ dbName: "./hikoutei.sqlite", entities: [User] });
138
+ ```
139
+
140
+ `HIKOUTEI_SYNC_SPREADSHEET_URL`이 없으면 `createTypedSheets()`는 로컬 전용
141
+ (SQLite)으로 유지됩니다. 시작 실패는 명확한 메시지로 진단됩니다: 잘못된 URL,
142
+ 없거나 잘못된 자격 증명 파일, 스프레드시트에 공유되지 않은 서비스 계정
143
+ (어떤 이메일을 공유해야 하는지 에러가 알려줍니다).
144
+
145
+ ### Service-account provider (googleSheetsApi)
146
+
147
+ 1. **서비스 계정을 만듭니다.** Cloud 프로젝트에서 Google Sheets API를
148
+ 활성화하고, `https://www.googleapis.com/auth/spreadsheets` 스코프의
149
+ 서비스 계정을 만든 대상 스프레드시트를 해당 이메일에 **편집자(Editor)**로
150
+ 공유합니다. provider가 탭을 만들고, 효과 행과 receipt 기록을 쓰고, 행
151
+ anchor를 관리하므로 뷰어 권한으로는 부족합니다.
152
+ 2. **키를 서버 측에 둡니다.** 서비스 계정 키 경로를 서버의
153
+ `GOOGLE_APPLICATION_CREDENTIALS`에, 스프레드시트 ID는 추적되지 않는
154
+ 비밀 저장소에 둡니다. 키를 브라우저 코드나 Git넣지 마세요.
155
+ 3. **내부 sync bootstrap을 기동합니다.** `googleSheetsApi`를 설정하면
156
+ 등록된 탭의 헤더를 만들고 검증한 뒤 outbox 전달과 User_Input 폴링을
157
+ 시작합니다.
158
+
159
+ Hikoutei는 내구성 있는 로컬 outbox, 멱등 전달, 충돌을 인지하는 업데이트를
160
+ 사용하므로 일시적인 API 실패가 커밋된 애플리케이션 쓰기를 잃게 하지 않습니다.
161
+ provider는 자격 증명, 스프레드시트 ID, URL, 페이로드를 로그에 남기지 않으며,
162
+ Google 할당량 창 안에 머물도록 요청 시작 간격을 조절합니다. 상세 상태 머신과
163
+ 복구 규칙은 [내부 정합성 모델](docs/internal-consistency-model.md)을
164
+ 참고하세요.
165
+
166
+ 라이브 Google 호출은 opt-in이며, 일반적인 검증 경로는 fake provider와 SQLite
167
+ fixture입니다. 자세한 설정과 문제 해결 단계는 [빠른 시작](docs/quick-start.md)을
168
+ 참고하세요.
169
+
170
+ ## 설치
171
+
172
+ 프로젝트와 npm 패키지 이름은 모두 `hikoutei`입니다. 내장 SQLite provider는
173
+ 현재 MikroORM을 필요로 합니다.
174
+
175
+ ```sh
176
+ npm install hikoutei @mikro-orm/core @mikro-orm/sql
177
+ ```
178
+
179
+ MikroORM은 구현 세부 사항이며 Hikoutei의 공개 엔티티 API에는 나타나지
180
+ 않습니다.
144
181
 
145
182
  ## 문서
146
183
 
147
- - [빠른 시작](docs/quick-start.md) — 설치, ORM lifecycle, service-side sync 설정.
148
- - [아키텍처](docs/architecture.md) — 로컬 저장소와 Sheet 화면의 관계.
184
+ - [빠른 시작](docs/quick-start.md) — 설치, ORM 생명주기, 서비스 동기화 설정
185
+ - [아키텍처](docs/architecture.md) — 로컬 저장소와 Sheet 화면이 맞물리는 방식
149
186
  - [쓰기 및 동기화 흐름](docs/write-and-synchronization-flow.md) — 비동기 전달과
150
- 복구 동작.
151
- - [개발 가이드](docs/development.md) — 로컬 개발 및 테스트 명령.
152
- - [벤치마크 기록](docs/sync-bulk-write-benchmark.md) 날짜별 측정 결과와
153
- 한계.
187
+ 복구 동작
188
+ - [내부 정합성 모델](docs/internal-consistency-model.md) — 내구성 outbox,
189
+ 멱등 전달, 충돌을 인지하는 업데이트
190
+ - [개발](docs/development.md) — 로컬 개발 및 테스트 명령어
191
+ - [벤치마크 노트](docs/sync-bulk-write-benchmark.md) — 날짜가 기록된 측정과
192
+ 그 한계
193
+
194
+ ## 한계
195
+
196
+ - Google Sheets에는 quota, 지연, API 요청 제한이 있습니다.
197
+ - 시트 업데이트는 비동기이며, 애플리케이션은 로컬 상태를 읽어야 합니다.
198
+ - SQLite는 서비스 로컬 전용이며 분산 조정 계층이 아닙니다.
199
+ - 스키마 변경, 수동 편집, 충돌 업데이트에는 여전히 애플리케이션의 운영 정책이
200
+ 필요합니다.
154
201
 
155
- ## 제한사항
202
+ ## 프로젝트 상태
156
203
 
157
- - Google Sheets에는 quota, 지연 시간, API rate limit이 있습니다.
158
- - Sheet 업데이트는 비동기이므로 애플리케이션은 로컬 상태를 읽어야 합니다.
159
- - SQLite는 서비스에 로컬이며 분산 조정 계층이 아닙니다.
160
- - 스키마 변경, 수동 편집, 충돌하는 변경에 대한 운영 정책은 애플리케이션이
161
- 별도로 정해야 합니다.
204
+ Hikoutei는 활발히 개발 중입니다. 엔티티 API 사용 가능하지만, 시트 편집
205
+ 수집과 충돌 표시는 아직 발전 중입니다. 마이너 버전 업그레이드 전에 릴리스
206
+ 노트를 확인하세요.
162
207
 
163
208
  ## 로드맵
164
209
 
165
- - Google Sheets에서 의도적인 사용자 편집을 수집하는 기능 완성.
166
- - update/delete 충돌 처리와 표시 개선.
167
- - 레지스트리 및 직접 provider 배포를 위한 설정 도구 추가.
168
- - 공개 패키지 릴리스 안정화.
210
+ - Google Sheets에서 의도적인 사용자 편집 수집 완성
211
+ - 업데이트·삭제 충돌 처리와 표시 개선
212
+ - 레지스트리 및 직접 provider 배포를 위한 설정 도구 추가
169
213
 
170
- 현재 작업은 [open issues](https://github.com/ManddarinShop/Hikoutei/issues)
171
- 에서 확인할 수 있습니다.
214
+ 현재 작업은 [오픈 이슈](https://github.com/ManddarinShop/Hikoutei/issues)
215
+ 참고하세요.
172
216
 
173
217
  ## 라이선스
174
218
 
175
- Hikoutei는 [MIT License](LICENSE)로 배포됩니다.
219
+ Hikoutei는 [MIT 라이선스](LICENSE)로 배포됩니다.