You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: rewrite README for demos, enhance CLAUDE.md with architecture patterns
README minimized to focus on the handoff problem and core value prop
(fully owned on-chain dapps with just II). CLAUDE.md expanded with
architectural documentation: handoff flow, dapp deploy sequence,
dashboard embedding, demos access codes, and icp-cli reference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
my-canister-dapp-cli (`dapp`) ── deploy to local/mainnet with II auth, run acceptance tests
@@ -53,6 +53,110 @@ Testing validates via:
53
53
Playwright E2E ── tests full flows against local ICP network
54
54
```
55
55
56
+
## Architecture & Key Patterns
57
+
58
+
### The Handoff Flow (II Principal Derivation)
59
+
60
+
The core challenge: Internet Identity derives a *different principal* for each domain. A user at the launcher (`mycanister.app`) gets principal A. At their canister (`<id>.icp0.io`), they get principal B. Ownership must be transferred to principal B.
61
+
62
+
**Solution**: Re-authenticate the user with II using the `derivationOrigin` parameter set to the new canister's domain. This forces II to derive the principal the user will have when visiting their canister directly.
63
+
64
+
**The flow (launcher)**:
65
+
1. User creates canister via the launcher app
66
+
2. Launcher adds its own origin to the canister's `/.well-known/ii-alternative-origins` (certified JSON endpoint that tells II which origins are authorized)
67
+
3. Launcher calls `AuthClient.login()` with `derivationOrigin = https://<canister-id>.icp0.io`
68
+
4. II derives the user's principal at the canister's domain and returns it
69
+
5. That principal is set as the canister controller
70
+
6. Launcher removes itself from alternative origins — the bridge is gone, user fully owns the canister
71
+
72
+
**Key files**:
73
+
-`canisters/icp-dapp-launcher/src/lib/remoteAuthentication/` — derivationOrigin construction and remote auth client
74
+
-`packages-rs/my-canister-dashboard/src/dashboard/alternative_origins.rs` — alternative origins management (add/remove origins, serve certified JSON)
The `dapp` CLI (`my-canister-dapp-cli`) deploys dapps and transfers ownership to the developer's II principal. Each deploy creates a **fresh detached canister** (new ID every time, no upgrades).
80
+
81
+
**Sequence**:
82
+
1. Build canister wasm (or use `--wasm` to provide one)
83
+
2. Create detached canister via `icp canister create --detached`
84
+
3. Install wasm into the canister
85
+
4. Start an ephemeral HTTP server on a random localhost port
86
+
5. Add `http://localhost:<port>` to the canister's alternative origins
87
+
6. Open browser for II authentication with `derivationOrigin` = canister's domain
88
+
7. Receive the derived principal via POST callback to the local server
89
+
8. Set the II principal on the canister
90
+
9. Remove the CLI origin from alternative origins
91
+
10. Update controllers to `[canister_id, user_principal]` — deployer relinquishes control (must be last step)
92
+
93
+
Deployments are tracked in `.dapp/deployments.jsonl`.
94
+
95
+
**Key files**:
96
+
-`packages-rs/my-canister-dapp-cli/src/commands/deploy.rs` — full deploy orchestration
97
+
-`packages-rs/my-canister-dapp-cli/src/auth/server.rs` — ephemeral auth server
98
+
-`packages-rs/my-canister-dapp-cli/src/auth/page.rs` — HTML/JS served for II authentication
The dashboard is a Svelte app that gets compiled and embedded into every user canister as part of the `my-canister-dashboard` Rust crate.
104
+
105
+
**Build process**:
106
+
1.`scripts/prebuild-mcd.sh` builds the Svelte dashboard frontend
107
+
2. Compiled assets (HTML, JS, CSS) are copied to `packages-rs/my-canister-dashboard/assets/`
108
+
3. Rust's `include_dir!()` macro embeds these files into the crate at compile time
109
+
4. At canister init, `setup_dashboard_assets()` registers them with the certified asset router
110
+
111
+
Every user canister serves the dashboard at `/canister-dashboard` with full HTTP certification, security headers (CSP), and the `/.well-known/ii-alternative-origins` endpoint.
112
+
113
+
**Key files**:
114
+
-`scripts/prebuild-mcd.sh` — builds dashboard frontend and copies to assets dir
115
+
-`packages-rs/my-canister-dashboard/src/dashboard/mod.rs` — asset embedding via `include_dir!()`
116
+
-`packages-rs/my-canister-dashboard/src/setup/mod.rs` — `setup_dashboard_assets()` function
> **Status**: This project is in active development. See the [FAQ](https://mycanister.app/faq) for more information.
8
+
> **Status**: Active development. Demos will be available at [mycanister.app](https://mycanister.app).
9
9
10
-
## The Problem
10
+
## The Handoff Problem
11
11
12
-
On the Internet Computer, canisters are deployed using the `dfx` CLI. This works well for developers, but creates a barrier for everyone else.
12
+
On the Internet Computer, a single canister can be a complete application — backend, frontend, and storage in one self-contained unit. But there's no way for a non-technical user to create and own one of these canisters from a browser.
13
13
14
-
Canisters have a unique capability: they can serve their own frontend—like a self-contained HTTP server. This means a single canister can be a complete application. But non-technical users have no easy way to create and control one of these canisters using just a browser and their Internet Identity.
15
-
16
-
There's also a subtle challenge: Internet Identity derives a *different principal* for each domain. If a user authenticates at `mycanister.app` to create a canister, they get one principal. But when they visit their new canister at `abc123.icp0.io`, II gives them a *different* principal. How do you hand off ownership?
14
+
There's also a subtle identity problem: Internet Identity derives a *different principal* for each domain. A user who authenticates at a launcher app gets one identity. When they visit their new canister at its own domain, they get a *different* identity. So how do you hand off ownership?
17
15
18
16
## The Solution
19
17
20
-
This repository provides libraries for developers to create **user-owned canisters**—dapps that:
21
-
22
-
- Can be created from a browser using only ICP and Internet Identity
23
-
- Include a built-in dashboard for management (cycles, upgrades, controllers)
24
-
- Are fully controlled by the user's II principal *at their canister's domain*
25
-
26
-
**The key insight**: After creating a canister, we re-authenticate the user with Internet Identity using the new canister's domain as the `derivationOrigin`. This produces the principal they'll use when visiting their dapp directly—and that principal becomes the controller.
27
-
28
-
## How It Works
29
-
30
-
1.**Fund**: User sends ICP to their account at the installer app
31
-
2.**Create**: ICP is sent to the Cycles Minting Canister, which creates a new canister
32
-
3.**Install**: The dapp's wasm is installed into the canister
33
-
4.**Transfer Control**: User re-authenticates with II using the new canister domain
34
-
5.**Own**: That II principal is set as the canister controller
35
-
36
-
The user now fully owns their canister. They can manage it directly at `<canister-id>.icp0.io/canister-dashboard`.
37
-
38
-
## For Developers
39
-
40
-
You build the wasm that users install. Your dapp becomes a template that anyone can instantiate as their own user-owned canister.
41
-
42
-
### What to use
18
+
This project provides the libraries and tooling to create **user-owned canisters** — dapps that anyone can install and fully own on the Internet Computer using only a browser and Internet Identity.
43
19
44
-
**Rust (backend)**:
45
-
-`my-canister-dashboard` — Embeds the dashboard UI and management endpoints
After creating a canister, we re-authenticate the user with Internet Identity *at the new canister's domain*. This produces the principal they'll always have when visiting their dapp — and that principal becomes the controller. The launcher steps away. The user fully owns their canister.
47
21
48
-
**JavaScript (frontend)**:
49
-
-`@web3nl/vite-plugin-canister-dapp` — Vite plugin for dev/prod environment detection
50
-
-`@web3nl/my-canister-dashboard` — Utilities for interacting with dashboard endpoints
22
+
### The flow
51
23
52
-
### Example
24
+
1.**Fund** — User sends ICP to their account at the launcher
25
+
2.**Launch** — A new canister is created and the dapp is installed
26
+
3.**Own** — User authenticates with II at the new canister's domain. That principal becomes the controller. The canister is theirs.
53
27
54
-
See [examples/my-hello-world](examples/my-hello-world/) for a complete implementation.
The user now manages their dapp directly at `<canister-id>.icp0.io/canister-dashboard` — cycles, upgrades, controllers, all from the browser.
78
29
79
30
## mycanister.app
80
31
81
-
[mycanister.app](https://mycanister.app) is the reference installer and dapp registry:
32
+
[mycanister.app](https://mycanister.app) is the reference launcher and dapp registry. Browse available dapps, launch them as your own canister, and manage them — all with Internet Identity.
82
33
83
-
-**Dapp Store**: Browse available dapps to install
84
-
-**Installer**: Create user-owned canisters with ICP + Internet Identity
85
-
-**My Dapps**: View and access your created canisters
86
-
87
-
Developers can submit their dapps to the registry, or users can install custom wasm files directly.
88
-
89
-
## Packages
90
-
91
-
| Package | Type | Description |
92
-
|---------|------|-------------|
93
-
|[my-canister-dashboard](https://crates.io/crates/my-canister-dashboard)| Rust | Dashboard assets and management endpoints |
|[@web3nl/vite-plugin-canister-dapp](https://www.npmjs.com/package/@web3nl/vite-plugin-canister-dapp)| npm | Vite plugin for environment config |
97
-
98
-
## Development
34
+
## For Developers
99
35
100
-
See [CLAUDE.md](CLAUDE.md) for the full project map, commands, and architecture details.
36
+
This is a monorepo containing Rust crates, npm packages, deployable canisters, and example dapps. See [CLAUDE.md](CLAUDE.md) for the full project map, architecture, and commands. Check out [examples/my-hello-world](examples/my-hello-world/) for a minimal implementation.
0 commit comments