Skip to content

feat: add users table and Yivi-based registration#15

Merged
rubenhensen merged 3 commits into
mainfrom
feat/add-users-table
Apr 22, 2026
Merged

feat: add users table and Yivi-based registration#15
rubenhensen merged 3 commits into
mainfrom
feat/add-users-table

Conversation

@rubenhensen

Copy link
Copy Markdown
Contributor

Summary

Schema changes

  • New users table (email unique, full_name, phone, org_id FK)
  • organizations.emailsigning_email (the email API keys use when signing)
  • Removed contact_name/phone from orgs, added contact_user_id FK to users
  • Added user_id to sessions

Auth changes

  • Login now matches Yivi-disclosed email against users.email instead of organizations.email
  • Registration: Yivi discloses email + full name + phone → domain derived from email → user enters org name only

New features

  • Members portal page: list/add/remove users, switch contact person
  • portalMembers feature flag (FF_PORTAL_MEMBERS)

Other fixes

  • Portal actions (revoke key, DNS verify, etc.) now respect impersonatingOrgId for admin impersonation
  • Visual border around Yivi QR codes
  • Admin org detail view uses proper grid layout
  • Migration checker supports -- safe: inline annotations

Staging rollout plan

The edge tag auto-deploys to staging. On deploy, the Kubernetes business-migrate Job runs scripts/migrate.ts before the new deployment starts (Terraform depends_on + wait_for_completion). This means:

  1. Migration runs first (0001_add-users-table.sql):
    • Creates users table
    • Renames organizations.emailsigning_email
    • Drops contact_name and phone from organizations
    • Adds contact_user_id to organizations and user_id to sessions
  2. Seed re-runs (idempotent): creates a user for the demo org if not present
  3. New deployment starts with code that expects the new schema

Since the migration Job uses the same container image as the deployment and runs before it, the schema and code are always in sync. No expand/contract needed — staging has no rolling deploys (the old pod is killed before the new one starts).

Existing staging data: The 3 orgs migrated from legacy api_keys do not have users rows yet. After this deploys, those orgs will have contact_user_id = NULL and no users — they won't be able to log in until users are created for them. Options:

  • Run a one-off kubectl exec to insert user rows for the 3 existing orgs
  • Or re-run the legacy migration script (--live) which now creates users

Feature flag: Add FF_PORTAL_MEMBERS=true to the staging env. This requires adding the variable to postguard-ops/environments/dev.tfvars and main.tf (business env block).

Test plan

  • docker-compose down -v && docker-compose up — migration + seed succeed
  • Login with Yivi (email matches users.email) → portal loads
  • Members page: list users, add member, remove member, switch contact person
  • Registration: Yivi disclosure → org name form → org + user created
  • Admin: org detail shows signing email + contact person, impersonation works
  • Verify existing tests pass (npx vitest run)

Introduces a `users` table so multiple people can belong to an
organisation. Login now matches Yivi-disclosed email against
`users.email` instead of `organizations.email`.

Key changes:
- New `users` table (email, full_name, phone, org_id)
- Rename `organizations.email` → `signing_email` (used by API keys)
- Remove `contact_name`/`phone` from orgs, add `contact_user_id` FK
- Add `user_id` to sessions
- New members portal page (add/remove users, switch contact person)
- Registration creates org + first user as contact person
- Fix impersonation 401s: portal actions now respect impersonatingOrgId
- Add visual border around Yivi QR code
- Migration checker supports `-- safe:` annotations to skip known-safe ops
Registration now uses Yivi to verify identity (email, full name, phone)
before creating an org. Only the organisation name is entered manually;
domain is derived from the disclosed email.

Also fixes admin org detail grid alignment and registration duplicate
domain error detection.
@rubenhensen rubenhensen merged commit 9c1097f into main Apr 22, 2026
7 checks passed
@rubenhensen rubenhensen deleted the feat/add-users-table branch April 22, 2026 12:46
dobby-coder Bot added a commit that referenced this pull request Apr 23, 2026
- Strike the "prerequisite blocker" section: the users table,
  sessions.user_id and user_type='user' all landed in #15. Quote the
  as-landed schema from src/lib/server/db/schema.ts rather than the
  org_users shape originally proposed.
- Spell out the additive migration SSO still needs (auth_source,
  sso_subject, last_login_at on users; partial unique index on
  (org_id, sso_subject)). Drop role/status — out of scope for SSO.
- Update the auth-flow pseudocode to reference users (not org_users)
  and to note last_login_at should be bumped on callback success.
- Strike chunk 2 in the rollout plan (landed as #15) and renumber
  chunks 3-7 accordingly.
- Add postguard-business#15 to the "Related" links and flag the
  refresh date in the status line.

No prose rewrite; no change to the auth flow, security considerations,
or open questions. The landed schema matched the proposal closely
enough that the plan survives intact — the drift is mostly additive.
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.

Replace registration form with Yivi disclosure Support multiple users per organisation

1 participant