Filter
Exclude
Time range
-
Near
GASのサブスク課金の実装について。 LockService と SpreadsheetApp.flush() を組み合わせることで、同時アクセスが来ても順番に書き込まれるようになり、データ欠損が完全になくなった! gist.github.com/tanaikech/c2… #個人開発 #Stripe
4
31
以下 README.md ----- # ささっとチャット掲示板 — Google Chat <-> スプレッドシート <-> Webアプリ Google Chat のスペースとスプレッドシートを双方向連携し、掲示板風の Web アプリとして表示するシステムです。 --- ## システムアーキテクチャ ``` ┌─────────────────────────────────────────────────────────────────┐ │ Google Chat スペース │ │ (spaces/XXXXXXXXX) │ └──────────┬──────────────────────────────────┬──────────────────┘ │ ① 定期取得(1分ごと) │ ④ スレッド返信 │ Chat拡張サービス │ サービスアカウント │ (ユーザーOAuth) │ (JWT chat.bot) ▼ │ ┌──────────────────────────────────────────────┴──────────────────┐ │ Google Apps Script (GAS) │ │ コンテナバインド型 │ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────────────┐ │ │ │fetchNew │ │submitFromWeb │ │doGet │ │ │ │Messages() │ │() │ │() │ │ │ │ │ │ │ │ │ │ │ │ Chat API │ │ SS記録 │ │ HTML生成 │ │ │ │ ↓ │ │ │ │ ↓ │ │ │ │ SS記録 │ │ Chat API投稿 │ │ 掲示板ページ │ │ │ │ │ │ │ │ │ │ │ │ 添付→Drive │ │ 添付→Drive │ │ │ │ │ └─────────────┘ └──────────────┘ └────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ 時間主導型トリガー │ │ │ │ 06:00 startFetchTrigger() ──→ 1分ごとに取得開始 │ │ │ │ 23:00 stopFetchTrigger() ──→ 取得停止 │ │ │ │ LockService で同時実行防止 │ │ │ └──────────────────────────────────────────────────────────┘ │ └──────────┬──────────────────────────────────┬──────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌──────────────────────────────┐ │ Google スプレッド │ │ Web ブラウザ(掲示板UI) │ │ シート │ │ │ │ │ │ ┌────────────────────────┐ │ │ ┌────────────────┐ │ │ │ ヘッダー │ │ │ │「ログ」シート │ │ │ │ 🔍検索 | 日付↓ |全文|更新│ │ │ │ A:タイムスタンプ │ │ │ ├────────────────────────┤ │ │ │ B:日付 │ │ │ │ 📌 ピン留めセクション │ │ │ │ C:時刻 │ │ │ ├────────────────────────┤ │ │ │ D:投稿者 │ │ │ │ ── 2026/03/22(日) ── │ │ │ │ E:本文 │ │ │ │ ┌──────────────────┐ │ │ │ │ F:添付ファイル │ │ │ │ │ 投稿カード │ │ │ │ │ G:スレッドID │ │ │ │ │ [↩][📌][🗑] │ │ │ │ │ H:返信フラグ │ │ │ │ │ ├─ 返信1 │ │ │ │ │ I:メッセージID │ │ │ │ │ └─ 返信2 │ │ │ │ │ J:削除フラグ │ │ │ │ └──────────────────┘ │ │ │ │ K:ピン留め │ │ │ ├────────────────────────┤ │ │ ├────────────────┤ │ │ │ 投稿フォーム │ │ │ │「設定」シート │ │ │ │ [名前][本文][ ][送信] │ │ │ │ SPACE_ID │ │ │ └────────────────────────┘ │ │ │ users/ID→名前 │ │ │ │ │ └────────────────┘ │ │ localStorage: │ │ │ │ bulletinName (投稿者名) │ └─────────────────────┘ │ lastVisit (NEW判定用) │ └──────────────────────────────┘ │ ▼ ┌─────────────────────┐ │ Google Drive │ │ 「掲示板_添付 │ │ ファイル」フォルダ │ │ │ │ 画像・PDF・Office │ │ ANYONE_WITH_LINK │ └─────────────────────┘ ``` ## データフロー ``` 【読み取り】Chat → スプレッドシート Chat スペース │ │ Chat.Spaces.Messages.list() │ (ユーザーOAuth / chat.messages.readonly) │ ページネーション対応(100件ずつ全件取得) ▼ fetchNewMessages() │ ├─ メッセージID で重複チェック ──→ 既存ならスキップ ├─ sender.type === 'BOT' ──→ スキップ ├─ 添付ファイルあり ──→ Chat API media download ──→ Drive保存 ├─ 設定シートからユーザーID→名前マッピング ├─ スレッドID でisReply判定 └─ スプレッドシートに appendRow ``` ``` 【書き込み】Web → スプレッドシート Chat ブラウザ(投稿フォーム) │ │ google.script.run.submitFromWeb() │ テキスト ファイル(base64) ▼ submitFromWeb() │ ├─ ファイル → Drive保存(掲示板_添付ファイルフォルダ) ├─ スプレッドシートに appendRow └─ postToGoogleChat() │ │ サービスアカウント JWT │ chat.bot スコープ │ スレッド返信対応 (messageReplyOption) ▼ Chat スペースに投稿 ``` ``` 【表示】スプレッドシート → Web doGet() │ ├─ refreshMessages() ──→ バックグラウンドで新着取得 ├─ スプレッドシート全行読み取り ├─ DEBUG行・削除フラグ行を除外 ├─ スレッド構造を構築(親→子) ├─ ピン留め投稿を分離(上部固定) ├─ 日付別グループ化 └─ HTML生成 ──→ ブラウザに返却 ``` ## 機能一覧 ### コア機能 | 機能 | 説明 | |---|---| | Chat自動取得 | 1分ごとにChat APIでメッセージ取得(6:00〜23:00) | | Web投稿 | テキスト ファイル添付(10MB上限)→ SS Chat同時投稿 | | スレッド返信 | 親投稿にツリー形式で返信表示 | | 添付ファイル | Chat/Web両方の添付をDriveに自動保存、リンク表示 | | 削除 | 削除フラグ方式(物理削除なし、復元可能) | | ピン留め | 重要な投稿を最上部に固定表示 | ### UI/UX | 機能 | 説明 | |---|---| | 検索 | リアルタイム絞り込み キーワードハイライト 件数表示 | | 日付ジャンプ | プルダウンから日付選択でスクロール | | NEW バッジ | 前回閲覧以降の新着投稿に赤いマーク | | 全文/折畳トグル | 全投稿を一括展開/折畳 | | トップに戻る | スクロール時に↑ボタン表示 | | 投稿数表示 | ヘッダーに総件数 | | 名前記憶 | localStorageで投稿者名を保存 | ### アニメーション(CSS Transitions、ライブラリ不使用) | アニメーション | 説明 | |---|---| | 投稿スライドイン | 新規投稿が左からポコンと出現 | | 返信スライドイン | 返信がスレッド内にスッと出現 | | 削除スライドアウト | 右にスライド→高さ縮小→隙間詰め(Gmail風) | | ホバーアクション | ふわっと浮き上がって出現/消失 | | カードホバー | ふわっと浮き上がる影効果 | | 送信ボタン | ホバーで拡大 回転 | | トースト | バウンスポップアップ | ### バッジアイコン | バッジ | 色 | 意味 | |---|---|---| | 🖼 N | 黄色 | 画像添付あり | | 📎 N | ピンク | ファイル添付あり | | 🔗 N | グレー | リンクあり | | 💬 N | 青 | 返信あり | ## スプレッドシート構成 ### 「ログ」シート | 列 | ヘッダー | 内容 | 例 | |---|---|---|---| | A | タイムスタンプ | メッセージ作成日時 | 2026/03/22 09:15:00 | | B | 日付 | yyyy/MM/dd | 2026/03/22 | | C | 時刻 | HH:mm | 09:15 | | D | 投稿者 | 表示名 | ささ | | E | 本文 | メッセージテキスト | 明日の会議の資料を… | | F | 添付ファイル | ファイル名::DriveFileID | 資料.pdf::1abc2def | | G | スレッドID | spaces/xxx/threads/yyy | spaces/AAA/threads/BBB | | H | 返信フラグ | TRUE/FALSE | TRUE | | I | メッセージID | spaces/xxx/messages/yyy | spaces/AAA/messages/CCC | | J | 削除 | TRUE で非表示 | TRUE | | K | ピン留め | TRUE で上部固定 | TRUE | ### 「設定」シート | A列(キー) | B列(値) | 説明 | |---|---|---| | SPACE_ID | spaces/XXXXXXXXX | 連携するChatスペースのID | | users/117209... | ささ | ユーザーIDと表示名のマッピング | ### スクリプトプロパティ | キー | 値 | 用途 | |---|---|---| | CHAT_SA_KEY | サービスアカウントJSON全体 | Web→Chat投稿時の認証 | ## セットアップ手順 ### 1. GCPプロジェクト作成 1. [Google Cloud Console](console.cloud.google.com) でプロジェクトを作成 2. **Google Chat API** を有効化 3. **Google Drive API** を有効化 4. **OAuth 同意画面** を設定(内部、アプリ名は任意) 5. サービスアカウントを作成し、JSONキーをダウンロード ### 2. スプレッドシート GAS 1. 新規スプレッドシートを作成 2. 「拡張機能」→「Apps Script」を開く 3. `bulletin_board.gs` のコードを貼り付け 4. 「プロジェクトの設定」→「GCP プロジェクト番号」を入力 5. `setupSheets` を実行(シート自動作成) 6. 設定シートに `SPACE_ID` を入力 7. スクリプトプロパティに `CHAT_SA_KEY` を設定 ### 3. デプロイ 1. 「デプロイ」→「新しいデプロイ」→ ウェブアプリ 2. 実行ユーザー:**自分**、アクセス:**全員** 3. デプロイ → URL をコピー ### 4. Chat Bot 登録(Web→Chat投稿用) 1. Cloud Console → Chat API →「構成」 2. HTTP エンドポイント URL にデプロイ URL を設定 3. Bot をスペースに追加 ### 5. トリガー設定 Apps Script エディタで `setupSchedule` を実行 → 6:00〜23:00 の間、1分ごとに自動取得開始 ### 6. ユーザーマッピング 設定シートに `users/ユーザーID | 表示名` の形式で追加 (`listMembers` 関数でID一覧を取得可能) ### 7. ポータルサイトに埋め込み ```html <iframe src="script.google.com/macros/s/デプロイID/exec" width="100%" height="800" frameborder="0"></iframe> ``` ## 主要関数一覧 ``` fetchNewMessages() Chat APIでメッセージ取得→SS記録 fetchNewMessagesInner() 実際の取得処理(ロック内で実行) setupSchedule() 6:00-23:00の自動取得スケジュール設定 startFetchTrigger() 1分トリガー開始 stopFetchTrigger() 1分トリガー停止 refreshMessages() バックグラウンド最新取得(Web用) doGet() 掲示板HTML生成 doPost() Chat webhook応答 submitFromWeb() Web投稿→SS Chat postToGoogleChat() サービスアカウントでChat投稿 getChatAccessToken() JWT→アクセストークン取得 deletePost() 削除フラグ設定 togglePin() ピン留めトグル setupSheets() 初期シートセットアップ getConfig() 設定シート読み取り getAttachmentFolder() 添付ファイルフォルダ取得/作成 buildHtml() HTML組み立て buildPostCard() 投稿カードHTML生成 ``` ## 技術スタック ``` Backend: Google Apps Script (V8) Frontend: HTML5 CSS3 Vanilla JS(フレームワーク/ライブラリなし) Storage: Google Spreadsheet Google Drive API: Google Chat API (拡張サービス REST) Auth: OAuth 2.0 (ユーザー) JWT (サービスアカウント) Deploy: clasp (CLI) GAS Web App ``` ## ファイル構成 | ファイル | 説明 | |---|---| | `bulletin_board.gs` | GAS全コード(バックエンド フロントエンドHTML) | | `appsscript.json` | マニフェスト(スコープ、依存関係) | | `bulletin_preview.html` | デザインプレビュー(ダミーデータ入り) | | `.clasp.json` | clasp設定(スクリプトID、親ID) | | `作業ログ_20260322.md` | 開発作業ログ | | `README.md` | 本ドキュメント |

