feat(user-core): dunite-user-core shared account vocabulary (DEV-517) #31
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/DEV-517-dunite-user-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
DEV-517 under the DEV-495 epic. a8n-tools and bunyip grew the same account model independently, and the vocabulary half of it is byte-identical on both sides. This crate is the single copy.
What moves in
UserRole,MembershipStatus,SubscriptionTierwith theiras_str+From<&str>/From<String>round-trips (identical in both repos today).select,trial_days,trial_label,display_name. They are functions of the admin-configured slot counts and trial windows, no database or clock involved.TierConfigResponse, the tier-settings read model (api/src/models/tier.rsandcrates/bunyip-domain/src/models/tier.rsdiff to nothing today).What deliberately stays per-app
Userrow struct andUserRepository. The schemas have drifted: bunyip carrieslast_login_country,login_location_alerts,first_name,last_name,phone,has_used_trial,avatar_updated_at,is_super_admin; a8n has no column for any of them. Sharing the row means migrating a8n'suserstable first, so that reconciliation is its own piece of work. (is_access_allowedis identical on both sides but lives on the row, so it waits for the same reconciliation.)sqlx::FromRow. a8n is on sqlx 0.7, bunyip on 0.8; a derive from one major does not satisfy the other's traits, so a shared row type would be unusable by one consumer. That is whyTierConfigRowstays local while the plain-serdeTierConfigResponseis shared. The crate depends on serde, chrono and uuid only.Tests
12 unit tests. The interesting ones pin the fallback direction of each
From<&str>, which is a security property rather than a formatting detail: an unrecognised role degrades toSubscriber(neverAdmin), an unrecognised status toNone(never an access-granting variant), an unrecognised tier toStandard(never one of the free tiers). Plus the access predicate (grace period grants, past-due does not) and the exclusive<boundary inselectthat pins the long-vs-short trial cutover.Consumer PRs in bunyip and a8n-tools follow.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CGnY8JKXCgH2jiUSqH6g4x