mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-14 19:02:22 +02:00
224 lines
14 KiB
Markdown
224 lines
14 KiB
Markdown
# Odysseus frontend architecture handbook
|
|
|
|
Status: F1 foundation and continuation guide, pending review. The final Notes
|
|
reference case study belongs to the comprehensive Notes draft PR; the recipient
|
|
handoff follows its integration. This document must evolve with reviewed internal
|
|
checkpoints and distinguish executed work from proposals.
|
|
|
|
Read the [ADR](ADR-001-source-and-deployment.md), [assessment](assessment.md),
|
|
[validation report](validation.md) and [Notes roadmap](notes-roadmap.md).
|
|
The frontend program ends with the Notes reference decomposition and handoff.
|
|
Calendar, Documents, Email, Chat, Skills, Settings and other later decompositions
|
|
belong to the designated frontend maintainer; do not start them automatically.
|
|
|
|
## Source, ownership and public APIs
|
|
|
|
`frontend/src/app/` composes public feature APIs and platform ports. Each
|
|
`features/<feature>/index.js` is an intentional API, with explicit named exports
|
|
and a compatibility default only when existing consumers require one. Internals
|
|
live under `domain/`, `application/`, `infrastructure/` or `ui/` as needed. Do not
|
|
create empty directories, boilerplate controllers or a framework by convention.
|
|
Feature names `app` and `shared` are reserved.
|
|
|
|
Keep pure business rules in domain; transitions and workflows in application;
|
|
HTTP/storage/browser services in infrastructure; DOM rendering and lifecycle in
|
|
UI. The index composes adapters, state and views. Application receives adapters
|
|
as explicit arguments or constructor ports, rather than importing concrete
|
|
infrastructure. Views call application operations; infrastructure does not own
|
|
business decisions. A public API returns data/operations, not mutable stores or
|
|
private DOM nodes. Importing an API should define capabilities; explicit lifecycle
|
|
methods activate them. Legacy side effects remain characterized until a reviewed
|
|
slice safely changes their placement.
|
|
|
|
Shared code has a named, proven cross-feature responsibility. `shared/domain/`
|
|
holds pure primitives, `shared/platform/` holds narrowly scoped platform adapters,
|
|
and `shared/ui/` holds common DOM capabilities. A named stateless root leaf such
|
|
as `shared/actionMenuOrder.js` is also allowed and receives domain restrictions.
|
|
Do not create a central `utils.js` collection or move feature business rules into
|
|
shared simply to satisfy an import rule.
|
|
|
|
## Mechanically checked dependency contract
|
|
|
|
| Importer | Permitted maintained-source targets |
|
|
| --- | --- |
|
|
| App composition | Other app code, shared code, feature `index.js` APIs |
|
|
| Feature index | Its own responsibility modules and shared code; other feature public indexes |
|
|
| Feature domain | Its own domain and shared domain/stateless leaves |
|
|
| Feature application | Its own application/domain, shared domain, other feature public indexes |
|
|
| Feature infrastructure | Its own infrastructure/domain, shared domain/platform |
|
|
| Feature UI | Its own UI/application/domain, shared domain/platform/UI |
|
|
| Shared domain leaf | Shared domain leaves only |
|
|
| Shared platform | Shared platform/domain only |
|
|
| Shared UI | Shared UI/platform/domain only |
|
|
|
|
No feature imports app composition. No shared code imports a feature. No external
|
|
feature imports private responsibility modules. UI and infrastructure communicate
|
|
with another feature through a supplied application operation/port. Maintained
|
|
source dependency cycles, including literal lazy imports, fail the architecture
|
|
gate. If features need bidirectional coordination, app composition injects a
|
|
callback or adapter instead of creating mutual imports. Prefer this even when a
|
|
one-way public index import would pass the gate.
|
|
|
|
Cross-feature events must document event name, payload, acknowledgement, owner,
|
|
subscription disposal and delivery timing. Keep them local and specific; F1 adds
|
|
no global event bus. Preserve `odysseus:notes-context-selected` and its synchronous
|
|
`accepted` acknowledgement in future Notes work. The server remains authoritative
|
|
for owner filtering and untrusted selected IDs. Frontend APIs cannot grant access.
|
|
|
|
The checker parses executable ESM, forbids computed imports in new source,
|
|
requires exact precache entries, rejects unresolved/remapped relative imports,
|
|
and permits only canonical static JS URLs with one unversioned identity for
|
|
maintained modules. Domain code cannot mention known browser/HTTP/timer globals
|
|
or an ambient clock; use `now`/clock inputs. This is a conservative vocabulary
|
|
check, including shadowed names, not a semantic purity proof. Randomness, hidden
|
|
side effects, authorization and lifecycle behavior require behavioral tests.
|
|
|
|
Legacy imports from new source default to forbidden. If an incremental bridge is
|
|
necessary, declare `legacyImports` on that source's manifest entry as a list of
|
|
`{ "specifier": "/static/js/example.js?v=existing", "reason": "contract, owner and removal slice" }`.
|
|
Only feature composition, infrastructure or UI boundaries may use it. Exact
|
|
specifier/reason and target existence are required; unused exceptions fail.
|
|
Keep the existing query identity. New domain/application modules receive no
|
|
legacy exception. F1 has zero exceptions. Do not use exceptions to invent new
|
|
shared platform dependencies on feature internals.
|
|
|
|
## State and lifecycle
|
|
|
|
Each feature has one authoritative mutable application-state owner. A transition
|
|
operation owns writes; UI receives a view/snapshot or subscription. Preserve
|
|
existing objects and initialization timing when extracting a stateful module.
|
|
Do not instantiate a new store in both the legacy facade and the feature API.
|
|
Compatibility facades only forward the same live implementation.
|
|
|
|
Document lifecycle scopes: page, authenticated user, session, mounted panel and
|
|
editor/draft. Name owners of subscriptions, DOM listeners, timers, observers,
|
|
pending requests and caches. Mounting must be idempotent; disposal releases the
|
|
resources it owns. Background reminders may outlive an open panel. Closing the
|
|
panel must not silently stop those reminders during extraction.
|
|
|
|
Keep request-generation and selected-session checks around asynchronous
|
|
completions. Serialize writes where the current contract requires it. Dispose
|
|
subscriptions explicitly and prevent late updates to a replaced view. Feature
|
|
state changes on user/session switch must follow current cleanup policy. Browser
|
|
storage is for preferences/drafts/cache state, never a substitute for backend
|
|
authorization, credential storage or owner filtering. Define every storage key's
|
|
owner, retention/reset behavior and compatibility format before moving it.
|
|
|
|
## Creating a module or introducing a feature
|
|
|
|
1. Identify responsibility, owner, public consumers, side effects and behavioral
|
|
evidence before editing. Start with a pure leaf when introducing a feature.
|
|
2. Place only the required source file(s), for example
|
|
`features/example/domain/calculate.js`. Add an index only when there is a
|
|
real supported feature API to compose.
|
|
3. Register each source in `frontend/modules.json`. A typical new mapping is
|
|
`features/example/domain/calculate.js` to
|
|
`js/features/example/domain/calculate.js`. Preserve the source/deployment
|
|
relative graph. The proof's legacy URL mapping is an explicit special case.
|
|
4. For an extracted leaf, the legacy feature coordinator may import its output
|
|
as a temporary composition bridge. New maintained features use public indexes;
|
|
the legacy tree is not globally forced into the new boundary rules in F1.
|
|
5. Add the exact output URL to the appropriate explicit SW array, retain lazy
|
|
evaluation timing and bump the cache name when the graph changes. Declare
|
|
`text eol=lf` for both mapped paths in repository-owned `.gitattributes`
|
|
files; source-tree or scoped output patterns are allowed. The publisher checks
|
|
effective Git rules, including nested overrides, and rejects a missing LF rule
|
|
even if output bytes already match. Do not broaden unrelated legacy checkout
|
|
rules or automatically rewrite all existing query identities.
|
|
6. Run the publisher, inspect the source/output diff, then run architecture,
|
|
identity, graph, offline and focused behavior checks. Include both sides of
|
|
the mapping in review. Retiring output requires a separate reviewed deletion;
|
|
the publisher does not clean the static tree.
|
|
|
|
```sh
|
|
python scripts/build_frontend.py
|
|
python scripts/build_frontend.py --check
|
|
npm ci --ignore-scripts --no-audit --no-fund
|
|
node scripts/check_frontend.mjs
|
|
node scripts/check_frontend.mjs --inventory
|
|
node --test tests/frontendArchitecture.test.mjs
|
|
./venv/bin/python -m pytest -q -rs tests/test_frontend_build.py tests/test_frontend_foundation_offline_js.py tests/test_frontend_module_graph.py tests/test_frontend_module_version_parity.py tests/test_panel_loader_js.py
|
|
./venv/bin/python scripts/verify_frontend_runtime.py
|
|
```
|
|
|
|
Use your actual repository virtualenv path; the F1 environment is recorded in
|
|
validation. Node 20+ follows current CI. Existing Playwright/browser prerequisites
|
|
are documented in `tests/README.md` and `tests/KNOWN_FAILURES.md`. Missing Node can
|
|
skip Python browser wrappers, which is a coverage gap, not a pass. The standalone
|
|
Node gates require locked development dependencies and fail when missing.
|
|
|
|
The publisher validates all inputs before writing and only overwrites owned
|
|
outputs whose bytes differ. It is idempotent and working-directory independent.
|
|
Git must be available for publication and `--check`; neither runs at application
|
|
startup. Attribute evaluation uses a private temporary Git repository and ignores
|
|
global/local overrides, so checkout consistency is reproducible in CI. It adds
|
|
no runtime configuration or backend imports. CI checks LF attributes, parity and source
|
|
syntax in existing jobs; the Node job also runs architecture self-tests. Existing
|
|
runtime identity tests remain authoritative across legacy imports, HTML and SW.
|
|
The isolated runtime probe is included in the new pytest publication tests.
|
|
|
|
## Review, release and rollback
|
|
|
|
Review the source/output mapping and exact exported API, then the owner/dependency
|
|
contract and behavior tests. Check manifests, URL identities, MIME/CSP, load timing,
|
|
storage compatibility and disposal. Reject unexplained feature behavior changes.
|
|
Do not repair unrelated defects under an extraction title.
|
|
|
|
Release from a validated revision with committed output. Native startup and
|
|
packagers consume static files without a compiler. Run parity before producing a
|
|
Docker or desktop artifact. Test the actual packaged application on its platform;
|
|
Linux contract probes cannot certify macOS/Windows executables. Deploy matching
|
|
shell, facades, graph and manifests as a unit. Keep an authorized path to the last
|
|
complete artifact. Rollback restores the whole matching set, not just an entry
|
|
file or cache version. Do not delete a facade until its public consumers have
|
|
migrated and compatibility tests make that decision reviewable.
|
|
|
|
## Proposal and PR templates
|
|
|
|
For a decomposition proposal, record: baseline; responsibility map; current public
|
|
API and consumers; state owner; I/O and lifecycle boundaries; planned slice;
|
|
allowed dependencies/temporary exceptions; preserved behavior; deterministic
|
|
characterization tests; deployment/offline changes; overlapping PRs; rollback;
|
|
explicit non-goals and remaining uncertainties.
|
|
|
|
For each migration PR, lead with the responsibility moved and resulting boundary.
|
|
Record source/output paths, API compatibility, state/lifecycle ownership,
|
|
characterization results, exact validation commands, platform gaps, exception
|
|
removal plan, upstream dependencies and rollback. Attach a concrete before/after
|
|
example when needed to establish behavioral equivalence. Preserve the repository
|
|
PR template and never claim unexecuted checks.
|
|
|
|
F1 is an entirely separate foundation-only PR. Deliver the complete Notes
|
|
decomposition, regression tests, compatibility validation and final reference
|
|
case study through one draft PR targeting official `dev`, using one Notes branch
|
|
and worktree after F1 integration. N0 through N6 and the N5 substages are internal
|
|
engineering checkpoints, not independent PRs or merges. Each checkpoint records
|
|
focused tests, review evidence, its validated revision or reproducible snapshot,
|
|
and rollback to the prior matching source/output/facade/precache set. Keep the
|
|
draft open while those checkpoints progress; mark it ready only after the entire
|
|
decomposition passes the [roadmap's acceptance gates](notes-roadmap.md).
|
|
|
|
Structure the Notes PR description around the final integrated design and link
|
|
each checkpoint's evidence. The receiving maintainer may use smaller independent
|
|
PRs for future frontend features at their discretion; the one-PR Notes decision
|
|
does not impose that delivery size on later work.
|
|
|
|
## Program backlog and final handoff
|
|
|
|
Priority order: review/integrate F1; resolve root offline certification with the
|
|
owner of PR #6227; complete the Notes checkpoints and final reference case study
|
|
within one draft PR following the [roadmap](notes-roadmap.md); integrate the
|
|
complete Notes PR after its acceptance gates; finalize the recipient handoff.
|
|
Only then does the receiving maintainer prioritize Calendar, Documents, Email,
|
|
Chat, Skills and Settings against current behavior and risk. Existing partial
|
|
packages and high fan-in helpers need assessment, not automatic replacement.
|
|
|
|
Final H acceptance requires a designated maintainer, the integrated Notes PR
|
|
revision and its internal checkpoint receipts, the actual public API/state/lifecycle
|
|
map and final reference case study included in that PR, validated deployment/offline
|
|
commands, known exceptions/debt,
|
|
outstanding PR dependencies, rollback evidence and a reproducible independent
|
|
setup by the recipient. F1 provides the handbook structure and contracts; it does
|
|
not claim Notes or the completed handoff have occurred. The initiating architect
|
|
then returns to separately authorized non-frontend architecture work.
|