research-document

Time Entry System — Large-View Architecture v0.1

Time Entry System — Large-View Architecture v0.1

Date: 2026-08-14 Status: Initial architecture Purpose: Record the high-level architecture for the first implementation of the time-entry system while preserving a strict separation between presentation, application/domain semantics, infrastructure/services, and persistence.

This document describes HOW the current implementation is organized.

It does not replace the business requirements or the application-specific state model.

Core architectural rule:

WASM owns application meaning. TypeScript and GitHub do not.

A second important rule:

Logical architectural layers do not have to be separate deployment processes.

The service layer may initially run in the browser while remaining architecturally distinct from presentation and domain code.


1. Large-View Architecture

The first implementation has four logical layers:

1. Presentation
   HTML / CSS / minimal TypeScript

2. Application + Domain
   WASM
   application-specific semantic state and behavior

3. Infrastructure / Services
   persistence coordination
   GitHub repository adapter
   synchronization
   authentication boundary
   version / conflict handling

4. Persistence
   GitHub repository
   JSON documents
   Git SHAs / versions
   commit history

High-level flow:

┌─────────────────────────────────────────────┐
│              Browser Application            │
│                                             │
│  HTML / CSS                                 │
│  Minimal TypeScript Kernel                  │
│  WASM Application / Domain Core             │
└──────────────────────┬──────────────────────┘
                       │
                       │ application commands / queries
                       ▼
┌─────────────────────────────────────────────┐
│                Service Layer                │
│                                             │
│  application operations                     │
│  persistence coordination                   │
│  version / conflict handling                │
│  GitHub protocol                            │
│  authentication boundary                    │
└──────────────────────┬──────────────────────┘
                       │
                       │ GitHub API
                       ▼
┌─────────────────────────────────────────────┐
│             GitHub Data Store               │
│                                             │
│  JSON documents                             │
│  Git versions / SHAs                        │
│  commits / history                          │
└─────────────────────────────────────────────┘

2. Layer 1 — Presentation

The presentation layer consists of:

HTML
CSS
minimal TypeScript

The presentation layer is responsible for browser interaction and visual behavior.

It is NOT the authoritative business/domain layer.

Presentation responsibilities

TypeScript may own:

  • DOM event handling;
  • DOM updates;
  • rendering;
  • route/history handling if needed;
  • browser-native fetch;
  • WASM bootstrap;
  • serialization bridge;
  • browser cache;
  • ephemeral UI state.

Examples of acceptable UI-only state:

  • selected day;
  • active tab;
  • open modal;
  • focused control;
  • scroll position;
  • current route;
  • temporary input before submission.

Presentation must NOT own

TypeScript must not independently implement:

  • time-entry lifecycle rules;
  • six-minute invariants;
  • overlap rules;
  • project eligibility rules;
  • split legality;
  • correction legality;
  • totals as an authoritative business calculation;
  • capability derivation;
  • semantic transition validity.

If a business rule exists in WASM/domain code, do not duplicate it in TypeScript.


3. Layer 2 — Application + Domain in WASM

WASM is the semantic center of the application.

This is where application-specific meaning lives.

The domain should be represented directly using application-specific types and operations.

Examples:

TimeEntry
Project
Label
Person

CreateTimeEntry
CorrectTimeEntry
SplitTimeEntry
VoidTimeEntry

Do not implement a generic metadata-driven state engine in place of these concepts.

WASM responsibilities

WASM should own:

  • TimeEntry domain types;
  • Project domain types;
  • Label domain types;
  • Person domain types;
  • TimeEntryStatus;
  • ProjectStatus;
  • six-minute unit representation;
  • domain invariants;
  • transition requirements;
  • split logic;
  • correction logic;
  • void/supersede logic;
  • overlap detection;
  • totals;
  • domain projections;
  • capability derivation;
  • structured domain diagnostics;
  • validation of persistence data into domain types where practical.

WASM should not know GitHub details

The domain/application layer should not depend directly on:

  • GitHub REST URL paths;
  • GitHub repository layout details;
  • GitHub HTTP headers;
  • GitHub token format;
  • GitHub Contents API implementation details.

Conceptually, the domain/application layer should work with service-level operations such as:

LoadWeek
SaveWeek
LoadProjects
SaveProject

rather than:

PUT /repos/.../contents/...

