私たちの市のGIS部門は、住民が道路の穴、水漏れ、落書き、不法投棄、規制違反などの懸念を報告し、スタッフがサードパーティの311製品を使わずにチケットを処理できる方法を必要としていました。既に運用しているArcGIS Enterprise上に構築し、現在はGitHubでシステム全体を公開しており、どの組織でも導入できるように一般化しています。
https://community.esri.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fgithub.com%2Fbrianmcleer%2Freport-a-concern
この投稿は、システムの構成方法と選択理由についての技術的な解説です。リポジトリには完全な展開手順書があります。
内容物
Experience Builder 1.21のウィジェットが2つ(公共提出ウィザードとスタッフ用チケットマネージャー)、属性ルール付きのエンタープライズジオデータベーススキーマ、小さなFlaskプロキシ(公共フィーチャサービスの前面)、Windowsタスクスケジューラで動作する7つのPythonスクリプト、アクセス可能なHTMLメールテンプレート、タスクスケジューラジョブ定義、およびドキュメントが含まれています。コード内には当組織固有のものはありません。ホスト名、メールアドレス、部署名、アイテムIDは2つのgit無視設定ファイルとウィジェット設定パネルから取得されます。
データモデル
すべては1つのSQL Serverエンタープライズジオデータベースに格納されています。記録システムはポイントフィーチャクラス「Tickets」で、GUIDチケットID、人間が読みやすいチケット番号、13種類のサブタイプとしてのカテゴリ、サブタイプごとに変わるコード値ドメインを持つサブカテゴリテキストフィールド、ステータス、割り当て部署、そのポイントが属する境界、提出者連絡先フィールド、およびスクリプトが監視する2つのフラグ(notification_sentとsurvey_sent)があります。写真用にTicketsには添付ファイル機能が有効です。
周囲にはチケット削除時に連鎖削除される複合リレーションシップクラスでチケットIDで結合された関連テーブルがあります:Ticket_Comments(is_publicフラグとemail_sentフラグ付き)、Ticket_Photos_Meta、およびSurvey_Responses。ルーティングを制御する3つの参照テーブル:Service_Boundaries(is_activeフラグ付きポリゴン)、Category_Boundary_Lookup(どのカテゴリがどの境界内で有効か、および無効な場合のリダイレクトメッセージ)、Ticket_Routing(カテゴリ、任意のサブカテゴリ、境界ID、デフォルト部署、部署メール)。Notification_Logはすべてのスクリプトとプロキシが書き込む追記専用監査テーブルです。
Tickets、コメント、および調査回答はバージョン管理およびアーカイブされています。参照テーブルとNotification_Logは意図的にバージョン管理されておらず、この点が以下で重要になります。
提出フロー(エンドツーエンド)
- 住民は公共Experience Builderアプリを開きピンをドロップします。提出ウィジェットはクライアント側でService_Boundariesを照会し、そのポイントを含む有効なポリゴンを特定し、その後Category_Boundary_Lookupを照会してその場所で有効なカテゴリのみを表示します。隣接する水道地区内では水関連チケットは提出できず、その地区の連絡先情報が表示されます。
- ウィジェットはapplyEditsをアプリ内同一オリジンURLに投稿し、直接フィーチャサービスには送信しません。IIS URL Rewrite(サイトレベルで設定されておりExperience Builder再公開でも消えません)がそのパスをApplication Request Routing経由でlocalhost上のFlaskプロキシに転送します。別のサイトレベルルールで外部からFeatureServerへの直接POSTには403を返します。
- プロキシはクライアントIPごとにレート制限し、一回のリクエストで複数フィーチャを拒否し、ジオメトリを境界ボックスと照合し、カテゴリ、説明文長さ、メールおよび電話形式を検証してからlocalhost上FeatureServerへ転送します。写真については最初の数バイトを読み、本物のJPEG, PNG, WebP, HEICのみ受け入れサイズ制限ありです。受理・拒否されたすべてのリクエストはクライアントIP付きでNotification_Logに記録されるためファイルログなしで監査証跡があります。
- ジオデータベース挿入時に5つのArcade属性ルールが動作します:ジオフェンス制約(境界外または無効カテゴリ提出を参照テーブルメッセージ付きでブロック)、ルーティング計算(境界特定後Ticket_Routingでカテゴリ+サブカテゴリ+境界一致試行し失敗時はカテゴリ全般行へフォールバックして割り当て部署設定)、SQLシーケンス10000開始から引くチケット番号計算、および必須項目と業務ルール検証制約2つです。ルーティングはコードではなくデータなので部署追加や水道地区担当変更は行編集だけです。
- 5分ごとに新規チケット通知スクリプトがnotification_sent=0のチケットを見つけて住民へステータスリンク付き確認メールを送り、割り当て部署へマネージャーアプリへの深いリンク付き作業通知メールを送信します。
スタッフ側
マネージャーウィジェットはPortalサインイン後内部Experience Builderアプリで動作します。Ticketsレイヤーと関連テーブルをウェブマップから読み込むため追加トークンやサービスURL設定不要です。スタッフはステータス・カテゴリ・部署バッジで絞り込み、チケットを開きステータス変更(変更時コメント必須・解決日遡及時内部監査ノート記録)、公開または内部コメント追加、ライトボックスで写真閲覧、調査回答確認ができます。公開コメントはコメントメール送信スクリプト経由で住民へメール送信されます。Excelエクスポートには概要シートと関連レコードがあります。当社ウィジェット共通パターンによるヘルプガイドも組み込まれています。
スクリプトと最初に間違えた2点
7つのスクリプトは設定・ログ・障害通知・メール・テンプレートレンダリング・監査書き込み共通モジュールを共有し、それぞれロジックのみ:新規チケット通知器、再割当通知器(assigned_to変更検知し新部署へメール)、公開コメントメール送信器、調査招待メール送信器(ResolvedまたはClosed到達時発火)、Survey123回答取得器(Survey_Responsesへ書き込み・住民要望あれば解決者へメール)、平日ディレクター向け未処理チケットカテゴリー別報告書、および月次全部署報告書です。実行中障害はまとめて終了時に1通通知メール送信しプロセス終了コード1でタスクスケジューラに表示されます。
コードに組み込まれた2つの教訓があります。一つ目は重複メール問題です。当初通知器はバッチ編集セッション内でメール送信し最後にフラグコミットしていましたが、そのコミット失敗時(スタッフがマネージャーで開いていてバージョン競合)にはすべてメール済みかつフラグロールバックとなり次回実行時再度全送信されました。現在は各チケットごと短い編集操作内でフラグコミット後にメール送信します。コミット失敗ならメールなし安全再試行可能、コミット成功かつ送信失敗ならログ記録され再送なしです。
二つ目は監査テーブル問題です。Notification_Logは元々バージョン管理されておりカーソル経由書き込みだったため遅くCompress依存でしたが現在非バージョン化され各書き込み者が直接SQL挿入しMAX OBJECTID+1指定短い再試行付きなのでジオデータベース行IDカウンター依存せず衝突もありません。この関連で調査メール送信器も基底テーブル読取時Compressまで解決済み見えず調査遅延問題がありましたが今ではすべてバージョン化フィーチャクラス経由読取しています。
調査ループ
チケット解決時住民へSurvey123フォームURL(チケットID入り)リンクが届きます。取得スクリプトがArcGIS Onlineから新回答取得しジオデータベースSurvey_Responsesへ書き込みます。また住民から折返し希望あれば解決者へメール送信します(編集者追跡情報+部署フォールバック)。マネージャーウィジェットでは評価とコメントが表示されます。
セキュリティとプライバシー
匿名ユーザーには公共ビュー読み取り権限のみあり作成はプロキシ経由限定です。サイトレベルIISヘッダーでHSTS, nosniff, frame options設定済みです。フィーチャサービスではアップロードファイル種別とサイズ制限があります。プロキシでは宣言コンテンツタイプを信用しません。保持管理は月別・カテゴリ別・部署別集計テーブルによって行われチケットIDや自由テキストなしなので個人情報含む古いチケットも統計情報保持したまま定期的に削除可能です。
導入方法
docs/deployment.md内ランブック手順:arcpyスクリプトでスキーマ構築(まずドライラン)、3サービス公開(公共書込・公共読取・スタッフ用)、属性ルール追加、「your-extensions」へ2ウィジェット配置してアプリビルド、サイトレベルIISルール設定、ArcGIS Pro Python環境クローン上プロキシ起動、config.pyおよびrac_secrets.py編集、タスクスケジューラジョブインポートですべて完了します。各スクリプトにはテストモード搭載済みなので切り替えるまで実際には住民へメール送信されません。また移行中作成したトラブルシューティング表もあります:プロキシ未起動時IIS HTML 500エラー、ARR未インストール404エラー、ウィジェットURL同一オリジン違反によるCORS失敗、およびジョブが基本ArcGIS Pro Python指しているWindows Server 2025タスクスケジューラエラーなどです。
ウィジェットzipファイルは各GitHubリリースに添付されています。不具合報告やプルリクエストもリポジトリで歓迎します。