feat(tenants): tenant own-company for general time logging (PMS-413) #309

Merged
vas2000-work merged 4 commits from feat/PMS-413-tenant-own-company into main 2026-06-18 06:38:56 +02:00
Owner

Establishes the tenant's own company as a first-class internal company so general / overhead time entries have a stable real company_id (unblocks MAPPS-243). Adds CompanyType::Internal and extends the companies.company_type CHECK; adds tenants.own_company_id (nullable FK). An idempotent TenantService::ensure_own_company creates one internal company per tenant named after the tenant and links it, wired into all provisioning paths; migration 062 does the same as a one-time, re-runnable backfill. Internal companies are hidden from the default GET /contacts/companies customer list (an explicit company_type=internal filter and id lookup still resolve them). own_company_id is exposed on the user payload (CurrentUser/User/UserResponse) via a correlated subquery so /auth/me and the login response carry it. Integration tests cover provisioning, idempotent backfill, the list exclusion, and creating a general entry against own_company_id.

#PMS-413

Establishes the tenant's own company as a first-class `internal` company so general / overhead time entries have a stable real `company_id` (unblocks MAPPS-243). Adds `CompanyType::Internal` and extends the `companies.company_type` CHECK; adds `tenants.own_company_id` (nullable FK). An idempotent `TenantService::ensure_own_company` creates one internal company per tenant named after the tenant and links it, wired into all provisioning paths; migration 062 does the same as a one-time, re-runnable backfill. Internal companies are hidden from the default `GET /contacts/companies` customer list (an explicit `company_type=internal` filter and id lookup still resolve them). `own_company_id` is exposed on the user payload (`CurrentUser`/`User`/`UserResponse`) via a correlated subquery so `/auth/me` and the login response carry it. Integration tests cover provisioning, idempotent backfill, the list exclusion, and creating a general entry against `own_company_id`. #PMS-413
feat(tenants): add tenant own-company for general time logging
Some checks failed
Check / fmt + clippy + compile + unit/doc tests (pull_request) Failing after 6s
E2E / Playwright against staging (pull_request) Successful in 34s
Integration / integration tests (pull_request) Failing after 3m59s
cf0a808dec
Establish "the tenant's own company" as a first-class internal company so general / overhead time entries have a stable, real company_id to attribute to (unblocks MAPPS-243). Added an `Internal` variant to `CompanyType` (crates/mokosh-types/src/contacts.rs) and extended the `companies.company_type` CHECK to accept 'internal' via migration 062.

Added `tenants.own_company_id UUID NULL REFERENCES companies(id)` and an idempotent `TenantService::ensure_own_company` that creates one internal company per tenant (named after the tenant) and links it; it is wired into every provisioning path (`create_tenant`, `ensure_personal_tenant`, `ensure_default_config`) and guarded so it only creates / sets where own_company_id is still NULL.

Migration 062 does both the schema change and a one-time backfill (one internal company per tenant lacking one, then set own_company_id), re-runnable as a no-op.

Excluded `internal` companies from the default `GET /contacts/companies` customer list (an explicit `company_type=internal` filter and lookup-by-id still resolve them) so the own-company never appears as a fake client in pickers.

Exposed `own_company_id` on the user payload: added the field to `CurrentUser`, `User`, and `UserResponse`, populated `User` via a correlated subquery against `tenants` in every user-load query, so `GET /api/v1/auth/me` (and the login response) carry it without an extra round-trip.

Added integration tests covering provisioning + idempotent backfill (tenants), the customer-list exclusion plus id-lookup (contacts), and creating a general entry against own_company_id (time_tracking).

#PMS-413

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(reports): exclude internal own-company from clients report; match CI rustfmt (PMS-413)
Some checks failed
E2E / Playwright against staging (pull_request) Successful in 40s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 1m6s
Integration / integration tests (pull_request) Failing after 7m47s
b3e163230b
The clients report counted the tenant's internal own-company, so its company total was one too high; exclude company_type = 'internal' to match the customer list. Also reformat the new contacts/tenants test asserts and the company-row insert to the rustfmt CI runs.

#PMS-413
fix(seed): exclude internal own-company from tenant emptiness checks (PMS-413)
Some checks failed
Check / fmt + clippy + compile + unit/doc tests (pull_request) Failing after 5s
E2E / Playwright against staging (pull_request) Successful in 34s
Integration / integration tests (pull_request) Successful in 3m48s
edbd8cdb7a
The auto-created internal own-company made seed_demo's tenant_has_companies see every tenant as non-empty, so demo data would never seed (a real regression); exclude company_type = 'internal' there. Also exclude internal from the seed_demo test company_count helper and the rls_isolation GUC count, which counted the backfilled own-company.

#PMS-413
style: match CI rustfmt for the PMS-413 emptiness-check edits (PMS-413)
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 33s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 1m5s
Integration / integration tests (pull_request) Successful in 3m46s
Create release / Create release from merged PR (pull_request) Has been skipped
45ecbb7e01
#PMS-413
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!309
No description provided.