Download Latest Version v0.4.0 -- Security fix + behavioral change_ manager hierarchy visibility source code.zip (1.3 MB)
Email in envelope

Get an email when there's a new version of openestate

Home / v0.1.2
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-07-31 6.2 kB
v0.1.2 -- 2FA lockout and fresh-install fixes source code.tar.gz 2026-07-31 734.9 kB
v0.1.2 -- 2FA lockout and fresh-install fixes source code.zip 2026-07-31 1.0 MB
Totals: 3 Items   1.8 MB 0

Upgrade from v0.1.1 as soon as practical. Two bugs in that release are severe enough on their own to justify this one:

  • Any account with 2FA enabled was permanently locked out of login, with no way back in — not even via a recovery code. The login response's 2FA-pending branch never set the CSRF cookie totp/verify requires, so every totp/verify call (including recovery-code attempts) 403'd with "CSRF token mismatch," unconditionally, for every account. If you're running v0.1.1 and have 2FA enabled on any staff account, upgrade before enrolling further users — those accounts have been unable to log in since enabling it, and existing locked-out accounts will need a staff admin to disable 2FA for them (POST /auth/totp/disable, or directly via the database) after upgrading, since the fix doesn't retroactively unlock an in-progress login attempt.
  • A genuinely fresh install failed immediately on the exact command the docs tell you to run. Every deploy/native/*.sh script an admin runs directly was git-tracked without the executable bit; sudo ./install-native.sh right after git clone died at "Permission denied" trying to exec setup-database.sh. Anyone who successfully installed v0.1.1 did so from a checkout that had picked up a local, uncommitted chmod +x somewhere along the way (e.g. copying files instead of cloning) — a literal fresh clone was never viable.

Fixed

  • The 2FA lockout above also had a second, independent bug: the code-verification schema only accepted 6 digits, rejecting every recovery code's XXXXX-XXXXX format before it reached the already-correct recovery-code check. Both fixed together; verified live end-to-end (enroll, login-requires-code, wrong code rejected, recovery code works once and is rejected on reuse).
  • Company config had no way to set companyGstin/gstStateCode after the initial seed, despite the frozen booking service already reading gstStateCode to decide CGST+SGST vs IGST. Added, with GSTIN format validation (checksum digit deferred — see docs/todo.md) and a Company Config UI section.
  • Health endpoint's version field was hardcoded 0.1.0 in every real deployment (npm_package_version is only set by pnpm run, never by systemd's/Docker's direct node dist/main.js). Now reads package.json directly.
  • 18 of 19 generic master types (unit types, inquiry sources, charge types, etc.) 500'd on any create/update call that included a description — createMasterSchema's optional description field is only backed by a real column on PaymentPlanTemplate; the shared factory blindly spread the whole dto into Prisma's data. Fixed once, at the root, in the factory.
  • DocumentType, InterestRule, and TransferFeeRule couldn't be created via the API at all — each has its own required, non-nullable columns (entityType; rateType/ratePercent/frequency; feeType) that the generic master schema never had, so every attempt 500'd on a Prisma "Argument missing" error instead of failing validation cleanly. The shared factory now supports a per-model extraFields schema extension.
  • LetterTemplate had no working create path at all — zero templates could ever exist, blocking demand/allotment/reminder letter generation entirely. It was routed through the generic master factory (whose schema has no subject/entityType/body) instead of a dedicated module; given one, mirroring the existing SmsTemplateModule precedent, with merge-field validation at save time.
  • Duplicate master names (any of the 18+ shared-factory types) returned a raw 500 instead of a clean "already exists" 400 — nothing in this codebase had ever caught Prisma's P2002 unique-constraint error for these dynamically-keyed services (unlike RolesService/UsersService, which pre-check via findFirst). Mapped once, in the factory.
  • install-native.sh/upgrade-native.sh's database migration step failed on any host where the git checkout lives under a directory tree the postgres OS user can't traverse (e.g. GitHub Actions runners: /home/runner is mode 0750) — Prisma 6.19+ auto-discovers a prisma.config.* file in the current working directory before running any command, and that lookup's lstat() fails EACCES (not ENOENT) in that case, which Prisma treats as a hard failure rather than "no config file, proceed." run_as_superuser() now runs from the already-world-traversable release directory instead of the checkout.
  • install-native.sh's final systemctl reload nginx failed outright ("nginx.service is not active, cannot reload") on any host where apt installed nginx without starting it — the script only ever checked that the nginx binary was present, never that the service was running. Now enables and reload-or-restarts it, correct whether nginx was already running or not.
  • CustomFieldDefinition.defaultValue — accepted by the create/update schema since it was written, but no backing column ever existed, so any real caller sending it 500'd. Added the missing column.
  • POST /users never returned the phone it had just saved — a select allowlist copy/paste gap (present in update(), missing from create()) left an admin with no way to confirm the phone number was stored.

Everything above except the two headline bugs was found by a full production-readiness pass and a new through-the-wire creation test for every master type and admin-creatable entity (users, roles, custom fields) — the existing suite seeded rows directly, which is exactly why these bugs survived to a tagged release. Also added: real-HTTP creation coverage for all 22 master types plus users/roles/custom fields, and a native-install CI job that runs the full native install on a real ubuntu-latest runner on every push. That CI job is not yet green — a separate, CI-runner-specific issue (the deployed app crash-looping with SIGSEGV, isolated to argon2's native module, confirmed not to reproduce on a real server) is still open and tracked in CLAUDE.md; it does not affect real installs, only that one job's own coverage.

Source: README.md, updated 2026-07-31