the-mews/SPEC.md

67 lines
3.1 KiB
Markdown
Raw Normal View History

2026-10-11 08:54:25 +03:00
# The Mews
2026-10-11 08:50:15 +03:00
## Project layout
- `app/` — Flutter application (main codebase)
- `mews-spec/` — Mews Profile definition files
- `nix-android-sdk/` — Nix flake providing the Android SDK for devbox
Flutter version: `3.41.9-sdk-links` (keep in sync with devbox.json).
---
# Product spec
## What it is
A Flutter browser/client for Mews Pages (see mews-spec).
## Approach
Local-first: all data is stored locally in a Drift database. Network operations are secondary and never block local functionality.
2026-10-11 08:50:15 +03:00
# Architecture directives
Keep files small and focused.
## Layer separation
- `presentation/` — rendering, input, gestures, navigation.
- `application/actors/` — isolate-backed actors for CPU/IO work (image processing, export, file I/O).
- `application/controllers/` — plain coordinators that own signals and handle synchronous UI commands.
- `database/` — Drift tables, DAOs, queries.
- Signals expose UI-consumable state derived from the application layer.
- No business logic in widgets.
## State management — Signals
- Use the `signals` package for reactive UI state.
- Widgets observe signals and dispatch actions to the application layer.
- Derived UI state should be computed, not manually synchronized.
- Do not duplicate state across multiple signals.
## Business logic — Actor Model (`actors` package)
Use the `actors` package only where Dart Isolate isolation is genuinely useful: CPU-heavy work, blocking I/O, or tasks that must not block the UI thread. Do not use it for pure UI state or simple synchronous coordination.
**Rules for all actors and coordinators:**
- Model interactions as explicit sealed command types.
- No business logic in widgets — dispatch commands to the application layer.
- Keep classes small and focused; avoid large catch-all actors.
- Pass references explicitly when communication is needed.
**Isolate constraint:** The `actors` package runs handlers in separate Dart Isolates. Handlers cannot directly update signals on the main isolate. Isolate-backed actors must return results via message passing; the calling code applies results to signals.
## Persistence — Drift
- Use `drift` for all tables, DAOs, and queries.
- Keep database definitions in `database/` separate from UI code.
## v1 reader UI
The v1 client presents one reader screen:
- An address field pinned at the top; it hides when the reader scrolls down and returns when they scroll up or reach the top.
- A swipe right goes back and a swipe left goes forward through the history stack.
- Scrolling a page fades in a FOB in the bottom-right corner; on pages that fit without scrolling it is present from the start. It opens a bottom sheet with the reader's presentation choices: typeface, text size, theme (light, dark, follow system), color variant (site, warm, cool, green, mono), and a bookmark and subscription toggle for the current page.
- Fonts are bundled. v1 ships Atkinson Hyperlegible; Verdana and Georgia follow once their font files are added to `app/assets/fonts/`. A font is one TTF plus one `fonts` entry in `app/pubspec.yaml` and one entry in `app/lib/presentation/reader/reader_fonts.dart`.