chore(bootstrap): import plum-side edits missed in initial commit
- @hardware/docs/IDEAS.md: card-form-wallet component layout sections - platform-api/entities/index.ts: import 9 peer-* entities that already existed in tree but weren't wired Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1b719e1fd7
commit
40534d4874
2 changed files with 332 additions and 11 deletions
|
|
@ -58,6 +58,136 @@ Edge / back view:
|
|||
optional pogo pads for factory recovery only
|
||||
```
|
||||
|
||||
### Component layout — does it all fit, does it balance?
|
||||
|
||||
Card footprint: standard ID-1 / credit-card, **85.6 × 54 mm**, target
|
||||
**3–4 mm thick**. Budget every external surface (front, back, edge)
|
||||
plus an internal Z-stack of ~5 layers. Heavy / area-hungry components
|
||||
get **stacked in Z** rather than fighting for X-Y real estate.
|
||||
|
||||
**Front face** (member-facing, calculator UX):
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ ◉ cocotte ▒ status LED │ ← top status row
|
||||
│ ┌────────────────────────────────────────────────┐ │
|
||||
│ │ e-ink display (~50 × 25 mm) │ │ ← display
|
||||
│ │ balance · peer handle · amount · code │ │
|
||||
│ └────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───┐ ┌───┐ ┌───┐ ┌─────┐ │
|
||||
│ │ 7 │ │ 8 │ │ 9 │ │ ÷ │ │
|
||||
│ ├───┤ ├───┤ ├───┤ ├─────┤ │ ← 3×4 numeric +
|
||||
│ │ 4 │ │ 5 │ │ 6 │ │ × │ │ 1×4 operator
|
||||
│ ├───┤ ├───┤ ├───┤ ├─────┤ │ membrane keypad
|
||||
│ │ 1 │ │ 2 │ │ 3 │ │ − │ │
|
||||
│ ├───┤ ├───┤ ├───┤ ├─────┤ │
|
||||
│ │ . │ │ 0 │ │ ⌫ │ │ + │ │
|
||||
│ └───┘ └───┘ └───┘ └─────┘ │
|
||||
│ │
|
||||
│ [ MENU ] [ ◉ SEND ] [ = / CONFIRM ] │ ← action row
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Front is the most pixel-budget-constrained surface. Membrane keypad
|
||||
sits directly on the main PCB; e-ink display is laminated above. No
|
||||
free area on the front to spare for the LED strip or piezo — those
|
||||
move to edge / back.
|
||||
|
||||
**Back face** (the radio + power face — everything stacks here):
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ serial · cocotte ······························· │
|
||||
│ ┌─────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ NFC antenna loop ── outer ring │ │ ← NFC + Qi coils
|
||||
│ │ ┌─────────────────────────────────────┐ │ │ stacked
|
||||
│ │ │ │ │ │ (flex multilayer,
|
||||
│ │ │ Qi v2.1 receiver coil │ │ │ same X-Y zone)
|
||||
│ │ │ ( ~38 × 38 mm spiral ) │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ └─────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ NFC tap zone (this whole region) │ │
|
||||
│ └─────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ▣ recovery QR (etched, flush) ◡ pogo indent │ ← smooth shallow
|
||||
│ (4–6 pads) │ indent, flush pogo
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
The Qi coil (~38 mm class) and the NFC antenna loop share the same
|
||||
X-Y real estate because they're on **different flex layers** and run
|
||||
at totally different frequencies (Qi ~100 kHz, NFC 13.56 MHz). Stack
|
||||
order is engineered so neither blocks the other; this is the standard
|
||||
trick on every card-form wallet that ships Qi today.
|
||||
|
||||
**Edge** (switch + status):
|
||||
|
||||
```
|
||||
top edge : ───── perimeter LED strip wraps all 4 sides ─────
|
||||
left edge : ◀── [ LOCK · SEND · RECV ] ──▶ ◉ piezo port
|
||||
░░░ (toggle pulse LED under detent)
|
||||
right edge : status LED · cellular antenna feed point
|
||||
bottom edge: (clean — no exposed metal, no port)
|
||||
```
|
||||
|
||||
Charging is wireless (Qi), so the bottom edge has no port and stays
|
||||
clean. Cellular antenna is a meandered trace along the inner side of
|
||||
the card edge — antenna real estate is what makes the perimeter
|
||||
ring useful for two things at once (radio + LEDs).
|
||||
|
||||
**Internal Z-stack** (top of card → back of card, ~3–4 mm total):
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐ ← 0.3 mm — front shell
|
||||
1 │ front shell + membrane keypad overlay │
|
||||
├──────────────────────────────────────────┤
|
||||
2 │ e-ink display module │ ← 0.5 mm
|
||||
├──────────────────────────────────────────┤
|
||||
3 │ main PCB — MCU · modem · secure │ ← 0.6 mm
|
||||
│ element (EAL6+) · iSIM/eSIM · BLE/NFC │ PCB + components
|
||||
│ controller · PMIC · piezo step-up · LED │
|
||||
│ drivers · supercap (SMD) │
|
||||
├──────────────────────────────────────────┤
|
||||
4 │ Li-Po pouch (~40 × 45 × 1.0 mm, │ ← 1.0 mm
|
||||
│ ~150 mAh, centered) │
|
||||
├──────────────────────────────────────────┤
|
||||
5 │ multilayer flex — Qi coil + NFC loop │ ← 0.4 mm
|
||||
│ + perimeter LED strip + piezo flex tail │
|
||||
├──────────────────────────────────────────┤
|
||||
6 │ back shell w/ pogo indent + QR window │ ← 0.3 mm
|
||||
└──────────────────────────────────────────┘
|
||||
≈ 3.1 mm ── fits the 3–4 mm budget
|
||||
```
|
||||
|
||||
**Balance / centre-of-mass check:**
|
||||
- Heaviest single component is the **Li-Po pouch** (~3–4 g). Placed
|
||||
centred so the card's CoM stays near geometric centre.
|
||||
- Display is heavy-ish but mounted at the top half of the front;
|
||||
battery sits in the lower half of layer 4 to **counterweight**.
|
||||
- Main PCB components (MCU + modem + secure element) are the densest
|
||||
silicon area — distribute around the edges of layer 3 rather than
|
||||
clustering, both for thermal and balance reasons.
|
||||
- Piezo, the supercap, and the LED drivers go to the *corners* of
|
||||
layer 3 — naturally balancing each other off-axis.
|
||||
- Perimeter LED strip + cellular antenna ring the whole card → mass
|
||||
is symmetric by construction.
|
||||
|
||||
**Does it all fit? Yes, with two tight spots:**
|
||||
- **Qi coil vs. NFC antenna** share X-Y but live on different flex
|
||||
layers — solved (already shipping pattern). The risk is yield.
|
||||
- **Front-face real estate**: keypad + display + action row + status
|
||||
row is exactly the front, with **zero margin** for adding more UI.
|
||||
Any future feature that needs front-face pixels (touch, fingerprint
|
||||
reader) means dropping a key or shrinking the display. Treat the
|
||||
front as **fully booked**.
|
||||
|
||||
Anything else added later — fingerprint sensor, second display,
|
||||
solar trickle cells, larger speaker — has to come out of layer 3
|
||||
(displace silicon) or grow the Z budget past 4 mm.
|
||||
|
||||
### Function
|
||||
- **Retrieval surface for E2EE + crypto.** Holds the keys / recovery material
|
||||
needed to decrypt member content and authorize crypto operations. Framed
|
||||
|
|
@ -209,9 +339,24 @@ start, both confirm, no roles.
|
|||
- SIM/radio provider strategy (MVNO vs. satellite IoT vs. LoRa-style mesh)?
|
||||
- Relationship to existing standards (Ledger/Trezor seed compat? FIDO2?
|
||||
custom?).
|
||||
- Session channel *after* the NFC introduction — BLE for nearby peers,
|
||||
in-band over the radio mesh for distant peers, or both? (Pairing
|
||||
transport itself is decided: NFC.)
|
||||
- **Session channel *after* the NFC introduction — this is the single
|
||||
biggest unresolved hardware decision.** Pairing transport itself is
|
||||
decided (NFC). The session that follows could be:
|
||||
- **BLE** — natural for nearby peers, off-the-shelf chipsets, also
|
||||
gives find-my-wallet a free local proximity stage. Costs an extra
|
||||
antenna + radio + paired-phone UX wrinkle. Does *not* work if
|
||||
the two members are not physically close (e.g. wallet-to-wallet
|
||||
remote tipping).
|
||||
- **In-band cellular, platform-relayed.** Both wallets push the
|
||||
session through the cocotte platform over their own LTE-M
|
||||
radios. Works at any distance. Costs platform availability for
|
||||
every transaction and adds latency (sub-second still, but not
|
||||
instant). Simpler BOM — no BLE radio at all. Find-my-wallet
|
||||
loses the BLE proximity stage.
|
||||
- **Custom sub-GHz peer mesh (LoRa-class).** No platform in the
|
||||
loop, works peer-to-peer at range, but adds another radio +
|
||||
antenna + cert burden.
|
||||
Decision blocks BOM (BLE chipset yes/no) and find-my-wallet design.
|
||||
- **Pogo-pad layout + adapter form factor.** Charging is decided
|
||||
(Qi primary + bundled USB-C→pogo adapter using the same back-pad
|
||||
contacts that also serve factory recovery). The contact area is a
|
||||
|
|
@ -281,14 +426,48 @@ that critique — but worth being explicit about the framing.
|
|||
fine, the hotel pad doesn't. Source:
|
||||
- https://graniteriverlabs.com/en-us/technical-blog/beyond-qi2-wireless-charging
|
||||
|
||||
**Power budget — the actual hard problem.**
|
||||
- A card-thin Li-Po cell is on the order of 100–200 mAh. Cellular LTE-M
|
||||
transmit bursts pull 100 mA+. The wallet must be **mostly asleep**:
|
||||
- Radio idle in LOCK (beacon-only or fully off).
|
||||
- Radio wakes only on toggle change, NFC tap, or scheduled push.
|
||||
- Display is e-ink so retention is free.
|
||||
This is a design constraint, not a blocker — IoT cellular trackers
|
||||
achieve months of life at this duty cycle.
|
||||
**Power budget — solvable with a 3-tier hybrid stack.**
|
||||
|
||||
The actual hard problem isn't bulk energy, it's the **peak-current
|
||||
mismatch**: a card-thin Li-Po can hold a few hundred mWh but can't
|
||||
deliver the 1–3 A spikes that LTE-M / NB-IoT transmit bursts demand
|
||||
for 1–2 seconds. The IoT industry already solved this for smart meters
|
||||
and cellular trackers; the same architecture maps directly onto a
|
||||
membership wallet:
|
||||
|
||||
1. **Bulk energy — ultra-thin Li-Po pouch.** Mass-produced down to
|
||||
0.4–1.0 mm. A 1.5–2.0 mm card-style cell delivers ~100–160 mAh at
|
||||
3.7 V (Serui, PADRE, Grepow, UFine, Samsung/LG plastic-pouch parts).
|
||||
Honeywell already ships products with 0.8 mm cells. Chinese supply
|
||||
chain is mature here.
|
||||
2. **Pulse buffer — supercapacitor (or Li-SOCl₂ + supercap hybrid).**
|
||||
Absorbs the 1–3 A LTE-M transmit burst the Li-Po alone can't
|
||||
deliver. A 220 F hybrid supercap part delivers ~15 A peak. During
|
||||
sleep the Li-Po trickle-recharges the cap. This is the *de facto*
|
||||
architecture for cellular IoT in 2026.
|
||||
3. **Aspirational always-on trickle — betavoltaic ("diamond")
|
||||
battery.** Betavolt's Ni-63 / diamond unit is **15 × 15 × 5 mm**
|
||||
today at 100 µW; a 1 W version is announced. Microwatts are
|
||||
nowhere near LTE-M's needs **directly**, but the betavoltaic's
|
||||
role is *trickle-recharging the supercap and Li-Po while the
|
||||
wallet sits in a drawer*. 50-year half-life on the isotope ≈ a
|
||||
wallet that doesn't go flat if a member loses it in a couch for a
|
||||
year. Real status: still pre-mass-market, regulatory questions on
|
||||
consumer radionuclides — treat as **v2 ambition, not v1 BOM**.
|
||||
|
||||
Sources:
|
||||
- https://www.serui-battery.com/News/xingyezixun/ultra-thin-1-5-2-0mm-3-7v-100mah-card-style-lithium-polymer-batteries.html
|
||||
- https://www.pdbattery.com/ultra-thin-battery.html
|
||||
- https://www.grepow.com/blog/ultra-thin-lithium-polymer-battery-for-thinnest-application.html
|
||||
- https://www.digikey.com/en/articles/use-hybrids-to-bring-the-benefits-of-both-batteries-and-supercapacitors-to-power-iot-designs
|
||||
- https://hackaday.com/2026/04/28/2026-green-powered-challenge-supercapacitor-enables-high-power-iot/
|
||||
- https://newatlas.com/energy/betavolt-diamond-nuclear-battery/
|
||||
- https://www.world-nuclear-news.org/articles/nuclear-battery-chinese-firm-aiming-for-mass-mark
|
||||
|
||||
Duty-cycle posture remains required regardless of stack:
|
||||
- Radio idle in LOCK (beacon-only or fully off).
|
||||
- Radio wakes only on toggle change, NFC tap, or scheduled push.
|
||||
- E-ink display retention is free (no draw while showing balance).
|
||||
|
||||
**Overall feasibility verdict — buildable with 2026 parts.**
|
||||
- No single component requires invention. Every piece ships somewhere.
|
||||
|
|
@ -301,6 +480,121 @@ that critique — but worth being explicit about the framing.
|
|||
than greenfield. ODM relationship + custom firmware + cocottetech
|
||||
brand layer is the shape of the project.
|
||||
|
||||
### Find-my-wallet
|
||||
|
||||
The cellular radio that exists for transfers doubles as a built-in
|
||||
**self-locator** — fundamentally better than AirTag / Tile (which rely
|
||||
on a crowd-sourced mesh of other people's phones). The wallet phones
|
||||
home on its own.
|
||||
|
||||
**The trigger is the *platform*, not the phone.** Member says "find my
|
||||
wallet" from the cocotte app, web view, or even SMS to the platform.
|
||||
The platform pushes an **OTA command** to the wallet over LTE-M —
|
||||
exactly the same downlink path used for any other platform-initiated
|
||||
message. The wallet doesn't have to be near the member's phone, BLE,
|
||||
or wifi to receive the find request. Critically: this means **a member
|
||||
who has lost both their wallet *and* their phone can still find the
|
||||
wallet** — they log in on a friend's device or call the platform.
|
||||
|
||||
Three response stages, escalating with how close the member is:
|
||||
|
||||
1. **Global — cellular self-report (LTE-M / NB-IoT).** On receipt of
|
||||
the platform OTA find command, the wallet immediately wakes the
|
||||
modem, posts the nearest cell tower IDs + signal strength back to
|
||||
the platform, and the member sees a city-level pin in the app /
|
||||
web. Wallets also self-report on a slow background schedule (e.g.
|
||||
1×/hour while in LOCK) so the *last known location* is always
|
||||
warm — useful when cellular happens to drop at the moment the
|
||||
member panics. Power impact is bounded by the duty-cycle posture
|
||||
already designed in (modem otherwise idle).
|
||||
2. **Local (~10–100 m) — *only if BLE is already on the BOM*.** This
|
||||
stage is **conditional**, not a given. BLE was originally proposed
|
||||
as the post-NFC session channel for peer transfers (see the
|
||||
transfer-session-channel open question). If that decision lands
|
||||
on BLE, then find-mode gets a free hot/cold proximity stage — the
|
||||
platform's OTA command flips the wallet into a higher-rate beacon
|
||||
and a member's phone shows a range bar. **If transfers end up
|
||||
running over cellular (relayed through the platform) instead of
|
||||
BLE, this whole stage disappears** and we go directly from stage
|
||||
1 (city-block cellular pin) to stage 3 (strobe + beep). The
|
||||
wallet is loud and bright enough on platform command that the
|
||||
missing middle stage is acceptable — you walk into the apartment
|
||||
and follow your ears.
|
||||
3. **In-hand (~cm) — perimeter LED strobe + loud piezo tone.** Same
|
||||
OTA escalation. The wallet drives the **full perimeter LED strip**
|
||||
in a high-contrast strobe (reusing the transfer-state hardware —
|
||||
see the Light language section) and fires a **simple loud tone
|
||||
generator** — sub-1 mm piezo bender driving a single fixed audible
|
||||
frequency (~3–4 kHz, the ear's peak sensitivity). Not a speaker,
|
||||
not a musical synth, not voice prompts: one tone, intermittent,
|
||||
loud enough to find the wallet under a couch cushion or inside a
|
||||
bag. The simplicity is the point — no codec, no DAC, single GPIO
|
||||
driving the piezo through a step-up, sub-mA at the cap-buffered
|
||||
peak.
|
||||
|
||||
Escalation is **member-controlled from the platform UI**, not
|
||||
automatic by RSSI — "show me on a map", "make it beep", "make it
|
||||
beep and flash" are three buttons that send three different OTA
|
||||
levels. The wallet has no idea how close the member's phone is; it
|
||||
just does what the platform last told it to do.
|
||||
|
||||
**The 30-year-old wallet argument for BLE.**
|
||||
|
||||
Re-examining the BLE question on **longevity / degradation** grounds:
|
||||
imagine the wallet is 30 years old. The piezo bender has died (glue
|
||||
fatigue, mechanical wear, solder joint failure). The perimeter LED
|
||||
strip has dimmed past usefulness (phosphor degradation, driver IC
|
||||
end-of-life). The e-ink display ghosts. Battery is shot — but the
|
||||
betavoltaic trickle (v2) keeps the radios alive.
|
||||
|
||||
In that future, **only the solid-state radios are reliably alive**:
|
||||
the cellular modem and (if equipped) BLE. The find sequence
|
||||
degrades as follows:
|
||||
|
||||
| Stage | Hardware needed | 30-yr survival |
|
||||
|---|---|---|
|
||||
| 1. Cellular pin | LTE-M modem + antenna | ✓ likely OK |
|
||||
| 2. BLE proximity | BLE chipset + antenna | ✓ likely OK |
|
||||
| 3a. Strobe | LED strip + drivers + power | ✗ failure-prone |
|
||||
| 3b. Piezo tone | piezo bender + step-up | ✗ failure-prone |
|
||||
|
||||
Without BLE, a 30-year-old wallet with dead transducers gives you a
|
||||
city-block pin and nothing else — you can't narrow from "in this
|
||||
house" to "in this drawer". **With BLE, even with all output
|
||||
hardware dead, the searcher's phone becomes the UI** (sound,
|
||||
vibration, visual hot/cold meter all run on the phone side). The
|
||||
wallet just has to emit a silent beacon — which is the same thing a
|
||||
$5 Tile does, with no transducers at all.
|
||||
|
||||
This reframes the BLE BOM question: BLE is justified **not only by
|
||||
the transfer-session-channel decision, but independently by
|
||||
**longevity guarantee****. A wallet that's a membership-grade
|
||||
artefact (potentially handed down, kept for decades) needs at least
|
||||
two redundant find paths, and the two that age best are both
|
||||
radios.
|
||||
|
||||
Verdict shift: **lean toward BLE on the BOM** regardless of the
|
||||
transfer-session-channel outcome. Even if transfers run
|
||||
platform-relayed over cellular, BLE earns its place as the
|
||||
last-mile finder when local output transducers are end-of-life.
|
||||
|
||||
**State + privacy:**
|
||||
- Find-mode is an **out-of-band command**, not a switch position. The
|
||||
hardware toggle stays where the member left it (LOCK / SEND / RECV);
|
||||
find is just an additional behaviour layered on top by the radio
|
||||
firmware.
|
||||
- The wallet's location reports are visible **only to the member's
|
||||
authenticated account** on the platform. The platform never shares
|
||||
wallet pings with third parties — and per the [[stance]] section,
|
||||
not with any regulatory or law-enforcement query either.
|
||||
- A member can **disable cellular self-reporting** in the app (the
|
||||
wallet then only locates via BLE while the member is within range,
|
||||
like a dumb Tile). Default is on; member-controlled.
|
||||
- "Anti-stalker" inversion is a non-problem here: unlike AirTag, this
|
||||
wallet can't be slipped into someone else's bag to track them — it's
|
||||
bound to a member account at provisioning and only reports to that
|
||||
account's owner.
|
||||
|
||||
### Prior art — is anyone already doing this? (2026-05-18)
|
||||
|
||||
**Short answer:** every *ingredient* ships somewhere; **the exact
|
||||
|
|
|
|||
|
|
@ -6,6 +6,15 @@ import { EngagementEventEntity } from './engagement-event.entity.js';
|
|||
import { MailboxEntity } from './mailbox.entity.js';
|
||||
import { OrgEntity } from './org.entity.js';
|
||||
import { OrgMemberEntity } from './org-member.entity.js';
|
||||
import { PeerCollaborationEntity } from './peer-collaboration.entity.js';
|
||||
import { PeerConnectionEntity } from './peer-connection.entity.js';
|
||||
import { PeerEndorsementEntity } from './peer-endorsement.entity.js';
|
||||
import { PeerGroupEntity } from './peer-group.entity.js';
|
||||
import { PeerGroupMemberEntity } from './peer-group-member.entity.js';
|
||||
import { PeerGroupMessageEntity } from './peer-group-message.entity.js';
|
||||
import { PeerMentorshipEntity } from './peer-mentorship.entity.js';
|
||||
import { PeerMessageEntity } from './peer-message.entity.js';
|
||||
import { PeerProfileEntity } from './peer-profile.entity.js';
|
||||
import { PersonaEntity } from './persona.entity.js';
|
||||
import { UserEntity } from './user.entity.js';
|
||||
|
||||
|
|
@ -20,6 +29,15 @@ export const entities = [
|
|||
AgentActionEntity,
|
||||
EngagementEventEntity,
|
||||
MailboxEntity,
|
||||
PeerProfileEntity,
|
||||
PeerConnectionEntity,
|
||||
PeerMessageEntity,
|
||||
PeerGroupEntity,
|
||||
PeerGroupMemberEntity,
|
||||
PeerGroupMessageEntity,
|
||||
PeerEndorsementEntity,
|
||||
PeerCollaborationEntity,
|
||||
PeerMentorshipEntity,
|
||||
] as const;
|
||||
|
||||
export { AgentActionEntity };
|
||||
|
|
@ -30,6 +48,15 @@ export { EngagementEventEntity };
|
|||
export { MailboxEntity };
|
||||
export { OrgEntity };
|
||||
export { OrgMemberEntity };
|
||||
export { PeerCollaborationEntity };
|
||||
export { PeerConnectionEntity };
|
||||
export { PeerEndorsementEntity };
|
||||
export { PeerGroupEntity };
|
||||
export { PeerGroupMemberEntity };
|
||||
export { PeerGroupMessageEntity };
|
||||
export { PeerMentorshipEntity };
|
||||
export { PeerMessageEntity };
|
||||
export { PeerProfileEntity };
|
||||
export { PersonaEntity };
|
||||
export { UserEntity };
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue