system

Villa Owner Trust System

The Villa Owner Trust System is a product I am building for villa management companies to make owner-facing reporting traceable to the records and evidence behind it.

The first implementation comes from a real Bali villa management project. The client had spent years on the owner side of villa construction and operations and was preparing to start a management company of his own. An owner portal was already part of what he considered important: the portal provided by his existing management company had helped influence his decision to work with them.

Studying that portal made the opportunity clearer. The useful part was not simply having a dashboard. Owners could see bookings, financial information, reports, and some expense proof. But the underlying records also exposed problems: booking data mixed different concepts, proof was inconsistent, and several reporting views could present financial information without making its source equally clear.

That shifted the problem from building a better owner portal to building a system around a stronger rule:

An important owner-facing claim should be traceable
to a structured record, evidence, or an explicit exception.

The owner and admin portals are interfaces into that system. The trust model underneath them is the product.

System boundary

The system is designed as an owner-facing trust and reporting layer for a villa management company.

It owns the structured records, access rules, evidence relationships, reporting rules, and finalized statements needed to explain what happened with an owner’s property and money.

It is deliberately not intended to become the operational system for every part of villa management.

Inside the system Outside the current boundary
Property and owner access Full property management system
Booking records Channel management
Calendar events Guest messaging
Income and expenses Full accounting
Maintenance records Workforce management
Proof and evidence Payment processing
Owner payouts Bank reconciliation
Monthly statements Dynamic pricing
Owner-safe exports Real-time OTA or PMS synchronization
Change history Self-service SaaS administration

External systems can provide inputs, but they do not automatically become authoritative.

For the current MVP, records become part of the owner-facing source of truth after they have been entered or imported into the system, reviewed, and accepted there.

The trust model

The system is record-first rather than dashboard-first.

Its main relationships can be viewed roughly as:

Management company

        ├── properties
        │      │
        │      ├── owner access
        │      ├── bookings
        │      ├── calendar events
        │      ├── income
        │      ├── expenses ─────────── proof
        │      ├── maintenance ──────── proof
        │      ├── payouts ──────────── proof
        │      └── statements

        └── users and access rules

The important part is not the number of record types. It is the relationship between them.

A maintenance item that creates an owner-chargeable cost should connect to the corresponding expense. An owner-visible expense should carry a clear proof state. A payout should connect to the reporting period and statement it belongs to. A finalized statement should preserve the records and values that were actually reported.

The dashboard and owner overview then summarize those records rather than becoming an independent source of financial truth.

Admin and owner surfaces

The application has two main protected surfaces with different responsibilities.

Admin portal
    creates and reviews trusted records

Owner portal
    explains trusted records

The admin side follows the management workflow. It is where properties and owners are configured, bookings and expenses are entered, maintenance is recorded, proof is attached, payouts are recorded, statements are reviewed, and unresolved trust issues are surfaced.

The owner side is read-only in the current MVP. It is organized around the owner’s property and reporting period rather than the management company’s internal workflow.

Its job is to answer practical questions:

What happened?
What did the villa earn?
What was spent?
What maintenance took place?
Where is the proof?
What was paid to me?
How was the monthly result calculated?

Those two interfaces use the same underlying business records but expose them through different authorization and visibility rules.

Source records and evidence

Proof is part of the domain model rather than a generic file library.

A receipt belongs to an expense. A maintenance invoice or completion photo belongs to the maintenance work and its related cost. Payment evidence belongs to a payout. A finalized statement can preserve its own PDF snapshot.

The system therefore distinguishes between two separate questions:

Does supporting evidence exist?

Can this owner see that evidence?

Proof existence and proof visibility are modeled separately.

Owner-chargeable expenses are expected to have supporting proof or an explicit state explaining why the proof is missing, pending, not required, or managed internally.

That avoids one of the weaknesses found in the existing portal: an empty file field should not leave an owner guessing whether evidence is absent, expected later, or intentionally unavailable.

Live records and finalized statements

Current operational data and finalized reporting have different jobs.

Bookings, expenses, maintenance, and payout information can change while a reporting period is open. These records provide live visibility into what is currently happening.

A finalized monthly statement has a stronger requirement:

It must preserve what was officially reported.

A finalized statement is therefore not just a live query rendered as a PDF.

The statement model preserves reporting-period data through statement records and statement lines, together with the relevant source-record relationships, totals, proof summary, and revision information.

If a source record changes after finalization, the old statement must not silently change with it. A correction requires revision rather than rewriting the historical reporting state.

The PDF is an output of that statement. It is not the statement itself.

Identity and business access

Authentication and business authorization are separate layers.

Better Auth establishes the login identity and session. The application owns the business relationships that determine what that identity can actually access.

Better Auth

    └── user + session


application access

    ├── management company
    ├── role
    ├── owner profile links
    ├── property access
    ├── record visibility
    ├── proof visibility
    ├── statement access
    └── export access

That separation matters because a login account and the business entity it represents are not always the same thing.

An owner profile can exist independently of a login user. Property access can then be assigned to the owner profile, while authentication remains concerned with who is signed in.

The request-level session context implemented in the application provides the base information that more specific property, record, proof, statement, and export authorization rules can build on.

Technical architecture

The MVP is being built as one server-rendered Astro application rather than separate frontend and backend applications.

Astro

    ├── Admin portal
    ├── Owner portal
    ├── Actions and endpoints
    └── Domain/application logic

PostgreSQL
    └── structured trust records

Drizzle
    └── schema, migrations, and typed database access

Better Auth
    └── identity and sessions

Cloudflare R2
    └── private proof and document objects

Netlify
    └── application runtime and deployment

PostgreSQL holds the durable relational business model. File binaries such as receipts, invoices, photos, and statement PDFs live in object storage, with their metadata and access rules kept in the database.

Private files are not meant to be exposed through unrestricted public object URLs. Access to records, exports, proof, and statements is checked by the application.

The architectural rule behind those choices is:

The trust model is the product.
The stack is delivery infrastructure.

Business rules such as evidence requirements, owner visibility, statement integrity, authorization, and export behavior therefore belong in the application domain rather than being defined by a hosting, authentication, or storage vendor.

Current scope

The first version is intentionally manual-first.

Bookings and expenses can be entered directly, with simple imports considered where they save meaningful administrative work. Proof is uploaded into the system and attached to the record it supports. Owners remain read-only.

Deep OTA, PMS, accounting, banking, OCR, and reconciliation integrations are deferred until the core trust workflow has been proven with real use.

The first implementation is also client-led rather than self-service SaaS. It is being built around the needs of a real management company while keeping the underlying trust model reusable beyond that first client.

Not every part of the planned MVP is implemented yet. The system architecture and product rules establish the boundary being built toward; individual Lab documents record concrete implementations as those parts become real.

software

Sharing Better Auth Configuration Between Astro Runtime and CLI

How Better Auth configuration is shared between the Astro runtime and CLI schema generation without sharing their environment-specific dependencies.

Application-Aware Session Context in Astro

How Better Auth sessions are resolved into app-owned access context with Drizzle and exposed through Astro middleware and locals.