Skip to content

PRD โ€” Time Reporting: model + UX update โ€‹

Status: Draft for Anton's review Author: Eric L Date: 8 June 2026 (v2 โ€” incorporating WBS proposal alignment) Decision needed by: Sprint planning, week 24


Summary โ€‹

The current Time Reporting work (VUL-319 + VUL-734 + VUL-896) spans three distinct purposes that are not currently distinguished in the backlog. This blurs ownership, makes stories ambiguous, and risks reimplementation across teams.

This PRD reframes the work around three layers, each with a clear owner, consumer, and boundary. It then proposes an eleven-entity data model anchored on a unified Resource registry, a deterministic rule engine, and a complete mobile + desktop UX โ€” all mapped to the right layer.

One sentence: A single Time Reporting service (Layer 1) derives cost, payroll, and billable streams from one raw shift; company-level workflows (Layer 2) and project-level views (Layer 3) consume the service through one API. No duplicated logic.

WBS alignment (v2 update): This PRD is now aligned with the parallel wbs-proposal.md. Labour CostLines under the project-side WBS materialise from the time service's engine output (write-through on clock-out). The two efforts share twelve resolved decisions (D1โ€“D12, see ยง Alignment with WBS proposal below). The Personnel entity from v1 has been replaced by a unified Resource entity in coresetup, used by planning, time, quotation, and project execution.


Layer 1 โ€” Time Reporting Service (technical foundation) โ€‹

The standalone microservice that owns the data, the registries, and the engine. Already partially specified in VUL-896.

What lives here โ€‹

CapabilityDescription
Raw time entries (TimeEntry)Polymorphic โ€” entity_type + entity_id lets entries reference work_package, work_order, absence, or future consumers. From VUL-896.
Registries (time-specific)SalaryType, Ruleset
Rule EngineDeterministic split of a raw shift into SalaryType segments per the Resource's Ruleset. Materialises labour CostLines on the project side (write-through on clock-out, D5).
Derivation APIReads registries + engine output, produces three streams: cost rows, payroll rows, billable rows. Snapshot rule (D3): materialised values are immutable; registry changes only affect new entries unless an admin explicitly re-derives.
Work Schedule TemplateContracted-hours baseline per Resource โ€” feeds variance detection.
Variance logAppend-only daily variance records (actual vs. contracted).

What doesn't live here (but L1 depends on) โ€‹

CapabilityWhere it livesL1 dependency
Resource registry (Resource, ResourceType, ResourceSubtype)Coresetup (D2)L1 reads Resource for clock-in identity + cost lookup. Shared with planning, quotation, project execution.
User โ†’ Resource linkCoresetup (User entity)L1 reads User.resource_id to resolve session identity โ†’ Resource โ†’ defaults for mobile clock-in.
AgreementContracts serviceL1 reads agreements to drive billable routing through Article.
Article + Subtype bindingCoresetup (Article register)L1 reads articles to route billable rows. New field Article.subtype_id binds time articles to a Subtype.
Project WorkPackage and CostLineProjects service (per wbs-proposal.md)L1 writes labour CostLines into the project WBS on clock-out (D4, D5).

Why a standalone service โ€‹

VUL-896 already states the why, summarised:

  • Work Order microservice + existing Work Package consumer need the same time data
  • Absence entries have no parent entity โ€” breaks any embedded-in-Projects model
  • Payroll, invoicing, cost control, dashboards all need one consistent source of truth
  • Cost of extraction now (no time data exists in active records) โ‰ˆ zero. Cost later โ‰ˆ high.

Layer 1 stories โ€‹

