D6 Household identity & invitations
- Area
- D — Content & household
- Audience
- both
- Kind
- feature
- Status
- accepted
- Maturity
- building
- Labels
- household, security
The feature in the specification · Read at
Requirements
A household member MUST require only one account, serving both watching and requesting.
The operator MUST NOT set or transmit another person's password.
- locked by
- 0.11.0 met
- recorded done
- lemonfibercrates/lemonfiber-contract/src/capabilities/identity.rscrates/lemonfiber-core/tests/integration/an_invitation_sets_nobodys_password.rscrates/lemonfiber-core/tests/integration/the_household_needs_no_account_here.rscrates/lemonfiber-api/src/admission.rscrates/lemonfiber-core/src/model/invitation.rscrates/lemonfiber-core/src/app/invite.rs
- cited by
- lemonfiber@d8b547c4e1lemonfiber@1ed6c4b4d2
Invitations MUST be single-use and MUST expire.
- locked by
- 0.11.0 met
- recorded done
- lemonfiberspec:10-functional/features/d-content/d6-household-identity.mdcrates/lemonfiber/src/render/invitation.rscrates/lemonfiber-core/src/invitation.rscrates/lemonfiber-core/src/model/invitation.rscrates/lemonfiber-core/src/app/invite.rs
- cited by
- lemonfiber@951e9ec617lemonfiber@aba9f8a468lemonfiber@30c8d55110
Invitations MUST be presented as both a URL and a QR code.
- locked by
- 0.11.0 met
- recorded done
- lemonfibercrates/lemonfiber/src/render/invitation.rs
- cited by
- lemonfiber@1ed6c4b4d2
Library access and any age limit MUST be selectable at invitation time in plain language.
- locked by
- 0.11.0 met
- recorded done
- lemonfibercrates/lemonfiber-contract/src/capabilities/identity.rscrates/lemonfiber-core/src/age_limit.rscrates/lemonfiber/src/render/trace.rscrates/lemonfiber-api/src/actions/asked.rscrates/lemonfiber/src/acting/inviting.rs
- cited by
- lemonfiber@aba9f8a468lemonfiber@db062d5fb5
An existing Jellyfin account MUST be detected and reused rather than duplicated.
Household members MUST be listable with their access, activity and requests in one place.
Removal MUST revoke access in both Jellyfin and Seerr.
Removal MUST state the effect on watch history and outstanding requests before confirming.
- locked by
- 0.11.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/app/remove.rscrates/lemonfiber/src/render/removal.rs
- cited by
- lemonfiber@5c730c030c
The operator MUST be able to issue a password reset without learning the password.
Invitations MUST state that access is limited to the home network.
An invitation issued while Seerr is unavailable MUST still create the Jellyfin account and complete the link later, reporting the partial state.
Expired invitations MUST be re-issuable without redefining the member.
lemonfiber MUST NOT grant household members any access to lemonfiber itself.
- locked by
- 0.11.0 met
- recorded done
- lemonfibercrates/lemonfiber-contract/src/capabilities/identity.rscrates/lemonfiber-core/tests/integration/an_invitation_sets_nobodys_password.rscrates/lemonfiber-core/tests/integration/the_household_needs_no_account_here.rscrates/lemonfiber-api/src/admission.rs
- cited by
- lemonfiber@c628072a05lemonfiber@aff8e725a8lemonfiber@1ed6c4b4d2
An invitation MUST carry a decline address whose page offers the invitee a refusal of that invitation only, served by a service the stack keeps running under its restart policy beside the household front door, at the household binding tier, and never by a process whose lifetime is an operator's session — the CLI, the TUI or lemonfiber ui (G1-R5); who built the serving image does not matter.
- locked by
- 0.17.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/app/invite/declining.rscrates/lemonfiber-sidecar/crates/lemonfiber-core/src/seed/run/decline.rscrates/lemonfiber-core/src/app/credentials/declining.rs
- recorded partial
- lemonfiber-declinesrc/serving.rssrc/page.rssrc/page/tests.rs::an_open_invitation_names_the_account_and_offers_the_refusal
- recorded partial
- lemonfiber-media-stackstack.tomlservices/decline.toml::confined
- cited by
- lemonfiber@a8084dde9alemonfiber@d089bab2cblemonfiber@b4c1223dbflemonfiber@3eea6a2f6blemonfiber-decline@9fff3820cclemonfiber-decline@f15033c6f2lemonfiber-decline@37237fb72clemonfiber-media-stack@4c7bc56170
A refusal MUST make the invitation unclaimable at once, MUST be kept by the stack until the core reads it, and the core MUST report it as the invitation's standing, declined, told apart from one that lapsed (expired).
- locked by
- 0.17.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/app/invite/declining.rscrates/lemonfiber-sidecar/crates/lemonfiber-core/src/seed/run/decline.rscrates/lemonfiber-core/src/app/credentials/declining.rs
- recorded partial
- lemonfiber-declinesrc/declining.rssrc/declining/tests.rs::declining_disables_the_account_and_records_the_refusalsrc/declining/tests.rs::a_second_refusal_writes_nothing
- cited by
- lemonfiber@a8084dde9alemonfiber@4388b37bfclemonfiber@e76265f2dclemonfiber@767a8600e8lemonfiber@3eea6a2f6blemonfiber-decline@f15033c6f2lemonfiber-web@ef496cb07d
Reading what removing a household member costs MUST answer with an offer naming what it read; the removal MUST take that offer as its yes, alike at the command line and over the web API (ARCH-R48), MUST build it again from what the media server and the request service hold when it runs, and MUST be refused, naming what moved, where the two differ. A bare confirm MUST NOT be a yes to a removal over the web API (N13-R7).
- locked by
- 0.18.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/app/remove.rscrates/lemonfiber-core/src/agreement.rscrates/lemonfiber-error/src/codes/remove.rscrates/lemonfiber-api/src/actions/asked/takers.rscrates/lemonfiber-api/src/actions/named/household.rscrates/lemonfiber/src/cli/request.rscrates/lemonfiber-core/tests/integration/what_removing_somebody_costs.rs::what_it_costs_is_said_without_removing_anybodycrates/lemonfiber-core/tests/integration/what_removing_somebody_costs.rs::confirmed_it_revokes_in_both_places_and_the_media_server_firstcrates/lemonfiber-core/tests/integration/what_removing_somebody_costs.rs::an_answer_to_a_reading_that_has_moved_is_refused_naming_what_moved
- cited by
- lemonfiber@cc1b83cf00
The removal envelope MUST state what removing the person does to their watch history, in the stack's words, in the reading before the removal and in the answer after it runs, so that no surface writes that statement itself (D6-R9, N13-R19).
- locked by
- 0.18.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/model/invitation.rscrates/lemonfiber-core/src/app/remove.rscrates/lemonfiber/src/render/removal.rscontract/web-api/defs/HouseholdRemoval.jsoncrates/lemonfiber-core/tests/integration/what_removing_somebody_costs.rs::what_it_costs_is_said_without_removing_anybodycrates/lemonfiber-core/tests/integration/what_removing_somebody_costs.rs::confirmed_it_revokes_in_both_places_and_the_media_server_firstcrates/lemonfiber/src/render/removal/tests.rs::the_watch_history_is_said_in_the_stacks_words
- cited by
- lemonfiber@cda3e3d58c
The core MUST answer a member's session with the member's display name as the media server holds it.
- locked by
- 0.19.0 open
The core MUST answer the operator's session with what a member invited with the household's default access and allowance would be told and could watch, and MUST NOT read or name any member's requests, allowance or watch history to answer it.
When an invitation's window closes, the stack MUST take it back without a lemonfiber process running: an account nobody was ever seen in MUST be removed, and one somebody has been in MUST be switched off and kept. An account MUST be removed only where reads made just before the removal show that the core's invitation table names it under the same issue time, that it is not an administrator, that it has no password, and that nobody has ever signed in to it or used it; on any other answer, or none, it MUST be switched off or left as it is. A declined invitation MUST NOT be taken back. The core MUST report an invitation taken back this way as expired, and MUST NOT report a removed one as an account that went missing.
- locked by
- 0.18.0 met
- recorded done
- lemonfibercrates/lemonfiber-sidecar/crates/lemonfiber-core/src/household/run/standing.rscrates/lemonfiber-core/src/doctor/declining.rsspec:10-functional/features/d-content/d6-household-identity.mdcrates/lemonfiber/src/render/invitation.rscrates/lemonfiber-core/src/invitation.rs
- recorded open
- lemonfiber-decline
- cited by
- lemonfiber@455f620b54
Every invitation that is not a rehearsal MUST carry a join link where the web surface has last been served encrypted on the network and its certificate and address can be read. The link MUST be lemonfiber://join? followed by these parameters, percent-encoded and no others: address, fingerprint, stack, expires and name, and claim exactly where the standing is made, waiting or reset. address, fingerprint and stack MUST be what pairing material carries at that moment (N1-R18, N1-R48, N1-R62), and the core MUST NOT build the address itself; expires MUST be the moment the offer lapses, or for joined the moment the invitation's hours from now run out, written as every instant is, in whole seconds since the Unix epoch (ARCH-R274); name MUST be the account's name as the media server holds it; claim MUST be a token of at least 128 random bits minted for this offer.
The core MUST keep a claim token only as a hash on the offer it was minted for. Offering the same person again, or reissuing, MUST mint a new token, and an older token MUST stop claiming anything.
Where no join link can be made (D6-R22), the invitation MUST still be made, MUST carry no join link, and MUST say why in words every surface can show, naming no command (N1-R76). A rehearsal MUST carry no join link and no such sentence, because it mints no token.
A claim MUST be refused unless the token's hash is on the offer standing for that account, the offer has not lapsed and has not been declined, and the account is unclaimed, not switched off and not an administrator. A claim that succeeds MUST set the password the person chose on their own account at the media server, acting as that account and never as the administrator; MUST spend the token; and MUST open a member session. The operator MUST NOT be able to read or set the chosen password (D6-R2).
- locked by
- 0.18.0 met
- recorded done
- lemonfibercrates/lemonfiber-api/src/admission.rscrates/lemonfiber-core/src/app/members.rscrates/lemonfiber-contract/src/capabilities/identity.rscrates/lemonfiber-api/tests/integration/what_a_claim_opens.rscrates/lemonfiber-core/tests/integration/what_an_invitation_guards.rs
- cited by
- lemonfiber@640f134910sdk-php@fabcd34ac6
A chosen password shorter than the minimum the core enforces for its own credential MUST be refused, naming that minimum, briefly and without lecturing.