Spacehub v2 — Feature & Implementation Plan

Greenfield TypeScript rewrite of Spacehub23 (XAF Blazor + XPO + SQL Server). Stack: Turborepo + Next.js 15 + Hono + Drizzle + Postgres 16 + Flutter mobile. Strategy: strangler fig per domain, aggressive simplification.

Phase 0 scaffold: shipped Library research: in progress Domain ports: not started
Current state. Monorepo scaffold pushed to github.com/spacehub-mn/spacehub26. API + web + Postgres + Redis up locally. Smoke verified: GET /v2/health returns {"status":"ok","db":"up"}.
Audit pass complete (May 26, 2026). 4 adversarial research agents stress-tested every library pick. 5 picks overturned: Next.js→TanStack Start, pg-boss+BullMQ→graphile-worker, @react-pdf/renderer→Playwright PDF, Hetzner Helsinki→Singapore region, @google/generative-ai→@google/genai (deprecated). Full change-log: Audit findings. Decision log updated.

How to read this plan

Each domain page follows the same shape: Scope (what's in / out) → Library picks (with rationale) → Data model (Drizzle sketch) → API surface (Hono routes) → Build steps (numbered, copy-pasteable) → Open questions (need your call before building).

Read the pages in the order shown in the sidebar. Architecture first, then Phases, then domain pages.

Feature map

Auth & sessions

Email/password + JWT for mobile, httpOnly cookie for web. SMS OTP for tenants. Refresh-token rotation.

Phase 1

Identity & ACL

User / Profile / PropertyOwner hierarchy. Postgres RLS replaces XAF custom operators.

Phase 1

Property & rooms

Property → Floor → Room hierarchy. Floor plans, pricing, owner assignment.

Phase 1

Contracts

Single Contract entity with payment schedule (jsonb where possible). Explicit transition functions.

Phase 2

Billing & invoices

Unified Invoice (kind: rent/utility/sale/discount). BigInt Money. Kills decimal-equality bug.

Phase 3

Payments

QPay + SocialPay clients. Webhook handlers with signature verification.

Phase 4

Bank reconciliation

Khan / Golomt / TDB statement import. Indexed fuzzy match — fixes O(N·M) leak.

Phase 4

eBarimt 3.0

Sale → outbox → BullMQ worker → eBarimt REST. Replaces fire-and-forget post-save hook.

Phase 4

SMS & push

131344 SMS gateway client, Firebase Admin (FCM v1), per-device token registry.

Phase 5

Reports

React-PDF or Puppeteer for invoice/statement PDFs. Replaces XtraReport DB blobs.

Phase 5

Chatbot

Gemini 2.5 streaming via Vercel AI SDK. Port 10 function-calling tools. PO whitelist → config.

Phase 5

File storage

S3-compatible (R2 / MinIO). Presigned uploads. sharp thumbnails.

Phase 5

Background jobs

BullMQ + Redis. Replaces external HTTP cron triggers. Daily contract-expiry SMS, bill generation, outbox drain.

Platform

OpenAPI & Flutter

Zod → OpenAPI (auto). Flutter regen via swagger_parser. Single API for web + mobile.

Platform

Observability

Pino + Sentry + OpenTelemetry. Request-id correlation. Drizzle query traces.

Platform

DevOps & hosting

Hetzner + Coolify (recommended). GitHub Actions + Turborepo remote cache. Docker multi-stage.

Platform

Headline simplifications vs Spacehub23

v1 (XAF)v2 (TS)Win
321 BO files, composite keys, 2-tier status enums~70 tables, UUID PKs, single status enum + transition fnKills KNOWN_ISSUES #3 desync
52 fat XAF ViewControllers (popup choreography)Hono route handlers + Next.js server components~70% LOC drop in controller layer
XAF PermissionPolicy + custom operators (implicit)Postgres RLS policies (DB-enforced, explicit)ACL bugs structurally impossible
Decimal == / <= payment comparisonBigInt Money + compare()Kills KNOWN_ISSUES #2 (0.25₮ underpaid)
Fire-and-forget post-save hooksOutbox table + BullMQ workerRetryable, observable, no race
External HTTP cron (cron-job.org)BullMQ repeatable jobs in-processNo external dep, idempotent by ID
XtraReport blobs in DB (ReportDataV2)React-PDF templates in repo (code-reviewed)Templates versioned, diffable
2 enum systems per status entity1 enum + explicit transitionTo()Kills desync class of bugs
85 enum files (many high-cardinality)~25 enums + reference tables for Bank/Region/etc.Add new bank without code change
3 .NET services (Blazor, ApiV2, Automation)3 TS apps (web, api, workers) — same model + langShared types, single deploy story

Open architectural questions (you decide on return)

Each is summarized on the linked page; pick before building the feature slice.

  1. Auth lib: better-auth vs Auth.js vs roll-our-own with jose + argon2.
  2. RLS bridging: SET LOCAL in transaction-per-request vs JWT-claim pattern (Supabase style).
  3. Money type: keep custom 50-LOC BigInt impl vs adopt dinero.js v2.
  4. Job queue: BullMQ (Redis) vs pg-boss (Postgres-only — drops a moving part).
  5. PDF lib: React-PDF (declarative) vs Puppeteer (HTML fidelity).
  6. File storage: Cloudflare R2 (cheap egress) vs self-host MinIO on the existing VPS.
  7. Hosting: Vercel (web) + Hetzner+Coolify (api) vs all-in-one on Hetzner.
  8. Migration: dual-write only vs Debezium CDC SQL Server ↔ Postgres.