tpt-tenant-verify-nz

Go

Tenant reference verification platform for New Zealand. Tenants build government-verified application packs using RealMe identity and share them with landlords. Go + Next.js 14 + PostgreSQL. Supports group applications, referee consent flows, and LINZ address autocomplete.

0 stars0 forks0 watchersMIT License
golangnatsnew-zealandnextjspostgresqlrealmerental-applicationsaml2tailwindcsstenant-verification

Languages

Go64.6%TypeScript33.1%PLpgSQL1.7%Makefile0.2%JavaScript0.2%Dockerfile0.1%CSS0.0%
README

tpt-tenant-verify-nz

Tenant reference verification and rental application system for the New Zealand market. Landlords create rental listings; tenants build shareable verified packs using RealMe identity and submit them to listings directly or as a group.

CI License: MIT

Features

  • RealMe identity — SAML 2.0 verified identity (MTS / ITE / Production)
  • Application packs — Tenants compile a reference pack (personal info, address, employment, references) and share it via a unique token link
  • Reference consent — Each referee receives a consent confirmation link before their details are shared
  • Pack expiry — Packs expire after a configurable number of days (default 60); background sweep keeps data clean
  • View tracking — Privacy-safe view count (SHA-256 hash of IP + User-Agent, no PII stored)
  • Listings browse — Public listing board; tenants can apply directly with their pack
  • Group applications — Multiple tenants (flatmates, couple) can link their packs into a group and apply together
  • Address autocomplete — LINZ Data Service integration for NZ address search (optional, degrades gracefully)
  • NATS events — Pack, application, and group lifecycle events published to JetStream (optional, no-op if unconfigured)

Architecture

