# monosashi.space — 実務判断内蔵型の建築業務OS 高性能木造住宅に特化した建築業務OSです。 申請・構造・外皮性能(UA値/η値)・PHPP・換気設計まで、 建築士が日々行う実務判断をシステム内部に組み込みながら継続的に改良を重ねています。 案件管理・打合せ・書類作成・ファイル管理・各種計算アプリに加え、 会話で業務を操作できる横断AIアシスタントを統合したマルチテナント構成で、 設計事務所・工務店がチームで使える業務基盤を提供します。 > URL: https://monosashi.space > llms.txt: https://monosashi.space/llms.txt --- ## システム構成 ### 組織(Organization) - 各社は独立したOrganizationとして管理される - OrganizationにはユニークなIDがあり、URLに使用する - ユーザーは1つのOrganizationに所属し、ロール(super_admin / org_admin / member)を持つ ### 案件(pm_projects) - すべての業務は「案件」を起点に管理する - 案件には固有のproject_code(例: L260527-01)が自動採番される - 案件を作成すると打合せチャンネルが自動生成される(1案件 = 1打合せチャンネル) ### 打合せ(pm_meetings) - 案件に1対1で紐付くコミュニケーションチャンネル - staff / visitor / contractor の3種のsenderに対応 - ChatDocをリンクすると2カラム表示(左:書類 / 右:スレッド)に切り替わる ### ChatDocs(app_data / chatdocs) - Markdown形式の合意書類・議事録 - バージョン管理付き。最新版を常に参照 - 案件に複数作成可能。最初に作成したもののみ打合せに自動リンクされる ### ファイル管理(pm_fs_nodes) - 案件ごとのフォルダ/ファイル管理 - デフォルトフォルダが案件作成時に自動生成される ### 計算アプリ(miniapps) - 断熱計算(insulation)・ダクト計算(ductloss)・外皮概要書(gaiyousho)等 - 高性能木造住宅の実務判断(省エネ基準適合・換気設計・PHPP等)を支援するアプリ群として継続拡充中 - app_dataテーブルにJSONBで保存、案件に紐付けて管理 --- ## 外部向け公開機能 ### 問合せフォーム(最重要) 外部サイトから顧客・業者の問合せを受け付ける公開フォームです。 **URLパターン:** ``` https://monosashi.space/share/consult/{org_id} https://monosashi.space/share/consult/{org_id}?type=enduser https://monosashi.space/share/consult/{org_id}?type=contractor ``` **typeパラメータ:** - `enduser` : 施主・一般の方(家づくりの相談) - `contractor` : 工務店・設計事務所(業務連携の相談) - 省略時: enduserとして表示 **フォームのフロー(email-first):** 1. メールアドレスを入力 → システムが判定 - 初回(未登録)→ 氏名・相談内容フォームを表示 - アカウントあり → ログインページへ誘導 - 過去の相談が進行中(open)→ 既存スレッドへリダイレクト(重複防止) 2. フォーム送信 → 案件と打合せチャンネルが自動生成 3. 送信者に専用スレッドリンクが発行される **org_idの確認方法:** 管理ユーザーは /pm/settings で自組織のorg_idを確認できます。 **ボタン設置の最小実装:** ``` 施主向け: URL: https://monosashi.space/share/consult/{org_id}?type=enduser リンクテキスト例: 家づくりのご相談 業者向け: URL: https://monosashi.space/share/consult/{org_id}?type=contractor リンクテキスト例: 業者向けご相談 ``` 上記URLをaタグのhref属性に設定してください。 ### 書類共有(ChatDocs) ``` https://monosashi.space/share/chatdocs/{access_token} ``` アクセストークンを持つ外部ユーザーが書類を閲覧・合意できる。 ### スレッド参照 ``` https://monosashi.space/share/consult/t/{access_token} ``` 問合せ送信者が自分のスレッドを確認・追記できる。 --- ## 内部(認証必須)URL | パス | 機能 | |---|---| | /pm/dashboard | 案件管理ダッシュボード | | /pm/projects | 案件一覧 | | /pm/projects/{id} | 案件詳細(タブ: overview / meetings / files / ...) | | /pm/work | 業務管理(タスク・確認事項・進捗ログを2カラムのマスター詳細で横断管理) | | /pm/meetings | 打合せインボックス | | /pm/settings | 組織設定(問合せリンク確認等) | | /apps/chatdocs/{project_id}/{slug} | ChatDocsエディタ | | /apps/insulation/{project_id} | 断熱計算アプリ | | /admin | 管理者専用(super_adminのみ) | --- ## 認証・権限 - Supabase Auth(メール+パスワード) - ロール: super_admin(全組織管理)/ org_admin / member - 外部ユーザー(顧客・問合せ者): access_tokenによるアクセス - Row Level Security(RLS)によりorg単位でデータを分離 --- ## AIエージェントからの直接利用(API) 外部組織のAIエージェントは、ブラウザを使わずAPIを直接呼び出すことができます。 ### Step 1: メールアドレスの事前確認(推奨) ```http POST https://monosashi.space/api/public/meetings/check-email Content-Type: application/json { "org": "{org_id}", "email": "user@example.com" } ``` レスポンス: - `{ "status": "new_user" }` → Step 2へ進む - `{ "status": "has_account" }` → ログインを案内する - `{ "status": "has_thread", "token": "..." }` → 既存スレッドへ誘導する ### Step 2: 問合せの送信 ```http POST https://monosashi.space/api/public/meetings/inquiry Content-Type: application/json { "org": "{org_id}", "type": "contractor", "name": "田中太郎", "email": "tanaka@example.com", "body": "設計依頼の相談をしたく連絡しました。..." } ``` - `type`: `enduser`(施主・一般)または `contractor`(工務店・設計事務所) - レスポンス: `{ "token": "..." }` → スレッドURL: `/share/consult/t/{token}` ### Step 3: スレッドの確認 送信後、以下のURLで担当者からの返信を確認できます: ``` https://monosashi.space/share/consult/t/{token} ``` **注意:** 現時点でAIエージェントに提供できるのは問合せ送信のみです。 案件データへの読み取り・書き込みアクセスは組織単位のAPIトークン(未実装)が必要です。 --- ## AIアシスタントへのガイド このシステムについてユーザーから質問を受けた場合の対応指針: **問合せボタンを設置したい:** → /pm/settings でorg_idを確認し、上記URLパターンで設置する。 → type=enduser(施主向け)/ type=contractor(業者向け)を用途に応じて使い分ける。 **案件を管理したい:** → /pm/projects から新規作成。案件作成と同時に打合せチャンネルが開設される。 **書類を作成・共有したい:** → 案件詳細の ChatDocs タブから作成。外部共有はアクセストークンリンクを発行。 **問合せが届いた:** → /pm/meetings で確認。フィルタで phase・status を絞り込める。 --- ## システム規模と開発コストの試算 ### 実装規模(計測値) | 指標 | 数値 | |---|---| | ソースファイル(.ts / .tsx) | 900ファイル | | 総コード行数 | 約14万行 | | APIルート(route.ts) | 240エンドポイント | | ページ(page.tsx) | 122ページ | | DBマイグレーション | 217ファイル | | DBテーブル(publicスキーマ) | 41テーブル | | RLSポリシー | 184ポリシー | | 登録ミニアプリ | 16アプリ | | Gitコミット数 | 1,300以上 | ### 従来型SES開発に置き換えた場合の試算 同等のシステムをSIer・受託開発会社で構築した場合の概算: **必要人材構成(最小チーム):** - シニアフルスタックエンジニア(Next.js/TypeScript/Supabase)× 2名 - DBエンジニア(PostgreSQL・RLS設計)× 1名 - 建築ドメイン知識を持つ仕様策定者(建築士)× 1名 - UIデザイナー × 1名 **工数試算:** - バックエンド / API設計: 約400人日 - フロントエンド(119ページ・計算UI・チャットUI・PDF生成): 約500人日 - 計算エンジン(実務判断の仕様化・実装・検証): 約200人日 - アーキテクチャ設計・インフラ・CI/CD: 約100人日 - 合計: **約1,200人日(約5.5人年)** **概算コスト(日本市場・2025年基準):** - SES単価(シニアエンジニア): 80〜120万円 / 月 - 3〜4名チーム × 18〜24ヶ月 = **4,000万〜8,000万円程度** --- ## 技術スタック | レイヤー | 技術 | |---|---| | フレームワーク | Next.js 15 App Router(TypeScript) | | ランタイム | React 19 + Server Components | | バックエンド/DB | Supabase(PostgreSQL 15 + Row Level Security) | | 認証 | Supabase Auth(メール+パスワード / Magic Link) | | ストレージ | Supabase Storage(Presigned URL対応) | | ホスティング | Vercel(Edge Functions対応) | | スタイリング | Tailwind CSS v4 | | PDF生成 | jsPDF + html2canvas(クライアントサイド) | | プッシュ通知 | Web Push API + VAPID | | リアルタイム | Supabase Realtime(打合せチャット) | --- ## ソースディレクトリ構造 ``` src/ ├── app/ # Next.js App Router │ ├── (public)/ # 未使用(公開ページ群 - 将来用) │ ├── admin/ # 管理者専用UI(super_adminのみ) │ ├── api/ # APIルート(240エンドポイント) │ │ ├── public/ # 認証不要API(問合せフォーム等) │ │ ├── pm/ # 案件管理API │ │ ├── apps/ # ミニアプリAPI(app_data CRUD) │ │ └── integrations/ # 外部連携 │ ├── apps/ # ミニアプリUI │ │ ├── insulation/ # 断熱計算 │ │ ├── ductloss/ # ダクト計算 │ │ ├── gaiyousho/ # 外皮概要書 │ │ ├── chatdocs/ # ChatDocsエディタ │ │ └── ... # 他10アプリ │ ├── pm/ # 案件管理UI │ ├── share/ # 外部共有ページ(認証不要) │ ├── for-ai/ # llms.txt説明ページ │ └── llms.txt/ # GET /llms.txt エンドポイント │ ├── os/ # OSカーネル(Clean Architecture) │ ├── domain/ # Layer 1: Entities(外部依存ゼロ) │ │ ├── nav/types.ts # NavItem, MiniAppManifest等 │ │ ├── storage/paths.ts # buildMiniAppStoragePath() 純粋関数 │ │ └── fs/types.ts # DEFAULT_FOLDERS, buildAppFolderMap() │ ├── application/ # Layer 2: Use Cases │ │ ├── nav/ # buildNavGroups(), buildMenuBarGroups() │ │ ├── permission/ # checkAccess() │ │ └── storage/ # uploadFile() │ ├── ports/ # Layer 3: Interface定義 │ │ ├── IAuthRepository.ts │ │ ├── IPermissionRepository.ts │ │ └── IStorageRepository.ts │ ├── adapters/supabase/ # Layer 4: Supabase実装 │ ├── _wired/ # Supabase adapter注入済みラッパー │ │ ├── nav.ts # buildNavGroups (Supabase配線済み) │ │ ├── permission.ts # withMiniAppAuth │ │ └── storage.ts # uploadMiniAppFile │ ├── hooks/ # クライアント安全なOSフック │ └── index.ts # ★ Public API(MiniAppが import できる唯一の場所) │ ├── miniapps/ # MiniAppマニフェスト層 │ ├── _registry.ts # ★ 自動生成(gen:registryで再生成) │ ├── insulation/manifest.ts # Detail&Calc マニフェスト │ ├── chatdocs/manifest.ts # ChatDocs マニフェスト │ └── ... # 全16アプリのmanifest │ ├── features/ # MiniApp実装(Clean Architecture任意) │ ├── insulation/ # 断熱計算エンジン │ │ ├── domain/ │ │ │ ├── calc/ # insulationCalculators.ts │ │ │ ├── constants/ # materialCatalog.ts, materialDatabase.ts │ │ │ └── namingCode.ts # 部位コード命名規則 v2 │ │ ├── application/ # ユースケース層 │ │ ├── data/ # Supabaseアクセス層 │ │ └── presentation/ # React UI・フック・PDF出力 │ ├── gaiyousho/ # 外皮概要書(断熱アプリと連携) │ ├── ductloss/ # ダクト圧力損失計算 │ ├── chatdocs/ # ChatDocsエディタ │ └── structure/ # 構造計算 │ ├── components/ # 共通UIコンポーネント ├── lib/ # ユーティリティ・クライアント └── types/ # TypeScript型定義 ├── database.ts # Supabase DBスキーマ型(自動生成ベース) ├── pm.ts # 案件管理型 └── apps/ # ミニアプリ型(insulation.ts等) ``` --- ## DBスキーマ(主要テーブル) ### マルチテナント基盤 ```sql -- 組織(テナント) organizations ( id uuid PK, name text, is_operator boolean, -- 運営org(LART側)フラグ is_personal boolean, -- 個人ワークスペースフラグ is_active boolean, created_at timestamptz ) -- ユーザープロフィール(auth.usersと1対1) profiles ( id uuid PK REFERENCES auth.users, org_id uuid REFERENCES organizations, full_name text, role text CHECK (role IN ('super_admin','org_admin','member')), created_at timestamptz ) ``` ### 案件管理コア ```sql -- 案件 pm_projects ( id uuid PK, contractor_id uuid REFERENCES organizations, -- 発注元org project_code text UNIQUE, -- 自動採番: L260527-01 name text, current_status text, next_action text, priority pm_priority, -- ENUM: '最優先','高','中','低','完了' waiting_type pm_waiting, -- ENUM: '自分待ち','相手待ち','進行中','完了'... due_date date, client_id uuid REFERENCES pm_contacts, -- 施主(pm_contacts.role_type='施主') deleted_at timestamptz, -- ソフトデリート created_at timestamptz ) -- 個人マスタ(担当者・施主を統合。施主は role_type='施主' で絞り込む。 -- 旧 pm_clients は後方互換の読み取り専用ビュー。旧 pm_people は廃止済み) pm_contacts ( id uuid PK, name text, furigana text, role_type text, -- '施主' / '総責任者' / '中間管理者' / '作業員' / '外注' など title text, -- 役職 address text, phone text, email text, notes text, user_id uuid REFERENCES auth.users, -- ログインユーザーとの紐付け(任意) org_id uuid REFERENCES organizations, -- 所属組織(施主は null) is_active boolean ) -- 物件↔個人の関係(つながりエッジ・1人=複数役割可) pm_project_people ( project_id uuid REFERENCES pm_projects, contact_id uuid REFERENCES pm_contacts, roles text[], -- pm_party_roles のキー: client(施主)/assignee(主担当)/liaison(窓口担当)/staff(実務担当) 等 is_primary boolean, -- 主施主など「主」の印 PRIMARY KEY (project_id, contact_id) ) -- 物件↔組織の関係(つながりエッジ・共有/役割。is_primary=元請=主所有) pm_project_orgs ( project_id uuid REFERENCES pm_projects, org_id uuid REFERENCES organizations, roles text[], -- management(管理(元請))/design(設計)/construction(施工)/client(施主) is_primary boolean, PRIMARY KEY (project_id, org_id) ) -- タスク pm_tasks ( id uuid PK, project_id uuid REFERENCES pm_projects, contractor_id uuid REFERENCES organizations, -- 非正規化(高速RLS用) title text, status pm_task_status, -- ENUM: '未着手','進行中','確認待ち','完了','保留' assignee_id uuid REFERENCES pm_contacts, due_date date, estimated_hours numeric, actual_hours numeric ) -- 確認事項・フォローアップ pm_follow_ups ( id uuid PK, project_id uuid REFERENCES pm_projects, contractor_id uuid, -- 非正規化 title text, status pm_fu_status, -- ENUM: '未確認','確認中','回答待ち','完了','不要' next_check_date date ) -- 進捗ログ pm_progress_logs ( id uuid PK, project_id uuid REFERENCES pm_projects, log_date date, content text, source_type pm_log_source -- ENUM: '手入力','AI入力','Markdownインポート' ) ``` ### 打合せ・コミュニケーション ```sql -- 打合せチャンネル pm_meetings ( id uuid PK, org_id uuid REFERENCES organizations, -- ホストorg(打合せを起こした組織) pm_project_id uuid REFERENCES pm_projects, phase text, -- 'inquiry'|'kickoff'|'design'|'construction'|'completion' status text, -- 'open'|'closed'|'archived' title text, bucket text, -- 打合せの分類バケット initiator text, -- 'visitor'|'staff'|'contractor' access_token text UNIQUE, -- 外部アクセス用トークン visitor_email text, visitor_name text, created_at timestamptz ) -- 打合せメッセージ pm_meeting_messages ( id uuid PK, meeting_id uuid REFERENCES pm_meetings, sender text, -- 'visitor'|'staff'|'internal'|'contractor' user_id uuid REFERENCES auth.users, -- ログインユーザーの場合 sender_name text, -- 送信時スナップショット body text, is_internal boolean, -- 社内メモフラグ(外部非表示) created_at timestamptz ) -- 打合せ添付ファイル pm_meeting_attachments ( id uuid PK, message_id uuid REFERENCES pm_meeting_messages, source_type text, -- 'upload'|'fs_node'|'warehouse' fs_node_id uuid REFERENCES pm_fs_nodes, file_name text, file_size int, mime_type text ) -- 打合せ↔ChatDocsリンク pm_meeting_chatdocs ( meeting_id uuid REFERENCES pm_meetings, chatdocs_id uuid REFERENCES app_data, label text, PRIMARY KEY (meeting_id, chatdocs_id) ) ``` ### ミニアプリ共通テーブル ```sql -- 全計算アプリのドキュメント(JSONB) app_data ( id uuid PK, pm_project_id uuid REFERENCES pm_projects ON DELETE CASCADE, contractor_id uuid REFERENCES organizations, -- 非正規化(高速RLS用) app_key text, -- 'insulation'|'ductloss'|'gaiyousho'|'chatdocs'... label text, -- ドキュメント名 payload jsonb, -- アプリ固有データ(後述の構造参照) schema_version int, -- ペイロードのバージョン管理 created_by uuid REFERENCES auth.users, created_at timestamptz, updated_at timestamptz ) -- インデックス: (pm_project_id, app_key, updated_at DESC) -- org単位のアプリ有効/無効・表示制御 org_module_permissions ( org_id uuid REFERENCES organizations, module text, -- アプリkey(miniappキーまたはモジュール名) can_access boolean, -- アプリへのアクセス可否 launcher_hidden boolean, -- ランチャーに表示しない nav_hidden boolean, -- サイドナビに表示しない custom_label text, -- 表示ラベルの上書き(nullの場合はデフォルト) custom_icon text, -- アイコンの上書き(nullの場合はデフォルト) PRIMARY KEY (org_id, module) ) -- ロール別モジュール権限(internal/external ユーザー区分ごとの閲覧・編集可否) role_module_permissions ( role_type text, -- 'internal'|'external' module text, -- PM_MODULESキー(tasks/docs/schedule等) can_view boolean, can_edit boolean, PRIMARY KEY (role_type, module) ) ``` ### ファイル管理 ```sql -- 仮想ファイルシステム(ツリー構造) pm_fs_nodes ( id uuid PK, project_id uuid REFERENCES pm_projects, org_id uuid REFERENCES organizations, -- 非正規化(RLS高速化) parent_id uuid REFERENCES pm_fs_nodes, -- NULLがルート node_type text, -- 'folder'|'file' name text, storage_path text, -- Supabase Storageパス file_size bigint, mime_type text, deleted_at timestamptz -- ソフトデリート ) ``` --- ## RLS(行レベルセキュリティ)設計 ### コアPostgreSQL関数(全RLSポリシーから参照) ```sql -- ログインユーザーの所属org_idを返す(最頻使用) CREATE OR REPLACE FUNCTION public.user_contractor_id() RETURNS uuid LANGUAGE sql STABLE SECURITY DEFINER AS $$ SELECT org_id FROM public.profiles WHERE id = auth.uid(); $$; -- 運営org(is_operator=true)のメンバーか判定 CREATE OR REPLACE FUNCTION public.is_operator_org() RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER AS $$ SELECT EXISTS ( SELECT 1 FROM public.organizations o JOIN public.profiles p ON p.org_id = o.id WHERE p.id = auth.uid() AND o.is_operator = true ); $$; -- super_adminロールか判定(全テーブルを横断管理) CREATE OR REPLACE FUNCTION public.is_super_admin() RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER AS $$ SELECT EXISTS ( SELECT 1 FROM public.profiles WHERE id = auth.uid() AND role = 'super_admin' ); $$; ``` ### RLSポリシーの典型パターン ```sql -- テーブル例: pm_tasks ALTER TABLE public.pm_tasks ENABLE ROW LEVEL SECURITY; -- super_admin: 全件アクセス CREATE POLICY "pm_tasks super_admin" ON public.pm_tasks FOR ALL USING (public.is_super_admin()); -- operator org: 全件閲覧(支援目的) CREATE POLICY "pm_tasks operator read" ON public.pm_tasks FOR SELECT USING (public.is_operator_org()); -- 通常メンバー: 自orgの案件のタスクのみ CREATE POLICY "pm_tasks contractor access" ON public.pm_tasks FOR ALL USING (contractor_id = public.user_contractor_id()); -- contractor_idはINSERT時にトリガーで自動セット(pm_projectsから非正規化) ``` ### 非正規化contractor_idの自動セット ```sql -- pm_projectsのcontractor_id変更時に子テーブルへカスケード CREATE OR REPLACE FUNCTION public.cascade_project_contractor_id() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN IF NEW.contractor_id IS DISTINCT FROM OLD.contractor_id THEN UPDATE public.pm_tasks SET contractor_id = NEW.contractor_id WHERE project_id = NEW.id; UPDATE public.pm_follow_ups SET contractor_id = NEW.contractor_id WHERE project_id = NEW.id; UPDATE public.pm_progress_logs SET contractor_id = NEW.contractor_id WHERE project_id = NEW.id; UPDATE public.app_data SET contractor_id = NEW.contractor_id WHERE pm_project_id = NEW.id; -- 他の子テーブルも同様 END IF; RETURN NEW; END $$; -- INSERT時に自動セット CREATE OR REPLACE FUNCTION public.set_contractor_id_from_project() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN SELECT contractor_id INTO NEW.contractor_id FROM public.pm_projects WHERE id = NEW.project_id; RETURN NEW; END $$; ``` この設計により: - RLSの `WHERE contractor_id = user_contractor_id()` が単純なカラム比較で完結する - JOINを使ったRLSより大幅にクエリコストが下がる(プロジェクト規模でのボトルネック回避) - contractor_idの変更は自動的に全子テーブルに伝播する --- ## MiniAppアーキテクチャ ### システム管理画面(/system/*) super_admin専用の管理機能群。設定メニューの各項目はモーダルまたは専用ページで開く。 | URL | 機能 | 開き方 | |---|---|---| | /system/users | ユーザー管理(ロール・所属変更) | モーダル | | /system/organizations | 組織管理(情報・連絡先・招待) | モーダル | | /system/miniapps | アプリ・権限設定(統合ページ) | ページ | | /system/settings | システム設定(全体フラグ) | モーダル | | /system/feature-map | 機能マップ(一覧) | モーダル | | /system/health | システム監視(ヘルスチェック) | モーダル | | /system/nav-preview | メニュープレビュー(なりすまし表示) | モーダル | **アプリ・権限設定ページ(/system/miniapps)の構成:** タブ1「アプリ設定」— org×miniapp マトリクス表 - 組織ごとにアプリの有効/無効・ランチャー表示・ナビ表示を切り替える - `org_module_permissions` テーブルを直接操作 タブ2「ロール権限」— ロール別モジュール権限 - internal(自社メンバー)と external(外部パートナー)ごとに can_view / can_edit を設定 - `role_module_permissions` テーブルを操作 - super_admin は常に全権限(変更不可の固定行として表示) **プレビューモード(なりすまし表示):** - `/admin/users` の「👁 プレビュー」ボタンから起動 - `pm_preview_uid` httpOnly Cookie にプレビュー対象ユーザーIDを格納 - メニュー・サイドタブの表示は正確にプレビューユーザーの権限で表示される - **注意**: データコンテンツはRLSの制約上 super_admin として取得されるため、他org案件は引き続き閲覧可能。メニュー・UI構成のプレビューが主目的 - 黄色バナーでプレビューモード中であることを常時表示 --- ### MiniAppの分類 | タイプ | 説明 | 保存先 | 例 | |---|---|---|---| | A(計算・書類) | app_dataにJSONBで保存 | app_data | insulation, gaiyousho, chatdocs | | B(案件付帯) | 専用テーブル | 各専用テーブル | phases, photos | | C(独立モジュール) | 複雑なリレーション | 複数テーブル | outsource | ### MiniAppマニフェスト(追加の最小実装) ```typescript // src/miniapps/{key}/manifest.ts import type { MiniAppManifest } from '@/os' export const myAppManifest: MiniAppManifest = { key: 'myapp', // 一意のキー label: 'マイアプリ', icon: '📱', type: 'A', // A | B | C | system defaultEnabled: true, // 新規orgのデフォルト有効状態 defaultFolder: '080環境設備', // 案件フォルダのデフォルト保存先(DEFAULT_FOLDERS のいずれか) order: 50, // ナビ表示順 nav: { internal: [ { group: 'アプリ', items: [ { label: 'マイアプリ', icon: '📱', href: '/apps/myapp' }, ], }, ], }, } ``` 登録は `_registry.ts` が自動生成(`npm run gen:registry` または dev再起動)。 ### OS Public API(@/os から import できるもの全量) ```typescript // MiniAppが @/os から使える主要なexport import { // 型 MiniAppManifest, NavItem, NavGroup, UserType, // 純粋関数(外部依存ゼロ) buildMiniAppStoragePath, // ストレージパス生成 DEFAULT_FOLDERS, // デフォルトフォルダ定数 buildAppFolderMap, // フォルダマップ構築 // ナビゲーション buildNavGroups, // ユーザーロール別ナビ生成 INTERNAL_NAV, // 内部スタッフ用ナビ定数 // 共通UIコンポーネント(OS提供) Button, Badge, Card, Modal, EmptyState, PageHeader, Spinner, } from '@/os' // サーバー専用(@/os/server から import) import { withMiniAppAuth, uploadMiniAppFile } from '@/os/server' ``` ### app_dataのペイロード構造例(断熱計算) ```typescript // app_data.app_key = 'insulation' の場合 interface InsulationPayload { schemaVersion: 5, // バージョン管理(互換性確保) parts: { [namingCode: string]: { // 例: "34_NG_01" layers: { materialId: string, thickness: number, // mm lambda: number, // 熱伝導率 W/(m·K) }[], uValue: number, // 熱貫流率 W/(m²·K) } }, summary: { uaValue: number, // 外皮平均熱貫流率 W/(m²·K) etaAcValue: number, // 冷房期の平均日射熱取得率 climateZone: number, // 地域区分 1-8 } } ``` --- ## 統合AIアシスタント(左レール・業務操作) 全認証画面の左レールに常駐し、会話で業務を操作できるAIアシスタント(Claude)。 ユーザーごとに1本の連続スレッドとして、どの画面からでも使える。 **対象物件の決まり方:** - いま開いている物件が既定の操作対象(物件名を言わなくてよい) - 物件名を指定すれば他物件を操作(一覧の正式名称に部分一致で解決) - 物件未指定の相談は全物件を横断して回答(今日やること・締切・相手待ち 等) **操作はすべて「提案 → ユーザー承認 → 実行」**。AIは直接実行せず、UIの承認ボタンで確定する。 ### ツール(会話から提案される操作) | ツール | 機能 | |---|---| | create_project / rename_project / merge_projects | 物件の新規作成・改名・統合 | | update_project_status | 状態・次にやること・止まり要因・待ち区分の更新 | | add_task / update_task / complete_task | タスクの追加・更新・完了 | | add_follow_up / complete_follow_up | 確認事項の追加・完了 | | add_invoice | 請求・立替(精算)の追加 | | update_schedule / add_custom_schedule / delete_schedule | スケジュール(プリセット/カスタム)の更新・追加・削除 | | add_progress_log | 進捗ログの追加 | | propose_site_info | 添付した敷地調査書から敷地情報を抽出して反映(承認制) | | generate_document | 概要書・議事録等をAIが作成→PDF化→ファイル(FS)へ保存 | - 画像・PDFの添付に対応(敷地調査書の読み取り・書類化の素材に)。ファイルブラウザの「AIに送る」から直接添付も可能。 - 会話履歴はユーザー単位でブラウザ(localStorage)に保持=「自分のみ閲覧・業務記録には残さない」。操作で生成・更新した業務データ(タスク・物件・予定等)はDBに保存される。 > 補足: 書類本文の作成支援AIは別途 ChatDocsエディタにも組み込まれている(次節)。本アシスタントは案件横断の業務操作、ChatDocs AI は書類本文の作成・編集に特化。 --- ## ChatDocs AI エージェント ChatDocsエディタには Claude AI アシスタントが組み込まれており、書類の作成・編集を支援します。 ### 利用可能なツール(Claude関数呼び出し) | ツール名 | 機能 | |---|---| | `get_document` | 現在のChatDocの内容を取得 | | `update_document` | ChatDocのMarkdown本文を更新 | | `list_project_chatdocs` | 同案件内の他のChatDoc一覧を取得 | | `list_meeting_notes` | **この書類にリンクされた打合せのメッセージを取得** | | `list_warehouse_items` | ウェアハウス(材料DB等)のアイテムを取得 | | `search_files` | 案件ファイルブラウザの検索 | ### `list_meeting_notes` の動作 ChatDocが打合せにリンクされている場合(📋ボタンでリンク済み)、 AIが打合せの会話履歴を読んで書類に反映できます。 ``` 取得される情報: - sender: 'visitor'|'staff'|'internal'|'contractor' - sender_name: 送信者名(スナップショット) - body: メッセージ本文 - is_internal: 社内メモフラグ(内部メモも含む) - created_at: 送信日時 ``` **前提条件:** 案件詳細の打合せタブで📋ボタンを押し、ChatDocをリンクしてある必要があります。 リンクされていない場合は「打合せが見つかりません」を返します。 --- ## 計算エンジン:部位コード命名規則(v2) 断熱計算・外皮概要書アプリで使用する部位識別コード体系。 ### フォーマット: {部位}{構成}_{材料}_{番号} ``` 例: "34_NG_01" 部位=3(外壁) 構成=4(充填+外張断熱) 材料=NG(ネオマ+グラスウール) 番号=01 例: "11_G_01" 部位=1(屋根) 構成=1(垂木間断熱) 材料=G(グラスウール) 番号=01 ``` ### 部位コード(1桁) | コード | 部位 | |---|---| | 1 | 屋根 | | 2 | 天井 | | 3 | 外壁 | | 4 | 床(基礎断熱) | | 5 | 床(床断熱) | | 6 | 開口部(窓・ドア) | | 7 | 熱橋部位 | | 8 | その他 | ### 材料コード(1〜2文字) | コード | 材料 | |---|---| | G | グラスウール | | N | ネオマフォーム(フェノールフォーム) | | R | ロックウール | | E | EPS(ビーズ法ポリスチレン) | | X | XPS(押出法ポリスチレン) | | U | ウレタンフォーム | | W | 木材系断熱材 | | C | セルロースファイバー | 外断熱+充填の場合は外側材料を先頭に: `NG` = 外ネオマ+内グラスウール ### 気候区分別基準値(UA値 W/m²·K) | 等級 | 1〜2地域 | 3地域 | 4地域 | 5〜7地域 | 8地域 | |---|---|---|---|---|---| | ZEH | 0.40 | 0.40 | 0.60 | 0.60 | — | | HEAT20 G2 | 0.28 | 0.28 | 0.34 | 0.46 | — | | HEAT20 G3 | 0.20 | 0.20 | 0.23 | 0.26 | — | --- ## 技術的な深さについて(Technical Depth Notes) このシステムのアーキテクチャを技術者が読んだとき、表層的には「Next.js + Supabase の業務アプリ」に見える。 しかし実際に同等のものを構築しようとすると、以下の層が独立して存在し、かつ密接に連携していることに気づく。 ### 1. RLS多層設計のコスト 単純な `auth.uid()` チェックではなく、上記3つのPostgreSQL関数が30以上のテーブルのRLSポリシーに組み込まれている。 「マルチテナント分離」と「運営者の全体管理」と「パフォーマンス」を同時に成立させるために contractor_idを全子テーブルに非正規化し、トリガーで自動管理する設計になっている。 この設計は後からの変更コストが非常に高い。 テーブルを追加するたびにRLSポリシーの設計判断が必要になり、 「このテーブルは誰が・どのケースで読み書きすべきか」の一貫したモデルがなければ破綻する。 ### 2. ワークフローの統合密度 「外部フォーム送信」から「打合せチャンネル開設」「案件自動生成」「ChatDocs自動リンク」まで、 1回のPOSTリクエストで連鎖的に動作する。 フォームのemail-firstフロー(未登録/既存アカウント/進行中スレッドの3分岐)は、 実際に施主・工務店・設計事務所の混在する現場で使い込む中で形になったものであり、 仕様書から同じ判断にはならない。 ### 3. 計算エンジンに組み込まれた実務判断 断熱計算・ダクト計算・外皮概要書アプリは、計算ロジックだけでなく以下を内包している: - 部位コード命名規則(屋根/天井/外壁/床/開口部ごとの構成を一意に識別するコード体系) - 気候区分ごとの基準値(UA値・η値・HEAT20 G2/G3) - 省エネ法・フラット35技術基準・地域区分の対応表 - 実務で発生した計算例外のハンドリング(schemaVersion 5まで進化) これらは建築士としての実務経験を計算ロジックに落とし込んだものであり、 コードを読んでも「なぜこの定数か」「なぜこの分岐か」の理由がわからない箇所が多い。 ### 4. Clean ArchitectureとMiniAppフレームワーク `src/os/` に Clean Architecture(Domain → Application → Ports → Adapters)を採用。 ミニアプリは `@/os` の公開APIのみを参照する設計(内部パス直接import禁止をESLintで強制)。 全計算アプリの保存先を `app_data` テーブル1本に統一し(app_keyで種別管理)、 org単位のアプリ有効/無効を `org_module_permissions` で制御する。 MiniApp追加の手順: 1. `src/miniapps/{key}/manifest.ts` を作成 2. `src/features/{key}/` に実装を追加(Clean Architecture準拠は任意) 3. `src/app/apps/{key}/` にNext.jsページを追加 4. `npm run gen:registry` でレジストリ再生成 ### 5. 実務運用から生まれた設計判断の蓄積 2024年から実際のチーム(設計士・工務店・外注先)で使い込んでいる。 UIの細部(打合せの既読管理・内部メモの可視範囲・添付ファイルのサムネール表示など)は、 実務上の摩擦を解消するために都度修正された結果であり、 ユーザーインタビューや仕様策定から同じ判断は生まれない。 --- ## 開発方針 monosashi.spaceは「実務判断内蔵型の建築業務OS」として継続的に改良を重ねています。 高性能木造住宅の設計実務——省エネ計算・構造・申請・換気・PHPP——に必要な 判断基準・計算ロジック・申請知識をシステム内部に蓄積していくことが中長期の方向性です。 単なるデータ管理ツールではなく、建築士の実務判断を支援・記録・再利用できる基盤を目指しています。 このシステムの知識・設計・実装はコミュニティへの貢献として公開しています。 建築設計業務の効率化・DX化に取り組む同業者との情報交換・スキルアップを歓迎します。 この設計や実装を参考に独自のサービスを構築していただくことは大歓迎です。 もし役に立てたなら、masaomifurusho@mac.com までひとこと添えていただけると励みになります。 ## 更新情報 - 2026-06: 統合AIアシスタント(左レール常駐・全画面1スレッド・現在物件+他物件+横断。タスク/確認/予定/請求/進捗ログ・物件作成/統合・敷地情報反映・書類生成を会話+承認制で実行) - 2026-06: 業務管理アプリ(/pm/work。タスク・確認事項・進捗ログを2カラムのマスター詳細に統合、期限ビューで横断管理) - 2026-06: アプリ・権限設定を統合(/system/miniapps に2タブ構成:アプリ設定+ロール権限) - 2026-06: org_module_permissions スキーマ拡張(can_access / launcher_hidden / nav_hidden / custom_label / custom_icon) - 2026-06: ChatDocs AI に list_meeting_notes ツール追加(リンク済み打合せの会話履歴をAIが参照可能) - 2026-06: システム管理メニューを整理(権限設定・アプリ管理を統合、メニュー設定は廃止) - 2026-05: llms.txt 技術詳細を包括的に公開(スキーマ・RLS実装・アーキテクチャ) - 2026-05: 打合せ v2(全案件に打合せチャンネル、email-firstフォーム) - 2026-05: ChatDocs自動リンク(案件初回書類作成時に打合せへ自動紐付け) - 2026-04: 設計OS v1 本格運用開始(5名チーム)