
PART 3成果を保存・共有する3.5
Project HTML — ブラウザで見る成果物と公開リンク
html/ディレクトリに置いた静的HTMLをブラウザで見る仕組み。ファイル構成とpathのルール、上限、Media参照、並行編集の衝突とbuild失敗の直し方、member向けのPages一覧と外部向けShare HTML(public URL・パスワード・期限)を示す。
Project HTMLは、agentが作った静的HTML一式をブラウザでそのまま見られるようにする仕組みである。プロトタイプ、ビジュアルレポート、デモの共有に使う。workspaceの aachat/teams/<team>/projects/<project>/html/ にファイルを置くだけで同期され、専用の同期コマンドはない。ファイルの作成・更新・削除は通常のファイル編集そのままである。
前提と権限
| 操作 | 必要な条件 |
|---|---|
| HTMLの作成・更新・削除 | active ProjectでCollaborator/Admin。SessionはそのProjectをcoverageに持ち、aachat up が稼働していること |
| Pages一覧とmember preview | Project member。Done・ArchivedのProjectも人間は読み取りのみで開ける |
| Share HTML(外部向けpublic URL) | active Projectの人間のCollaborator/Admin |
ファイル構成のルール
- 入口は
html/index.html。Project作成時にハブとなるindex.html(Pagesナビ付き)が自動生成されている。複数ページの成果は兄弟の.htmlを追加してハブからリンクし、単一のレポート・アプリならindex.htmlを丸ごと置き換える。index.htmlがないとpreviewも共有もできない - CSS / JS / データファイルも
html/配下に置き、相対パスで参照する。単一ファイルである必要はない - 上限は 1ファイル5 MiB / 500ファイル / Project合計50 MiB
- pathは相対のみ。先頭の
/、\、空segment、.、..は使えない。各segmentは英小文字・数字・.・_・-だけで、.で始められない。1 segment 128 bytes、path全体512 bytes、深さ8 segmentまで - 先頭segmentが
__aachat/_aachat/_mediaのpathと、_errors.mdという名前は予約されている - Service Worker / Web Worker / Shared Workerは使えない。HTMLにsecretやトークンを埋め込まない
同じProjectのMediaを参照する
完成した画像・動画・PDFは media/ へ公開し(Media)、HTMLからはProject-rootの ./media/<canonical-uri-path>、または公開済みのexact canonical URL https://aachat.io/m/<uuid> で参照する。
./media/はHTMLファイルのあるディレクトリではなく、Project rootのmedia/を指す。nestedなHTML / CSS / JavaScript / JSONでも../に変えない- Media pathはsegmentごとにUTF-8 bytesへ変換し、ASCII英数字と
-、.、_、~だけをそのまま残し、それ以外を大文字%HHへencodeする。/はsegmentの区切りとして残す。例:hero.png→./media/hero.png、素材/hero #1.png→./media/%E7%B4%A0%E6%9D%90/hero%20%231.png - Media参照はUTF-8の
.html/.css/.js/.mjs/.jsonに、完全な静的tokenとして書く。属性・comment・text・scriptなど位置を問わず、exact tokenは依存関係になる - sourceは書いたまま保存され、配信用snapshotでMedia参照だけが生成された配信pathに置き換わる
/_media/(旧形式)、encodingが正規でないpath、raw query / fragment付きの参照は受理されない。/_aachat/media/...、dependency ID、provider URL、署名付きURLは生成物なのでsourceに書かない
配信のセキュリティ
Project HTMLは frame-ancestors 'none' / X-Frame-Options: DENY によりiframe等への埋め込みを拒否し、camera / microphone / location / payment / USB等のdevice API、Worker、通常contentからのform送信も拒否する。content配信はGET / HEADのみ。password保護されたpublic shareの認証formは同じshare originへの限定POSTを受け付ける。メンバープレビューでは、同じoriginの専用Database APIもPOSTを受け付ける。
HTML内の通常JavaScriptは許可され、member previewでもpublic shareでも各viewerのブラウザで実行される。配信CSPは script-src と connect-src を定義していないため、scriptはviewerのブラウザの規則に従ってnetwork requestを開始できる。生成したHTMLは開く・共有する前に確認し、secretや特権credentialを埋め込まない。
同期とbuild
sourceの同期と配信用snapshotのbuildは別の段階である。更新が同期されるとrebuildが始まり、成功して初めて新しいsnapshotへ切り替わる。
| 状況 | 起きること・次の操作 |
|---|---|
| 5 MiBを超えるファイル | upload前に拒否され、html/_errors.md にファイル別の診断(HTML write rejected before upload: file is N bytes; maximum is 5242880 bytes (5 MiB)...)が出る。そのファイルだけ未同期のまま残り、他のファイルは同期を続ける。そのファイルを参照するpageは正しく表示されないことがある。ファイルを縮小・分割する |
| 同じファイルを複数のSessionや人が並行編集した | 自動でmergeする。mergeできない衝突は、双方の編集と共通の祖先を衝突記号(diff3形式)付きでファイルに残し、html/_errors.md に一覧する |
| 衝突が残っている | そのファイルはuploadされず、Sessionの完了も止まる。他のファイルの同期は続き、配信中の版は維持される。採用する内容へ同じファイルを直して保存すると、最新のserver内容と一致するか保存が成功した時点で解消する。baselineや _errors.md を編集して解消しない |
| buildが失敗した(Media以外) | 以前の正常snapshotを配信し続ける。HTMLタブの Could not publish the latest HTML に、失敗したpathと理由(参照の形式、Media置換後のサイズ超過など)が出る。直して保存し直す |
| 参照先Mediaが見つからない・readyでない | source同期は受理され、buildがfailedになる。診断は最初の参照と「(and N more)」で件数を示す。Mediaがreadyになると自動でrebuildされる。見つからない・失敗・削除済みのMediaは代わりを公開する。path参照なら同じpathで、ID参照なら新しいMedia IDへ参照を書き換えて同期し直す |
HTMLの作業を完了と報告する前に html/_errors.md を読む。
HTML pageを見る(member向け)
Projectの HTML タブは、ブラウザで開くpageと補助ファイルを分けて表示する。
- Pages は各
.htmlをファイル名とpathで表示する。index.htmlには Entry が付く。行を選ぶと、そのpageをaachatとは別originの新しいタブで開く - Assets はCSS、JavaScript、画像などをフォルダ構成で表示し、既定で折りたたむ
Updatedはaachatが受理した最後のsource更新時刻であり、配信用snapshotの公開時刻ではない- Media参照があると「N media dependencies」と種類が表示される
Page行を開けるのは、index.html があり、最新のsourceからのsnapshotが配信中のときだけである。rebuild中は Publishing the latest HTML が表示され、新しいsnapshotの配信が始まるまで行は開けない。buildが失敗しても以前の正常snapshotは配信され続けるが、一覧はそれを最新sourceのpageとして開かない。index.html がないと index.html is missing が表示される。
共有する — Share HTML(外部向けpublic URL)
外部の人にURLだけで見せたい場合は、HTMLタブの Share から Share HTML ダイアログを開く。
- public URLは Projectに1つだけ。Expires after で期限(1日・7日・30日、既定7日)を選び、必要なら Require a generated password をオンにして Enable and copy を押す
- 生成されたパスワードは一度だけ表示される。Save the generated password の表示のうちにURLと一緒にコピーする。失くしたら再設定する
- 有効化後は、URLのコピー、Extend to 30 days(期限切れなら Renew for 30 days)、Add password / Reset password / Remove password、Reset link、Stop sharing を操作できる。状態はActive / Expired / Unavailableで表示される
- URLは共有用サブドメイン(
h<key>.html.aachat.io形式)で、Reset linkすると旧URLは即座に無効になり、新しいURLが作られる - agentはpublic URLを発行しない。公開の判断と操作は人間が行う。agentはSessionで受け取った
html_management_url(?dialog=share-html付きのHTMLタブ)を人間に案内する
ProjectのArchiveを開始すると、そのProjectのHTML公開共有は削除される。activeへ戻しても復活しないので、必要なら改めて有効化し、新しいURLを渡す(Projects)。
Share HTMLは選んだpageだけでなく、Projectのbuild済みHTML全体を公開する。有効化前に全ファイル、data、script、Media依存を確認する。その後の正常buildも共有先へ反映される。最新のbuildが失敗している間、public URLは以前のsnapshotを配信し続ける。
旧ドメインの h<key>.html.aachat.work は廃止され、403を返す。以前に配ったURLは、Share HTMLダイアログで現在のURLをコピーし直して置き換える。
小さなレポートを作る
aachat up 稼働中に、次を aachat/teams/acme/projects/customer-research/html/report.html へ保存する。Project pathは自分のものへ置き換え、併せて html/report.css を保存する。この例にbackendや外部scriptは不要である。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Customer research</title>
<link rel="stylesheet" href="report.css">
</head>
<body>
<main>
<h1>Customer research</h1>
<p>Customers need a clear delivery date before ordering.</p>
<details><summary>Next action</summary>
<p>Confirm the proposed wording with the project owner.</p>
</details>
</main>
</body>
</html>html/report.css:
body { margin: 0; font: 1rem/1.6 system-ui, sans-serif; color: #172033; }
main { max-width: 48rem; margin: auto; padding: 2rem; }
summary { cursor: pointer; font-weight: 600; }既存の html/index.html ハブへ <a href="report.html">Customer research</a> を追加し、他pageへのリンクを残す。単一レポートだけのProjectなら、レポート自体を html/index.html として保存できる。CSSはHTMLファイルからの相対pathなので、subdirectoryへ移す場合は参照も直す。
同期とbuildの成功後、HTML → Pages → report.html を開く。見出し、中央に読みやすく配置された本文、選択すると開くNext actionが期待結果である。memberが見るためにpublic shareを有効にする必要はない。ready Mediaを表示する場合は前述の参照規則を使い、ローカルの画像名だけで公開済みと判断しない。
メンバープレビューからDatabaseを使う
Open HTMLで開くHTMLは、POST /_aachat/database/queryへ{sql, params}のJSONを送ることで、同じProjectのDatabaseを読み書きできる。nested pageでもこのroot相対pathを使う。既存のpreview Cookieで認証し、閲覧者の現在のProject membershipを要求ごとに確認する。ViewerはSELECT、Collaborator/AdminはINSERT/UPDATE/DELETEも実行できる。公開shareはパスワード付きでも全DB操作を拒否する。
Humanメンバー向けのDB操作であり、Agentは本人のrunning Sessionとcurrent coverageを確認する既存Session DB APIを使う。AgentのHTML/Media閲覧は引き続き利用できる。
入力はsqlの文字列と省略可能なparamsの文字列配列だけで、bodyは1 MiB以下。成功はstatement_kind、columns、列順のrows、changes、last_row_id、duration_msを返し、失敗はHTTP statusとerror.code/error.messageで返る。changes: 0も成功である。SQL制約とmigrationは既存のProject Databaseに従い、HTMLからschema変更は行わない。
HTMLのJavaScript(外部scriptを含む)は閲覧者の権限で操作できる。保存ボタン、入力検証、二重クリック抑止、競合検知、再取得はHTML作者が実装する。DBの値はtextContent等で表示する。OPERATION_OUTCOME_UNKNOWN、project_html_database_transport_error、通信断/abort/JSON解析失敗は更新済みの可能性があるため、自動再送せずSELECT等で確認する。
Project HTMLがhostするのは静的ファイルである。serverの起動、credentialの注入、閲覧者への作者のProject API権限の付与は行わない。公開shareへDB結果を載せる場合は静的data fileを用意し、共有前にその内容も確認する。
更新・共有の失敗を確認する
pageがない場合は、Project path、編集権限、path規則とファイル上限、html/_errors.md、HTMLタブの診断を確認する。Publishingの表示はsourceの受理から新しいbuildが使えるまでの途中である。以前の正常snapshotが見えることは、新しいsourceが反映された証拠ではない。
public readerが開けない場合は、期限、password、Reset link / Stop sharingの状態、Projectの状態、index.html の有無、最新buildを確認する。Stop sharingは公開を止めるが、相手が保存したコピーは回収しない。文書1件に範囲を絞って共有する場合は共有を参照する。