┌─────────────────────────────────────────────────────┐
│                  Next.js 14 Frontend                 │
│         (TypeScript, Tailwind CSS, App Router)       │
└──────────────────┬──────────────────────────────────┘
                   │ /api/* → :8080
┌──────────────────▼──────────────────────────────────┐
│                 Go 1.23 Backend (Chi)                │
│  ┌────────────┐  ┌─────────────┐  ┌──────────────┐  │
│  │  Handlers  │  │  Services   │  │  Repository  │  │
│  └─────┬──────┘  └──────┬──────┘  └──────┬───────┘  │
│        │                │                │          │
│        ▼                ▼                ▼          │
│  RealMe SAML       Pack / Group       PostgreSQL 16  │
│  (SAML 2.0)        / Listing svc      (pgx v5)      │
└──────────────────────┬──────────────────────────────┘
                       │
          ┌────────────┴──────────┐
          ▼                       ▼
    NATS JetStream           LINZ Data Service
    (optional events)        (address autocomplete)

Tech Stack

| Layer | Technology | |---|---| | Backend | Go 1.23, Chi v5, pgx v5 | | Frontend | Next.js 14, TypeScript, Tailwind CSS 3 | | Database | PostgreSQL 16 | | Identity | RealMe SAML 2.0 (DIA) | | Events | NATS 2.10 JetStream (optional) | | Address | LINZ Data Service API (optional) |

Quick Start

Prerequisites

  • Go 1.23+
  • Node.js 20+ and npm
  • Docker + Docker Compose
  • RealMe certificates (dev uses the bundled mock IdP — no real certs needed)

1. Start infrastructure

make dev
# starts PostgreSQL 16, Redis 7, NATS 2.10

2. Apply database migrations

psql "postgres://tptnz:tptnz_dev@localhost:5432/tptnz?sslmode=disable" \
  -f migrations/001_init.sql \
  -f migrations/002_features.sql

3. Generate a dev certificate

mkdir -p certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout certs/sp.key -out certs/sp.crt \
  -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost"

4. Start the mock RealMe IdP

cd packages/realme-go
go run ./cmd/mock-idp -addr :8081

5. Run the backend

go run ./cmd/server
# → http://localhost:8080

6. Run the frontend

cd web
npm install
npm run dev
# → http://localhost:3000  (proxies /api/* to :8080)

All-in-one (Docker Compose)

cp .env.example .env   # fill in REALME_* paths
docker compose up

Environment Variables

| Variable | Default | Description | |---|---|---| | LISTEN_ADDR | :8080 | Server listen address | | DATABASE_URL | postgres://tptnz:tptnz_dev@localhost:5432/tptnz?sslmode=disable | PostgreSQL connection string | | NATS_URL | (empty — events disabled) | NATS server URL e.g. nats://localhost:4222 | | LINZ_API_KEY | (empty — autocomplete disabled) | LINZ Data Service API key | | PACK_EXPIRY_DAYS | 60 | Days before an application pack expires | | REALME_ENVIRONMENT | mts | mts, ite, or production | | REALME_CERT_FILE | certs/sp.crt | Path to SP certificate | | REALME_KEY_FILE | certs/sp.key | Path to SP private key | | REALME_ENTITY_ID | http://localhost:8080/auth/metadata | SAML entity ID | | REALME_ACS_URL | http://localhost:8080/auth/callback | SAML assertion consumer URL | | REALME_IDP_METADATA_FILE | (empty) | Local IdP metadata XML file | | REALME_IDP_METADATA_URL | http://localhost:8081/metadata | IdP metadata URL (mock default) | | COOKIE_DOMAIN | (empty) | Session cookie domain |

API Reference

Public (no authentication)

| Method | Path | Description | |---|---|---| | GET | /health | Health check | | GET | /listings/active | Browse active listings | | GET | /address/suggest?q=... | NZ address autocomplete (LINZ) | | GET | /consent/{token} | Referee consent confirmation page |

Authentication

| Method | Path | Description | |---|---|---| | GET | /auth/login | Initiate RealMe SAML login | | GET | /auth/callback | RealMe SAML ACS callback | | GET | /auth/logout | Clear session | | GET | /auth/metadata | SAML SP metadata XML | | GET | /auth/status | Current session status |

Tenant (requires RealMe Verified session)

| Method | Path | Description | |---|---|---| | POST | /application-packs | Create an application pack | | GET | /packs/{token} | View a pack by shareable token | | GET | /my-packs | List your packs | | POST | /listings/{id}/applications | Apply to a listing with a pack |

Pack Groups

| Method | Path | Description | |---|---|---| | POST | /pack-groups | Create a group | | GET | /pack-groups/{id} | Get group details and members | | POST | /pack-groups/join/{token} | Join a group via invite token | | POST | /pack-groups/{id}/invite | Regenerate invite token | | POST | /pack-groups/{id}/apply | Submit group application to a listing |

Landlord (requires RealMe Verified session)

| Method | Path | Description | |---|---|---| | POST | /listings | Create a rental listing | | GET | /listings | List your properties | | GET | /listings/{id} | Get listing details | | GET | /listings/{id}/applications | View applications for a listing | | PATCH | /listings/{id}/applications/{appId} | Approve or reject an application |

RealMe Setup

MTS — Local Development (no registration required)

# Start the bundled mock IdP
cd packages/realme-go && go run ./cmd/mock-idp -addr :8081

# Backend picks it up automatically via the default REALME_IDP_METADATA_URL

ITE / Production

  1. Register a Service Provider at the RealMe Developer Portal
  2. Submit your SP metadata XML (GET /auth/metadata) to DIA
  3. DIA provides IdP metadata URL and environment-specific certificate requirements
  4. Set REALME_ENVIRONMENT=ite (or production) and point REALME_IDP_METADATA_URL to the DIA-provided URL

Database Migrations

Migrations are plain SQL files in migrations/. Apply in order:

# 001 — core schema (packs, references, listings, applications)
psql "$DATABASE_URL" -f migrations/001_init.sql

# 002 — feature additions (expiry, view tracking, consent tokens, pack groups)
psql "$DATABASE_URL" -f migrations/002_features.sql

Using Atlas:

make migrate DATABASE_URL="$DATABASE_URL"

Testing

# Backend
go test ./...
go test -race ./...

# Frontend (type-check + build)
cd web && npm run build

Repository Layout

.
├── cmd/server/          — main entrypoint
├── internal/
│   ├── events/          — NATS publisher
│   ├── handlers/        — HTTP handlers (+ tests)
│   ├── models/          — domain types
│   ├── repository/      — PostgreSQL queries
│   └── services/        — business logic
├── migrations/          — SQL migration files
├── packages/
│   ├── nz-common/       — shared NZ utilities (LINZ, MBIE, money, health)
│   └── realme-go/       — RealMe SAML 2.0 provider library
├── scripts/db/          — Docker init SQL
└── web/                 — Next.js 14 frontend
    ├── app/             — App Router pages
    └── components/      — shared React components

Contributing

See CONTRIBUTING.md.

Security

See SECURITY.md for responsible disclosure information.

License

MIT — © 2026 TPT NZ Public Contributors