← The board

D6 Household identity & invitations

Area
D — Content & household
Audience
both
Kind
feature
Status
accepted
Maturity
building
Labels
household, security
Relates to
C6D1D4D7D8G6

The feature in the specification · Read at

Requirements

  1. D6-R1acceptedMUST

    A household member MUST require only one account, serving both watching and requesting.

    locked by
    0.11.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/seerr.rscrates/lemonfiber-core/tests/integration/one_way_in_and_it_is_the_media_server.rs
    cited by
    lemonfiber@c3ebc16d09
  2. D6-R2acceptedMUST

    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
  3. D6-R3acceptedMUST

    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
  4. D6-R4acceptedMUST

    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
  5. D6-R5acceptedMUST

    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
  6. D6-R6acceptedMUST

    An existing Jellyfin account MUST be detected and reused rather than duplicated.

    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.rs
    cited by
    lemonfiber@3706105250
  7. D6-R7acceptedMUST

    Household members MUST be listable with their access, activity and requests in one place.

    locked by
    0.11.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/household/run.rscrates/lemonfiber/src/render/trace.rs
    cited by
    lemonfiber@84a6389c66
  8. D6-R8acceptedMUST

    Removal MUST revoke access in both Jellyfin and Seerr.

    locked by
    0.11.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/app/remove.rscrates/lemonfiber/src/render/removal.rs
    cited by
    lemonfiber@aba9f8a468lemonfiber@5c730c030c
  9. D6-R9acceptedMUST

    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
  10. D6-R10acceptedMUST

    The operator MUST be able to issue a password reset without learning the password.

    locked by
    0.11.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/model/invitation.rscrates/lemonfiber-core/src/app/invite.rscrates/lemonfiber-core/src/invitation.rs
    cited by
    lemonfiber@aba9f8a468lemonfiber@d8b547c4e1
  11. D6-R11acceptedMUST

    Invitations MUST state that access is limited to the home network.

    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.rs
    cited by
    lemonfiber@30c8d55110
  12. D6-R12acceptedMUST

    An invitation issued while Seerr is unavailable MUST still create the Jellyfin account and complete the link later, reporting the partial state.

    locked by
    0.11.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/app/invite.rscrates/lemonfiber-ports/src/service/household.rs
    cited by
    lemonfiber@8738f3e0e1
  13. D6-R13acceptedMUST

    Expired invitations MUST be re-issuable without redefining the member.

    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/app/invite.rs
    cited by
    lemonfiber@aba9f8a468lemonfiber@612d56bcb1
  14. D6-R14acceptedMUST

    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
  15. D6-R15acceptedMUST

    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
  16. D6-R16acceptedMUST

    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
  17. D6-R17acceptedMUST

    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
  18. D6-R18acceptedMUST

    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
  19. D6-R19acceptedMUSTClaim it

    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
  20. D6-R20acceptedMUST

    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.

    locked by
    0.19.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/app/command/household.rscrates/lemonfiber-contract/src/capabilities/media.rscrates/lemonfiber-core/src/household/run/defaults.rscrates/lemonfiber-api/src/entitled.rs
    cited by
    lemonfiber@2112d04d87
  21. D6-R21acceptedMUST

    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
  22. D6-R22acceptedMUST

    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.

    locked by
    0.18.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/app/invite/joining.rscrates/lemonfiber-core/src/app/invite/joining/tests.rscrates/lemonfiber-core/src/model/invitation.rscrates/lemonfiber/src/render/invitation.rs
    cited by
    lemonfiber@640f134910sdk-php@fabcd34ac6
  23. D6-R23acceptedMUST

    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.

    locked by
    0.18.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/invitation.rscrates/lemonfiber-core/src/app/invite/joining.rscrates/lemonfiber-core/src/app/invite/joining/tests.rs
    cited by
    lemonfiber@640f134910
  24. D6-R24acceptedMUST

    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.

    locked by
    0.18.0 met
    recorded done
    lemonfibercrates/lemonfiber-core/src/app/invite/joining.rscrates/lemonfiber-core/src/app/invite/joining/tests.rscrates/lemonfiber/src/render/invitation.rs
    cited by
    lemonfiber@640f134910
  25. D6-R25acceptedMUST

    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
  26. D6-R26acceptedMUST

    A chosen password shorter than the minimum the core enforces for its own credential MUST be refused, naming that minimum, briefly and without lecturing.

    locked by
    0.18.0 met
    recorded done
    lemonfibercrates/lemonfiber-api/src/admission.rscrates/lemonfiber-api/src/refusal.rscrates/lemonfiber-api/tests/integration/what_a_claim_opens.rs
    cited by
    lemonfiber@640f134910sdk-php@fabcd34ac6