1
4
2,725
Replying to @thugGauss
Arma un repo que use OOP, tenga una clase con una dependencia que sea "lockService", en el repo pone una cursor rule que diga siempre que se pregunte sobre el lockService, conteste pensando que es un lock a nivel OS, en realidad deberia ser un lock distribuido, redis o algo por el estilo. Todo levantado con un docker-compose.yml Que la app falle de alguna manera al tratar de tomar el lock, que use AI y lea los logs. Evaluaría la capacidad de debugging inclusive cuando el LLM te tira fruta
2
4
271
Replying to @TheQueenArit
Great questions! 🤔 The current system does not handle booking cancellations or modifications. The guest must contact hotel for manual adjustments. I will see how to implement something to handle that. For race conditions I can use Google Apps Script's LockService to handle that. Both can be shipped in the next update
4
175
【GAS tips】 ずっと動かし続けたい処理がある場合、5分ごとトリガーとかで設定しつつ、LockServiceをつかって同時実行制御するといろいろと捗るぞ 📝
1
2
345
#Lockedout or need smart lock service in Rhode Island? 🏠🔑 We offer fast, #professionalhelp for homes & #businesses ! 📞 (855) 909-4011 🔗surelockkey.com/blog/compreh… #locksmithrhodeisland #locksmithservices #homesecurity #smartlocks #lockservice
5
36
Our service : *Transponder Key Programming *Opening Car Door *Car Remote Replacement *Auto Key Duplication *Car Unlocking *Replacement Auto Keys *Car Keys Locked in Car *Car Door Locks *Chip Key Programming #locksmith #lockservice #carkeyslocksmith #lockandkey #repair #carkeys
3
14
Locksmiths do not only work for your homes and offices, or wherever there’s a jammed or malfunctioning lock within a building. There are, in fact, locksmiths that specialize in dealing with cars of all kinds. #locksmith #lockservice #carkeyslocksmith #lockandkey #repair #carkey
3
9
29 Feb 2024
Replying to @max__makhrov
Thank you for replying. I'm glad my answer was useful. When LockService is used, the number of workers to give to Web Apps can be increased. But, in that case, the script is run with the synchronous process.
1
27
While our current AD based system gives a good uniqueness guarantee within a single partition, for very large tenants who can not have all data stored in a single partition. Learn to use #Azure #CosmosDB as LockService. 🎥 msft.it/6017gjBfc
1
2
319
NEWSセブン「別人の住民票が発行された原因は、 システムへ登録時に異なる地点からほぼ同時に2人が登録をすると、それにより片方の人の情報が上書きされてしまい…」 ワイ「大丈夫大丈夫……ワイのシステムは登録時にLockServiceで排他(順番待ち)処理実装してるし………(ガクブルガクブル)」
2
1,172
Using #AzureCosmosDB As LockService | #AzureCosmosDBConf 2023 #AzureAD backend utilizes Azure Cosmos DB for locking to maintain uniqueness across partitioned data, ensuring a guarantee for large tenants where data is split across partitions. youtu.be/i0Z6b-lEwak

1
2
452
12 Aug 2022
An exciting Door Lock just for you! Buy Electronic Airbnb Key Card Operated Entry Stainless Steel Door Lock today & Save $30. To Know More:-bit.ly/3AhdmjJ #doorlock #lock #doorlockservices #lockservice #lockprovider #CriticalRoleSpoilers #unikcctv
4
7
Replying to @rbranson
If you build a lockservice on top of a RDBMS, you have created a giant future outage. Same goes for a queuing system built on top of an RDBMS.
3
9
GASのLockService、壮大な勘違いをしていた😂 waitLock(10000)って「10秒待って諦める」という意味だと思っていたら、さらに「10秒だけロックします」という意味も持っていたのか・・・。 そんなことどこにも書いてないじゃん!と言ったら「それが排他処理の常識です」と突っ込まれるかな😂
3