Data Architecture

国ごとの違いは条件分岐ではなく
データに持たせます

韓国と日本をひとつのシステムで運営するための構造です。物件プロファイルがルールを持ち、料金は行として立ち、台帳の上に分析層が別に立ちます。

Principle

コードに「日本なら…」の分岐を置きません

国ごとの違いは条件分岐ではなく物件プロファイルに持たせます。物件ごとに下の9つを指定すれば、ルールがついてきます。だから韓国と日本がひとつのシステム・ひとつの台帳で回ります。

プロファイル韓国日本
請求サイクル暦月サイクル — 入居日を基準に翌月同日の前日まで
長期/短期の判定契約月数サイクル6個以上で長期。最初の契約時に1回だけ判定し、更新しても再判定しません
日割りの分母その月の実日数長期=実日数/短期の最終残余=28日固定
請求のタイミング毎月の支払期限日入居月=当月日割+翌月分を同時/以降は前月1日/3サイクル未満は一括
更新手数料なし(協議)更新後賃料の10%・長期のみ(免除交渉は可能)
法定届出賃貸借届出の対象該当なし — 韓国の制度です。日本の契約にはこのステップが生まれません
入居可能時点整備リードタイム D+n退去+7日
新規募集の開始満了 D-60退去予定日の1ヶ月前
中途解約の違約金なし長期=2サイクルの通知/それ以内の退去は2サイクル分(その期間の賃料は二重請求しません)・短期=残期間全額

サイクルが最大の違いです。 暦月とは別の軸なので、画面ではなく計算エンジンが分かれます。物件プロファイルを見ずに実装すると、二国のうち必ずどちらかが間違います。

Hierarchy

マスター階層

「拠点」と呼んでいたものは物件のブランド名であり、その上に法人・エリア・投資家・建物の階層が抜けていました。

法人 Entity通貨・税制・T番号・勘定科目がここから継承されます
Areaエリア
Investors投資家(オーナー)
Property 物件物件・建物・ブランド名 + プロファイル9種
Unit 号室料金・原価・光熱費・ステータス
法人が新しい軸です。 株式会社ホームズカンパニージャパンと韓国法人は別法人であり、 通貨・税制・適格請求書発行事業者登録番号(T番号)・勘定科目が法人から継承されます。 日本=JPY・消費税2区分(0%・10%)・T番号(2023年のインボイス制度導入以降、請求書に必須)/韓国=KRW・付加価値税10%。 あとから入れると過去データに遡及できないため、いま入れています。

Tables

テーブル関係

マスター・台帳・イベントを区別します。台帳は事実を積み、イベントはその事実がいつ・なぜ変わったかを残します。

法人 › 物件 › 号室通貨と税制が法人から継承され、物件がプロファイル9種を持ち、号室が料金・原価・光熱費・ステータスを持ちます。
顧客 › 問い合わせ › 契約リード1:0..1契約。契約には賃借人(1:1)と送付先(1:N)が付きます — 契約者と受け取る方が異なるケースが実際にあります。
イベント3種ステータス履歴(トラック・転換率の根拠、無効フラグあり)・会話ログ(チャネルが分かれてもスレッドはひとつ)・内見(同じ方が二度来れば2行)。
号室価格履歴契約スナップショットの根拠。料金表を変えても、すでに締結した契約は変わりません。
仲介会社流入経路の下位値ではなく独立マスター+FK。表記が揺れても集計が割れません。
収支項目 › 取引勘定科目をデータとして定義します。新しい項目が必要なら、開発ではなく行を追加します。

v5

料金は号室の「列」ではなく「行」です

期間区分は物件ごとに異なり、数も違います — 韓国2区分・日本3区分。列にすると区分が増えるたびに列を追加することになり、物件ごとに異なる数を持てません。

マスター物件プロファイル9種
1 : N期間区分区分名・最小/最大・適用料金・敷金ルール・支払方式
1 : N号室料金号室×区分・金額・坪単価・適用開始日/終了日
スナップショット契約契約時点の料金で固定
区分期間敷金支払
超短期3ヶ月以下なし一括(全額前払い)
短期3ヶ月超〜6ヶ月未満なし3ヶ月分前払い後に月払い
長期6ヶ月以上賃料1ヶ月分敷金+賃料前払い後に月払い

日本基準の例です。区分の境界は「最小以上〜最大未満」ひとつに固定しています — 含むかどうかを区分ごとに決めさせると、「6ヶ月」がどこに属するのか誰も確信できなくなります。

⚠ 号室テーブルに料金の列をつくらないでください。 つくると物件が増えるたびにマイグレーションが必要になります。 日本は価格が2段なのに支払方式が3段で、列方式では3つ目の境界を置く場所がありませんでした。

Ledger

台帳スキーマ — 12ドメイン

PostgreSQLのマイグレーション29件で立っています。運営システムが使うテーブルと分析が読むテーブルが、同じ台帳を見ます。

assetアセット物件・号室・運営契約・物件別タイムゾーン
catalog商品商品・募集・価格・単価例外
crm需要問い合わせ・リード・内見・入居申込・仲介会社
leasing契約契約・仲介手数料ポリシー・法定届出
inventory在庫稼働・仮押さえ・ブロック・稼働差異
billing精算請求・入金・敷金・申込金
facility設備整備チケット・法定点検・入退去点検
party主体顧客・組織・住所
metrics指標指標定義のバージョン(不変)
sharing共有外部共有契約・項目定義
securityセキュリティアクセス・監査
platform共通共通型・通貨コード

Policies

台帳を台帳たらしめる6つ

スキーマだけでは台帳になりません。以下はコードではなくポリシー文書として固定されています。

イベント不変現在の状態とappend-onlyのイベントが並存します。イベント行は修正・削除せず、集約シーケンスで順序を保証します。
稼働の記録根拠稼働行ごとにOBSERVED(実測)とDERIVED_FROM_CONTRACT(契約由来)を区別します。稼働率は契約ではなく実際の稼働日から出ます。
個人情報の封筒暗号化顧客の識別情報は封筒暗号化で保存し、検索はblind indexで行います。原文をインデックスに露出させません。
保存とパーティショニングイベントテーブルはパーティション+保存ポリシーを持ち、変更の伝播はoutbox CDCで出ます。
指標定義の不変稼働率・平均賃料の定義は承認されたバージョンで固定されます。変えるには新しいバージョンをつくる必要があり、過去の数字はそのまま再現されます。
多通貨・物件別タイムゾーン金額は通貨コードを伴って持ち回り、タイムゾーンは物件ごとにIANA値で検証されます。通貨が違えば合計を合算しません。

通貨は法人から継承されます。 物件と取引がそれぞれ決めると必ず食い違います。画面の合計も ¥55,196,240 · 79,909万ウォンのように分けて出します — 換算してひとつの行にすると、その為替レートがそのまま根拠のない数字になります。

Analytics

台帳の上に分析層が別に立ちます

指標を画面で計算しません。系譜があり、各段階にデータテストが掛かります。

台帳PostgreSQLasset・crm・leasing・inventory・billing
stagingstg_*アセット・契約・在庫・精算・宿泊・指標定義
corefct_unit_day
fct_lease_term_day
号室1日=1行・契約期間1日=1行
martmart_occupancy_daily
mart_amr_monthly
稼働率・平均賃料

データテスト8種 — 稼働率の範囲検証・ブロック号室の稼働禁止・平均賃料の順序・タイムゾーンの妥当性ほか。