StoryNew / ExistingNotes
VUL-896 Time Reporting service extractionExistingAnchor โ€” establishes the service boundary
VUL-350 Raw Time Block (TimeEntry)RewriteReplace total_hours / billable_hours decimal model with start/end/break/appointed_subtype + polymorphic entity reference (entity_type=work_package per D6)
VUL-854 Work Schedule TemplateExisting โ€” keepBaseline source for variance
VUL-352 Variance DetectionExisting โ€” keepL1 capability, surfaced in L2
Resource registry (coresetup)NewResource + ResourceType (system, D9: LABOR/EQUIPMENT/MATERIAL/SUBCONTRACTOR/SERVICE/OTHER) + ResourceSubtype (tenant, with preset library). User gets nullable resource_id FK. Cross-service: planning + quotation + projects + time all read from here.
SalaryType + Ruleset registriesNewTier multipliers + locale-aware salary codes; rule groups (Overtime, Weekend, Normal in MVP). Lives in the time service.
Rule Engine + derivation + CostLine materialisationNewThe 1โ†’N derivation logic; reads registries + Agreement + Article binding; writes labour CostLines under the project WBS with snapshot fields (D3); materialises on clock-out (D5).
Agreement registry + resolution chainNewLives in contracts service, not time service. Project โ†’ Contract โ†’ Framework โ†’ Company default.
Article โ†” Subtype bindingNewSchema change in coresetup. Adds subtype_id to Article (nullable, backwards-compatible).
ResourceSubtype preset library (sv-SE + nl-NL)NewSeed catalogue of craftsman trades + equipment classes per market. Onboarding tick-list. Versioned so Rise can update presets without overwriting customer customisations.

Layer 2 โ€” Company-level UX (HR / payroll surface) โ€‹

The pan-company workflows: attestation, variance review, registry configuration, salary export. Cross-employee, cross-project. Owned by the payroll / HR admin role.

What lives here โ€‹

CapabilityDescription
Payroll attestation workbenchPeriod-level bulk attest per Resource; variance pills surface exceptions; ready-to-export preview
Variance reviewDrill-down per Resource into days under/over schedule
Registry configAdmin UI for SalaryType, ResourceSubtype, Ruleset, Agreement, Resource competencies
Salary exportGenerates per-employee ร— date ร— salary code rows to Fortnox (SE) / Exact Online / Nmbrs (NL)
Billable feedEmits T&M billable rows for invoicing consumers

Layer 2 stories โ€‹

StoryNew / ExistingNotes
VUL-353 Payroll & invoicing exportRewriteAdd canonical schema. Pulls from L1 derivation API.
VUL-351 Approval workflowTrimSingle-step PM approval, weekly bulk
Payroll attestation workbenchNewThe desktop workbench drawn in time-views.html
Billable feed to invoice draftNewSplit from VUL-353; routes billable rows to T&M invoice drafts

Layer 3 โ€” Project-level UX (PM / field worker surface) โ€‹

The user-facing surfaces where time and materials are logged and where projects consume the data. Owned by Anton + frontend.

What lives here โ€‹

CapabilityDescription
Mobile clock-in/outThree reporting patterns (pre-select, skip + allocate, switch mid-shift) + end-of-day confirmation with draggable timeline. See eric-time-reporting-complete.html.
Mobile material loggingAlready covered by VUL-855 + VUL-764 + VUL-752 โ€” needs reconciliation with the new time model
PM Labor cost & billable viewProject-level desktop view โ€” hours, cost, billable, margin per Resource + activity. See time-views.html.
T&M invoice draftPulls billable rows from L2 feed, presents as draft lines
My WeekEric's personal mobile dashboard โ€” articles produced, no prices
AI NL time entryVoice / text โ†’ raw time block, engine handles the rest

Layer 3 stories โ€‹

StoryNew / ExistingNotes
VUL-773 AI NL time entryReworkProduces raw entries; engine derives the split. No more pre-computed allocations.
VUL-855 Combined T&M entry pointDescription update in VUL-734Time section writes through L1's Raw Time Block API instead of its own decimal model
Mobile time reporting flowNewClock-in/out + 3 patterns + end-of-day allocation. Single sprint.
PM Labor cost & billable viewNewDesktop view from the dashboard mockup
My Week โ€” articles viewNewPersonal week view, articles only, no prices
VUL-355 Time AnalyticsDefer to FullTag full
VUL-852 My Day suggestionsDefer to FullTag full
VUL-853 My Day AI layerDefer to FullTag full
VUL-851 Spike: event storageExisting โ€” keepPedro's go/no-go

The data model โ€‹

Eleven entities. Resource-centred: one row per physical thing (person, machine, material lot), shared across services.