GitHub is an infrastructure implementation detail.


4. Layer 3 — Service / Infrastructure Layer

The service layer coordinates communication between the application/domain and external persistence.

This is a logical architectural layer.

It does not necessarily require a separate server process in v0.1.

Service responsibilities

The service layer owns:

  • loading weekly documents;
  • loading project documents;
  • loading labels;
  • saving weekly documents;
  • saving projects;
  • GitHub API interaction;
  • serialization/deserialization coordination;
  • expected Git SHA / version tracking;
  • optimistic concurrency;
  • conflict detection;
  • write reconciliation;
  • authentication handoff;
  • synchronization state;
  • mapping GitHub failures into meaningful application-facing results.

Example conceptual service operations

LoadWeek(personId, weekStarting)

SaveWeek(
    expectedVersion,
    weeklyDocument
)

LoadProject(projectId)

SaveProject(
    expectedVersion,
    projectDocument
)

These are conceptual application/infrastructure operations.

Their concrete implementation may use GitHub REST APIs.


5. Logical Service Layer vs Physical Server

The service layer does NOT have to be a standalone backend in the first version.

Initial deployment may be:

Browser
    ├── HTML / CSS
    ├── TypeScript kernel
    ├── WASM domain/application
    └── GitHub service adapter
             │
             ▼
           GitHub

This keeps the experiment small.

The service layer remains architecturally distinct even when it executes inside the browser.

Later, authentication or multi-user requirements may justify:

Browser
   │
   ▼
Small Service
   │
   ▼
GitHub

That deployment change should not alter domain meaning.

Important principle:

Service boundary and deployment boundary are not the same thing.


6. Layer 4 — GitHub Persistence

GitHub is the persistent datastore.

GitHub stores:

  • JSON documents;
  • Git object versions / SHAs;
  • commit history;
  • authorship/timestamps from Git operations.

GitHub persistence must not become application meaning.

Persistence flow

GitHub JSON
    ->
service layer
    ->
parse / schema validation
    ->
WASM domain construction
    ->
domain operations
    ->
serialization
    ->
service layer
    ->
GitHub JSON

Raw JSON must not be manipulated as if it is authoritative domain state.


7. Persistence Document Partition

Recommended initial layout:

/data/
    projects/
        <project-id>.json

    labels/
        labels.json

    people/
        <person-id>/
            <year>/
                <month>/
                    <week-start>.json

Example:

/data/people/kevin/2026/08/2026-08-10.json

The week is the natural initial persistence boundary because it aligns with:

  • weekly review;
  • weekly totals;
  • overlap validation;
  • conflict scope;
  • future approval;
  • Git write locality.

8. Versioning and Optimistic Concurrency

The service layer must retain the GitHub file/blob SHA or equivalent version when loading a document.

Saving is conceptually:

SaveWeek(expectedVersion, updatedWeek)

If the remote version has changed:

Conflict

not:

silently overwrite

Last-write-wins is not allowed for semantic data.

The Git SHA acts as an authoritative external version token for persistence concurrency.


9. Unknown Write Outcomes

A network failure after a GitHub write is sent does not prove that the write failed.

The infrastructure layer therefore needs explicit execution state:

Clean
ModifiedLocally
Saving
SaveFailed
SaveOutcomeUnknown
Conflict

Important distinction:

TimeEntryStatus

is domain state.

SyncState

is execution/persistence state.

Do not combine them.

OutcomeUnknown flow

write sent
    ->
response becomes indeterminate
    ->
SaveOutcomeUnknown
    ->
inspect GitHub state
    ->
determine whether intended write exists
    ->
resolve to Clean or ModifiedLocally

Do not blindly resend while the previous operation's outcome is unknown.


10. Conflict Resolution

On Git SHA/version conflict:

1. fetch latest remote state
2. compare with expected base
3. identify semantic differences
4. merge only when explicitly safe
5. otherwise surface conflict

Example potentially mergeable:

local:
    correct description on Entry A

remote:
    add unrelated Entry B

Example semantic conflict:

local:
    split Entry A

remote:
    change Entry A duration

Do not assume a generic JSON merge is semantically safe.


11. Dependency Direction

Preferred conceptual dependency direction:

Presentation
    ↓
Application / Domain
    ↓
Service abstraction
    ↓
GitHub implementation

