@www.hyperlinks.space/program-kit 1.2.91881 → 18.18.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +19 -0
- package/README.md +3 -3
- package/api/{base.ts → _base.ts} +1 -1
- package/api/wallet/_auth.ts +143 -0
- package/api/wallet/register.ts +151 -0
- package/api/wallet/status.ts +89 -0
- package/app/index.tsx +319 -5
- package/assets/images/PreviewImage.png +0 -0
- package/database/start.ts +0 -1
- package/database/wallets.ts +266 -0
- package/fullREADME.md +142 -71
- package/index.js +3 -0
- package/npmReadMe.md +3 -3
- package/package.json +7 -2
- package/scripts/test-api-base.ts +2 -2
- package/telegram/post.ts +44 -8
- package/docs/ai_and_search_bar_input.md +0 -94
- package/docs/ai_bot_messages.md +0 -124
- package/docs/blue_bar_tackling.md +0 -143
- package/docs/bot_async_streaming.md +0 -174
- package/docs/build_and_install.md +0 -129
- package/docs/database_messages.md +0 -34
- package/docs/fonts.md +0 -18
- package/docs/npm-release.md +0 -46
- package/docs/releases.md +0 -201
- package/docs/releases_github_actions.md +0 -188
- package/docs/scalability.md +0 -34
- package/docs/security_plan_raw.md +0 -244
- package/docs/security_raw.md +0 -345
- package/docs/timing_raw.md +0 -63
- package/docs/tma_logo_bar_jump_investigation.md +0 -69
- package/docs/update.md +0 -205
- package/docs/wallet_telegram_standalone_multichain_proposal.md +0 -192
- package/docs/wallets_hosting_architecture.md +0 -257
package/docs/releases.md
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# GitHub Releases Automation Plan (Final)
|
|
2
|
-
|
|
3
|
-
This document defines the production plan for release detection, deduped GitHub Release publishing, and near-instant app update signaling.
|
|
4
|
-
|
|
5
|
-
## Goals
|
|
6
|
-
|
|
7
|
-
- Build the Windows installer on GitHub Actions (`windows-latest`) with `npm run build:win` (no `.exe` committed to git).
|
|
8
|
-
- Publish the installer to a GitHub Release only when that release tag does not already exist.
|
|
9
|
-
- Notify an app-update service immediately after a new release is published.
|
|
10
|
-
- Keep app-side update detection near-instant using push notification plus fallback polling.
|
|
11
|
-
|
|
12
|
-
## Source of Truth
|
|
13
|
-
|
|
14
|
-
- The **GitHub Release tag** is the release identity (`release_id`), for example `build_03252026_1929`.
|
|
15
|
-
- Locally, `windows/cleanup.cjs` moves the built installer to `releases/builder/build_MMDDYYYY_HHMM/HyperlinksSpaceProgramInstaller_<stamp>.exe` (other artifacts under `dev/`). In CI you can set `RELEASE_BUILD_ID` to match a chosen tag, or leave it unset so the folder name comes from build time.
|
|
16
|
-
|
|
17
|
-
## Workflow Trigger
|
|
18
|
-
|
|
19
|
-
- **Manual only:** `workflow_dispatch` (Actions → “Windows release (CI build)”).
|
|
20
|
-
- Optional input **release_id** (`build_MMDDYYYY_HHMM`). If empty, the tag is taken from the build output folder after `cleanup.cjs` runs.
|
|
21
|
-
|
|
22
|
-
Example trigger:
|
|
23
|
-
|
|
24
|
-
```yaml
|
|
25
|
-
on:
|
|
26
|
-
workflow_dispatch:
|
|
27
|
-
inputs:
|
|
28
|
-
release_id:
|
|
29
|
-
description: "Optional tag, e.g. build_03252026_1929"
|
|
30
|
-
required: false
|
|
31
|
-
default: ""
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Dedupe Rules (No Duplicate Releases)
|
|
35
|
-
|
|
36
|
-
1. Run `npm run build:win` (or use optional `RELEASE_BUILD_ID` so the output folder matches the intended tag).
|
|
37
|
-
2. Resolve `release_id` from the optional input or from `releases/builder/build_*/HyperlinksSpaceProgramInstaller_*.exe`.
|
|
38
|
-
3. Check whether GitHub Release/tag already exists for that `release_id`.
|
|
39
|
-
4. If it exists:
|
|
40
|
-
- Exit successfully (`0`)
|
|
41
|
-
- Do not upload assets
|
|
42
|
-
- Do not send webhook notification
|
|
43
|
-
5. If it does not exist:
|
|
44
|
-
- Create GitHub Release/tag
|
|
45
|
-
- Upload all files from that folder as release assets
|
|
46
|
-
- Continue to webhook notification
|
|
47
|
-
|
|
48
|
-
Recommended extra safety:
|
|
49
|
-
|
|
50
|
-
- Use workflow `concurrency` keyed by `release_id` to avoid race conditions.
|
|
51
|
-
|
|
52
|
-
## Endpoint Contract
|
|
53
|
-
|
|
54
|
-
- Webhook endpoint path: `api/releases.ts`
|
|
55
|
-
- Route URL: `POST /api/releases`
|
|
56
|
-
- Purpose: accept release-published events from GitHub Actions and fan out update notifications to app clients.
|
|
57
|
-
|
|
58
|
-
## Security
|
|
59
|
-
|
|
60
|
-
- GitHub Actions sends auth header:
|
|
61
|
-
- `x-release-token: <secret>`
|
|
62
|
-
- Endpoint validates against:
|
|
63
|
-
- `process.env.RELEASE_WEBHOOK_TOKEN`
|
|
64
|
-
- Optional hardening:
|
|
65
|
-
- Add HMAC signature verification for request body.
|
|
66
|
-
|
|
67
|
-
If auth fails:
|
|
68
|
-
|
|
69
|
-
- Return `401` and do not process payload.
|
|
70
|
-
|
|
71
|
-
## Payload Shape
|
|
72
|
-
|
|
73
|
-
`POST /api/releases` expects JSON:
|
|
74
|
-
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"release_id": "build_03252026_1929",
|
|
78
|
-
"version": "1.0.0",
|
|
79
|
-
"published_at": "2026-03-25T19:29:00Z",
|
|
80
|
-
"platform": "windows",
|
|
81
|
-
"assets": [
|
|
82
|
-
{
|
|
83
|
-
"name": "HyperlinksSpaceProgramInstaller.exe",
|
|
84
|
-
"url": "https://github.com/<org>/<repo>/releases/download/build_03252026_1929/HyperlinksSpaceProgramInstaller.exe",
|
|
85
|
-
"sha256": "<optional>"
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
"github_release_url": "https://github.com/<org>/<repo>/releases/tag/build_03252026_1929"
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Endpoint Behavior (`api/releases.ts`)
|
|
93
|
-
|
|
94
|
-
1. Accept only `POST`.
|
|
95
|
-
2. Validate auth token/signature.
|
|
96
|
-
3. Parse and validate required fields:
|
|
97
|
-
- `release_id`, `published_at`, `assets`.
|
|
98
|
-
4. Enforce idempotency by `release_id`:
|
|
99
|
-
- If already processed, return `200 { ok: true, duplicate: true }`.
|
|
100
|
-
5. Store/update latest release metadata in persistent storage.
|
|
101
|
-
6. Push update signal to clients (WebSocket/SSE/Firebase/Expo push).
|
|
102
|
-
7. Return quickly with `200 { ok: true }`.
|
|
103
|
-
|
|
104
|
-
## GitHub Actions Notification Step
|
|
105
|
-
|
|
106
|
-
After successful release creation and asset upload:
|
|
107
|
-
|
|
108
|
-
1. Read webhook URL and token from repository secrets:
|
|
109
|
-
- `RELEASE_WEBHOOK_URL`
|
|
110
|
-
- `RELEASE_WEBHOOK_TOKEN`
|
|
111
|
-
2. Send `POST` to `/api/releases` with release payload.
|
|
112
|
-
3. Retry webhook call with backoff on transient failures.
|
|
113
|
-
|
|
114
|
-
Important:
|
|
115
|
-
|
|
116
|
-
- Do not send webhook if release already existed (dedupe branch).
|
|
117
|
-
|
|
118
|
-
## When You Must Make a New Installer Release
|
|
119
|
-
|
|
120
|
-
Use this section as the decision rule between OTA update and installer release.
|
|
121
|
-
|
|
122
|
-
### Native/runtime changes (installer required)
|
|
123
|
-
|
|
124
|
-
Create a new installer release when a change affects native binaries or runtime compatibility, including:
|
|
125
|
-
|
|
126
|
-
- Installing, removing, or updating any package that forces you to rebuild the app.
|
|
127
|
-
- Changing app permissions or native capabilities (camera, notifications, background modes, deep links, etc.).
|
|
128
|
-
- Changing package identifiers, signing, entitlements, or other platform build settings.
|
|
129
|
-
- Changing Expo SDK or React Native version in a way that changes native runtime.
|
|
130
|
-
- Changing `runtimeVersion` policy/behavior or bumping app version when runtime compatibility changes.
|
|
131
|
-
- Any change that requires running a fresh native build to take effect.
|
|
132
|
-
|
|
133
|
-
### Non-native changes (OTA only, no installer)
|
|
134
|
-
|
|
135
|
-
Do not make a new installer release for:
|
|
136
|
-
|
|
137
|
-
- JavaScript/TypeScript business logic changes.
|
|
138
|
-
- UI/layout/style changes.
|
|
139
|
-
- Text/copy changes and static asset updates that are OTA-compatible.
|
|
140
|
-
- Server/API behavior changes that do not require new native modules in app.
|
|
141
|
-
|
|
142
|
-
### Exact release checklist
|
|
143
|
-
|
|
144
|
-
Make a new installer release if at least one statement is true:
|
|
145
|
-
|
|
146
|
-
1. "This change cannot work without rebuilding native binaries."
|
|
147
|
-
2. "This change modifies runtime compatibility between app binary and updates."
|
|
148
|
-
3. "This change touches native permissions/capabilities/config."
|
|
149
|
-
|
|
150
|
-
If all three are false, ship via OTA update instead of installer release.
|
|
151
|
-
|
|
152
|
-
### Team policy
|
|
153
|
-
|
|
154
|
-
- Prefer OTA by default for speed.
|
|
155
|
-
- Use installer releases only for native/runtime boundaries.
|
|
156
|
-
- When uncertain, treat as installer-required and verify in staging before production.
|
|
157
|
-
|
|
158
|
-
## App Update Strategy
|
|
159
|
-
|
|
160
|
-
Primary strategy:
|
|
161
|
-
|
|
162
|
-
- Real-time push signal from backend triggered by `/api/releases`.
|
|
163
|
-
|
|
164
|
-
Fallback strategy:
|
|
165
|
-
|
|
166
|
-
- App checks latest release on:
|
|
167
|
-
- app foreground/resume
|
|
168
|
-
- periodic interval (for example every 5-15 minutes)
|
|
169
|
-
|
|
170
|
-
Client behavior:
|
|
171
|
-
|
|
172
|
-
1. Compare local build/version with latest server metadata.
|
|
173
|
-
2. If newer exists:
|
|
174
|
-
- Show "Update available" prompt or trigger controlled update flow.
|
|
175
|
-
|
|
176
|
-
## Reliability and Observability
|
|
177
|
-
|
|
178
|
-
- Idempotent handling on `release_id`.
|
|
179
|
-
- Structured logs for each stage:
|
|
180
|
-
- detected -> published/skipped -> webhook sent -> app signal broadcast
|
|
181
|
-
- Alert on partial failure:
|
|
182
|
-
- release created but webhook failed
|
|
183
|
-
- Keep webhook processing fast and non-blocking for external calls.
|
|
184
|
-
|
|
185
|
-
## Rollout Plan
|
|
186
|
-
|
|
187
|
-
1. Deploy `api/releases.ts` in staging.
|
|
188
|
-
2. Run workflow in dry-run mode to validate folder parsing and dedupe checks.
|
|
189
|
-
3. Enable real release creation for test folder.
|
|
190
|
-
4. Enable webhook call to staging endpoint.
|
|
191
|
-
5. Verify end-to-end with one client device.
|
|
192
|
-
6. Promote to production after stable validation.
|
|
193
|
-
|
|
194
|
-
## Acceptance Criteria
|
|
195
|
-
|
|
196
|
-
- A new `releases/builder/build_.../` folder produces exactly one GitHub Release.
|
|
197
|
-
- Re-running workflow for the same `release_id` does not create duplicates.
|
|
198
|
-
- Webhook is called only for newly created releases.
|
|
199
|
-
- `POST /api/releases` rejects unauthorized requests.
|
|
200
|
-
- Connected app receives update signal near-instantly in normal conditions.
|
|
201
|
-
- Fallback polling still discovers updates if push delivery fails.
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# GitHub Releases Automation Plan (Final)
|
|
2
|
-
|
|
3
|
-
This document defines the production plan for release detection, deduped GitHub Release publishing, and near-instant app update signaling.
|
|
4
|
-
|
|
5
|
-
## Goals
|
|
6
|
-
|
|
7
|
-
- Build the Windows installer on GitHub Actions (`windows-latest`) with `npm run build:win` (no `.exe` committed to git).
|
|
8
|
-
- Publish the installer to a GitHub Release only when that release tag does not already exist.
|
|
9
|
-
- Notify an app-update service immediately after a new release is published.
|
|
10
|
-
- Keep app-side update detection near-instant using push notification plus fallback polling.
|
|
11
|
-
|
|
12
|
-
## Source of Truth
|
|
13
|
-
|
|
14
|
-
- The **GitHub Release tag** is the release identity (`release_id`), for example `build_03252026_1929`.
|
|
15
|
-
- Locally and in CI, `windows/cleanup.cjs` places the installer under `releases/builder/build_MMDDYYYY_HHMM/HyperlinksSpaceProgramInstaller_<stamp>.exe` (other files under `dev/`). In CI, set `RELEASE_BUILD_ID` to pin the folder/tag, or omit it to use the timestamp from build time.
|
|
16
|
-
|
|
17
|
-
## When You Must Make a New Installer Release
|
|
18
|
-
|
|
19
|
-
Create a new installer/GitHub Release when a change is native/runtime-level and cannot be delivered safely by OTA update alone.
|
|
20
|
-
|
|
21
|
-
Native/runtime changes include:
|
|
22
|
-
|
|
23
|
-
- Adding, removing, or upgrading native libraries/modules (anything requiring a new Android/iOS/desktop binary).
|
|
24
|
-
- Changing app permissions or OS capabilities (camera, notifications, background modes, file access, etc.).
|
|
25
|
-
- Changing Expo config plugins or native project settings that affect the compiled binary.
|
|
26
|
-
- Upgrading Expo SDK/React Native/runtime where binary compatibility changes.
|
|
27
|
-
- Changing `runtimeVersion` strategy/value, or bumping app version when `runtimeVersion.policy` depends on it.
|
|
28
|
-
- Changing signing/notarization/install packaging behavior for distributed installers.
|
|
29
|
-
- Any fix that touches native code or build-time platform configuration.
|
|
30
|
-
|
|
31
|
-
Do not make a new installer release for:
|
|
32
|
-
|
|
33
|
-
- Pure JavaScript/TypeScript logic changes.
|
|
34
|
-
- UI changes in React components.
|
|
35
|
-
- Asset/text/content updates that are OTA-compatible.
|
|
36
|
-
- API integration changes that do not alter native dependencies.
|
|
37
|
-
|
|
38
|
-
Practical decision checklist:
|
|
39
|
-
|
|
40
|
-
1. Does this change require rebuilding a platform binary to work? If yes, make installer release.
|
|
41
|
-
2. Does this change alter native modules, permissions, SDK/runtime, or build config? If yes, make installer release.
|
|
42
|
-
3. If both answers are no, publish OTA update only and skip installer release.
|
|
43
|
-
|
|
44
|
-
## Workflow Trigger
|
|
45
|
-
|
|
46
|
-
- **Manual only:** `workflow_dispatch` (workflow “Windows release (CI build)”).
|
|
47
|
-
- Optional input **release_id** (`build_MMDDYYYY_HHMM`). If empty, the tag is taken from the build output after `cleanup.cjs`.
|
|
48
|
-
|
|
49
|
-
Example trigger:
|
|
50
|
-
|
|
51
|
-
```yaml
|
|
52
|
-
on:
|
|
53
|
-
workflow_dispatch:
|
|
54
|
-
inputs:
|
|
55
|
-
release_id:
|
|
56
|
-
description: "Optional tag, e.g. build_03252026_1929"
|
|
57
|
-
required: false
|
|
58
|
-
default: ""
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Dedupe Rules (No Duplicate Releases)
|
|
62
|
-
|
|
63
|
-
1. Run `npm run build:win` (optionally with `RELEASE_BUILD_ID` so the output folder matches the intended tag).
|
|
64
|
-
2. Resolve `release_id` from the workflow input or from `releases/builder/build_*/HyperlinksSpaceProgramInstaller_*.exe`.
|
|
65
|
-
3. Check whether GitHub Release/tag already exists for that `release_id`.
|
|
66
|
-
4. If it exists:
|
|
67
|
-
- Exit successfully (`0`)
|
|
68
|
-
- Do not upload assets
|
|
69
|
-
- Do not send webhook notification
|
|
70
|
-
5. If it does not exist:
|
|
71
|
-
- Create GitHub Release/tag
|
|
72
|
-
- Upload `HyperlinksSpaceProgramInstaller.exe` as the release asset
|
|
73
|
-
- Continue to webhook notification
|
|
74
|
-
|
|
75
|
-
Recommended extra safety:
|
|
76
|
-
|
|
77
|
-
- Use workflow `concurrency` keyed by `release_id` to avoid race conditions.
|
|
78
|
-
|
|
79
|
-
## Endpoint Contract
|
|
80
|
-
|
|
81
|
-
- Webhook endpoint path: `api/releases.ts`
|
|
82
|
-
- Route URL: `POST /api/releases`
|
|
83
|
-
- Purpose: accept release-published events from GitHub Actions and fan out update notifications to app clients.
|
|
84
|
-
|
|
85
|
-
## Security
|
|
86
|
-
|
|
87
|
-
- GitHub Actions sends auth header:
|
|
88
|
-
- `x-release-token: <secret>`
|
|
89
|
-
- Endpoint validates against:
|
|
90
|
-
- `process.env.RELEASE_WEBHOOK_TOKEN`
|
|
91
|
-
- Optional hardening:
|
|
92
|
-
- Add HMAC signature verification for request body.
|
|
93
|
-
|
|
94
|
-
If auth fails:
|
|
95
|
-
|
|
96
|
-
- Return `401` and do not process payload.
|
|
97
|
-
|
|
98
|
-
## Payload Shape
|
|
99
|
-
|
|
100
|
-
`POST /api/releases` expects JSON:
|
|
101
|
-
|
|
102
|
-
```json
|
|
103
|
-
{
|
|
104
|
-
"release_id": "build_03252026_1929",
|
|
105
|
-
"version": "1.0.0",
|
|
106
|
-
"published_at": "2026-03-25T19:29:00Z",
|
|
107
|
-
"platform": "windows",
|
|
108
|
-
"assets": [
|
|
109
|
-
{
|
|
110
|
-
"name": "HyperlinksSpaceProgramInstaller.exe",
|
|
111
|
-
"url": "https://github.com/<org>/<repo>/releases/download/build_03252026_1929/HyperlinksSpaceProgramInstaller.exe",
|
|
112
|
-
"sha256": "<optional>"
|
|
113
|
-
}
|
|
114
|
-
],
|
|
115
|
-
"github_release_url": "https://github.com/<org>/<repo>/releases/tag/build_03252026_1929"
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Endpoint Behavior (`api/releases.ts`)
|
|
120
|
-
|
|
121
|
-
1. Accept only `POST`.
|
|
122
|
-
2. Validate auth token/signature.
|
|
123
|
-
3. Parse and validate required fields:
|
|
124
|
-
- `release_id`, `published_at`, `assets`.
|
|
125
|
-
4. Enforce idempotency by `release_id`:
|
|
126
|
-
- If already processed, return `200 { ok: true, duplicate: true }`.
|
|
127
|
-
5. Store/update latest release metadata in persistent storage.
|
|
128
|
-
6. Push update signal to clients (WebSocket/SSE/Firebase/Expo push).
|
|
129
|
-
7. Return quickly with `200 { ok: true }`.
|
|
130
|
-
|
|
131
|
-
## GitHub Actions Notification Step
|
|
132
|
-
|
|
133
|
-
After successful release creation and asset upload:
|
|
134
|
-
|
|
135
|
-
1. Read webhook URL and token from repository secrets:
|
|
136
|
-
- `RELEASE_WEBHOOK_URL`
|
|
137
|
-
- `RELEASE_WEBHOOK_TOKEN`
|
|
138
|
-
2. Send `POST` to `/api/releases` with release payload.
|
|
139
|
-
3. Retry webhook call with backoff on transient failures.
|
|
140
|
-
|
|
141
|
-
Important:
|
|
142
|
-
|
|
143
|
-
- Do not send webhook if release already existed (dedupe branch).
|
|
144
|
-
|
|
145
|
-
## App Update Strategy
|
|
146
|
-
|
|
147
|
-
Primary strategy:
|
|
148
|
-
|
|
149
|
-
- Real-time push signal from backend triggered by `/api/releases`.
|
|
150
|
-
|
|
151
|
-
Fallback strategy:
|
|
152
|
-
|
|
153
|
-
- App checks latest release on:
|
|
154
|
-
- app foreground/resume
|
|
155
|
-
- periodic interval (for example every 5-15 minutes)
|
|
156
|
-
|
|
157
|
-
Client behavior:
|
|
158
|
-
|
|
159
|
-
1. Compare local build/version with latest server metadata.
|
|
160
|
-
2. If newer exists:
|
|
161
|
-
- Show "Update available" prompt or trigger controlled update flow.
|
|
162
|
-
|
|
163
|
-
## Reliability and Observability
|
|
164
|
-
|
|
165
|
-
- Idempotent handling on `release_id`.
|
|
166
|
-
- Structured logs for each stage:
|
|
167
|
-
- detected -> published/skipped -> webhook sent -> app signal broadcast
|
|
168
|
-
- Alert on partial failure:
|
|
169
|
-
- release created but webhook failed
|
|
170
|
-
- Keep webhook processing fast and non-blocking for external calls.
|
|
171
|
-
|
|
172
|
-
## Rollout Plan
|
|
173
|
-
|
|
174
|
-
1. Deploy `api/releases.ts` in staging.
|
|
175
|
-
2. Run workflow in dry-run mode to validate folder parsing and dedupe checks.
|
|
176
|
-
3. Enable real release creation for test folder.
|
|
177
|
-
4. Enable webhook call to staging endpoint.
|
|
178
|
-
5. Verify end-to-end with one client device.
|
|
179
|
-
6. Promote to production after stable validation.
|
|
180
|
-
|
|
181
|
-
## Acceptance Criteria
|
|
182
|
-
|
|
183
|
-
- A new `releases/builder/build_.../` folder produces exactly one GitHub Release.
|
|
184
|
-
- Re-running workflow for the same `release_id` does not create duplicates.
|
|
185
|
-
- Webhook is called only for newly created releases.
|
|
186
|
-
- `POST /api/releases` rejects unauthorized requests.
|
|
187
|
-
- Connected app receives update signal near-instantly in normal conditions.
|
|
188
|
-
- Fallback polling still discovers updates if push delivery fails.
|
package/docs/scalability.md
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Scalability overview and challenges
|
|
2
|
-
|
|
3
|
-
**Stack:** Vercel serverless (webhook, API), Neon Postgres, Telegram bot (Grammy), OpenAI, single `messages` table for bot + TMA.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
- **Webhook:** Stateless. Returns 200 immediately; update is processed in `waitUntil`. No in-memory state between requests. Vercel scales out with traffic (more concurrent requests → more instances).
|
|
10
|
-
- **Bot:** One bot instance per serverless instance (module-level in webhook). No global singleton; fits serverless.
|
|
11
|
-
- **Dedupe / “only latest wins”:** Done in the DB (`telegram_update_id` unique constraint + `getMaxTelegramUpdateIdForThread`). Works across instances; no reliance on in-process state.
|
|
12
|
-
- **Messages:** One table, indexed by `(user_telegram, thread_id, type, created_at)` and unique on `(..., telegram_update_id)` for bot. Per-request load is small (insert user, get history, insert assistant, optional max-update-id read).
|
|
13
|
-
- **Database:** Neon with **connection pooling** already on (supports up to 10,000 concurrent connections). Use the pooled `DATABASE_URL` in Vercel so serverless invocations go through the pooler.
|
|
14
|
-
|
|
15
|
-
The design is horizontally scalable: more users → more invocations → more instances; no single bottleneck in the app logic.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## Challenges and what to do
|
|
20
|
-
|
|
21
|
-
| Area | Challenge | What to do |
|
|
22
|
-
|------|-----------|------------|
|
|
23
|
-
| **DB connections** | Pooling is already on (up to 10,000 concurrent connections). | Ensure `DATABASE_URL` in Vercel is the **pooled** connection string from Neon. |
|
|
24
|
-
| **OpenAI** | Limits are per key (RPM/TPM). One key can scale. | Raise **usage tier** (limits increase with spend/account age—e.g. Tier 4: 10k RPM, 2M TPM). Enterprise: **Scale Tier** for dedicated capacity. Optionally multiple keys or queue only if you need beyond tier limits. |
|
|
25
|
-
| **Vercel** | Hobby has invocation/duration limits; long AI flows need enough timeout. | Use Pro (or Enterprise) for production at scale; set function timeout to cover longest flow (e.g. streaming + DB). |
|
|
26
|
-
| **Messages table** | Grows with users and time; very large tables can slow queries and increase cost. | Retention (delete or archive old threads); optional partitioning by time or user; keep `getThreadHistory` with a small `limit`. |
|
|
27
|
-
| **Observability** | At scale, bottlenecks and errors are hard to see without metrics. | Logging, metrics, and alerts (errors, latency, DB pool usage, OpenAI rate limits) in Vercel/Neon or a third-party tool. |
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Summary
|
|
32
|
-
|
|
33
|
-
- **Scalable:** Stateless webhook, 200-first response, DB-backed dedupe and history, Neon connection pooling.
|
|
34
|
-
- **To scale to very high traffic:** Neon pooling is already on (10k connections); keep using the pooled `DATABASE_URL`. For OpenAI, extend plan/usage to reach a higher tier (or Scale Tier for enterprise); one key is enough. Plan for Vercel limits/timeouts; add message retention and monitoring.
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
# Security Implementation Plan (Telegram-First Wallet)
|
|
2
|
-
|
|
3
|
-
This file describes a practical implementation plan for the security model defined in `security.md`, focused on the repository-root Expo/Vercel codebase and a serverless backend.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Phase 0 – Prerequisites & Plumbing
|
|
8
|
-
|
|
9
|
-
- **0.1. Bot & Mini App configuration**
|
|
10
|
-
- Ensure main Mini App is configured in @BotFather with:
|
|
11
|
-
- `https://hsbexpo.vercel.app` (or new URL) as base.
|
|
12
|
-
- `startapp` support enabled.
|
|
13
|
-
- Confirm `telegram-web-app.js` is loaded in the Mini App shell.
|
|
14
|
-
|
|
15
|
-
- **0.2. Serverless backend basics**
|
|
16
|
-
- Use existing Vercel project (repository root) API routes:
|
|
17
|
-
- Create a shared util for **Telegram initData validation** (WebApp) in `api/_lib/telegram.ts`:
|
|
18
|
-
- `validateInitData(initData: string): { username: string }`.
|
|
19
|
-
- Create a shared util for **Telegram Login widget validation** (web/native) in `api/_lib/telegram_login.ts`:
|
|
20
|
-
- `validateLoginPayload(payload): { username: string }`.
|
|
21
|
-
|
|
22
|
-
- **0.3. Database**
|
|
23
|
-
- Choose a serverless DB (e.g. Neon, Supabase, PlanetScale, Vercel Postgres).
|
|
24
|
-
- Define tables (supporting **multiple wallets per user**, including app-created and TonConnect-linked):
|
|
25
|
-
- `users`:
|
|
26
|
-
- `telegram_username` (PK or unique, text).
|
|
27
|
-
- `created_at`, `updated_at`.
|
|
28
|
-
- `last_login_at` – last successful Telegram login (any platform).
|
|
29
|
-
- `last_tma_seen_at` – last time user opened the Mini App.
|
|
30
|
-
- `locale` – preferred language (derived from Telegram).
|
|
31
|
-
- `time_zone` (optional, from app settings).
|
|
32
|
-
- `number_of_wallets` – cached count for quick UI/query.
|
|
33
|
-
- `default_wallet` – optional reference/key to the user’s default wallet (e.g. `wallet_address` + `wallet_blockchain` + `wallet_net` tuple or UI identifier).
|
|
34
|
-
- `security_flags` (JSON) – e.g. `{ "high_value_user": true, "require_extra_confirm": false }`.
|
|
35
|
-
- `marketing_opt_in` (bool) – whether user agreed to non-transactional notifications.
|
|
36
|
-
- `wallets`:
|
|
37
|
-
- `telegram_username` (FK to `users`).
|
|
38
|
-
- `address` (text).
|
|
39
|
-
- `blockchain` (text, e.g. `'ton'`).
|
|
40
|
-
- `net` (text, e.g. `'mainnet'`, `'testnet'`).
|
|
41
|
-
- `type` (`'internal' | 'tonconnect' | 'other'`) – app-created vs external/connected.
|
|
42
|
-
- `label` (optional user-friendly name, e.g. “Main wallet”, “Tonkeeper”).
|
|
43
|
-
- `is_default` (bool) – which wallet to show first in UI.
|
|
44
|
-
- Composite PK/unique: (`telegram_username`, `wallet_address`, `wallet_blockchain`, `wallet_net`).
|
|
45
|
-
- `created_at` – when this wallet record was created (first seen / added).
|
|
46
|
-
- `updated_at` – when this wallet record was created (first seen / added).
|
|
47
|
-
- `last_used_at` – last time a transaction was initiated or confirmed with this wallet.
|
|
48
|
-
- `last_seen_balance_at` – last time we refreshed its on-chain balance
|
|
49
|
-
- `source` – 'miniapp', 'tonconnect', 'imported' (how it was added)
|
|
50
|
-
- `notes` – (optional text): free-form user note about this wallet.
|
|
51
|
-
- Timestamps / metadata (last_used_at, etc.).
|
|
52
|
-
- `pending_transactions`:
|
|
53
|
-
- `id` (UUID / text, PK).
|
|
54
|
-
- `telegram_username` (FK to `users`).
|
|
55
|
-
- `wallet_address` (text).
|
|
56
|
-
- `wallet_blockchain` (text).
|
|
57
|
-
- `wallet_net` (text).
|
|
58
|
-
- `payload` (JSONB / text).
|
|
59
|
-
- `status` (`pending | confirmed | rejected | failed`).
|
|
60
|
-
- `created_at`, `updated_at`.
|
|
61
|
-
- Add minimal DB client in `api/_lib/db.ts`.
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Phase 1 – Telegram Mini App: Wallet Creation & Device Auth
|
|
66
|
-
|
|
67
|
-
- **1.1. Mini App bootstrap**
|
|
68
|
-
- Create a dedicated Mini App entry screen in Expo web (`app/app/index.tsx` or a nested route) that:
|
|
69
|
-
- Accesses `window.Telegram.WebApp.initData`.
|
|
70
|
-
- Calls a backend endpoint `POST /api/tg/init` to:
|
|
71
|
-
- Validate `initData`.
|
|
72
|
-
- Upsert a bare `users` row if needed (without wallet).
|
|
73
|
-
|
|
74
|
-
- **1.2. Wallet creation flow (TMA)**
|
|
75
|
-
- Implement a React flow in the Mini App:
|
|
76
|
-
- Step 1: Intro + explanation (self-custody, seed phrase).
|
|
77
|
-
- Step 2: Generate mnemonic (client-side) with a TON/crypto library.
|
|
78
|
-
- Step 3: Show mnemonic & confirmation quiz.
|
|
79
|
-
- Step 4:
|
|
80
|
-
- Derive wallet master key from mnemonic.
|
|
81
|
-
- Store it via `Telegram.WebApp.SecureStorage.setItem('wallet_master_key', <key>)`.
|
|
82
|
-
- Derive/encode wallet seed or root key, encrypt with master key → `seed_cipher`.
|
|
83
|
-
- Store `seed_cipher` via `Telegram.WebApp.CloudStorage.setItem('wallet_seed_cipher', <cipher>)`.
|
|
84
|
-
- Derive `wallet_address` from mnemonic/root key.
|
|
85
|
-
- Call `POST /api/wallet/register` with `{ telegram_username, wallet_address }` (initData-validated).
|
|
86
|
-
- Step 5: Success screen explaining:
|
|
87
|
-
- “Wallet created in Telegram; keep your mnemonic safe.”
|
|
88
|
-
- “Use Android/iOS/web to view wallet after logging in with Telegram.”
|
|
89
|
-
|
|
90
|
-
- **1.3. New Telegram device authorization**
|
|
91
|
-
- At Mini App start:
|
|
92
|
-
- Check `SecureStorage.getItem('wallet_master_key')`.
|
|
93
|
-
- If present → user can operate without extra input.
|
|
94
|
-
- If absent but `CloudStorage.getItem('wallet_seed_cipher')` exists:
|
|
95
|
-
- Show “Authorize this device” screen:
|
|
96
|
-
- Prompt for mnemonic once.
|
|
97
|
-
- Derive new master key, store in `SecureStorage`.
|
|
98
|
-
- Optionally re-encrypt `seed_cipher` (or just reuse old one).
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Phase 2 – iOS/Android App Flow (Single App)
|
|
103
|
-
|
|
104
|
-
(All implemented in the repository root app using Expo Router / React Native.)
|
|
105
|
-
|
|
106
|
-
- **2.1. Local state**
|
|
107
|
-
- Add a simple secure storage wrapper (e.g. `expo-secure-store`):
|
|
108
|
-
- Keys:
|
|
109
|
-
- `telegram_username`
|
|
110
|
-
- `wallet_address`
|
|
111
|
-
- Add a React context or hook `useCurrentUser()` that:
|
|
112
|
-
- On app start, reads these keys.
|
|
113
|
-
- Exposes `state: 'anonymous' | 'linked'`, `telegram_username`, `wallet_address`.
|
|
114
|
-
|
|
115
|
-
- **2.2. “Log in with Telegram” screen**
|
|
116
|
-
- Create a route (e.g. `app/app/login/telegram.tsx`) used on mobile startup when `state === 'anonymous'`:
|
|
117
|
-
- Copy text from `security.md`:
|
|
118
|
-
- Explain benefits of Telegram-based wallet creation and storage.
|
|
119
|
-
- Buttons:
|
|
120
|
-
- **Open Telegram to create wallet**:
|
|
121
|
-
- Use `Linking.openURL('https://t.me/<bot_username>?startapp=wallet_onboarding')`.
|
|
122
|
-
- **I already created my wallet in Telegram / Log in with Telegram**:
|
|
123
|
-
- Opens a WebView or browser to hosted login page (e.g. `/login/telegram`).
|
|
124
|
-
|
|
125
|
-
- **2.3. Telegram Login for Websites (web page + API)**
|
|
126
|
-
- Create a web page (static route in repository root or separate) that:
|
|
127
|
-
- Embeds the Telegram Login widget configured for your bot & domain.
|
|
128
|
-
- On success, posts the payload (via `data-onauth` callback) to `POST /api/login/telegram`.
|
|
129
|
-
- `POST /api/login/telegram`:
|
|
130
|
-
- Validates login payload (`hash` + `auth_date`) per [Telegram widget docs](https://core.telegram.org/widgets/login).
|
|
131
|
-
- Extracts `username`.
|
|
132
|
-
- Looks up `users` by `telegram_username`.
|
|
133
|
-
- Responds with:
|
|
134
|
-
- On success: `{ telegram_username, wallet_address }`.
|
|
135
|
-
- On missing wallet: `{ error: 'NO_WALLET' }`.
|
|
136
|
-
- In the mobile WebView:
|
|
137
|
-
- When login completes, post a message back to the React Native layer with the above payload.
|
|
138
|
-
- Native side saves `telegram_username` + `wallet_address` via secure storage and updates `useCurrentUser()` state.
|
|
139
|
-
|
|
140
|
-
- **2.4. Main wallet UI on mobile**
|
|
141
|
-
- When `useCurrentUser()` reports `state === 'linked'`:
|
|
142
|
-
- Show wallet balances / positions (read-only) via:
|
|
143
|
-
- Direct chain APIs or your own serverless `GET /api/wallet/state?address=...`.
|
|
144
|
-
- For any **sensitive action** (swap, send, etc.) use the serverless + bot confirmation flow (Phase 3).
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## Phase 3 – Serverless Transaction Flow & Bot Confirmation
|
|
149
|
-
|
|
150
|
-
- **3.1. Create transaction (serverless route)**
|
|
151
|
-
- Add `POST /api/tx/create`:
|
|
152
|
-
- Auth:
|
|
153
|
-
- From Mini App: validate `initData`, resolve `telegram_username`.
|
|
154
|
-
- From web/mobile: require a session or signed JWT containing `telegram_username` from Telegram login.
|
|
155
|
-
- Validate payload (action, amount, destination).
|
|
156
|
-
- Insert into `pending_transactions` with status `pending`.
|
|
157
|
-
- Use bot token to call `sendMessage` with:
|
|
158
|
-
- Text summary.
|
|
159
|
-
- Inline `web_app` button pointing to `https://t.me/<bot_username>?startapp=tx_<id>`.
|
|
160
|
-
- Return `{ id }` to caller for polling.
|
|
161
|
-
|
|
162
|
-
- **3.2. Confirmation page in Mini App**
|
|
163
|
-
- Implement a `tx/[id]`-like route in the Mini App (or use `start_param` parsing on the main screen) that:
|
|
164
|
-
- Reads `start_param` → extracts `<id>`.
|
|
165
|
-
- Calls `GET /api/tx/<id>`:
|
|
166
|
-
- Validates `initData`, ensures tx belongs to `telegram_username`.
|
|
167
|
-
- Returns tx summary (read-only).
|
|
168
|
-
- UI:
|
|
169
|
-
- Shows:
|
|
170
|
-
- Asset, amount, from / to addresses, network, estimated fee.
|
|
171
|
-
- A big, unambiguous **“Confirm”** button and a **“Reject”** button.
|
|
172
|
-
|
|
173
|
-
- **3.3. Local signing & completion**
|
|
174
|
-
- On **Confirm**:
|
|
175
|
-
- Mini App:
|
|
176
|
-
- Reconstructs the on-chain transaction from the payload and `wallet_address`.
|
|
177
|
-
- Signs it with the wallet key derived from mnemonic / master key in `SecureStorage`.
|
|
178
|
-
- Sends `POST /api/tx/<id>/complete` with:
|
|
179
|
-
- `id`
|
|
180
|
-
- `signedTx` (or `txHash` if client broadcasts).
|
|
181
|
-
- `decision: 'confirmed'`.
|
|
182
|
-
- `POST /api/tx/<id>/complete`:
|
|
183
|
-
- Validates `initData` and ownership.
|
|
184
|
-
- Verifies tx is still `pending`.
|
|
185
|
-
- Option A (backend broadcasting):
|
|
186
|
-
- Broadcast `signedTx` to RPC endpoint.
|
|
187
|
-
- On success/failure, update `status` accordingly and store `tx_hash`.
|
|
188
|
-
- Option B (client broadcasting):
|
|
189
|
-
- Trust `txHash` and mark as `confirmed`, or perform lightweight verification.
|
|
190
|
-
- Returns final status to Mini App.
|
|
191
|
-
|
|
192
|
-
- **3.4. Rejection path**
|
|
193
|
-
- On **Reject**:
|
|
194
|
-
- Mini App calls `POST /api/tx/<id>/complete` with `decision: 'rejected'`.
|
|
195
|
-
- Backend sets status `rejected`.
|
|
196
|
-
|
|
197
|
-
- **3.5. Client status updating**
|
|
198
|
-
- Any client that initiated the tx (Mini App, web, mobile app):
|
|
199
|
-
- Polls `GET /api/tx/<id>` until `status !== 'pending'`.
|
|
200
|
-
- Or uses lightweight WebSocket/SSE if desired.
|
|
201
|
-
|
|
202
|
-
---
|
|
203
|
-
|
|
204
|
-
## Phase 4 – Hardening & Observability
|
|
205
|
-
|
|
206
|
-
- **4.1. Logging & audit**
|
|
207
|
-
- Add structured logging in all API routes:
|
|
208
|
-
- User identity (`telegram_username`), tx id, IP, user agent.
|
|
209
|
-
- Consider a `tx_history` view for user self-audits.
|
|
210
|
-
|
|
211
|
-
- **4.2. Rate limiting & abuse protection**
|
|
212
|
-
- Add rate limiting (IP + username) on:
|
|
213
|
-
- `/api/tx/create`
|
|
214
|
-
- `/api/login/telegram`
|
|
215
|
-
- Consider CAPTCHA or additional friction on spammy accounts.
|
|
216
|
-
|
|
217
|
-
- **4.3. Secrets & config**
|
|
218
|
-
- Store:
|
|
219
|
-
- Bot token, DB URL, RPC URLs, etc. in Vercel environment variables.
|
|
220
|
-
- Never log full mnemonics or keys; ensure any debug logging never prints sensitive values.
|
|
221
|
-
|
|
222
|
-
- **4.4. UX safety rails**
|
|
223
|
-
- On confirmation pages (Mini App & web):
|
|
224
|
-
- Highlight destination address and allow user to copy it.
|
|
225
|
-
- Show human-readable asset names & verify network.
|
|
226
|
-
- For large amounts, add extra confirmation step or warning.
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## Phase 5 – Optional Enhancements
|
|
231
|
-
|
|
232
|
-
- **5.1. Advanced local wallets (non-default)**
|
|
233
|
-
- In the mobile app and/or web app, optionally add:
|
|
234
|
-
- “Import mnemonic to this device” flow (explicit, with big warnings).
|
|
235
|
-
- Keep Telegram-first as the recommended path in docs and UI.
|
|
236
|
-
|
|
237
|
-
- **5.2. Multi-device / guardian support (future)**
|
|
238
|
-
- Extend smart contract / wallet to support multiple keys or social recovery.
|
|
239
|
-
- Use Telegram as one guardian channel among others.
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
This plan should be implemented iteratively: Phase 1 (Mini App wallet), Phase 2 (mobile login shell), Phase 3 (serverless tx + confirmations), then hardening and enhancements. Each step can be validated independently (unit tests on API routes, manual testing in TMA, Expo mobile, and web).
|
|
244
|
-
|