EntityLayer / ServiceRole
UserAuth โ€” coresetupLogin identity. New nullable FK resource_id bridges auth session โ†’ Resource. Worker users have it set; admins/portal users null.
ResourceCoresetupThe unified registry. One row per physical thing. Replaces the previous Personnel. Carries type + subtype + (LABOR-only) hourly_cost, ruleset, competencies.
ResourceTypeCoresetup โ€” system-definedLevel 1 classification. ~5โ€“6 fixed values: LABOR, EQUIPMENT, MATERIAL, SUBCONTRACTOR, SERVICE, OTHER. No admin CRUD.
ResourceSubtypeCoresetup โ€” tenant-definedLevel 2 classification. Plumber, Electrician, Excavator 14โ€“18T, Concrete, etc. Rise ships a preset library per market; companies extend freely.
SalaryTypeTime serviceTier register (NORMAL, OB1, OB2, OT). Multiplier drives cost; salary_code drives payroll export per locale.
RulesetTime serviceRules turning a raw shift into SalaryType segments. Assigned per Resource (LABOR only).
TimeEntryTime service (VUL-896)Polymorphic raw shift. entity_type + entity_id lets entries reference work_package, work_order, absence.
WorkScheduleTime service (VUL-854)Contracted-hours template per Resource. Feeds variance.
VarianceLogTime service (VUL-352)Append-only daily variance. Surfaced in Attestation + Variance review.
AgreementContracts serviceBilling rules + price overrides + validity. Resolution chain: Project โ†’ Contract โ†’ Framework โ†’ Company default.
ArticleCoresetupCatalog item with default_billable_rate and new subtype_id field binding time articles to a ResourceSubtype.

Entity-relationship diagram โ€‹

The eleven entities and their references, grouped by owning service. CostLine is shown only as the engine's write-through target โ€” it is owned by the projects service (per wbs-proposal.md), not the time service.