The domain should not depend upward on:

  • UI concerns;
  • DOM;
  • browser widgets;
  • GitHub API mechanics.

Infrastructure may depend on abstractions exposed by the application/service boundary, not the reverse.


12. Browser/WASM Interaction Pattern

Example:

User clicks Split at 10:00
    ->
TypeScript captures UI event
    ->
TypeScript invokes WASM SplitTimeEntry command
    ->
WASM validates:
    current state
    six-minute boundary
    source duration
    split invariants
    overlap
    provenance
    ->
WASM returns:
    valid updated projection
    OR structured diagnostic
    ->
TypeScript renders result

TypeScript must not independently decide whether 10:00 is a legal split.


13. State Ownership

The architecture intentionally separates state dimensions.

Domain state

Owned by WASM/domain:

TimeEntryStatus
    Recorded
    Voided
    Superseded

ProjectStatus
    Active
    Archived

Execution/synchronization state

Owned by service/infrastructure:

Clean
ModifiedLocally
Saving
SaveFailed
SaveOutcomeUnknown
Conflict

Ephemeral UI state

Owned by TypeScript/presentation:

selected day
active tab
modal open
focus
route
scroll position

Do not create one global application state object containing all three dimensions unless it is merely a projection/composition for rendering.

Authority remains separated.


14. No Duplicate Business Semantics

The same business rule must not be reimplemented in:

WASM
TypeScript
JSON metadata
GitHub adapter

Example:

The rule:

Recorded entries for the same person may not overlap

belongs in the domain/application layer.

TypeScript may display an overlap error, but must not independently establish the authoritative rule.

GitHub persistence must store the result, not independently reinterpret the rule.


15. Minimal Dependencies

Default to no external libraries unless genuinely required.

Prefer:

  • browser-native APIs;
  • standard library;
  • native language/runtime features;
  • explicit code;
  • WASM standard interop.

Do not add:

  • React;
  • Redux;
  • Vue;
  • Angular;
  • generic client state framework;
  • workflow framework;
  • generic state-machine framework

unless a later explicit requirement justifies it.


16. Authentication Boundary

For a trusted single-user experimental version, a narrowly scoped GitHub credential may be used.

The browser architecture must not assume this is the final production authentication model.

If multi-user or broader deployment emerges, the service layer can move behind:

  • GitHub App;
  • OAuth;
  • short-lived credentials;
  • minimal server/token exchange.

This should not require rewriting domain logic.


17. Why This Architecture Is Being Tested

This application is also an architecture experiment.

We are testing whether:

application-specific domain semantics in WASM

combined with:

minimal TypeScript browser mechanics

and:

explicit service/persistence boundaries

produce software that is:

  • easier for AI agents to understand;
  • harder for AI agents to mutate incorrectly;
  • lower in duplicated semantics;
  • simpler to change;
  • safer under concurrent writes;
  • safer under uncertain external outcomes;
  • less dependent on large SPA frameworks.

The experiment should remain small enough that these claims can be evaluated honestly.


18. Architecture Non-Goals

Do not turn the first version into:

  • microservices;
  • distributed service mesh;
  • generic domain framework;
  • generic semantic runtime;
  • generic state engine;
  • event-sourcing platform;
  • generalized workflow engine;
  • large SPA framework;
  • metadata-driven application builder.

The architecture should be only as complicated as required by:

browser
    +
WASM domain/application
    +
service/infrastructure adapter
    +
GitHub JSON persistence

19. Current Large-View Architecture Summary

The system is:

Browser Application
    |
    |-- HTML / CSS
    |
    |-- Minimal TypeScript Kernel
    |       browser events
    |       DOM
    |       rendering
    |       fetch
    |       WASM bridge
    |
    |-- WASM Application / Domain Core
            TimeEntry
            Project
            Label
            Person
            state machines
            transitions
            invariants
            capabilities
            totals
            diagnostics
    |
    v
Service / Infrastructure Layer
    GitHub adapter
    load/save coordination
    optimistic concurrency
    authentication handoff
    synchronization
    conflict detection
    OutcomeUnknown reconciliation
    |
    v
GitHub Data Store
    JSON files
    SHAs / versions
    commits
    history

Final governing principle:

The WASM application/domain layer owns meaning. The TypeScript layer owns browser mechanics. The service layer owns external coordination. GitHub owns durable persistence and history.