DataTalksClub / DataTalksClub/dataops
Show signed-in identity and authorized teammates’ Task/Card work
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Show signed-in identity and authorized teammates’ Task/Card work
Status: blocked for coordinated release — combined Designer/Tester PASS and PM ACCEPTED; exact commit 3e835a19017da18f2177d81fb7e084764970dee3 is clean on issue-164-stage-b, held off main and unpushed; no shipped/deployed claim
Tags: enhancement, portal, frontend, backend, work-engine, data, testing, design, P1
Depends on: #217 preview/deployment/post-deployment identity gate for coordinated publication; #161, #166, #180, and #182 prerequisites are satisfied locally or closed
Blocks: the #162 access/system and work-execution redesign slices
Next owner: Orchestrator after #217 release/identity PASS, for safe local integration and normal push; then On-Call
Resume condition: #217 completes its HUMAN preview, ordinary main/OIDC deployment, terminal On-Call result, and HUMAN identity verification; then resume coordinated publication without carrying the rejected old #146 candidate.
Product outcome
An authenticated operator can always answer “who am I?” from the canonical shell, deliberately inspect work owned by another active teammate, and help execute that teammate’s Tasks. The authenticated actor never changes: the Task keeps its assignee, while completion, waiting, follow-up, response, proof, file, and other ordinary Task-work history records the real teammate who performed the action.
This issue owns the missing identity, team-directory, owner-projection, filtering, and owner-aware authorization contract. It does not redesign every Tasks/Cards screen; #162 later applies the shared design system while preserving this behavior.
Accepted foundations and contract corrections
-
#179 is Tester/PM accepted at
02ee455efad09865ecdbd578e940c59e0bf7dc36; #168 is Tester/PM accepted at41dca9e3748fe627c195f48a7f97ae203b343f60. Both are ancestors of current local DataOps source. Their required Task version/history and atomic Task/Card counter/lifecycle/audit contracts are fixed inputs to #164, not open local implementation blockers. -
Those commits are not deployed. No #166 production phase has run, and #164 must not enter the reviewed Phase D artifact or change its readiness contract. Local #164 work stays isolated and unpushed until the repaired #166/#182 sequence and cleanup are complete.
-
The persisted aggregate is a Card, not a bundle or a second workflow record. #164 adds optional administrative
ownerIdto the canonical Card shape; it does not add/api/bundles, a bundle alias, a second owner model, or a lifecycle fallback. Existing or system-created Cards without an explicit owner are honestlyUnassigned. -
The #161 account/work-scope prototype is present in pushed source at
57b879145590b917d8cf1e15ae0df2f0c7f3cb1a, but #161’s final Home work is still pending. #180 is also pending and owns overlapping shell, Task UI, browser-isolation, and accessibility repairs. Neither blocks the backend-only Stage A below; both must be accepted before Stage B edits their frontend/browser surfaces.
Current contract and gaps
-
/api/mereturns the authenticated user and the portal cookie is propagated to/work/api/me, but the shell exposes only a generic Settings gear. A disabled or deleted user already fails closed in portal mode; every supported cookie/bearer seam must behave the same way. -
GET /api/userssupplies the existing role-aware Users surface and stripspasswordHash. It is not an appropriate work projection because it includes account-management fields such as email. -
Tasks persist
assigneeId,createdBy, and completion/history actor IDs. The UI can resolve an assignee name after loading/api/users, but the task list APIs have no owner filter and may expose raw/unresolved IDs. -
Cards have no persisted owner. Their Tasks can have different assignees, so Task assignees alone are not a durable Card owner contract.
-
Today, any authenticated operator can call the generic Task and Card write routes for any record. Client-supplied
x-user-idis stripped outside the explicit test bypass, but task collaboration, assignment changes, deletion, and direct Card administration are not distinguished. Teammate execution therefore needs a deliberate server-side action boundary, not a client-side identity switch.
Access model
The workspace currently has two supported roles, admin and operator.
| Actor / record | Read identity/team directory | Read Task/Card | Mutate Task | Administer Card | Reassign owner |
| --- | --- | --- | --- | --- | --- |
| Active operator, own record | Yes | Yes | Yes | Yes for a Card they own | No |
| Active operator, active peer record | Safe teammate projection | Yes | Yes: ordinary Task execution, real actor attribution | No direct Card administration | No |
| Active operator, unassigned/disabled/stale owner | Safe state only | Yes | Yes: ordinary Task execution when otherwise valid | No | No |
| Active admin | Yes | Yes | Yes | Yes | Yes, to an active user or unassigned |
| Disabled, deleted, expired-session, missing-role, or unknown-role actor | No team access | No peer access | No | No | No |
Completing or reopening any visible Task may update the accepted #168 Card counters, lifecycle, completion metadata, and public-safe lifecycle audit in the same transaction. That is the consequence of an authorized Task action, not permission to change the teammate-owned Card title, dates, owner, references, or active stage. Card completion/archive remains system-owned and is never a manual administration permission. The task assignee remains unchanged and history records the verified actor who performed the work.
An operator-created manual Task defaults to that operator as assignee when assigneeId is omitted. An operator-created Card defaults to that operator as owner. Operators cannot create work assigned to a peer, change assigneeId/ownerId, administratively edit unassigned work, or claim it implicitly. They may still perform the explicitly allowed ordinary execution actions on an otherwise visible unassigned Task without changing its assignee or Card owner. Admins retain explicit assignment and recovery authority. Existing and system-created unowned Cards remain Unassigned; do not guess or backfill an owner from historical text or Task data.
Staged implementation and release sequencing
Stage A — backend identity, projection, ownership, and authorization (locally eligible now)
Implement in a clean isolated worktree based on accepted #179/#168 source:
-
one shared verified interactive actor resolver that loads the current User for cookie/session/API-token requests and fails closed for deleted, disabled, missing-role, or unsupported-role actors before team reads or Task/Card writes;
-
the safe
/api/team-membersprojection, safe Task/Card/actor projections, owner filters, CardownerId, and the server-enforced Task execution versus Task/Card administration boundary below; -
focused backend domain/handler/API tests under
backend/tests, including both canonical/apiand rewritten/work/apibehavior. Do not create a broad Playwright request/CRUD suite; -
no frontend, Playwright, deploy-workflow, SAM-template, #166 preparer/verifier, import/export/restore, migration, table-creation, or data-mutation work.
Stage A may receive independent Tester and PM review and an explicit-path Refs #164 checkpoint commit. Keep it on its isolated branch: do not merge it into local main, push it, or include it in #166 Phase D.
Stage B — accepted frontend behavior and real browser journeys (blocked on #161 and #180 acceptance)
Start from the final accepted #161/#180 source, then connect the existing account/work-scope prototype to /api/me, /api/team-members, canonical owner deep links, Task/Card projections, delegated Task execution, honest partial failure, and role-derived controls. Remove routine /api/users use from account/work views; keep that API only for the Admin/Users surface.
Playwright owns real operator journeys, navigation, focus, accessibility, and responsive evidence. Backend tests own request matrices, authorization, filters, conflicts, and privacy. Preserve #180’s independent fixtures/diagnostics and the independent non-deploy-blocking browser workflow; do not reintroduce serial coupling, broad API CRUD specs, fixed sleeps, exact incidental copy, raw IDs, or screenshot-pixel assertions.
Stage B may be reviewed and committed on the held #164 branch, but remains unmerged/unpushed while #166 is active.
Stage C — integrate and release from steady state (blocked on #166 cleanup)
After repaired #166 A → B → C, the in-sequence #182 Cards preflight, Phase D production evidence, and accepted cleanup have restored ordinary main-push OIDC deployment:
-
rebase or reconstruct the accepted #164 changes on the exact clean steady-state
mainwithout preserving temporary compatibility; -
rerun the complete backend/frontend/browser/SAM verification and source/SAM parity against that final combined source;
-
merge and push through the ordinary DataOps lifecycle, then let On-Call monitor the normal workflow.
No manual app deploy, workflow dispatch for #164, AWS call, owner backfill, source-data import, or production data edit is part of any stage.
API and data contract
Identity and safe teammate projection
-
GET /api/meandGET /work/api/mereturn the same authenticated{ user }identity for a real cookie or bearer session. The user containsid,name,email,role, anddisabled: false; it never containspasswordHashor session material. -
Missing, expired, deleted-user, or disabled-user sessions return JSON
401at both prefixes and never redirect an API request to HTML. A missing or unsupported role cannot use team reads or work mutations. -
Add a purpose-built authenticated
GET /api/team-membersprojection for activeadminandoperatoractors. Each entry contains only stable ID, display name, supported role, andactive/disabledavailability. It omits email, password/session data, private profile data, and external avatar URLs. Active members are valid assignment targets; disabled members exist only to resolve historical ownership. -
Task responses retain canonical
assigneeIdand add a safeassigneeprojection. Card responses persist optional administrativeownerId, add a safeownerprojection, and expose a deduplicated safetaskAssigneessummary derived from their Tasks. Task history actor display is resolved through the same safe projection. Routine UI never displays raw user IDs. -
No new image storage is introduced. The shell avatar is deterministic initials derived from the authenticated display name, with a neutral fallback when identity is unavailable.
Owner filters and deep links
-
GET /api/tasksacceptsowner=me|team|unassigned|<user-id>alone or in combination with one existing date/range/cardId/status filter.meis resolved from the verified server actor,teammeans records assigned to any active teammate, and a concrete active/disabled/stale reference returns only that owner’s records with its honest availability projection. Existing filter priority must not silently discardowner. -
GET /api/cardsaccepts the same owner values against persisted CardownerId;GET /api/cards/:idand/api/cards/:id/tasksreturn the safe owner/team projections. Opening a teammate Card may expose its Task execution actions without granting direct Card administration. No/api/bundlesalias is added. -
Canonical UI routes preserve
owner=me|team|unassigned|<user-id>on/#/tasksand/#/cardsthrough direct load, refresh, Back, Forward, Task/Card relationship navigation, and close/return. The visible picker labels areMy work,Team work,Unassigned, and teammate display names; a raw ID is never used as visible fallback copy. -
A disabled owner remains selectable only when referenced by retained work and is labelled
Disabled teammate. A missing user reference rendersTeammate unavailable, retains the exact deep link and any readable work, and offers a clear-filter recovery action. It never falls back silently to My work or Team work. -
Owner list/filter failures are honest partial failures: already loaded work stays visible, the owner filter is marked unavailable, and no false empty or fabricated teammate is shown.
Server-enforced collaboration boundary
-
Every ordinary task-execution path uses the verified actor and works for visible own, teammate, or unassigned tasks: atomic waiting/follow-up/response/completion/reopen actions plus task-bound proof/file evidence. These actions retain
assigneeIdand append the verified actor to history; an owner filter, form value, or browser header cannot impersonate the assignee. -
Task create and general metadata update use the verified actor. An operator-created Task with omitted assignee defaults to that actor; explicit peer assignment, assignee changes, ownership claims, Task deletion, and Task-Card membership changes affecting a Card the operator does not own are admin-only. A routine delegated action cannot silently reassign the Task, move it between Cards, rewrite its creator, erase history, or bypass #179 expected-version conflicts.
-
Every existing Card administration path enforces the table above: create, metadata update, active-stage edit, and single/batch Template-update apply. An operator may administer only a Card whose persisted
ownerIdmatches them;ownerIdchanges are admin-only and unassigned Cards are admin-managed. Do not restore the removed manual Card archive/delete routes or direct lifecycle-field writes. Derived #168 counters/lifecycle/audit from a valid teammate-Task action remain allowed and retain the Card owner. -
A forbidden assignment, deletion, membership change, or direct Card-administration write returns JSON
403with stable codework_admin_forbidden; unsupported-role team reads return403withteam_read_forbidden. A stale record remains404, validation remains400, and an ownership/version race remains409; no denial is represented as success. -
Interactive Task/Card routes never fall back to
system,portal-admin, a requested owner, or an assignee when the verified actor is absent. Existing authenticated CLI/channel paths resolve the same active supported User; genuinely scheduled/internal mutations retain their explicit stable system actor and do not become an impersonation route. -
Card
ownerIdis administrative metadata outside the #168 aggregate calculation. Authorized Task completion/reopen/membership transactions retain it unchanged while atomically applying the accepted Task history, Card counters/lifecycle/version, and lifecycle audit with the verified action actor. -
Browser-supplied identity headers, owner query values, form fields, and stale client state cannot change the actor. Re-fetching after a role/disabled/ownership change immediately applies the new server decision.
-
Existing admin-only Users mutations and domain-specific approval/finance/assistant policies remain unchanged. This issue does not grant peer approval or administration rights on any other surface.
Shell and responsive behavior
-
Replace the generic desktop/mobile Settings trigger with a persistent account control backed by
/api/me. Desktop shows initials plus the current display name; mobile shows the initials control without consuming the page title/action area. Both expose an accessible name such asAccount for Avery Operator,aria-haspopup, and expanded state. -
The existing Settings surface opens from that control and begins with the signed-in user’s name, own email, and role, followed by the already-authorized appearance/version/Admin/Users/Sign out actions. Operator controls remain role-derived from the server; the account control is not an admin shortcut.
-
Escape, outside click where applicable, close, route change, and sign out preserve the accepted focus/session behavior. Closing restores focus to the account control. Identity loading shows a neutral skeleton; failure shows
Identity unavailablewith Retry and Sign out rather than a guessed name or role. -
At 1440x900 the account control, work-scope picker, selected teammate state, and Task/Card heading do not crowd the shell. At 390x844 the control remains at least 44×44 CSS px, the account view is keyboard/touch operable, and the work-scope picker plus first work item fit without horizontal overflow or clipped actions.
-
A teammate Task detail identifies its assignee and keeps the state-valid task execution controls. After a delegated action, visible history says which signed-in operator performed it and the assignee remains unchanged. Assignment, deletion, and direct Card-administration controls remain role-derived and separate.
-
Changed ready, empty, loading, partial-failure, forbidden, disabled-owner, stale-owner, and Settings-open states have correct headings/list/form/popover semantics, visible focus, and zero critical or serious WCAG A/AA findings in automated scans.
Real behavior tests
Use synthetic users such as Avery Operator, Morgan Teammate, Casey Disabled, and Riley Admin with example.test addresses. Do not use real names, production IDs, contact details, private avatars, or operational work.
-
Add focused backend handler/domain contract coverage (suggested
backend/tests/team-visibility.test.ts) for both API prefixes, cookie and bearer identity, safe team projections, filter combinations, Card owner persistence, delegated Task-action success with stable assignee and real actor history, assignment/deletion/direct-Card restrictions, spoofed-header rejection, disabled/deleted/role-change fail-closed behavior, and stable 400/403/404/409 responses. Do not put this request matrix in Playwright. -
Add a normal real-server Playwright behavior suite without request interception (suggested
backend/e2e/team-visibility-behavior.spec.js) with exact titled journeys for: desktop/mobile identity and account-menu focus; own/peer/team/unassigned filters and deep-link history; delegated teammate-Task completion/proof/waiting with unchanged assignee and real actor history; direct Card-administration denial; and disabled/stale owner plus partial-source recovery. -
Assert API payload privacy: no
passwordHash, token, cookie, session value, peer email, private avatar URL, or raw identifier copy appears in the team/work projections, DOM, screenshots, logs, or accessibility tree. -
Update the durable capability/state mapping with exact passing normal-browser titles, including the retained Home-ready pointer affected by identity hydration; update the source/SAM parity state contract for all changed shell/Task/Card states.
Tester captures and reads exactly these synthetic images under .tmp/screenshots/issue-164/:
-
source-identity-settings-desktop-1440x900.png -
sam-identity-settings-desktop-1440x900.png -
source-owner-filter-mobile-390x844.png -
sam-owner-filter-mobile-390x844.png -
source-teammate-Task-action-desktop-1440x900.png -
sam-teammate-Task-action-desktop-1440x900.png -
source-disabled-owner-mobile-390x844.png -
sam-disabled-owner-mobile-390x844.png
Source/SAM pairs use identical fixtures and prove matching route/query, signed-in actor, assignee, and Card-owner labels, delegated mutation result, unchanged ownership, accessible-name summary, console/page-error result, and asset hashes. Pixel similarity is supporting evidence only. The directory contains exactly these eight PNGs at native dimensions and no stale extras; screenshots are evidence, not behavior proof or tracked artifacts.
Run and report exact commands, exit codes, test counts, and evidence paths in this order:
npm --prefix backend test
npm --prefix backend run typecheck
npm --prefix backend run build
node backend/scripts/verify-frontend-artifact.mjs --source frontend --artifact backend/dist
npm --prefix backend run test:e2e
npm --prefix backend run test:e2e:frontend-parity
make sam-validate
make sam-build
node backend/scripts/verify-frontend-artifact.mjs --source frontend --artifact .aws-sam/build/BackendFunction
make ci
git diff --check
Dependency and sequencing
-
Accepted source contract — locally satisfied. #179
02ee455efad09865ecdbd578e940c59e0bf7dc36and #16841dca9e3748fe627c195f48a7f97ae203b343f60define the only Task/Card version, history, transaction, counters, lifecycle, conflict, and audit behavior #164 may extend. Stage A can implement and receive local review now. -
#161 and #180 — block Stage B frontend/browser paths. The pushed #161 prototype is a design/input, not proof of the final backend guarantee. Wait for both issues’ Tester/PM-accepted source before editing shared account, Home, Task/Card, navigation, or browser coverage. #164 must preserve their accepted journeys and genuine accessibility fixes.
-
#166 with #182 — blocks integration, push, and production evidence. No production phase has run. #164 must not be an ancestor of or modification to the reviewed Phase D artifact. Wait through repaired A/B/C, #182’s final no-replacement Cards preflight while writers are closed, reviewed D, canonical first-write evidence, and accepted cleanup restoring the ordinary push workflow. Then integrate #164 from clean steady-state source.
-
#162 — downstream redesign, not an implementation prerequisite. Its access/system and Task/Card redesign slices consume this identity/owner contract after #164 is released; they must preserve rather than reinterpret it.
-
External deployment blockers do not prevent isolated local Stage A/B review, but no #164 source is merged/pushed and no deployed verification is claimed before the explicit Stage C resume condition.
Lifecycle gates
-
Stage A Software Engineer implementation in an isolated worktree, with no frontend, browser, or deploy-workflow paths
-
Stage A Architect review of identity propagation, owner data, query behavior, Task/Card transaction interaction, and authorization boundaries
-
Stage A Tester PASS and PM ACCEPTED; explicit-path
Refs #164checkpoint commit held offmain -
#161 and #180 Tester/PM accepted before Stage B starts
-
Stage B frontend and real-browser implementation on the held branch
-
Designer PASS on the exact issue-scoped desktop/mobile evidence
-
Combined Tester PASS with API/browser/security/accessibility/source-SAM evidence
-
Combined PM ACCEPTED for own/peer/admin operator journeys
-
#166/#182 Phase D, production evidence, and accepted cleanup complete; ordinary push deploy restored
-
Accepted #164 changes reconstructed or rebased on clean steady-state
main, reverified, and committed withCloses #164 -
Orchestrator local merge and push
-
On-Call normal source CI/CD result
Out of scope
-
External avatar providers, image upload/storage, profile editing, presence, chat, comments, mentions, notifications, teams/groups, invitations, organization/workspace membership, or more roles/ACL dimensions.
-
Broad #162 navigation/visual redesign, changes to #161 queue prioritization, a second shell/router/frontend, framework migration, alternate routes, or a legacy bundle API.
-
Identity impersonation; teammate reassignment/deletion; peer account/role/approval/administration; implicit ownership claims; ownership inference/backfill from text; or silent reassignment of unassigned/stale records. Ordinary teammate-Task execution with real actor attribution is explicitly in scope.
-
Changes to assistant, artifact, sponsor, finance, bookkeeping, newsletter, calendar, mailing-export, Docs knowledge, Git, or external provider behavior.
-
Raw SOPs, private operational content, real people/emails, private images/links, production identifiers, credentials-adjacent setup, generated artifacts, or edits to source repos/private knowledge/AWS infra.
-
Manual deploy, workflow dispatch/rerun, AWS/IAM/CloudFormation mutation, external account/provider call, production write, or destructive migration.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the accepted #179/#168 source and the Stage A contract; inspect the shared actor and the /api/me, /api/team-members, /api/tasks, and /api/cards entry points. Run the focused tests under backend/tests for both /api and /work/api. Done means safe projections, owner filters, and enforced execution-versus-administration permissions pass without frontend or deployment changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, authorization, backend, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100