feat: add users table and Yivi-based registration#15
Merged
Conversation
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.
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.
This was referenced Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
userstable to separate org signing attributes from user/contact person identity (closes Support multiple users per organisation #13)Schema changes
userstable (emailunique,full_name,phone,org_idFK)organizations.email→signing_email(the email API keys use when signing)contact_name/phonefrom orgs, addedcontact_user_idFK to usersuser_idto sessionsAuth changes
users.emailinstead oforganizations.emailNew features
portalMembersfeature flag (FF_PORTAL_MEMBERS)Other fixes
impersonatingOrgIdfor admin impersonation-- safe:inline annotationsStaging rollout plan
The
edgetag auto-deploys to staging. On deploy, the Kubernetesbusiness-migrateJob runsscripts/migrate.tsbefore the new deployment starts (Terraformdepends_on+wait_for_completion). This means:0001_add-users-table.sql):userstableorganizations.email→signing_emailcontact_nameandphonefromorganizationscontact_user_idtoorganizationsanduser_idtosessionsSince 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_keysdo not haveusersrows yet. After this deploys, those orgs will havecontact_user_id = NULLand no users — they won't be able to log in until users are created for them. Options:kubectl execto insert user rows for the 3 existing orgs--live) which now creates usersFeature flag: Add
FF_PORTAL_MEMBERS=trueto the staging env. This requires adding the variable topostguard-ops/environments/dev.tfvarsandmain.tf(business env block).Test plan
docker-compose down -v && docker-compose up— migration + seed succeedusers.email) → portal loadsnpx vitest run)