mermaid
erDiagram
    %% โ”€โ”€โ”€ Coresetup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    User |o--o| Resource : "resource_id (worker bridge, nullable)"
    ResourceType ||--o{ ResourceSubtype : "type_id"
    ResourceType ||--o{ Resource : "type_id"
    ResourceSubtype ||--o{ Resource : "subtype_id"
    ResourceSubtype }o--o{ Resource : "competencies (M:N, LABOR)"
    ResourceSubtype |o--o{ Article : "subtype_id (binds time article)"

    %% โ”€โ”€โ”€ Time service โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    Ruleset |o--o{ Resource : "ruleset_id (LABOR only)"
    Ruleset }o--o{ SalaryType : "splits a shift into tier segments"
    Resource ||--o{ TimeEntry : "resource_id"
    ResourceSubtype |o--o{ TimeEntry : "appointed_subtype_id"
    Resource ||--o{ WorkSchedule : "contracted hours"
    Resource ||--o{ VarianceLog : "actual vs contracted"
    WorkSchedule ||--o{ VarianceLog : "baseline"

    %% โ”€โ”€โ”€ Contracts service โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    Agreement }o--o{ Article : "billing rule -> article (+ price override)"

    %% โ”€โ”€โ”€ Engine output โ€” projects service (external) โ”€โ”€โ”€
    TimeEntry ||--o{ CostLine : "materialised on clock-out (D4, D5)"
    SalaryType ||--o{ CostLine : "tier (labour)"
    Article ||--o{ CostLine : "billable line (labour)"

    User {
        Guid id PK
        Guid resource_id FK "nullable โ€” worker users only"
        string email
    }
    Resource {
        Guid id PK
        Guid type_id FK "to ResourceType"
        Guid subtype_id FK "to ResourceSubtype"
        Guid ruleset_id FK "to Ruleset โ€” LABOR only, nullable"
        string number
        string name
        decimal hourly_cost "LABOR only, nullable"
        enum status "active|archived"
    }
    ResourceType {
        Guid id PK
        enum code "LABOR|EQUIPMENT|MATERIAL|SUBCONTRACTOR|SERVICE|OTHER"
        string name
        int sort_order
    }
    ResourceSubtype {
        Guid id PK
        Guid type_id FK "to ResourceType"
        string name
        string preset_key "nullable โ€” preset origin"
        decimal default_hourly_cost "nullable"
        decimal default_billable_rate "nullable"
        enum status "active|archived"
    }
    SalaryType {
        Guid id PK
        string code "NORMAL|OB1|OB2|OT"
        decimal multiplier "drives cost"
        string salary_code "per locale โ€” drives payroll"
    }
    Ruleset {
        Guid id PK
        string name
        json rules "shift to SalaryType segments"
    }
    TimeEntry {
        Guid id PK
        Guid resource_id FK "to Resource"
        Guid appointed_subtype_id FK "to ResourceSubtype, nullable"
        string entity_type "work_package|work_order|absence"
        Guid entity_id "polymorphic โ€” null for absence"
        timestamp start_time
        timestamp end_time
        int break_minutes
        enum status "draft|submitted|approved"
    }
    WorkSchedule {
        Guid id PK
        Guid resource_id FK "to Resource"
        decimal contracted_hours
        string period
    }
    VarianceLog {
        Guid id PK
        Guid resource_id FK "to Resource"
        date date
        decimal actual_hours
        decimal contracted_hours
        decimal variance
    }
    Agreement {
        Guid id PK
        string scope "Project|Contract|Framework|Company"
        json billing_rules "subtype + tier to article + override"
        date valid_from
        date valid_to
    }
    Article {
        Guid id PK
        Guid subtype_id FK "to ResourceSubtype, nullable (new)"
        string code
        decimal default_billable_rate
    }
    CostLine {
        Guid id PK
        Guid work_package_id FK "projects service โ€” external"
        enum cost_kind
        Guid resource_ref FK "to Resource"
        Guid time_entry_ref FK "to TimeEntry (labour)"
    }

Cost resolution โ€‹

Cost per segment = (Resource.hourly_cost ?? Subtype.default_hourly_cost) ร— SalaryType.multiplier

Payroll resolution โ€‹

Payroll row = SalaryType.salary_code_{locale} ร— hours per segment

Billable resolution โ€‹

For each segment (per appointed_subtype + salary_type tier):
  Find matching BillingRule in resolved Agreement
  Route segment to bound Article (via Article.subtype_id)
  Apply Agreement's price override or Article's default_billable_rate
  Materialise as Labour CostLine under the project's WorkPackage (D4, D5)

Snapshot rule (D3) โ€‹

When a labour CostLine is materialised, the engine writes both the FK references AND a snapshot of the resolved values at that moment (snapCostRate, snapMultiplier, snapSellingRate). The engine never silently rewrites historical CostLines. Changes to Resource.hourly_cost, Article.default_billable_rate, or Agreement.billing_rules only affect CostLines materialised after the change. An admin can explicitly trigger "Recompute since date X" โ€” confirmation-gated. This prevents a typo correction from retroactively changing last quarter's invoiced revenue.


Alignment with WBS proposal โ€‹

The parallel wbs-proposal.md defines the project-execution WBS (Project โ†’ WorkPackage โ†’ CostLine) that materialised labour rows land in. Twelve decisions (D1โ€“D12) reconcile the two efforts:

#DecisionResolution
D1Typed sub-lines vs flat CostLineFlat โ€” CostLine carries all type-specific fields conditional on costKind; there are no separate per-kind sub-line entities.
D2Where Resource livescoresetup โ€” shared registry.
D3hourlyRate modellingDrop the single hourlyRate ref. Replace with appointedSubtypeRef + salaryTypeRef + articleRef. Engine writes snapshot values. Never updates reported data unless prompted.
D4Bridge from TimeEntry to CostLineBack-reference โ€” each materialised labour CostLine carries timeEntryRef. Mirrors how material CostLines carry purchaseOrderReferences[]. Full audit trail.
D5When engine writesWrite-through on clock-out (status=submitted). Lines remain editable until PM approves the week.
D6TimeEntry.entity_type valueResolved: work_package. WorkOrder is a separate execution entity, not a node inside the WBS.
D7Two entry flowsBoth supported. Time-first (mobile clock-in โ†’ TimeEntry โ†’ engine โ†’ CostLine) for SE small-contractor reality. Work-first (PM pre-fills concept CostLines โ†’ mechanic fills date+employee) for NL formal-execution. Same data outcome.
D8Concept labour CostLinesYes, they exist. PM can plan "8h of Electrician work" before any clock-in. Realised lines link to concept via originCalcLine. Enables planned-vs-actual at line level.
D9costKind enum valueslabour, material, subcontracting, equipment, service, other โ€” both service (predictable outsourced) and other (truly uncategorisable).
D10TimeEntry vs RawTimeEntry namingTimeEntry โ€” matches the WBS proposal's existing diagrams. "Raw" prefix was only meaningful when there were derived sibling tables, which there aren't.
D11Fixed-price WorkPackagesEngine still derives billable rows for fixed-price, controlled by company-level toggle derive_billable_on_fixed (default ON). Lines are informational for fixed price; the WorkPackage's fixed sellingPriceTotals drives the invoice.
D12priceDetermination simplificationAccept WBS proposal as-is for MVP (Fixed price / T&M / warranty / additional). Optional suggestion: simplify to Fixed / Billable + flags for warranty / additional / T&M-with-cap. Defer to WBS implementation team.

These decisions resolve all alignment open questions between this PRD and the WBS proposal. The WBS proposal has been updated to reference them inline.


What the field worker actually sees โ€‹

The whole point of the architecture is to push complexity into one-time setup and keep daily reporting near-trivial.

Eric's normal workday โ€” 4 taps. Clock in (1) โ†’ optional appointed-subtype override (1) โ†’ clock out (1) โ†’ submit (1). Everything else comes from setup or context. See eric-time-reporting-complete.html for the full UX walkthrough.

The model never appears in his UI. He doesn't see OB1, OB2, salary codes, billable rates, or agreements. He sees: project, activity, hours. The engine handles the rest.


MVP / Full split โ€‹

MVP โ€” what must ship for SE pilot (week 26):

  • All Layer 1 stories
  • All Layer 2 stories
  • Mobile time reporting flow (Layer 3)
  • PM Labor view (Layer 3)
  • My Week (Layer 3)
  • VUL-855 description update
  • 5 existing rewrites + 3 keeps

Full โ€” deferred, tagged full:

  • VUL-355 Time analytics
  • VUL-852 / VUL-853 My Day + My Day AI
  • Special Rules group (holidays) โ€” acceptance criterion on Rule Engine story
  • Night Work group โ€” acceptance criterion on Rule Engine story
  • Per-Article billable tier overrides โ€” acceptance criterion on Agreement story
  • Per-diem and km automation โ€” acceptance criterion on Mobile flow story

The model accommodates all Full-tier items without migration.


Changes to existing epics โ€‹

VUL-319 (Time Reporting) โ€” scope expands and reorganises โ€‹

Scope today: registration / approval / integration with billability derived from contract compensation form. Largely Layer 3-flavoured but with backend mixed in.

Scope proposed: the whole three-layer effort. The epic description gets rewritten to reflect L1 / L2 / L3 explicitly and to anchor VUL-896 inside it.

Stories disposition:

  • 5 rewrites (VUL-319, 350, 351, 353, 773)
  • 3 keeps (VUL-352, 854, 851)
  • 3 defers (VUL-355, 852, 853)
  • 10 new (5 L1 incl. Resource registry + preset library, 2 L2, 3 L3)
  • VUL-896 anchored as the L1 parent

VUL-734 (Material & Cost Reporting) โ€” one story description updated โ€‹

Only one change: VUL-855's time section description updated to write through L1's TimeEntry API instead of its own total_hours / billable_hours model. The engine materialises labour CostLine under the project's WorkPackage (per WBS proposal alignment, D4 + D5). VUL-734's overall scope is unchanged.

Project execution WBS โ€” coordinated, not blocked โ€‹

The wbs-proposal.md initiative defines the project-execution WBS that consumes labour from this PRD. The two efforts are aligned via D1โ€“D12 (see ยง Alignment with WBS proposal). No backlog changes triggered in projects-side epics by this PRD โ€” but the WBS proposal team needs to adopt D1:B (collapsed sub-lines) and D3:A (drop hourlyRate ref) before their implementation lands.


Decisions Anton needs to make โ€‹

Most of the v1 decisions are resolved by D1โ€“D12 (see ยง Alignment with WBS proposal). Three remain open for Anton:

  1. Mobile flow story scope โ€” bundle 3 patterns + end-of-day allocation + tier preview into one story (proposed), or split? My estimate: one sprint with a stretch goal.

  2. Layer 2 attestation workbench scope โ€” one story for workbench + variance review, or split? Proposed: one story; variance review is a tab inside the workbench.

  3. D12 priceDetermination simplification โ€” adopt the WBS proposal's enum as-is (Fixed price | T&M | warranty | additional), or push the optional simplification (Fixed | Billable + flags)? Proposed: accept as-is for MVP, flag the simplification as a future cleanup. The decision affects how Layer 2 / Layer 3 read WorkPackage.priceDetermination.

Decisions for Pedro (backend lead) โ€‹

Most resolved by D1โ€“D12. Two remain:

  1. VUL-896 story tree โ€” does VUL-896 swallow the registries + engine as part of its own scope, or are they sibling stories that depend on VUL-896? Proposed: siblings. VUL-896 = service extraction + polymorphic TimeEntry; new stories = registries + engine + CostLine materialisation. Cleaner story-level estimates.

  2. Article-Subtype binding sequencing โ€” adding subtype_id to Article is a coresetup schema change. Confirm with Mladjan / Filip nothing in VUL-660 (Quote Canvas import) collides. 5-minute Slack check; blocking if it surfaces a conflict.

Joint decisions (Eric + Pedro + WBS proposal author) โ€‹

These are not blocking but benefit from a sync before either initiative goes final:

  1. D1:B sign-off โ€” โœ… signed off (WBS author, June 2026). The WBS proposal now documents the flat CostLine shape (collapsed sub-lines, no labour sub-line) as the migration target. Both documents are aligned.

  2. entity_type naming (D6) โ€” โœ… resolved: work_package (aligned with the WBS proposal's WorkPackage naming).

  3. D11 toggle scope โ€” derive_billable_on_fixed company-level toggle: confirm default behaviour and admin UI placement.


Risks โ€‹

RiskLikelihoodMitigation
Model rewrite blocks Quote Canvas integrationMedium1-hour design review with Pedro + Mladjan before merging the Article-Subtype binding story
Mobile flow scope creep into Full tierHighAcceptance criteria explicitly mark MVP vs Full; stretch goals separate
Fortnox payroll schema rejects tiered rowsLowSchema spike before Layer 2 development; fallback to flattening at export
WBS proposal author rejects D1:B (collapsed sub-lines)โœ… ResolvedD1:B signed off by the WBS author (June 2026); both documents are aligned on the flat CostLine. Risk closed โ€” no fallback to D1:A needed.
Engine snapshot rule (D3) misunderstood as cachingLowDocument explicitly that snapshots are immutable values, not cache; admin "Recompute since X" is the only re-derive path
Service extraction (VUL-896) creates cross-team couplingMediumAll consumers go through one API; no internal database access. Standard microservice discipline.

Backlog impact โ€‹

BeforeAfter
VUL-319: 10 storiesVUL-319: ~18 stories (12 active MVP + 3 deferred Full + cross-layer additions)
VUL-734: 5 storiesVUL-734: 5 stories (only VUL-855 description updated)
VUL-896 floating in backlogVUL-896 anchored as L1 parent in VUL-319
Net+8 stories, but with clear layer ownership and no duplication risk

The +8 buys: working OB/OT splits, accurate payroll export, working T&M billable feed, three-pattern mobile UX, PM + payroll desktop views, AND clean service architecture that doesn't have to be undone later.


What I want from this PRD โ€‹

  1. Anton's sign-off on the L2 / L3 stories and the VUL-855 reconciliation
  2. Pedro's sign-off on the L1 story tree and Agreement / Article-Subtype boundaries
  3. A 30-minute three-person sync (Eric + Anton + Pedro) before sprint planning to nail down the ordering and the cross-service questions
  4. Commitment to ship MVP for week 26 SE pilot

Reference โ€‹

  • Companion document: wbs-proposal.md โ€” project execution WBS, consumer of labour CostLines materialised by this PRD's engine
  • Architecture map: time-reporting-architecture.html โ€” L1 / L2 / L3 overview with artifact linkage
  • Data & schema: time-reporting-data-flow.html โ€” eleven entities, schema diagram, Eric's shift walkthrough, view โ†’ data matrix
  • Design artifact: eric-time-reporting-complete.html โ€” full consolidated UX
  • Desktop views: time-views.html โ€” PM Labor view (L3) + Payroll attestation workbench (L2)
  • Rule engine specification: Confluence Rule engine-driven time reporting
  • Existing Jira: VUL-319, VUL-350, VUL-351, VUL-352, VUL-353, VUL-355, VUL-734, VUL-751, VUL-752, VUL-764, VUL-773, VUL-851, VUL-852, VUL-853, VUL-854, VUL-855, VUL-896

Built with VitePress | v1.2.0 | ๐Ÿš€ Week One Sprint