mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
12 KiB
12 KiB
Feature Plan: Occurrence Detail Page (now_ls)
1️⃣ Assumptions & Scope
- The current
/occurrenceexperience is backed byCrossSearchTableand reusesLocalityDetailsfor detail routing (/occurrence/:id), so this feature introduces a dedicated Occurrence detail view instead of locality detail reuse. - Occurrence identity must be composite (
lid+species_id) becausenow_lshas no primary key; we will not change DB schema or add migrations. - Backend and frontend contracts should remain additive and backward compatible; existing Locality/Species detail pages and list/table flows must continue to work.
- Required tabs should map to meaningful
now_lscolumns/groups, and an Updates tab should be present as a placeholder shell only (no update-log implementation yet), matching existing tab UX patterns. - Linking behavior from occurrence listings should open the new Occurrence detail route using
lid+species_idkey, while preserving existing table filter/sort/pagination query params for return navigation. - Authorization model remains unchanged: read access follows current authenticated behavior; edit affordances follow existing role checks (Admin/EditUnrestricted/EditRestricted) already used around detail pages.
- No database structure changes, no Prisma migration files, and no table/model renames.
2️⃣ High-Level Plan
-
Occurrence identity and routing design
- Define a stable URL shape for composite keys (e.g.
/occurrence/:lid/:speciesId), and retain list URL compatibility (/occurrence?...). - Update route wiring so occurrence detail resolves to a new Occurrence detail component instead of
LocalityDetails.
- Define a stable URL shape for composite keys (e.g.
-
Backend read endpoint for one occurrence (composite key)
- Add/extend an endpoint to fetch one
now_lsrow bylid+species_idwith required joins (species/locality context fields needed for header + tabs). - Reuse existing services/query utilities where possible to stay DRY and avoid duplicated SQL mapping.
- Add/extend an endpoint to fetch one
-
Frontend data model + API client wiring
- Add shared/frontend type(s) for occurrence detail payload shaped around
now_ls+ related display fields. - Add query hook/client call for fetching one occurrence by composite key.
- Add shared/frontend type(s) for occurrence detail payload shaped around
-
Build Occurrence detail feature component (DRY with existing DetailView patterns)
- Create
OccurrenceDetailscomponent mirroring Locality/Species detail architecture (DetailView, tab config array, validator wiring). - Group tabs by
now_lsdomain columns (e.g., core occurrence info, microwear/mesowear, measurements/notes as available in schema). - Add Updates tab placeholder using standard tab container/panel only, no data implementation yet.
- Create
-
Linking from occurrence list to detail
- Ensure row actions/links in occurrence table navigate with composite key (
lid,species_id) rather than locality-only id. - Preserve table query state (
columnfilters,sorting,pagination) in return navigation state.
- Ensure row actions/links in occurrence table navigate with composite key (
-
Permissions + UX parity
- Keep edit/delete capability checks consistent with existing role policy; if detail is read-only initially, explicitly disable write actions.
- Keep tab deep-linking behavior (
?tab=n) consistent withuseSyncTabSearchand existing detail pages.
-
Validation, testing, docs
- Add/adjust backend integration tests for composite-key fetch and error paths.
- Add frontend tests for route parsing, tab rendering (including Updates placeholder), and occurrence row-to-detail navigation.
- Update docs/changelog notes for new occurrence detail page and composite key route contract.
3️⃣ Tasks (JSON)
[
{
"id": "T1",
"title": "Define composite-key occurrence route and page wiring",
"summary": "Introduce occurrence detail routing that accepts lid + species_id and maps to a dedicated OccurrenceDetails component instead of LocalityDetails.",
"app": "frontend",
"files_touched": [
"frontend/src/router/index.tsx",
"frontend/src/components/pages.tsx",
"frontend/src/components/Page.tsx"
],
"migrations": false,
"permissions": [
"Accessible to logged-in users who can view occurrence list",
"No role escalation; existing page-level role checks remain intact"
],
"acceptance_criteria": [
"Navigating to /occurrence/<lid>/<species_id> opens Occurrence detail page",
"Navigating to /occurrence?columnfilters=[]&sorting=[]&pagination={...} still opens occurrence list",
"Legacy /occurrence/<id> behavior is either redirected safely or handled explicitly"
],
"test_plan": [
"Add router-level test for occurrence composite route",
"Add regression test for occurrence list route query parsing"
],
"estimate_hours": 2.0,
"priority": "high"
},
{
"id": "T2",
"title": "Add backend occurrence-detail read endpoint by lid + species_id",
"summary": "Implement composite-key lookup for a single now_ls occurrence with required joins/shape for detail tabs and header metadata.",
"app": "backend",
"files_touched": [
"backend/src/routes/occurrence.ts",
"backend/src/controllers/occurrenceController.ts",
"backend/src/services/occurrenceService.ts",
"backend/src/services/queries/crossSearchQuery.ts"
],
"migrations": false,
"permissions": [
"Available to authorized readers under existing auth middleware",
"Write permissions unchanged (no new mutation endpoint)"
],
"acceptance_criteria": [
"GET endpoint returns one occurrence by exact lid + species_id",
"Missing pair returns 404 with structured error payload",
"Invalid keys return 400 with validation message"
],
"test_plan": [
"Add backend integration tests for success/404/400 cases",
"Add unit tests for service query parameter handling"
],
"estimate_hours": 3.5,
"priority": "high"
},
{
"id": "T3",
"title": "Create occurrence detail types and data hook",
"summary": "Add shared/frontend types and query hook/API client for composite-key occurrence detail retrieval.",
"app": "frontend",
"files_touched": [
"frontend/src/shared/types/data.ts",
"frontend/src/redux/services/api.ts",
"frontend/src/hooks/**"
],
"migrations": false,
"permissions": [
"Read-only data retrieval inherits existing auth token handling"
],
"acceptance_criteria": [
"Hook accepts lid + species_id and returns typed detail payload",
"Loading/error states align with existing detail pages"
],
"test_plan": [
"Add hook/API tests for correct URL and response mapping",
"Type-check verifies no implicit any in detail payload usage"
],
"estimate_hours": 2.0,
"priority": "high"
},
{
"id": "T4",
"title": "Implement OccurrenceDetails with now_ls-based tabs and Updates placeholder",
"summary": "Build dedicated detail UI using shared DetailView primitives; include required tabs from now_ls columns and a standard placeholder Updates tab (no updates logic yet).",
"app": "frontend",
"files_touched": [
"frontend/src/components/Occurrence/OccurrenceDetails.tsx",
"frontend/src/components/Occurrence/Tabs/*.tsx",
"frontend/src/components/DetailView/common/UpdateTab.tsx"
],
"migrations": false,
"permissions": [
"Edit controls shown only for roles already allowed by policy",
"If mutations are not implemented, controls remain disabled/hidden"
],
"acceptance_criteria": [
"Detail page renders tab set derived from now_ls fields",
"Updates tab is visible and clearly marked placeholder",
"Tab deep-linking works via ?tab=<index>"
],
"test_plan": [
"Add component tests for tab labels/content and placeholder tab",
"Add test for out-of-range tab param fallback behavior"
],
"estimate_hours": 4.0,
"priority": "high"
},
{
"id": "T5",
"title": "Wire occurrence table row navigation to composite-key detail",
"summary": "Update occurrence list row action/linking so each row opens its specific occurrence detail using lid + species_id key.",
"app": "frontend",
"files_touched": [
"frontend/src/components/CrossSearch/CrossSearchTable.tsx",
"frontend/src/components/TableView/TableView.tsx",
"frontend/src/hooks/useReturnNavigation.ts"
],
"migrations": false,
"permissions": [
"Row visibility restrictions remain unchanged",
"Navigation does not bypass protected routes"
],
"acceptance_criteria": [
"Clicking an occurrence row opens /occurrence/<lid>/<species_id>",
"Return button restores prior list URL including filter/sort/pagination query",
"No regression in locality/species table row navigation"
],
"test_plan": [
"Add frontend tests asserting navigation target path composition",
"Regression tests for return navigation stack behavior"
],
"estimate_hours": 2.5,
"priority": "high"
},
{
"id": "T6",
"title": "Quality gate, docs, and rollout safeguards",
"summary": "Run lint/type/tests, document route contract and placeholder status, and ensure feature is safely reviewable/deployable.",
"app": "fullstack",
"files_touched": [
"README.md",
"frontend/docs/routing.md",
"frontend/tests/**",
"backend/src/api-tests/**"
],
"migrations": false,
"permissions": [
"Verify role-based UI states for read/edit users"
],
"acceptance_criteria": [
"Lint + type-check pass in affected scopes",
"New/updated tests pass",
"Docs mention composite key route and Updates tab placeholder"
],
"test_plan": [
"npm run lint:frontend && npm run lint:backend",
"npm run tsc:frontend && npm run tsc:backend",
"Run targeted frontend/backend test suites for occurrence detail"
],
"estimate_hours": 2.0,
"priority": "medium"
}
]
4️⃣ Risks & Mitigations
- Auth Failures: New detail route could miss existing guard expectations.
Mitigation: Keep route under existing authenticated shell and add explicit unauthorized tests for restricted edit actions. - Composite Key Ambiguity: Using only
lidcould open wrong record when multiple species share locality.
Mitigation: Enforcelid + species_idin route, API contract, and row navigation helpers. - Performance: Occurrence detail joins may fetch unnecessary fields.
Mitigation: Select only tab-needed columns; defer heavy/related datasets to lazy queries if needed. - Error Handling: Bad URL params may produce opaque failures.
Mitigation: Add input validation and consistent 400/404 JSON errors; render friendly UI fallback. - Security: Query construction risk if custom SQL is touched.
Mitigation: Keep Prisma/parameterized query patterns and avoid string interpolation for user params. - Rollback: Route change could disrupt existing deep links.
Mitigation: Add compatibility redirect/fallback for legacy paths and keep change isolated behind clean commits.
5️⃣ Out of Scope
- Any database schema/table/index/primary-key changes for
now_ls. - Implementing actual Updates tab data loading/editing/audit timeline logic.
- Broad UI redesign beyond adding occurrence detail page and required tabs.
- Refactoring unrelated list/detail pages (Locality, Species, etc.) outside minimal DRY extraction.
- Non-feature performance tuning unrelated to occurrence detail fetch/render.
6️⃣ Definition of Done ✅
- All acceptance criteria in tasks T1–T6 are satisfied.
- Occurrence detail is accessible via composite key route (
lid+species_id). - Required
now_ls-based tabs are implemented and Updates tab placeholder is present. - No DB migrations/schema changes are introduced.
- Unit/integration/frontend route tests for new behavior pass.
- Linting and TypeScript checks pass in affected scopes.
- Role-based read/edit behavior is verified unchanged.
- Documentation is updated with new route contract and placeholder note.