Skip to content

fix(dev): make the local tenant-site fallback self-explanatory - #8

Merged
Asapteejo merged 3 commits into
mainfrom
fix/local-tenant-dx
Sep 17, 2026
Merged

Asapteejo merged 3 commits into
mainfrom
fix/local-tenant-dx

Conversation

@Asapteejo

Copy link
Copy Markdown
Owner

The report

npm run dev + http://localhost:3000 renders the platform marketing page instead of a tenant site, logging:

"fallbackSlug":"acme-realty","resolvedCompanyId":null,
"fallbackToPlatform":true,"fallbackReason":"no-tenant-host-match"

The natural reading is "my local database has no seeded company". That reading is wrong, and the README actively encouraged it.

What is actually happening

Verified against the local database before changing anything:

Check Result
Database reachable Yes — estateos_dev at localhost:5432
Schema applied Yes — prisma migrate status: up to date, 51/51
acme-realty company exists Yes — ?devTenant=acme-realty and acme-realty.localhost:3000 both render it
/api/readyz configured: true, migrations.missing: []

The cause is in resolveTenantContext:

const resolvedCompany = area === "marketing"
  ? hintedCompany                                          // host or ?devTenant ONLY
  : selectAuthenticatedCompany({ ..., fallbackCompany });   // DEFAULT_COMPANY_SLUG lives here

DEFAULT_COMPANY_SLUG is deliberately not consulted for public pages, so a fallback can never serve one tenant's public site on another host in production. localhost therefore can never show a tenant site regardless of seeding — the log even shows the fallback slug being resolved and then discarded.

No production rule is changed here. Only the explanation is.

Changes

  1. Actionable dev log — on fallback, development now logs the cause, both supported entry points, and the company slugs actually present, so an unseeded database is distinguishable from correct host-based behavior:

    No tenant site matched host "localhost:3000", so the platform marketing page is being rendered. Public pages resolve the tenant from the host; DEFAULT_COMPANY_SLUG applies to signed-in areas only… Companies in this database: acme-realty. To open a tenant site locally use http://localhost:3000/?devTenant=acme-realty (needs DEV_ACCESS_MODE=true) or http://acme-realty.localhost:3000.

    Once per host per process, never in production. When no companies exist it says to run npm run db:seed.

  2. README — corrected the false claim that public pages use DEFAULT_COMPANY_SLUG in development (the line that caused this), and added "Opening A Tenant Site Locally" with both workflows and the create/migrate/seed commands.

  3. CI — the E2E server now runs as NODE_ENV=development rather than test. Next skips .env.local under NODE_ENV=test, so running CI's own command locally started a server with no database and reported every migration missing. That false failure cost real debugging time in this session; development keeps the dev-session bypass available on a production build and loads .env.local locally, while CI supplies its database through the job env either way.

Verification

Command Result
npm run check 535 tests, typecheck, lint, build — green
npm run migrations:check manifest up to date (51 migrations)
E2E suite 63 passed, 3.0m

🤖 Generated with Claude Code

Asapteejo and others added 3 commits September 17, 2026 10:05
Public pages resolve the tenant from the host, and DEFAULT_COMPANY_SLUG is
applied to signed-in areas only, so plain localhost always falls back to the
platform marketing page. The existing log said "no-tenant-host-match" without
saying what to do about it, and the natural reading — "my database is not
seeded" — is usually wrong.

Development now logs the cause, both supported local entry points, and the
company slugs actually present in the database, so a genuinely unseeded
database is distinguishable from correct host-based behavior. Once per host
per process, never in production. The resolution rule itself is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t access

The README stated that tenant public pages can use DEFAULT_COMPANY_SLUG in
development. They cannot: the fallback is deliberately restricted to
authenticated areas so it can never serve one tenant's public site on another
host. Following the old text leads to "localhost shows the platform page" and
a hunt for a database fault that does not exist.

Adds "Opening A Tenant Site Locally" covering ?devTenant= and
<slug>.localhost, which of the two is the day-to-day workflow, and the
create/migrate/seed commands for a genuinely empty database.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Next skips .env.local when NODE_ENV=test, so running CI's own E2E command
locally started a server with no DATABASE_URL and reported every migration
missing — a false failure that is easy to misread as a broken local database.
NODE_ENV=development keeps the dev-session bypass available on a production
build and loads .env.local locally; CI supplies its database through the job
env either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
estate-os Ready Ready Preview Sep 17, 2026 9:09am UTC

@Asapteejo
Asapteejo merged commit c19a0e6 into main Sep 17, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — f2077aff Deployed Sep 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant