You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
8.5 KiB
Markdown
225 lines
8.5 KiB
Markdown
+++
|
|
title = "Refactor to single-crate with api and ui binaries"
|
|
priority = 8
|
|
status = "done"
|
|
ticket_type = "task"
|
|
dependencies = ["ec118c"]
|
|
+++
|
|
|
|
<goal>
|
|
Collapse the three separate sub-crates (`api/`, `ui/`, `tests/`) into a single Cargo crate rooted at `quotesdb/`. This simplifies the project structure, enables direct code sharing between the api and ui via `src/lib.rs`, and makes `cargo test` run all tests (unit + integration) in a single invocation.
|
|
|
|
**Status: done.** This ticket is kept for historical reference.
|
|
</goal>
|
|
|
|
<current-state>
|
|
```
|
|
quotesdb/
|
|
├── api/ # independent crate "quotesdb-api"
|
|
│ ├── Cargo.toml
|
|
│ ├── src/main.rs
|
|
│ ├── src/tests.rs
|
|
│ ├── docs/
|
|
│ └── README.md
|
|
├── ui/ # independent crate "quotesdb-ui"
|
|
│ ├── Cargo.toml
|
|
│ ├── src/main.rs
|
|
│ ├── src/tests.rs
|
|
│ ├── index.html
|
|
│ ├── Trunk.toml
|
|
│ ├── docs/
|
|
│ └── README.md
|
|
├── tests/ # independent crate "quotesdb-tests"
|
|
│ ├── Cargo.toml
|
|
│ ├── docs/
|
|
│ └── README.md
|
|
├── infra/
|
|
└── docs/
|
|
```
|
|
|
|
Problems with the old structure:
|
|
- Shared types/logic must go through `../../common` — no quotesdb-specific shared code.
|
|
- Running tests requires `cd`ing into each sub-crate separately.
|
|
- Three `Cargo.toml` files to maintain, three `cargo fmt/check/clippy` invocations.
|
|
- Trunk must be run from `ui/`, not the project root.
|
|
</current-state>
|
|
|
|
<target-state>
|
|
```
|
|
quotesdb/
|
|
├── Cargo.toml # single crate "quotesdb", default-run = "api"
|
|
├── src/
|
|
│ ├── lib.rs # shared code (types, models, auth logic, etc.)
|
|
│ └── bin/
|
|
│ ├── api/
|
|
│ │ └── main.rs # api binary entrypoint
|
|
│ └── ui/
|
|
│ └── main.rs # ui binary entrypoint (for Trunk)
|
|
├── tests/ # integration tests — run by `cargo test`
|
|
│ └── (*.rs files)
|
|
├── index.html # Trunk HTML entry (moved from ui/)
|
|
├── Trunk.toml # updated to point to ui binary
|
|
├── infra/
|
|
└── docs/
|
|
├── PLANNING.md
|
|
├── ARCHITECTURE.md
|
|
└── plans/
|
|
└── 2026-02-27-quotesdb-design.md
|
|
```
|
|
|
|
Developer workflow after refactor (unchanged from user perspective):
|
|
- `cargo run` — starts the API server (default binary is `api`)
|
|
- `trunk serve` — compiles ui to Wasm and serves it
|
|
- `cargo test` — runs unit tests + integration tests
|
|
</target-state>
|
|
|
|
<changes>
|
|
### 1. Create `quotesdb/Cargo.toml`
|
|
|
|
Single crate manifest with:
|
|
- `name = "quotesdb"`
|
|
- `default-run = "api"` — ensures `cargo run` launches the api
|
|
- `edition = "2021"`, `license = "MIT OR Apache-2.0"`
|
|
- `[profile.release]` block (opt-level z, lto, strip, codegen-units 1)
|
|
- All api dependencies (axum, tokio, workers-rs, sqlx, nanoid, etc.)
|
|
- All ui dependencies (yew, wasm-bindgen, web-sys, etc.)
|
|
- All test dependencies (reqwest, tokio, etc.) under `[dev-dependencies]`
|
|
- Two `[[bin]]` entries:
|
|
```toml
|
|
[[bin]]
|
|
name = "api"
|
|
path = "src/bin/api/main.rs"
|
|
|
|
[[bin]]
|
|
name = "ui"
|
|
path = "src/bin/ui/main.rs"
|
|
```
|
|
|
|
### 2. Create `src/lib.rs`
|
|
|
|
Shared module for code used by both binaries:
|
|
- Domain types: `Quote`, `QuoteTag`, pagination structs, request/response shapes
|
|
- Auth code generation (4-word passphrase) — shared so ui can display it and api generates it
|
|
- NanoID generation utility
|
|
- Any other shared logic
|
|
|
|
### 3. Move api source
|
|
|
|
- `api/src/main.rs` → `src/bin/api/main.rs`
|
|
- `api/src/tests.rs` → `src/bin/api/tests.rs` (or inline unit tests within the binary module)
|
|
- Delete `api/Cargo.toml`
|
|
|
|
### 4. Move ui source
|
|
|
|
- `ui/src/main.rs` → `src/bin/ui/main.rs`
|
|
- `ui/src/tests.rs` → `src/bin/ui/tests.rs`
|
|
- Delete `ui/Cargo.toml`
|
|
|
|
### 5. Move Trunk files
|
|
|
|
- `ui/index.html` → `quotesdb/index.html`
|
|
- `ui/Trunk.toml` → `quotesdb/Trunk.toml`
|
|
|
|
Update `Trunk.toml` to explicitly name the ui binary:
|
|
```toml
|
|
[build]
|
|
target = "index.html"
|
|
|
|
[build.cargo]
|
|
args = ["--bin", "ui"]
|
|
```
|
|
|
|
### 6. Move integration tests
|
|
|
|
- Content from `tests/` sub-crate moves into `quotesdb/tests/` as `.rs` files (standard Cargo integration test layout).
|
|
- Delete `tests/Cargo.toml`.
|
|
- Integration tests import from the crate root (`use quotesdb::...`) and from dev-dependencies.
|
|
- They run with `cargo test` automatically — no separate crate needed.
|
|
|
|
### 7. Consolidate docs
|
|
|
|
Merge per-sub-crate docs into the project-level `docs/` directory:
|
|
- `api/docs/PLANNING.md` and `ui/docs/PLANNING.md` → merge into `docs/PLANNING.md`
|
|
- `api/docs/ARCHITECTURE.md` and `ui/docs/ARCHITECTURE.md` → merge into `docs/ARCHITECTURE.md`
|
|
- `api/README.md` and `ui/README.md` and `tests/README.md` → consolidate into `README.md`
|
|
- Delete the now-empty `api/docs/`, `ui/docs/`, `tests/docs/` directories.
|
|
|
|
### 8. Update `CLAUDE.md`
|
|
|
|
Update `quotesdb/CLAUDE.md` to reflect:
|
|
- New directory structure (single crate, not three sub-crates)
|
|
- New validation commands run from `quotesdb/` root, not from sub-directories
|
|
- Updated branch naming and ticket hierarchy (the sub-project split is now logical, not a file-system split)
|
|
- Updated agent dispatch instructions (agents work in `src/bin/api/` or `src/bin/ui/`, not separate crates)
|
|
|
|
### 9. Delete orphaned sub-crate roots
|
|
|
|
After moving all contents:
|
|
- Delete `api/` directory entirely
|
|
- Delete `ui/` directory entirely
|
|
- Delete `tests/` old sub-crate directory (but `quotesdb/tests/` integration test files stay)
|
|
</changes>
|
|
|
|
<constraints>
|
|
### Compilation targets
|
|
|
|
The `api` binary compiles for the **host** target during local dev (`cargo run`). The `ui` binary compiles for `wasm32-unknown-unknown` via Trunk. These are separate compilation invocations — they don't conflict in a single Cargo crate.
|
|
|
|
**Shared code in `src/lib.rs` must compile for both targets.** Avoid host-only APIs (threading, filesystem) in `lib.rs`. Use `#[cfg(target_arch = "wasm32")]` and `#[cfg(not(target_arch = "wasm32"))]` guards where needed.
|
|
|
|
### `cargo test` and Wasm
|
|
|
|
`cargo test` runs on the host target. The `ui` binary's tests cannot use DOM/browser APIs directly. Yew component tests that require a browser context must use `wasm-bindgen-test` and `wasm-pack test` — these cannot be run by `cargo test`. Therefore:
|
|
- Unit tests in `src/bin/ui/` must be limited to pure logic (routing, data transformations, API client request construction) guarded with `#[cfg(test)]`.
|
|
- Browser-only tests (component rendering) are out of scope for `cargo test` and remain a future concern.
|
|
- Integration tests in `tests/` exercise the **api** only and run on the host — these work fine with `cargo test`.
|
|
|
|
### workers-rs and local dev
|
|
|
|
The api uses `workers-rs` for Cloudflare Workers deployment. For local development `cargo run`, the api should either:
|
|
- Use a plain Axum server (conditional compilation: `#[cfg(not(target_env = "worker"))]`), OR
|
|
- Use the workers-rs local dev entrypoint.
|
|
|
|
### Dependency conflicts
|
|
|
|
Some dependencies may not compile for all targets. Use `[target.'cfg(not(target_arch = "wasm32"))'.dependencies]` for api-only deps and `[target.'cfg(target_arch = "wasm32")'.dependencies]` for ui-only deps in `Cargo.toml` where needed.
|
|
</constraints>
|
|
|
|
<validation>
|
|
From `quotesdb/` root:
|
|
|
|
```sh
|
|
cargo fmt # must pass cleanly
|
|
cargo check # must pass for host target
|
|
cargo clippy # must pass with no warnings
|
|
cargo test # must run and pass all tests (unit + integration)
|
|
trunk build # must successfully compile the ui binary to wasm
|
|
```
|
|
</validation>
|
|
|
|
<summary>
|
|
| Action | Path |
|
|
|--------|------|
|
|
| CREATE | `quotesdb/Cargo.toml` |
|
|
| CREATE | `quotesdb/src/lib.rs` |
|
|
| MOVE | `api/src/main.rs` → `src/bin/api/main.rs` |
|
|
| MOVE | `api/src/tests.rs` → `src/bin/api/tests.rs` |
|
|
| MOVE | `ui/src/main.rs` → `src/bin/ui/main.rs` |
|
|
| MOVE | `ui/src/tests.rs` → `src/bin/ui/tests.rs` |
|
|
| MOVE | `ui/index.html` → `index.html` |
|
|
| MOVE | `ui/Trunk.toml` → `Trunk.toml` (update `--bin ui`) |
|
|
| MERGE | `api/docs/` + `ui/docs/` + `tests/docs/` → `docs/` |
|
|
| MERGE | `api/README.md`, `ui/README.md`, `tests/README.md` → `README.md` |
|
|
| DELETE | `api/Cargo.toml` |
|
|
| DELETE | `ui/Cargo.toml` |
|
|
| DELETE | `tests/Cargo.toml` |
|
|
| DELETE | `api/` (after moving contents) |
|
|
| DELETE | `ui/` (after moving contents) |
|
|
| UPDATE | `Trunk.toml` (add `[build.cargo] args = ["--bin", "ui"]`) |
|
|
| UPDATE | `quotesdb/CLAUDE.md` (structure, validation paths, agent instructions) |
|
|
</summary>
|
|
|
|
<commit>
|
|
`refactor(quotesdb): collapse to single crate with api and ui binaries`
|
|
</commit>
|